pep_tune.c
changeset 29 23fa36d480fb
child 30 a66ed0454ca8
equal deleted inserted replaced
28:c035fbbab184 29:23fa36d480fb
       
     1 
       
     2 /* Copyright 2009-2012 Myhailo Danylenko
       
     3  *
       
     4  * This file is part of mcabber-pep
       
     5  *
       
     6  * mcabber-pep is free software: you can redistribute it and/or modify
       
     7  * it under the terms of the GNU General Public License as published by
       
     8  * the Free Software Foundation, either version 2 of the License, or
       
     9  * (at your option) any later version.
       
    10  *
       
    11  * This program is distributed in the hope that it will be useful,
       
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    14  * GNU General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU General Public License
       
    17  * along with this program.  If not, see <http://www.gnu.org/licenses/>. */
       
    18 
       
    19 #include <glib.h>
       
    20 #include <loudmouth/loudmouth.h>
       
    21 #include <stdlib.h>                 // atoi
       
    22 #include <time.h>
       
    23 
       
    24 #include <mcabber/settings.h>
       
    25 #include <mcabber/utils.h>
       
    26 #include <mcabber/xmpp.h>
       
    27 #include <mcabber/xmpp_helper.h>
       
    28 #include <mcabber/logprint.h>
       
    29 #include <mcabber/hooks.h>
       
    30 #include <mcabber/modules.h>
       
    31 
       
    32 #include "pep.h"
       
    33 #include "tune.h"
       
    34 
       
    35 #include "config.h"
       
    36 
       
    37 //
       
    38 //  module description
       
    39 //
       
    40 
       
    41 void pep_tune_init   (void);
       
    42 void pep_tune_uninit (void);
       
    43 
       
    44 #define DESCRIPTION ( \
       
    45 	"PEP tune event handler\n" \
       
    46 	"Recognizes option tune_interval" )
       
    47 
       
    48 static const gchar *deps[] = { "pep", NULL };
       
    49 
       
    50 static module_info_t info_tune_dev = {
       
    51 	.branch      = "dev",
       
    52 	.api         = 20,
       
    53 	.version     = PROJECT_VERSION,
       
    54 	.description = DESCRIPTION,
       
    55 	.requires    = deps,
       
    56 	.init        = pep_tune_init,
       
    57 	.uninit      = pep_tune_uninit,
       
    58 	.next        = NULL,
       
    59 };
       
    60 
       
    61 static module_info_t info_tune_0_10_0 = {
       
    62 	.branch      = "0.10.0",
       
    63 	.api         = 1,
       
    64 	.version     = PROJECT_VERSION,
       
    65 	.description = DESCRIPTION,
       
    66 	.requires    = deps,
       
    67 	.init        = pep_tune_init,
       
    68 	.uninit      = pep_tune_uninit,
       
    69 	.next        = &info_tune_dev,
       
    70 };
       
    71 
       
    72 module_info_t info_pep_tune = {
       
    73 	.branch      = "0.10.1",
       
    74 	.api         = 1,
       
    75 	.version     = PROJECT_VERSION,
       
    76 	.description = DESCRIPTION,
       
    77 	.requires    = deps,
       
    78 	.init        = pep_tune_init,
       
    79 	.uninit      = pep_tune_uninit,
       
    80 	.next        = &info_tune_0_10_0,
       
    81 };
       
    82 
       
    83 //
       
    84 //  globals
       
    85 //
       
    86 
       
    87 #define MAX_NO ( 6 )
       
    88 
       
    89 static tune_pair_t info[] = {
       
    90 	{ "artist", NULL },
       
    91 	{ "length", NULL },
       
    92 	{ "rating", NULL },
       
    93 	{ "source", NULL },
       
    94 	{ "title",  NULL },
       
    95 	{ "track",  NULL },
       
    96 	{ "uri",    NULL },
       
    97 	{ NULL,     NULL },
       
    98 };
       
    99 
       
   100 static GQuark            tune_gerror_quark    = 0;
       
   101 static gboolean          publish_delayed      = FALSE;
       
   102 static guint             tune_hid_connect     = 0;
       
   103 static guint             tune_hid_disconnect  = 0;
       
   104 static guint             tune_hid_tuneout     = 0;
       
   105 static guint             tune_interval        = 0;
       
   106 static time_t            tune_timestamp       = 0;
       
   107 static LmMessageHandler *tune_reply_handler   = NULL;
       
   108 static guint             tune_source          = 0;
       
   109 static gboolean          tune_guard_installed = FALSE;
       
   110 
       
   111 //
       
   112 //  predeclarations
       
   113 //
       
   114 
       
   115 static void tune_publish_info (void);
       
   116 
       
   117 //
       
   118 //  code
       
   119 //
       
   120 
       
   121 static LmHandlerResult tune_publish_reply_handler (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer userdata)
       
   122 {
       
   123 	switch (lm_message_get_sub_type (message)) {
       
   124 	case LM_MESSAGE_SUB_TYPE_RESULT:
       
   125 		break;
       
   126 	
       
   127 	case LM_MESSAGE_SUB_TYPE_ERROR:
       
   128 		
       
   129 		{
       
   130 			LmMessageNode *node   = lm_message_get_node (message);
       
   131 			const gchar   *type;
       
   132 			const gchar   *reason;
       
   133 
       
   134 			node = lm_message_node_get_child (node, "error");
       
   135 			type = lm_message_node_get_attribute (node, "type");
       
   136 			if (node->children)
       
   137 				reason = node->children->name;
       
   138 			else
       
   139 				reason = "undefined";
       
   140 
       
   141 			scr_log_print (LPRINT_LOGNORM, "tune: Publish failed: %s - %s", type, reason);
       
   142 		}
       
   143 
       
   144 		break;
       
   145 	
       
   146 	default:
       
   147 		return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
   148 		break;
       
   149 	}
       
   150 
       
   151 	return LM_HANDLER_RESULT_REMOVE_MESSAGE;
       
   152 }
       
   153 
       
   154 static gboolean tune_delayed_publish_cb (gpointer data)
       
   155 {
       
   156 	tune_source = 0;
       
   157 	tune_publish_info ();
       
   158 	return FALSE;
       
   159 }
       
   160 
       
   161 static void tune_publish_info (void)
       
   162 {
       
   163 	if (!xmpp_is_online ()) {
       
   164 		scr_log_print (LPRINT_DEBUG, "tune: Not online, delaying publish.");
       
   165 		publish_delayed = TRUE;
       
   166 		return;
       
   167 	}
       
   168 
       
   169 	// check for frequency of publihes
       
   170 	if (tune_interval) {
       
   171 		time_t now = time (NULL);
       
   172 
       
   173 		if (now - tune_timestamp < tune_interval) {
       
   174 
       
   175 			scr_log_print (LPRINT_DEBUG, "tune: Publish interval not passed, delaying publish.");
       
   176 			if (!tune_source)
       
   177 				tune_source = g_timeout_add_seconds ( tune_interval - ( now - tune_timestamp ), tune_delayed_publish_cb, NULL );
       
   178 			return;
       
   179 
       
   180 		} else
       
   181 			tune_timestamp = now;
       
   182 	}
       
   183 
       
   184 	// publish
       
   185 	LmMessage     *request = lm_message_new_with_sub_type (NULL, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET);
       
   186 	LmMessageNode *node    = lm_message_get_node (request);
       
   187 	lm_message_node_set_attribute (node, "from", lm_connection_get_jid (lconnection));
       
   188 
       
   189 	node = lm_message_node_add_child (node, "pubsub", NULL);
       
   190 	lm_message_node_set_attribute (node, "xmlns", NS_PUBSUB);
       
   191 
       
   192 	node = lm_message_node_add_child (node, "publish", NULL);
       
   193 	lm_message_node_set_attribute (node, "node", NS_TUNE);
       
   194 
       
   195 	node = lm_message_node_add_child (node, "item", NULL);
       
   196 
       
   197 	node = lm_message_node_add_child (node, "tune", NULL);
       
   198 	lm_message_node_set_attribute (node, "xmlns", NS_TUNE);
       
   199 
       
   200 	{ // put data inside
       
   201 		int i;
       
   202 
       
   203 		for (i = 0; i <= MAX_NO; ++i)
       
   204 			if (info[i].value)
       
   205 				lm_message_node_add_child (node, info[i].name, info[i].value);
       
   206 	}
       
   207 
       
   208 	{ // send
       
   209 		GError *error = NULL;
       
   210 
       
   211 		lm_connection_send_with_reply (lconnection, request, tune_reply_handler, &error);
       
   212 
       
   213 		if (error) {
       
   214 			scr_log_print (LPRINT_DEBUG, "tune: Publishing error: %s.", error -> message);
       
   215 			g_error_free (error);
       
   216 		}
       
   217 	}
       
   218 
       
   219 	lm_message_unref (request);
       
   220 }
       
   221 
       
   222 void tune_publish (const tune_pair_t *pairs)
       
   223 {
       
   224 	gboolean           publish    = FALSE;
       
   225 	const tune_pair_t *tag;
       
   226 	tune_pair_t        new_info[] = {
       
   227 		{ "artist", NULL },
       
   228 		{ "length", NULL },
       
   229 		{ "rating", NULL },
       
   230 		{ "source", NULL },
       
   231 		{ "title",  NULL },
       
   232 		{ "track",  NULL },
       
   233 		{ "uri",    NULL },
       
   234 		{ NULL,     NULL },
       
   235 	};
       
   236 
       
   237 	// populate new_info with new values
       
   238 	for (tag = pairs; tag->name; ++tag) {
       
   239 		int i;
       
   240 		for (i = 0; i <= MAX_NO; ++i)
       
   241 			if (!g_strcmp0 (tag->name, new_info[i].name))
       
   242 				new_info[i].value = tag->value;
       
   243 	}
       
   244 
       
   245 	{ // check, if it differ from info
       
   246 		int i;
       
   247 		for (i = 0; i <= MAX_NO; ++i)
       
   248 			if (g_strcmp0 (new_info[i].value, info[i].value)) {
       
   249 				publish = TRUE;
       
   250 				break;
       
   251 			}
       
   252 	}
       
   253 
       
   254 	if (publish) {
       
   255 
       
   256 		{ // copy new values to info
       
   257 			int i;
       
   258 			for (i = 0; i <= MAX_NO; ++i) {
       
   259 				if (info[i].value)
       
   260 					g_free (info[i].value);
       
   261 				info[i].value = g_strdup (new_info[i].value);
       
   262 			}
       
   263 		}
       
   264 
       
   265 		tune_publish_info ();
       
   266 	}
       
   267 }
       
   268 
       
   269 gboolean tune_request ( const gchar *to, GError **err )
       
   270 {
       
   271 	LmMessage *request;
       
   272 	LmMessageNode *node;
       
   273 
       
   274 	if (!xmpp_is_online ()) {
       
   275 		g_set_error ( err, tune_gerror_quark, TUNE_ERROR_NOTCONNECTED, "You are not connected" );
       
   276 		return FALSE;
       
   277 	}
       
   278 
       
   279 	request = lm_message_new_with_sub_type ( to, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET );
       
   280 	node = lm_message_get_node (request);
       
   281 	lm_message_node_set_attribute (node, "from", lm_connection_get_jid (lconnection));
       
   282 
       
   283 	node = lm_message_node_add_child (node, "pubsub", NULL);
       
   284 	lm_message_node_set_attribute (node, "xmlns", NS_PUBSUB);
       
   285 
       
   286 	node = lm_message_node_add_child (node, "items", NULL);
       
   287 	lm_message_node_set_attribute (node, "node", NS_TUNE);
       
   288 
       
   289 	{ // send, result will be handled by pep
       
   290 		GError *error = NULL;
       
   291 
       
   292 		lm_connection_send ( lconnection, request, &error );
       
   293 
       
   294 		if ( error ) {
       
   295 			g_propagate_error ( err, error );
       
   296 			return FALSE;
       
   297 		}
       
   298 	}
       
   299 
       
   300 	lm_message_unref (request);
       
   301 
       
   302 	return TRUE;
       
   303 }
       
   304 
       
   305 static void tune_handler ( const gchar *from, const gchar *node, LmMessageNode *n, const gchar *id, gpointer ignore )
       
   306 {
       
   307 	LmMessageNode *tag;
       
   308 	hk_arg_t args[] = {
       
   309 		{ "artist", NULL },
       
   310 		{ "length", NULL },
       
   311 		{ "rating", NULL },
       
   312 		{ "source", NULL },
       
   313 		{ "title",  NULL },
       
   314 		{ "track",  NULL },
       
   315 		{ "uri",    NULL },
       
   316 		{ "from",   from },
       
   317 		{ NULL,     NULL },
       
   318 	};
       
   319 
       
   320 	for ( tag = n -> children; tag; tag = tag -> next ) {
       
   321 		const gchar *name  = tag -> name;
       
   322 		if ( name ) {
       
   323 			int i;
       
   324 			for ( i = 0; i <= MAX_NO; ++i )
       
   325 				if ( ! g_strcmp0 ( name, args[i].name ) ) {
       
   326 					const gchar *value = lm_message_node_get_value ( tag );
       
   327 					if ( value )
       
   328 						args[i].value = value;
       
   329 				}
       
   330 		}
       
   331 	}
       
   332 
       
   333 	hk_run_handlers ( HOOK_TUNE_IN, args );
       
   334 }
       
   335 
       
   336 static guint tune_hch (const gchar *htype, hk_arg_t *args, gpointer udata)
       
   337 {
       
   338 	if (publish_delayed) {
       
   339 		scr_log_print (LPRINT_DEBUG, "tune: Publishing delayed data.");
       
   340 
       
   341 		publish_delayed = FALSE;
       
   342 		tune_publish_info ();
       
   343 	}
       
   344 
       
   345 	return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
   346 }
       
   347 
       
   348 static guint tune_hdh (const gchar *htype, hk_arg_t *args, gpointer udata)
       
   349 {
       
   350 #ifdef HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER
       
   351 	if (lconnection && tune_reply_handler)
       
   352 		lm_connection_unregister_reply_handler (lconnection, tune_reply_handler);
       
   353 #endif
       
   354 
       
   355 	return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
   356 }
       
   357 
       
   358 static guint tune_htoh ( const gchar *htype, hk_arg_t *args, gpointer udata )
       
   359 {
       
   360 	tune_publish ( (const tune_pair_t *) args );
       
   361 	return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
   362 }
       
   363 
       
   364 static gchar *tune_guard (const char *key, const char *new_value)
       
   365 {
       
   366 	if (new_value)
       
   367 		tune_interval = atoi (new_value);
       
   368 	else
       
   369 		tune_interval = 0;
       
   370 
       
   371 	if (tune_source) {
       
   372 		g_source_remove (tune_source);
       
   373 		tune_source = 0;
       
   374 		// this will reinstall source with proper timeout, if necessary
       
   375 		tune_publish_info ();
       
   376 	}
       
   377 
       
   378 	return g_strdup (new_value);
       
   379 }
       
   380 
       
   381 void pep_tune_init(void)
       
   382 {
       
   383 	tune_gerror_quark = g_quark_from_string ( "pep-tune-gerror-quark" );
       
   384 
       
   385 	tune_interval = settings_opt_get_int ("tune_interval");
       
   386 
       
   387 	tune_guard_installed = settings_set_guard ("tune_interval", tune_guard);
       
   388 	if (!tune_guard_installed)
       
   389 		scr_log_print (LPRINT_LOGNORM, "tune: Warning: cannot install option guard for 'tune_interval'");
       
   390 
       
   391 	pep_register_xmlns_handler (NS_TUNE, tune_handler, NULL, NULL);
       
   392 
       
   393 	tune_reply_handler = lm_message_handler_new ( tune_publish_reply_handler, NULL, NULL );
       
   394 
       
   395 	tune_hid_connect    = hk_add_handler ( tune_hch,  HOOK_POST_CONNECT, G_PRIORITY_DEFAULT, NULL );
       
   396 	tune_hid_disconnect = hk_add_handler ( tune_hdh,  HOOK_PRE_DISCONNECT, G_PRIORITY_DEFAULT, NULL );
       
   397 	tune_hid_tuneout    = hk_add_handler ( tune_htoh, HOOK_TUNE_OUT, G_PRIORITY_DEFAULT, NULL );
       
   398 
       
   399 	xmpp_add_feature ( NS_TUNE        );
       
   400 	xmpp_add_feature ( NS_TUNE_NOTIFY );
       
   401 }
       
   402 
       
   403 void pep_tune_uninit ( void )
       
   404 {
       
   405 	xmpp_del_feature ( NS_TUNE        );
       
   406 	xmpp_del_feature ( NS_TUNE_NOTIFY );
       
   407 
       
   408 	hk_del_handler ( HOOK_POST_CONNECT,   tune_hid_connect );
       
   409 	hk_del_handler ( HOOK_PRE_DISCONNECT, tune_hid_disconnect );
       
   410 	hk_del_handler ( HOOK_TUNE_OUT,       tune_hid_tuneout );
       
   411 
       
   412 	if ( tune_source )
       
   413 		g_source_remove ( tune_source );
       
   414 
       
   415 	pep_unregister_xmlns_handler ( NS_TUNE );
       
   416 
       
   417 	if ( tune_reply_handler ) {
       
   418 #ifdef HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER
       
   419 		if ( lconnection )
       
   420 			lm_connection_unregister_reply_handler ( lconnection, tune_reply_handler  );
       
   421 #endif
       
   422 
       
   423 		lm_message_handler_invalidate ( tune_reply_handler );
       
   424 		lm_message_handler_unref ( tune_reply_handler );
       
   425 	}
       
   426 
       
   427 	{
       
   428 		int i;
       
   429 		for ( i = 0; i <= MAX_NO; i ++ )
       
   430 			g_free ( info[i].value );
       
   431 	}
       
   432 
       
   433 	if ( tune_guard_installed )
       
   434 		settings_del_guard ( "tune_interval" );
       
   435 }
       
   436 
       
   437 /* vim: se ts=4 sw=4: */