Merge pep modules & use events
* merge mood, tune, activity, geoloc, avatar
* split them into functionality/ui
* tune, geoloc: fix timeout bug
* geoloc: fix guard unregistering
* tune, mood: fix memleaking delayed info
* mood: fix non-publish of offline-delayed data
* activity: unregister reply handler on disconnect
* fix silly copyright typo
* update hgignore
* v0.0.3
--- a/.hgignore Wed Jun 29 19:25:16 2011 +0300
+++ b/.hgignore Sun May 20 22:15:51 2012 +0300
@@ -1,25 +1,7 @@
-# ignore generated by libtool files (no more necessary)
-.*\.a
-.*\.o
-.*\.lo
-.*\.la
-.*\.so
-.*\.lai
-.*\.so\..*
# ignore backup files
-.*~
-# ignore docs: they are not important and apiref is generated on the fly
-.*\.html
-# ignore generated makefile
-Makefile
-# ignore cmake files
-.*\.cmake
-CMake.*
-CPack.*
-# ignore generated header
-config\.h
-# ignore resulting bundles
-.*\.deb
-.*\.tar\.bz2
+~$
+\.swp$
+\.orig$
+\.rej$
# ignore build dir
-build
+^build$
--- a/CMakeLists.txt Wed Jun 29 19:25:16 2011 +0300
+++ b/CMakeLists.txt Sun May 20 22:15:51 2012 +0300
@@ -16,7 +16,7 @@
cmake_minimum_required(VERSION 2.6)
project(pep C)
-set(PROJECT_VERSION "0.0.1")
+set(PROJECT_VERSION "0.0.3")
## User settable options
@@ -25,31 +25,61 @@
pkg_check_modules(GLIB REQUIRED glib-2.0)
pkg_check_modules(LM REQUIRED loudmouth-1.0)
pkg_check_modules(MCABBER REQUIRED mcabber)
+include(CheckSymbolExists)
+set(CMAKE_REQUIRED_INCLUDES ${LM_INCLUDE_DIRS})
+set(CMAKE_REQUIRED_LIBRARIES ${LM_LIBRARIES})
+set(CMAKE_REQUIRED_FLAGS ${LM_LDFLAGS} ${LM_CFLAGS})
+check_symbol_exists(lm_connection_unregister_reply_handler loudmouth/loudmouth.h HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER)
link_directories(${GLIB_LIBRARY_DIRS}
${LM_LIBRARY_DIRS}
${MCABBER_LIBRARY_DIRS})
## Target definitions
-add_library(pep MODULE pep.c)
+add_library(pep MODULE pep.c pep.h)
+add_library(mood MODULE mood.c mood.h)
+add_library(pep_mood MODULE pep_mood.c mood.h pep.h)
+add_library(tune MODULE tune.c tune.h)
+add_library(pep_tune MODULE pep_tune.c tune.h pep.h)
+add_library(geoloc MODULE geoloc.c geoloc.h)
+add_library(pep_geoloc MODULE pep_geoloc.c geoloc.h pep.h)
+add_library(activity MODULE activity.c activity.h)
+add_library(pep_activity MODULE pep_activity.c activity.h pep.h)
## Compiler setup
+if(DEBUG)
+ set(DEBUG_COMPILE_FLAGS "-g")
+endif()
configure_file(config.h.in config.h)
include_directories(SYSTEM ${GLIB_INCLUDE_DIRS}
${LM_INCLUDE_DIRS}
${MCABBER_INCLUDE_DIRS})
-target_link_libraries(pep ${GLIB_LIBRARIES}
- ${LM_LIBRARIES}
- ${MCABBER_LIBRARIES})
+target_link_libraries(pep ${GLIB_LIBRARIES} ${LM_LIBRARIES} ${MCABBER_LIBRARIES})
+target_link_libraries(mood ${GLIB_LIBRARIES} ${MCABBER_LIBRARIES})
+target_link_libraries(pep_mood ${GLIB_LIBRARIES} ${LM_LIBRARIES} ${MCABBER_LIBRARIES})
+target_link_libraries(tune ${GLIB_LIBRARIES} ${MCABBER_LIBRARIES})
+target_link_libraries(pep_tune ${GLIB_LIBRARIES} ${LM_LIBRARIES} ${MCABBER_LIBRARIES})
+target_link_libraries(geoloc ${GLIB_LIBRARIES} ${MCABBER_LIBRARIES})
+target_link_libraries(pep_geoloc ${GLIB_LIBRARIES} ${LM_LIBRARIES} ${MCABBER_LIBRARIES})
+target_link_libraries(activity ${GLIB_LIBRARIES} ${MCABBER_LIBRARIES})
+target_link_libraries(pep_activity ${GLIB_LIBRARIES} ${LM_LIBRARIES} ${MCABBER_LIBRARIES})
include_directories(${pep_SOURCE_DIR}
${pep_BINARY_DIR})
-set_target_properties(pep PROPERTIES COMPILE_FLAGS "-Wall")
+set_target_properties(pep PROPERTIES COMPILE_FLAGS "-Wall ${DEBUG_COMPILE_FLAGS}")
+set_target_properties(mood PROPERTIES COMPILE_FLAGS "-Wall ${DEBUG_COMPILE_FLAGS}")
+set_target_properties(pep_mood PROPERTIES COMPILE_FLAGS "-Wall ${DEBUG_COMPILE_FLAGS}")
+set_target_properties(tune PROPERTIES COMPILE_FLAGS "-Wall ${DEBUG_COMPILE_FLAGS}")
+set_target_properties(pep_tune PROPERTIES COMPILE_FLAGS "-Wall ${DEBUG_COMPILE_FLAGS}")
+set_target_properties(geoloc PROPERTIES COMPILE_FLAGS "-Wall ${DEBUG_COMPILE_FLAGS}")
+set_target_properties(pep_geoloc PROPERTIES COMPILE_FLAGS "-Wall ${DEBUG_COMPILE_FLAGS}")
+set_target_properties(activity PROPERTIES COMPILE_FLAGS "-Wall ${DEBUG_COMPILE_FLAGS}")
+set_target_properties(pep_activity PROPERTIES COMPILE_FLAGS "-Wall ${DEBUG_COMPILE_FLAGS}")
## Packaging information
set(CPACK_PACKAGE_NAME libmcabber-pep)
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
set(CPACK_PACKAGE_VENDOR "IsBear")
set(CPACK_PACKAGE_CONTACT "Myhailo Danylenko <isbear@ukrpost.net>")
-set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Common PEP listener module")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "PEP modules")
set(CPACK_RESOURCE_FILE_LICENSE ${pep_SOURCE_DIR}/COPYING)
set(CPACK_SOURCE_GENERATOR TBZ2)
set(CPACK_GENERATOR DEB CACHE TEXT "Binary package generator, eg DEB, RPM, TGZ, NSIS...")
@@ -64,12 +94,22 @@
set(CPACK_SOURCE_IGNORE_FILES "/\\\\..*;\\\\.swp;~$;/build/;\\\\.tar\\\\.;\\\\.deb;\\\\.so")
include(CPack)
-configure_file(pep.avv.in pep.avv)
+configure_file(avv/pep.in avv/pep)
+configure_file(avv/mood.in avv/mood)
+configure_file(avv/pep_mood.in avv/pep_mood)
+configure_file(avv/tune.in avv/tune)
+configure_file(avv/pep_tune.in avv/pep_tune)
+configure_file(avv/geoloc.in avv/geoloc)
+configure_file(avv/pep_geoloc.in avv/pep_geoloc)
+configure_file(avv/activity.in avv/activity)
+configure_file(avv/pep_activity.in avv/pep_activity)
## Installation
-install(TARGETS pep DESTINATION lib/mcabber)
+install(TARGETS pep mood pep_mood tune pep_tune geoloc pep_geoloc activity pep_activity DESTINATION lib/mcabber)
install(FILES pep.rc COPYING TODO README DESTINATION share/doc/${CPACK_PACKAGE_NAME})
-install(FILES pep.h DESTINATION include/mcabber)
-install(FILES ${PROJECT_BINARY_DIR}/pep.avv DESTINATION share/mcabber/avv/modules RENAME pep)
+install(DIRECTORY doc/ DESTINATION share/doc/${CPACK_PACKAGE_NAME})
+install(FILES pep.h mood.h tune.h geoloc.h activity.h DESTINATION include/mcabber)
+install(DIRECTORY help DESTINATION share/mcabber)
+install(DIRECTORY ${PROJECT_BINARY_DIR}/avv/ DESTINATION share/mcabber/avv/modules)
## The End ## vim: se ts=4: ##
--- a/README Wed Jun 29 19:25:16 2011 +0300
+++ b/README Sun May 20 22:15:51 2012 +0300
@@ -1,11 +1,41 @@
-This is a pep module for mcabber. It just provides common message
-listener for other modules like tune, avatar etc.
+# Personal Eventing Protocol modules
+
+This is a set of modules, that provide notfication about other's events
+and allow you to publish yours.
+
+Pep module provides common listener for incoming PEP events.
+
+Tune module provides '/tune' command to publish music, you are listening
+to at the moment. However, it does not by itself does that. You'll need
+some other module, that will provide music information, like 'mpd' one.
+Alternatively, you can set up some scripts to publish information with
+'/tune' command via fifo.
+
+Mood module provides '/mood' command to publish your current mood.
+Currently it does not check for validity of its input, so, it's strongly
+suggested to use provided completion for first argument.
-This module have no options, and generally should be loaded
-automatically by other modules.
+Geoloc module provides '/geoloc' command to publish your current location.
+Currently, there are no known use cases of this module, but I hope, that
+someday there will be a module, that will retrieve geolocation information
+from devices and use this module to publish it.
+
+Activity module provides '/activity' command to publish your current activity.
+Currently it does not check for validity of its input either, so, please
+use completion for first two arguments.
-INSTALLATION
+Note: In order for you to actually publish something, your server must
+support PEP, and that is still not that widely available. Still, even
+if your server does not, you can load modules to be notified about your
+buddies events.
+
+All of the modules also provide C headers for other C modules to use
+to publish data. Note, however, that I plan to switch to events interface
+for that - it provides multiplexing ability, and in general is more
+flexible.
+
+# Installation
To install it, you need:
cmake
@@ -30,16 +60,15 @@
Users of other distributions can select appropriate package
generator, using cache editor.
-LICENSE
+# License
This code underlies terms of GNU GPL v2 or later. You can find it in file COPYING
from this distribution or on a GNU web-site <http://www.gnu.org/licenses/>.
-CONTACTS
+# Contacts
I will be happy to get feedback, patches, suggestions, etc.
You can send me email or contact via jabber <isbear@unixzone.org.ua>.
-- Myhailo Danylenko <isbear@ukrpost.net>
-
--- a/TODO Wed Jun 29 19:25:16 2011 +0300
+++ b/TODO Sun May 20 22:15:51 2012 +0300
@@ -1,5 +1,17 @@
-do we need to export functions in some special way?
-startup/shutdown hook to inform other modules, that they should free/register handlers?
-due to server bugs, some offline buddies are still notified on publication, causing error reply, that pep accepts as event. check message type/presence of error tag.
+* due to server bugs, some offline buddies are still notified on publication,
+ causing error reply, that pep accepts as event. check message type/presence of error tag.
+* do something about information duplication in CMakeLists
+* check input/output for validity, where applicable
+* extract common code into one place
+* either put request methods into ui modules (compatibility measure) or rename them into pep_*
+* add avatar
+ * pep_avatar, avatar_cache, avatar, aavatar (separate)
+ * hook_avatar_metadata_in @ pep_avatar
+ | hook_avatar_need_data_in (or symbol-resolved request) @ avatar_cache
+ V hook_avatar_data_in @ pep_avatar
+ hook_avatar_in @ avatar_cache
+ * (!!!) how to handle outgoing event? what and where should do what?
+ * handle url avatars (curl)
+ * report absence of avatar
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/activity.c Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,330 @@
+/*
+ * activity.c -- Pep activity events
+ *
+ * Copyright (C) 2009-2012 Myhailo Danylenko <isbear@ukrpost.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <glib.h>
+#include <string.h>
+
+#include <mcabber/utils.h>
+#include <mcabber/screen.h>
+#include <mcabber/logprint.h>
+#include <mcabber/hbuf.h> // HBUF_PREFIX_*
+#include <mcabber/roster.h>
+#include <mcabber/hooks.h>
+#include <mcabber/commands.h>
+#include <mcabber/compl.h>
+#include <mcabber/modules.h>
+
+#include "activity.h"
+
+#include "config.h"
+
+//
+// module description
+//
+
+void activity_init (void);
+void activity_uninit (void);
+
+#define DESCRIPTION ( "PEP activity support\nProvides command /activity" )
+static const gchar *deps[] = { "pep_activity", NULL };
+
+static module_info_t info_activity_dev = {
+ .branch = "dev",
+ .api = 20,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = activity_init,
+ .uninit = activity_uninit,
+ .next = NULL,
+};
+
+static module_info_t info_activity_0_10_1 = {
+ .branch = "0.10.1",
+ .api = 1,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = activity_init,
+ .uninit = activity_uninit,
+ .next = &info_activity_dev,
+};
+
+module_info_t info_activity = {
+ .branch = "0.10.0",
+ .api = 1,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = activity_init,
+ .uninit = activity_uninit,
+ .next = &info_activity_0_10_1,
+};
+
+//
+// globals
+//
+
+#ifdef MCABBER_API_HAVE_CMD_ID
+static gpointer activity_cmid = NULL;
+static gboolean activity_set_safe = FALSE;
+#endif
+
+static guint activity_cid1 = 0;
+static guint activity_cid2 = 0;
+static guint activity_hid_activityin = 0;
+
+//
+// code
+//
+
+static void do_activity (char *arg)
+{
+ if (!*arg) { // request
+
+ GError *error = NULL;
+
+ activity_request ( CURRENT_JID, &error );
+ if ( error ) {
+ scr_log_print ( LPRINT_NORMAL, "Error sending request: %s.", error -> message );
+ g_error_free ( error );
+ } else
+ scr_log_print ( LPRINT_NORMAL, "Request sent." );
+
+ } else { // publish
+
+ hk_arg_t hookargs[] = {
+ { "major", NULL },
+ { "minor", NULL },
+ { "text", NULL },
+ { NULL, NULL },
+ };
+
+ if ( arg[0] != '-' || arg[1] != '\0' ) {
+ gchar **args = split_arg ( arg, 3, 1 );
+
+ hookargs[0].value = to_utf8 ( args[0] );
+
+ if ( args[1] ) {
+ if ( args[1][0] != '-' || args[1][1] != '\0' )
+ hookargs[1].value = to_utf8 ( args[1] );
+
+ if ( args[2] )
+ hookargs[2].value = to_utf8 ( args[2] );
+ }
+
+ free_arg_lst ( args );
+ }
+
+ hk_run_handlers ( HOOK_ACTIVITY_OUT, hookargs );
+
+ g_free ( (gchar *) hookargs[0].value );
+ g_free ( (gchar *) hookargs[1].value );
+ g_free ( (gchar *) hookargs[2].value );
+ }
+}
+
+static guint activity_haih ( const gchar *hid, hk_arg_t *args, gpointer userdata )
+{
+ const gchar *from = NULL;
+ const gchar *major = NULL;
+ const gchar *minor = NULL;
+ const gchar *text = NULL;
+
+ {
+ hk_arg_t *arg;
+ for ( arg = args; arg -> name; arg ++ ) {
+ const gchar *value = arg -> value;
+ if ( value ) {
+ const gchar *name = arg -> name;
+ if ( ! strcmp ( name, "from" ) )
+ from = value;
+ else if ( ! strcmp ( name, "major" ) )
+ major = value;
+ else if ( ! strcmp ( name, "minor" ) )
+ minor = value;
+ else if ( ! strcmp ( name, "text" ) )
+ text = value;
+ }
+ }
+ }
+
+ { // print to buddy's buffer
+ gchar *jid = jidtodisp (from);
+ gchar *mesg = NULL;
+
+ // this can be implemented easier with gstring...
+ if (major && text) {
+ if (minor)
+ mesg = g_strdup_printf ("Activity: %s (%s) - %s.", major, minor, text);
+ else
+ mesg = g_strdup_printf ("Activity: %s - %s.", major, text);
+ } else if (major) {
+ if (minor)
+ mesg = g_strdup_printf ("Activity: %s (%s).", major, minor);
+ else
+ mesg = g_strdup_printf ("Activity: %s.", major);
+ } else if (text)
+ mesg = g_strdup_printf ("Activity: %s.", text);
+
+ scr_write_incoming_message (jid, mesg ? mesg : "No specific activity.", 0, HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0); // NO conversion from utf-8
+
+ g_free (mesg);
+ g_free (jid);
+ }
+
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+static const gchar *defined_general_activities[] = {
+ "doing_chores",
+ "drinking",
+ "eating",
+ "exercising",
+ "grooming",
+ "having_appointment",
+ "inactive",
+ "relaxing",
+ "talking",
+ "traveling",
+ "working",
+ NULL,
+};
+
+static const gchar *defined_minor_activities[] = {
+ "buying_groceries",
+ "cleaning",
+ "cooking",
+ "doing_maintenance",
+ "doing_the_dishes",
+ "doing_the_laundry",
+ "gardening",
+ "running_an_errand",
+ "walking_the_dog",
+ "having_a_beer",
+ "having_coffee",
+ "having_tea",
+ "having_a_snack",
+ "having_breakfast",
+ "having_dinner",
+ "having_lunch",
+ "cycling",
+ "dancing",
+ "hiking",
+ "jogging",
+ "playing_sports",
+ "running",
+ "skiing",
+ "swimming",
+ "working_out",
+ "at_the_spa",
+ "brushing_teeth",
+ "getting_a_haircut",
+ "shaving",
+ "taking_a_bath",
+ "taking_a_shower",
+ "day_off",
+ "hanging_out",
+ "hiding",
+ "on_vacation",
+ "praying",
+ "scheduled_holiday",
+ "sleeping",
+ "thinking",
+ "fishing",
+ "gaming",
+ "going_out",
+ "partying",
+ "reading",
+ "rehearsing",
+ "shopping",
+ "smoking",
+ "socializing",
+ "sunbathing",
+ "watching_tv",
+ "watching_a_movie",
+ "in_real_life",
+ "on_the_phone",
+ "on_video_phone",
+ "commuting",
+ "cycling",
+ "driving",
+ "in_a_car",
+ "on_a_bus",
+ "on_a_plane",
+ "on_a_train",
+ "on_a_trip",
+ "walking",
+ "coding",
+ "in_a_meeting",
+ "studying",
+ "writing",
+ NULL,
+};
+
+void activity_init (void)
+{
+ activity_cid1 = compl_new_category ();
+ if (activity_cid1) {
+ const gchar **activity;
+
+ for (activity = defined_general_activities; *activity; ++activity)
+ compl_add_category_word (activity_cid1, *activity);
+ }
+
+ activity_cid2 = compl_new_category ();
+ if (activity_cid2) {
+ const gchar **activity;
+
+ for (activity = defined_minor_activities; *activity; ++activity)
+ compl_add_category_word (activity_cid2, *activity);
+ }
+
+#ifndef MCABBER_API_HAVE_CMD_ID
+ cmd_add ("activity", "", activity_cid1, activity_cid2, do_activity, NULL);
+#else
+ activity_cmid = cmd_add ("activity", "", activity_cid1, activity_cid2, do_activity, NULL);
+ activity_set_safe = cmd_set_safe ("activity", TRUE);
+#endif
+
+ activity_hid_activityin = hk_add_handler (activity_haih, HOOK_ACTIVITY_IN, G_PRIORITY_DEFAULT, NULL);
+}
+
+void activity_uninit (void)
+{
+ hk_del_handler (HOOK_ACTIVITY_IN, activity_hid_activityin);
+
+#ifndef MCABBER_API_HAVE_CMD_ID
+ cmd_del ("activity");
+#else
+ if (activity_cmid)
+ cmd_del (activity_cmid);
+ if (activity_set_safe)
+ cmd_set_safe ("activity", FALSE);
+#endif
+
+ if (activity_cid1)
+ compl_del_category (activity_cid1);
+ if (activity_cid2)
+ compl_del_category (activity_cid2);
+}
+
+/* vim: se ts=4 sw=4: */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/activity.h Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,40 @@
+
+#ifndef MCABBER_ACTIVITY_H
+#define MCABBER_ACTIVITY_H
+
+/*
+ * activity.h -- Pep activity events
+ *
+ * Copyright (C) 2012 Myhailo Danylenko <isbear@ukrpost.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <glib.h>
+
+#define NS_ACTIVITY ( "http:/" "/jabber.org/protocol/activity" )
+#define NS_ACTIVITY_NOTIFY ( "http:/" "/jabber.org/protocol/activity+notify" )
+
+#define HOOK_ACTIVITY_IN ( "activity-in" )
+#define HOOK_ACTIVITY_OUT ( "activity-out" )
+
+#define ACTIVITY_ERROR_NOTCONNECTED ( 0x01 )
+
+void activity_publish ( const gchar *major, const gchar *minor, const gchar *text );
+gboolean activity_request ( const gchar *to, GError **error );
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/avv/activity.in Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,13 @@
+
+Name: activity
+Method: glib
+Version: ${PROJECT_VERSION}
+Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}
+# commands depend on building environment - 4, 3 or 2+1
+Requires: commands:4 + ( compl:3 | compl:2 ) + (hooks:5 | hooks:4 | hooks:3 | hooks:2 ) +
+ pep_activity:1 + logprint:3 + ( hbuf:3 | hbuf:2 | hbuf:1 ) +
+ ( screen:10 | screen:9 | screen:8 | screen:7 | screen:6 | screen:5 | screen:4 ) +
+ ( roster:4 | roster:3 | roster:2 | roster:1 ) + utils:2
+Init: activity_init
+Uninit: activity_uninit
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/avv/geoloc.in Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,14 @@
+
+Name: geoloc
+Method: glib
+Version: ${PROJECT_VERSION}
+Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}
+# commands depend on compilaton environment
+Requires: ( roster:4 | roster:3 | roster:2 | roster:1 ) + commands:4 + ( compl:3 | compl:2 ) +
+ ( hooks:5 | hooks:4 | hooks:3 | hooks:2 | hooks:1 ) + utils:2 +
+ pep_geoloc:1 + logprint:3 +
+ ( screen:10 | screen:9 | screen:8 | screen:7 | screen:6 | screen:5 | screen:4 ) +
+ ( hbuf:3 | hbuf:2 | hbuf:1 )
+Init: geoloc_init
+Uninit: geoloc_uninit
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/avv/mood.in Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,15 @@
+
+Name: mood
+Method: glib
+Version: ${PROJECT_VERSION}
+Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}
+# commands depend on building environment: 4, 3, 2+1
+Requires: ( roster:4 | roster:3 | roster:2 | roster:1 ) + commands:4 +
+ ( compl:3 | compl:2 | compl:1 ) + utils:2 +
+ ( hooks:5 | hooks:4 | hooks:3 | hooks:2 ) +
+ logprint:3 + pep_mood:1 +
+ ( screen:10 | screen:9 | screen:8 | screen:7 | screen:6 | screen:5 | screen:4 ) +
+ ( hbuf:3 | hbuf:2 | hbuf:1 )
+Init: mood_init
+Uninit: mood_uninit
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/avv/pep.in Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,13 @@
+
+Name: pep
+Method: glib
+Version: ${PROJECT_VERSION}
+Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}
+ Provides common listener infrastructure for various other
+ modules, eg avatar, geoloc, mood, tune.
+Requires: ( xmpp:4 | xmpp:3 | xmpp:2 | xmpp:1 ) +
+ ( hooks:5 | hooks:4 | hooks:3 | hooks:2 )
+Provides: pep:1
+Init: pep_init
+Uninit: pep_uninit
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/avv/pep_activity.in Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,12 @@
+
+Name: pep_activity
+Method: glib
+Version: ${PROJECT_VERSION}
+Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}
+Requires: ( hooks:5 | hooks:4 | hooks:3 | hooks:2 ) +
+ ( xmpp:4 | xmpp:3 | xmpp:2 | xmpp:1 ) + pep:1 + logprint:3 +
+ utils:2 + ( xmpp_helper:2 | xmpp_helper:1 )
+Provides: pep_activity:1 + activity:1
+Init: pep_activity_init
+Uninit: pep_activity_uninit
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/avv/pep_geoloc.in Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,13 @@
+
+Name: pep_geoloc
+Method: glib
+Version: ${PROJECT_VERSION}
+Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}
+Requires: ( hooks:5 | hooks:4 | hooks:3 | hooks:2 | hooks:1 ) + utils:2 +
+ ( xmpp:4 | xmpp:3 | xmpp:2 | xmpp:1 ) + pep:1 + logprint:3 +
+ settings:1 + guards:2 +
+ ( xmpp_helper:2 | xmpp_helper:1 )
+Provides: pep_geoloc:1 + geoloc:1
+Init: pep_geoloc_init
+Uninit: pep_geoloc_uninit
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/avv/pep_mood.in Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,13 @@
+
+Name: pep_mood
+Method: glib
+Version: ${PROJECT_VERSION}
+Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}
+# commands depend on building environment: 4, 3, 2+1
+Requires: utils:2 + ( hooks:5 | hooks:4 | hooks:3 | hooks:2 ) +
+ ( xmpp:4 | xmpp:3 | xmpp:2 | xmpp:1 ) + pep:1 + logprint:3 +
+ ( xmpp_helper:2 | xmpp_helper:1 )
+Provides: pep_mood:1 + mood:1
+Init: pep_mood_init
+Uninit: pep_mood_uninit
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/avv/pep_tune.in Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,13 @@
+
+Name: pep_tune
+Method: glib
+Version: ${PROJECT_VERSION}
+Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}
+Requires: ( hooks:5 | hooks:4 | hooks:3 | hooks:2 ) +
+ ( xmpp:4 | xmpp:3 | xmpp:2 | xmpp:1 ) + pep:1 + logprint:3 +
+ settings:1 + guards:2 + utils:2 +
+ ( xmpp_helper:2 | xmpp_helper:1 )
+Provides: pep_tune:1 + tune:1
+Init: pep_tune_init
+Uninit: pep_tune_uninit
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/avv/tune.in Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,12 @@
+
+Name: tune
+Method: glib
+Version: ${PROJECT_VERSION}
+Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}
+Requires: commands:4 + ( compl:3 | compl:2 ) + ( hooks:5 | hooks:4 | hooks:3 | hooks:2 ) + logprint:3 +
+ ( screen:10 | screen:9 | screen:8 | screen:7 | screen:6 | screen:5 | screen:4 ) +
+ ( roster:4 | roster:3 | roster:2 | roster:1 ) + utils:2 +
+ ( hbuf:3 | hbuf:2 | hbuf:1 ) + pep_tune:1
+Init: tune_init
+Uninit: tune_uninit
+
--- a/config.h.in Wed Jun 29 19:25:16 2011 +0300
+++ b/config.h.in Sun May 20 22:15:51 2012 +0300
@@ -2,6 +2,8 @@
#ifndef LOCAL_CONFIG_H
#define LOCAL_CONFIG_H
+#cmakedefine HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER
+
#define PROJECT_VERSION ( "${PROJECT_VERSION}" )
#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/activities.txt Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,78 @@
+ * doing_chores
+ + buying_groceries
+ + cleaning
+ + cooking
+ + doing_maintenance
+ + doing_the_dishes
+ + doing_the_laundry
+ + gardening
+ + running_an_errand
+ + walking_the_dog
+ * drinking
+ + having_a_beer
+ + having_coffee
+ + having_tea
+ * eating
+ + having_a_snack
+ + having_breakfast
+ + having_dinner
+ + having_lunch
+ * exercising
+ + cycling
+ + dancing
+ + hiking
+ + jogging
+ + playing_sports
+ + running
+ + skiing
+ + swimming
+ + working_out
+ * grooming
+ + at_the_spa
+ + brushing_teeth
+ + getting_a_haircut
+ + shaving
+ + taking_a_bath
+ + taking_a_shower
+ * having_appointment
+ * inactive
+ + day_off
+ + hanging_out
+ + hiding
+ + on_vacation
+ + praying
+ + scheduled_holiday
+ + sleeping
+ + thinking
+ * relaxing
+ + fishing
+ + gaming
+ + going_out
+ + partying
+ + reading
+ + rehearsing
+ + shopping
+ + smoking
+ + socializing
+ + sunbathing
+ + watching_tv
+ + watching_a_movie
+ * talking
+ + in_real_life
+ + on_the_phone
+ + on_video_phone
+ * traveling
+ + commuting
+ + cycling
+ + driving
+ + in_a_car
+ + on_a_bus
+ + on_a_plane
+ + on_a_train
+ + on_a_trip
+ + walking
+ * working
+ + coding
+ + in_a_meeting
+ + studying
+ + writing
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/api.mdwn Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,119 @@
+
+# Events interface
+
+Events are currently designed for useage with pep notifications, but
+potentially could be used with any notification system, eg a module, that adds
+currently playing song to your status.
+
+Every module pair (eg pep_tune and tune) use a pair of hooks. One for incoming
+notifications ('*-in') and one for the cases, when server needs to be notified
+about user state change ('*-out'). Note, that '*-out' causes server
+notification, not vice versa. In general, these hooks have the same set of fields,
+except that incoming events also have 'from' field, that is mandatory.
+
+For more clear description of fields and what can be put in there, refer to
+corresponding XEPs.
+
+* [XEP-0118](http://xmpp.org/extensions/xep-0118.html) - tune
+* [XEP-0107](http://xmpp.org/extensions/xep-0107.html) - mood
+* [XEP-0108](http://xmpp.org/extensions/xep-0108.html) - activity
+* [XEP-0080](http://xmpp.org/extensions/xep-0080.html) - geoloc
+
+## tune-*
+* argtist
+* length
+* rating
+* source
+* title
+* track
+* uri
+
+## mood-*
+* mood
+* text
+
+## activity-*
+* major
+* minor
+* text
+
+## geoloc-*
+* accuracy
+* alt
+* area
+* bearing
+* building
+* country
+* datum
+* description
+* error
+* floor
+* lat
+* locality
+* lon
+* postalcode
+* region
+* room
+* speed
+* street
+* text
+* timestamp
+* uri
+
+# C interface
+
+## general conventions
+
+### NS_*
+XMLNS namespace constants.
+
+### HOOK_*
+Hook name constants. Usually are the same as actual hook name, but
+uppercased, with 'HOOK_' added and with underscores instead of dashes.
+
+### *_request ( to, error )
+Request corresponding data from the jid, specified in 'to'.
+'error' may be used for error control. If no error occured,
+and remote side have replied with notification stanza, call
+to one of this functions will eventually result in corresponding
+event '*-in'. Currently there's no way to detect an
+error on the remote side (eg, if it does not support PEP).
+
+### *_publish ( ... )
+Publish supplied data as corresponding user's update. Note,
+that this function bypasses event interface, thus, it can
+be used to publish *only* via PEP. In general, it is
+suggested to use event (hooks) interface, as it allows
+multiplexing and non-breaking extensibility.
+
+## pep
+
+### (*pep_xmlns_handler_t) ( from, node, n, id, userdata )
+Type of function to supply as a handler for pep xmlns namespace.
+'from' is a jid.
+'node' is pep node.
+'n' is loudmouth message node object, containing xmlns-specific data.
+'userdata' is pointer to data, passed at registration time.
+
+### pep_register_xmlns_handler ( xmlns, handler, userdata, notify )
+Specify a handler for xmlns namespace.
+'userdata' will be directly specified.
+'notify' is a function, that may be called for userdata destruction.
+
+### pep_unregister_xmlns_handler ( xmlns )
+Remove handler from given xmlns namespace.
+
+## tune
+'tune_publish' takes list of key-value pairs.
+
+## mood
+'mood_publish' takes two string arguments - mood and mood message.
+
+## activity
+'activity_publish' takes three string arguments - major activity, minor, and
+activity message.
+
+## geoloc
+'geoloc_publish' takes list of key-value pairs.
+
+<!-- -->
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/moods.txt Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,84 @@
+afraid
+amazed
+amorous
+angry
+annoyed
+anxious
+aroused
+ashamed
+bored
+brave
+calm
+cautious
+cold
+confident
+confused
+contemplative
+contented
+cranky
+crazy
+creative
+curious
+dejected
+depressed
+disappointed
+disgusted
+dismayed
+distracted
+embarrassed
+envious
+excited
+flirtatious
+frustrated
+grateful
+grieving
+grumpy
+guilty
+happy
+hopeful
+hot
+humbled
+humiliated
+hungry
+hurt
+impressed
+in_awe
+in_love
+indignant
+interested
+intoxicated
+invincible
+jealous
+lonely
+lost
+lucky
+mean
+moody
+nervous
+neutral
+offended
+outraged
+playful
+proud
+relaxed
+relieved
+remorseful
+restless
+sad
+sarcastic
+satisfied
+serious
+shocked
+shy
+sick
+sleepy
+spontaneous
+stressed
+strong
+surprised
+thankful
+thirsty
+tired
+undefined
+weak
+worried
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/geoloc.c Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,323 @@
+/*
+ * geoloc.c -- Pep geographical location events
+ *
+ * Copyright (C) 2009-2012 Myhailo Danylenko <isbear@ukrpost.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <glib.h>
+#include <string.h>
+
+#include <mcabber/commands.h>
+#include <mcabber/compl.h>
+#include <mcabber/utils.h>
+#include <mcabber/screen.h>
+#include <mcabber/logprint.h>
+#include <mcabber/hbuf.h> // HBUF_PREFIX_*
+#include <mcabber/roster.h>
+#include <mcabber/hooks.h>
+#include <mcabber/modules.h>
+
+#include "geoloc.h"
+
+#include "config.h"
+
+//
+// module description
+//
+
+void geoloc_init (void);
+void geoloc_uninit (void);
+
+#define DESCRIPTION ( \
+ "PEP geoloc event handling\n" \
+ "Provides command /geoloc" )
+
+static const gchar *deps[] = { "pep_geoloc", NULL };
+
+static module_info_t info_geoloc_dev = {
+ .branch = "dev",
+ .api = 20,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = geoloc_init,
+ .uninit = geoloc_uninit,
+ .next = NULL,
+};
+
+module_info_t info_geoloc = {
+ .branch = "0.10.1",
+ .api = 1,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = geoloc_init,
+ .uninit = geoloc_uninit,
+ .next = &info_geoloc_dev,
+};
+
+//
+// globals
+//
+
+#ifdef MCABBER_API_HAVE_CMD_ID
+static gpointer geoloc_cmid = NULL;
+static gboolean geoloc_set_safe = FALSE;
+#endif
+
+static guint geoloc_cid = 0;
+static guint geoloc_hid_geolocin = 0;
+
+//
+// code
+//
+
+static void do_geoloc (char *arg)
+{
+ geoloc_pair_t tags[] = {
+ { "accuracy", NULL },
+ { "alt", NULL },
+ { "area", NULL },
+ { "bearing", NULL },
+ { "building", NULL },
+ { "country", NULL },
+ { "countrycode", NULL },
+ { "datum", NULL },
+ { "description", NULL },
+ { "error", NULL },
+ { "floor", NULL },
+ { "lat", NULL },
+ { "locality", NULL },
+ { "lon", NULL },
+ { "postalcode", NULL },
+ { "region", NULL },
+ { "room", NULL },
+ { "speed", NULL },
+ { "street", NULL },
+ { "text", NULL },
+ { "timestamp", NULL },
+ { "uri", NULL },
+ { NULL, NULL },
+ };
+
+ if (!*arg) { // request
+
+ GError *error = NULL;
+
+ geoloc_request ( CURRENT_JID, &error );
+ if ( error ) {
+ scr_log_print ( LPRINT_NORMAL, "Error sending request: %s.", error -> message );
+ g_error_free ( error );
+ } else
+ scr_log_print ( LPRINT_NORMAL, "Request sent." );
+
+ return;
+
+ } else if (arg[0] != '-' || arg[1] != '\0') { // publish
+
+ char *p;
+ char *argstart = NULL;
+ char *argstop = NULL;
+ char *tagstart = NULL;
+ char *tagstop = NULL;
+ char *wordstart = arg;
+ gboolean proceed = TRUE;
+
+// pt = p, ws = wordstart, ts = tagstart, tt = tagstop, as = argstart, at = arstop
+// tag=value value tag=value
+// w p
+// s t
+// t ta
+// s t*
+// tag=value value tag=value
+// t ta p
+// s t* t
+// t ta aw
+// s ts ts
+// tag=value value tag=value
+// t ta aw p
+// s ts ts t
+// t ta aw
+// s ts ts
+// tag=value value tag=value
+// t ta aw p
+// s ts ts t
+// t ta
+// s t*
+// tag=value value tag=value
+// t ta p
+// s t* t
+// t ta a
+// s ts t
+
+ for (p = arg; proceed; ++p) {
+ switch (*p) {
+ case '=':
+ if (tagstart && tagstop - tagstart) {
+ // process previous args
+ geoloc_pair_t *tag;
+
+ for (tag = tags; tag->name; ++tag) {
+ if (!strncmp (tag->name, tagstart, tagstop - tagstart)) {
+ g_free ( (gchar *) tag -> value );
+ if (argstop - argstart) {
+ *argstop = '\0';
+ tag->value = to_utf8 (argstart);
+ }
+ break;
+ }
+ }
+ }
+
+ tagstart = wordstart;
+ tagstop = p;
+ argstop = p+1;
+ argstart = p+1;
+ break;
+
+ case '\0':
+ argstop = p;
+
+ if (tagstop - tagstart) {
+ // process previous args
+ geoloc_pair_t *tag;
+
+ for (tag = tags; tag->name; ++tag) {
+ if (!strncmp (tag->name, tagstart, tagstop - tagstart)) {
+ g_free ( (gchar *) tag -> value );
+ if (argstop - argstart)
+ tag->value = to_utf8 (argstart);
+ break;
+ }
+ }
+ }
+
+ proceed = FALSE;
+ break;
+
+ case ' ':
+ argstop = p;
+ wordstart = p+1;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ hk_run_handlers ( HOOK_GEOLOC_OUT, (hk_arg_t *) tags );
+
+ {
+ geoloc_pair_t *tag;
+
+ for ( tag = tags; tag -> name; ++ tag )
+ g_free ( (gchar *) tag -> value );
+ }
+}
+
+static guint geoloc_hgih ( const gchar *hid, hk_arg_t *args, gpointer userdata )
+{
+ GString *mesg = g_string_new (NULL);
+ const gchar *from = NULL;
+
+ {
+ hk_arg_t *arg;
+ for ( arg = args; arg -> name; ++ arg )
+ if ( arg -> value ) {
+ if ( ! strcmp ( arg -> name, "from" ) )
+ from = arg -> value;
+ else
+ g_string_append_printf ( mesg, "\n - %s: %s", arg -> name, arg -> value);
+ }
+ }
+
+ if (mesg->len)
+ g_string_prepend (mesg, "Now located at:");
+ else
+ g_string_overwrite (mesg, 0, "No location information.");
+
+ { // print to buddy's buffer
+ gchar *jid = jidtodisp (from);
+
+ scr_write_incoming_message (jid, mesg->str, 0, HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0); // NO conversion from utf-8
+
+ g_free (jid);
+ }
+
+ g_string_free (mesg, TRUE);
+
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+void geoloc_init ( void )
+{
+ geoloc_cid = compl_new_category ();
+ if (geoloc_cid) {
+ compl_add_category_word (geoloc_cid, "accuracy=");
+ compl_add_category_word (geoloc_cid, "alt=");
+ compl_add_category_word (geoloc_cid, "area=");
+ compl_add_category_word (geoloc_cid, "bearing=");
+ compl_add_category_word (geoloc_cid, "building=");
+ compl_add_category_word (geoloc_cid, "country=");
+ compl_add_category_word (geoloc_cid, "countrycode=");
+ compl_add_category_word (geoloc_cid, "datum=");
+ compl_add_category_word (geoloc_cid, "description=");
+ compl_add_category_word (geoloc_cid, "error=");
+ compl_add_category_word (geoloc_cid, "floor=");
+ compl_add_category_word (geoloc_cid, "lat=");
+ compl_add_category_word (geoloc_cid, "locality=");
+ compl_add_category_word (geoloc_cid, "lon=");
+ compl_add_category_word (geoloc_cid, "postalcode=");
+ compl_add_category_word (geoloc_cid, "region=");
+ compl_add_category_word (geoloc_cid, "room=");
+ compl_add_category_word (geoloc_cid, "speed=");
+ compl_add_category_word (geoloc_cid, "street=");
+ compl_add_category_word (geoloc_cid, "text=");
+ compl_add_category_word (geoloc_cid, "timestamp=");
+ compl_add_category_word (geoloc_cid, "uri=");
+ }
+
+#ifndef MCABBER_API_HAVE_CMD_ID
+ cmd_add ("geoloc", "", geoloc_cid, geoloc_cid, do_geoloc, NULL);
+#else
+ geoloc_cmid = cmd_add ("geoloc", "", geoloc_cid, geoloc_cid, do_geoloc, NULL);
+ geoloc_set_safe = cmd_set_safe ("geoloc", TRUE);
+#endif
+
+ geoloc_hid_geolocin = hk_add_handler (geoloc_hgih, HOOK_GEOLOC_IN, G_PRIORITY_DEFAULT, NULL);
+}
+
+void geoloc_uninit ( void )
+{
+ hk_del_handler (HOOK_GEOLOC_IN, geoloc_hid_geolocin);
+
+#ifndef MCABBER_API_HAVE_CMD_ID
+ cmd_del ("geoloc");
+#else
+ if (geoloc_cmid)
+ cmd_del (geoloc_cmid);
+ if (geoloc_set_safe)
+ cmd_set_safe ("geoloc", FALSE);
+#endif
+
+ if (geoloc_cid)
+ compl_del_category (geoloc_cid);
+}
+
+/* vim: se ts=4 sw=4: */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/geoloc.h Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,45 @@
+
+#ifndef MCABBER_GEOLOC_H
+#define MCABBER_GEOLOC_H
+
+/*
+ * geoloc.h -- Pep geographical location events
+ *
+ * Copyright (C) 2009-2012 Myhailo Danylenko <isbear@ukrpost.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <glib.h>
+
+#define NS_GEOLOC ( "http:/" "/jabber.org/protocol/geoloc" )
+#define NS_GEOLOC_NOTIFY ( "http:/" "/jabber.org/protocol/geoloc+notify" )
+
+#define HOOK_GEOLOC_IN ( "geoloc-in" )
+#define HOOK_GEOLOC_OUT ( "geoloc-out" )
+
+#define GEOLOC_ERROR_NOTCONNECTED ( 0x01 )
+
+typedef struct {
+ const gchar *name;
+ gchar *value;
+} geoloc_pair_t;
+
+void geoloc_publish ( const geoloc_pair_t *pairs );
+gboolean geoloc_request ( const gchar *to, GError **error );
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/help/en/hlp_activity.txt Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,12 @@
+
+ /ACTIVITY [general|- [minor|- [message]]]
+
+Publishes your activity. For valid activities see completion or standard.
+Note, that it does not validate specified values, so, it is your responsibility to take care about that.
+
+/activity
+ Requests current buddy's activity.
+/activity -
+ Publishes empty information about your activity.
+/activity general-activity [minor-activity|- [message]]
+ Publishes your activity. To specify only general activity and message without minor, specify '-' in place of minor activity.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/help/en/hlp_geoloc.txt Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,13 @@
+
+ /GEOLOC [-]
+ /GEOLOC [key=[value] ...]
+
+Publish your geographical location via pep. For a list of valid keys see completion or standard.
+Note: It will not complain about wrong keys, it will just skip them.
+
+/geoloc
+ Request position from current buddy's server.
+/geoloc -
+ Publish empty position.
+/geoloc [key=[value] ...]
+ Publish some data.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/help/en/hlp_mood.txt Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,12 @@
+
+ /MOOD [-|mood [message]]
+
+Publishes your mood via pep. For valid moods see standard or completion.
+Note, that it does not checks, if specified value is valid, it only provides completion.
+
+/mood
+ Sends request for current buddy's mood.
+/mood -
+ Publishes empty mood (no mood).
+/mood mood [message]
+ Publishes specified mood.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/help/en/hlp_tune.txt Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,5 @@
+
+ /TUNE [artist|length|rating|source|title|track|uri=[value] ...]
+
+Sends tune publish request with supplied information. Value can contain embedded spaces.
+Note: unknown keys will be just silently ignored.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mood.c Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,294 @@
+/*
+ * mood.c -- Pep mood events
+ *
+ * Copyright (C) 2009-2012 Myhailo Danylenko <isbear@ukrpost.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <glib.h>
+#include <string.h>
+
+#include <mcabber/commands.h>
+#include <mcabber/compl.h>
+#include <mcabber/utils.h>
+#include <mcabber/screen.h>
+#include <mcabber/logprint.h>
+#include <mcabber/roster.h>
+#include <mcabber/hbuf.h> // HBUF_PREFIX_*
+#include <mcabber/hooks.h>
+#include <mcabber/modules.h>
+
+#include "mood.h"
+
+#include "config.h"
+
+//
+// module description
+//
+
+void mood_init (void);
+void mood_uninit (void);
+
+#define DESCRIPTION ( "PEP mood events handling\nProvides command /mood" )
+
+static const gchar *deps[] = { "pep_mood", NULL };
+
+static module_info_t info_mood_dev = {
+ .branch = "dev",
+ .api = 20,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = mood_init,
+ .uninit = mood_uninit,
+ .next = NULL,
+};
+
+module_info_t info_mood = {
+ .branch = "0.10.1",
+ .api = 1,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = mood_init,
+ .uninit = mood_uninit,
+ .next = &info_mood_dev,
+};
+
+//
+// globals
+//
+
+#ifdef MCABBER_API_HAVE_CMD_ID
+static gpointer mood_cmid = NULL;
+static gboolean mood_set_safe = FALSE;
+#endif
+
+static guint mood_cid = 0;
+static guint mood_hid_moodin = 0;
+
+//
+// code
+//
+
+static void do_mood (char *arg)
+{
+ if (!*arg) { // request
+
+ GError *error = NULL;
+
+ mood_request ( CURRENT_JID, &error );
+ if ( error ) {
+ scr_log_print ( LPRINT_NORMAL, "Error sending request: %s.", error -> message );
+ g_error_free ( error );
+ } else
+ scr_log_print ( LPRINT_NORMAL, "Request sent." );
+
+ return;
+
+ } else { // publish
+
+ hk_arg_t hookargs[] = {
+ { "mood", NULL },
+ { "text", NULL },
+ { NULL, NULL },
+ };
+
+ if ( arg[0] != '-' || arg[1] != '\0' ) {
+ gchar **args = split_arg ( arg, 2, 1 );
+
+ hookargs[0].value = to_utf8 ( args[0] );
+
+ if ( args[1] )
+ hookargs[1].value = to_utf8 ( args[1] );
+
+ free_arg_lst ( args );
+ }
+
+ hk_run_handlers ( HOOK_MOOD_OUT, hookargs );
+
+ g_free ( (gchar *) hookargs[0].value );
+ g_free ( (gchar *) hookargs[1].value );
+ }
+}
+
+static guint mood_hmih (const gchar *hid, hk_arg_t *args, gpointer userdata)
+{
+ const gchar *from = NULL;
+ const gchar *mood = NULL;
+ const gchar *text = NULL;
+
+ {
+ hk_arg_t *arg;
+ for ( arg = args; arg -> name; arg ++ ) {
+ const gchar *value = arg -> value;
+ if ( value ) {
+ const gchar *name = arg -> name;
+ if ( ! strcmp ( name, "from" ) )
+ from = value;
+ else if ( ! strcmp ( name, "mood" ) )
+ mood = value;
+ else if ( ! strcmp ( name, "text" ) )
+ text = value;
+ }
+ }
+ }
+
+ { // print to buddy's buffer
+ gchar *jid = jidtodisp (from);
+ gchar *mesg = NULL;
+
+ if (mood && text)
+ mesg = g_strdup_printf ("Mood: %s - %s.", mood, text);
+ else if (mood || text)
+ mesg = g_strdup_printf ("Mood: %s.", mood ? mood : text);
+
+ scr_write_incoming_message (jid, mesg ? mesg : "No specific mood.", 0, HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0); // NO conversion from utf-8
+
+ g_free (mesg);
+ g_free (jid);
+ }
+
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+static const gchar *defined_moods[] = {
+ "afraid",
+ "amazed",
+ "amorous",
+ "angry",
+ "annoyed",
+ "anxious",
+ "aroused",
+ "ashamed",
+ "bored",
+ "brave",
+ "calm",
+ "cautious",
+ "cold",
+ "confident",
+ "confused",
+ "contemplative",
+ "contented",
+ "cranky",
+ "crazy",
+ "creative",
+ "curious",
+ "dejected",
+ "depressed",
+ "disappointed",
+ "disgusted",
+ "dismayed",
+ "distracted",
+ "embarrassed",
+ "envious",
+ "excited",
+ "flirtatious",
+ "frustrated",
+ "grateful",
+ "grieving",
+ "grumpy",
+ "guilty",
+ "happy",
+ "hopeful",
+ "hot",
+ "humbled",
+ "humiliated",
+ "hungry",
+ "hurt",
+ "impressed",
+ "in_awe",
+ "in_love",
+ "indignant",
+ "interested",
+ "intoxicated",
+ "invincible",
+ "jealous",
+ "lonely",
+ "lost",
+ "lucky",
+ "mean",
+ "moody",
+ "nervous",
+ "neutral",
+ "offended",
+ "outraged",
+ "playful",
+ "proud",
+ "relaxed",
+ "relieved",
+ "remorseful",
+ "restless",
+ "sad",
+ "sarcastic",
+ "satisfied",
+ "serious",
+ "shocked",
+ "shy",
+ "sick",
+ "sleepy",
+ "spontaneous",
+ "stressed",
+ "strong",
+ "surprised",
+ "thankful",
+ "thirsty",
+ "tired",
+ "undefined",
+ "weak",
+ "worried",
+ NULL,
+};
+
+void mood_init (void)
+{
+ mood_cid = compl_new_category ();
+ if (mood_cid) {
+ const gchar **mood;
+
+ for (mood = defined_moods; *mood; ++mood)
+ compl_add_category_word (mood_cid, *mood);
+ }
+
+#ifndef MCABBER_API_HAVE_CMD_ID
+ cmd_add ( "mood", "", mood_cid, 0, do_mood, NULL );
+#else
+ mood_cmid = cmd_add ( "mood", "", mood_cid, 0, do_mood, NULL );
+ mood_set_safe = cmd_set_safe ( "mood", TRUE );
+#endif
+
+ mood_hid_moodin = hk_add_handler ( mood_hmih, HOOK_MOOD_IN, G_PRIORITY_DEFAULT, NULL );
+}
+
+void mood_uninit (void)
+{
+ hk_del_handler ( HOOK_MOOD_IN, mood_hid_moodin );
+
+#ifndef MCABBER_API_HAVE_CMD_ID
+ cmd_del ( "mood" );
+#else
+ if ( mood_cmid )
+ cmd_del ( mood_cmid );
+ if ( mood_set_safe )
+ cmd_set_safe ( "mood", FALSE );
+#endif
+
+ if ( mood_cid )
+ compl_del_category ( mood_cid );
+}
+
+/* vim: se ts=4 sw=4: */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mood.h Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,40 @@
+
+#ifndef MCABBER_MOOD_H
+#define MCABBER_MOOD_H
+
+/*
+ * mood.h -- Pep mood events
+ *
+ * Copyright (C) 2009-2012 Myhailo Danylenko <isbear@ukrpost.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <glib.h>
+
+#define NS_MOOD ( "http:/" "/jabber.org/protocol/mood" )
+#define NS_MOOD_NOTIFY ( "http:/" "/jabber.org/protocol/mood+notify" )
+
+#define HOOK_MOOD_IN ( "mood-in" )
+#define HOOK_MOOD_OUT ( "mood-out" )
+
+#define MOOD_ERROR_NOTCONNECTED ( 0x01 )
+
+void mood_publish ( const gchar *mood, const gchar *text );
+gboolean mood_request ( const gchar *to, GError **error );
+
+#endif
+
--- a/pep.avv.in Wed Jun 29 19:25:16 2011 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-
-Name: ${PROJECT_NAME}
-Method: glib
-Version: ${PROJECT_VERSION}
-Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}
- Provides common listener infrastructure for various other
- modules, eg avatar, geoloc, mood, tune.
-Requires: ( xmpp:4 | xmpp:3 | xmpp:2 | xmpp:1 ) +
- ( hooks:5 | hooks:4 | hooks:3 | hooks:2 )
-Provides: pep:1
-Init: pep_init
-Uninit: pep_uninit
-
--- a/pep.c Wed Jun 29 19:25:16 2011 +0300
+++ b/pep.c Sun May 20 22:15:51 2012 +0300
@@ -1,7 +1,7 @@
/*
* pep.c -- Common pep routines
*
- * Copyrigth (C) 2009 Myhailo Danylenko <isbear@ukrpost.net>
+ * Copyright (C) 2009 Myhailo Danylenko <isbear@ukrpost.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
--- a/pep.rc Wed Jun 29 19:25:16 2011 +0300
+++ b/pep.rc Sun May 20 22:15:51 2012 +0300
@@ -1,3 +1,37 @@
-module load pep
+# Modules, that provide internal infrastructure, and will
+# be loaded automatically by dependencies:
+#module load pep
+#module load pep_mood
+#moudle load pep_tune
+#module load pep_activity
+#module load pep_geoloc
+#module load pep_avatar
+
+# Minimum interval betweet two publishes. Any too frequent
+# publish requests will be discarded. Set to 0 to disable.
+# (pep_tune option)
+set tune_interval = 10
+# Minimum interval between two publishes. Any too frequent
+# publish requests will be discarded. Set to 0 to disable.
+# (pep_geoloc option)
+set geoloc_interval = 5
+
+module load mood
+
+module load tune
+
+module load activity
+
+module load geoloc
+
+# Directory, where avatars will be saved. Avatars are saved by
+# their id (sha1sum of png data), and symlinked by jids.
+# I.e. '12345...679.png' contains png data and 'foo@bar.org' is a
+# symlink to '12345...679.png'
+set avatar_directory = ~/.mcabber/avatars
+
+module load avatar
+
+# the end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pep_activity.c Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,347 @@
+/*
+ * pep_activity.c -- Pep activity events
+ *
+ * Copyright (C) 2009-2012 Myhailo Danylenko <isbear@ukrpost.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <glib.h>
+#include <loudmouth/loudmouth.h>
+#include <string.h>
+
+#include <mcabber/utils.h>
+#include <mcabber/logprint.h>
+#include <mcabber/hooks.h>
+#include <mcabber/modules.h>
+#include <mcabber/xmpp.h>
+#include <mcabber/xmpp_helper.h>
+
+#include "pep.h"
+#include "activity.h"
+
+#include "config.h"
+
+//
+// module description
+//
+
+void pep_activity_init (void);
+void pep_activity_uninit (void);
+
+#define DESCRIPTION ( "PEP activity support" )
+static const gchar *deps[] = { "pep", NULL };
+
+static module_info_t info_activity_dev = {
+ .branch = "dev",
+ .api = 20,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = pep_activity_init,
+ .uninit = pep_activity_uninit,
+ .next = NULL,
+};
+
+static module_info_t info_activity_0_10_1 = {
+ .branch = "0.10.1",
+ .api = 1,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = pep_activity_init,
+ .uninit = pep_activity_uninit,
+ .next = &info_activity_dev,
+};
+
+module_info_t info_pep_activity = {
+ .branch = "0.10.0",
+ .api = 1,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = pep_activity_init,
+ .uninit = pep_activity_uninit,
+ .next = &info_activity_0_10_1,
+};
+
+//
+// globals
+//
+
+static GQuark activity_gerror_quark = 0;
+static gboolean activity_delayed = FALSE;
+static guint activity_hid_connect = 0;
+static guint activity_hid_disconnect = 0;
+static guint activity_hid_activityout = 0;
+static gchar *activity_major = NULL;
+static gchar *activity_minor = NULL;
+static gchar *activity_text = NULL;
+static LmMessageHandler *activity_reply_handler = NULL;
+
+//
+// code
+//
+
+static LmHandlerResult activity_publish_reply_handler (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer userdata)
+{
+ switch (lm_message_get_sub_type (message)) {
+ case LM_MESSAGE_SUB_TYPE_RESULT:
+ break;
+
+ case LM_MESSAGE_SUB_TYPE_ERROR:
+
+ {
+ LmMessageNode *node = lm_message_get_node (message);
+ const gchar *type;
+ const gchar *reason;
+
+ node = lm_message_node_get_child (node, "error");
+ type = lm_message_node_get_attribute (node, "type");
+ if (node->children)
+ reason = node->children->name;
+ else
+ reason = "undefined";
+
+ scr_log_print (LPRINT_LOGNORM, "activity: Publish failed: %s - %s", type, reason);
+ }
+
+ break;
+
+ default:
+ return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+ break;
+ }
+
+ return LM_HANDLER_RESULT_REMOVE_MESSAGE;
+}
+
+void activity_publish (const gchar *major, const gchar *minor, const gchar *text)
+{
+ if (!xmpp_is_online ()) {
+ g_free (activity_major);
+ g_free (activity_minor);
+ g_free (activity_text);
+
+ activity_major = g_strdup (major);
+ activity_minor = g_strdup (minor);
+ activity_text = g_strdup (text);
+ activity_delayed = TRUE;
+
+ return;
+ }
+
+ LmMessage *request = lm_message_new_with_sub_type (NULL, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET);
+ LmMessageNode *node = lm_message_get_node (request);
+ lm_message_node_set_attribute (node, "from", lm_connection_get_jid (lconnection));
+
+ node = lm_message_node_add_child (node, "pubsub", NULL);
+ lm_message_node_set_attribute (node, "xmlns", NS_PUBSUB);
+
+ node = lm_message_node_add_child (node, "publish", NULL);
+ lm_message_node_set_attribute (node, "node", NS_ACTIVITY);
+
+ node = lm_message_node_add_child (node, "item", NULL);
+
+ node = lm_message_node_add_child (node, "activity", NULL);
+ lm_message_node_set_attribute (node, "xmlns", NS_ACTIVITY);
+
+ if (major) {
+ LmMessageNode *mnode = lm_message_node_add_child (node, major, NULL);
+
+ if (minor)
+ lm_message_node_add_child (mnode, minor, NULL);
+ }
+
+ if (text)
+ lm_message_node_add_child (node, "text", text);
+
+ { // send
+ GError *error = NULL;
+
+ lm_connection_send_with_reply (lconnection, request, activity_reply_handler, &error);
+
+ if (error) {
+ scr_log_print (LPRINT_DEBUG, "activity: Publish failed: %s.", error -> message);
+ g_error_free (error);
+ }
+ }
+
+ lm_message_unref (request);
+}
+
+gboolean activity_request ( const gchar *to, GError **err )
+{
+ LmMessage *request;
+ LmMessageNode *node;
+
+ if ( ! xmpp_is_online () ) {
+ g_set_error ( err, activity_gerror_quark, ACTIVITY_ERROR_NOTCONNECTED, "You are not connected" );
+ return FALSE;
+ }
+
+ request = lm_message_new_with_sub_type (to, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET);
+ node = lm_message_get_node (request);
+ lm_message_node_set_attribute (node, "from", lm_connection_get_jid (lconnection));
+
+ node = lm_message_node_add_child (node, "pubsub", NULL);
+ lm_message_node_set_attribute (node, "xmlns", NS_PUBSUB);
+
+ node = lm_message_node_add_child (node, "items", NULL);
+ lm_message_node_set_attribute (node, "node", NS_ACTIVITY);
+
+ { // send, result will be handled by pep
+ GError *error = NULL;
+
+ lm_connection_send (lconnection, request, &error);
+
+ if (error) {
+ g_propagate_error ( err, error );
+ return FALSE;
+ }
+ }
+
+ lm_message_unref (request);
+
+ return TRUE;
+}
+
+static void activity_handler ( const gchar *from, const gchar *enode, LmMessageNode *n, const gchar *id, gpointer ignore )
+{
+ LmMessageNode *node;
+ hk_arg_t args[] = {
+ { "major", NULL },
+ { "minor", NULL },
+ { "text", NULL },
+ { "from", from },
+ { NULL, NULL },
+ };
+
+ for ( node = n -> children; node; node = node -> next ) {
+ const gchar *name = node -> name;
+
+ if ( ! strcmp ( name, "text" ) )
+ args[2].value = lm_message_node_get_value ( node );
+ else {
+ LmMessageNode *mnode = node -> children;
+
+ if ( mnode ) // XXX check for xmlns presence?
+ args[1].value = mnode -> name;
+
+ args[0].value = name;
+ }
+ }
+
+ hk_run_handlers ( HOOK_ACTIVITY_IN, args );
+}
+
+static guint activity_hch ( const gchar *hid, hk_arg_t *args, gpointer userdata )
+{
+ if (activity_delayed) {
+ gchar *tmp_major = activity_major;
+ gchar *tmp_minor = activity_minor;
+ gchar *tmp_text = activity_text;
+
+ activity_delayed = FALSE;
+ activity_major = activity_minor = activity_text = NULL;
+
+ activity_publish (tmp_major, tmp_minor, tmp_text);
+
+ g_free (tmp_major);
+ g_free (tmp_minor);
+ g_free (tmp_text);
+ }
+
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+static guint activity_hdh ( const gchar *hid, hk_arg_t *args, gpointer userdata )
+{
+#ifdef HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER
+ if ( lconnection && activity_reply_handler )
+ lm_connection_unregister_reply_handler ( lconnection, activity_reply_handler );
+#endif
+
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+static guint activity_haoh ( const gchar *hid, hk_arg_t *args, gpointer userdata )
+{
+ const gchar *minor = NULL;
+ const gchar *major = NULL;
+ const gchar *text = NULL;
+
+ {
+ hk_arg_t *arg;
+ for ( arg = args; arg -> name; arg ++ ) {
+ const gchar *value = arg -> value;
+ if ( value ) {
+ const gchar *name = arg -> name;
+ if ( ! strcmp ( name, "major" ) )
+ major = value;
+ else if ( ! strcmp ( name, "minor" ) )
+ minor = value;
+ else if ( !strcmp ( name, "text" ) )
+ text = value;
+ }
+ }
+ }
+
+ activity_publish ( major, minor, text );
+
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+void pep_activity_init (void)
+{
+ activity_gerror_quark = g_quark_from_string ( "pep-activity-gerror-quark" );
+
+ activity_reply_handler = lm_message_handler_new (activity_publish_reply_handler, NULL, NULL);
+
+ pep_register_xmlns_handler (NS_ACTIVITY, activity_handler, NULL, NULL);
+
+ activity_hid_connect = hk_add_handler (activity_hch, HOOK_POST_CONNECT, G_PRIORITY_DEFAULT, NULL);
+ activity_hid_disconnect = hk_add_handler (activity_hdh, HOOK_PRE_DISCONNECT, G_PRIORITY_DEFAULT, NULL);
+ activity_hid_activityout = hk_add_handler (activity_haoh, HOOK_ACTIVITY_OUT, G_PRIORITY_DEFAULT, NULL);
+
+ xmpp_add_feature ( NS_ACTIVITY );
+ xmpp_add_feature ( NS_ACTIVITY_NOTIFY );
+}
+
+void pep_activity_uninit (void)
+{
+ xmpp_del_feature ( NS_ACTIVITY );
+ xmpp_del_feature ( NS_ACTIVITY_NOTIFY );
+
+ hk_del_handler ( HOOK_POST_CONNECT, activity_hid_connect );
+ hk_del_handler ( HOOK_PRE_DISCONNECT, activity_hid_disconnect );
+ hk_del_handler ( HOOK_ACTIVITY_OUT, activity_hid_activityout );
+
+ pep_unregister_xmlns_handler ( NS_ACTIVITY );
+
+#ifdef HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER
+ if (lconnection)
+ lm_connection_unregister_reply_handler (lconnection, activity_reply_handler);
+#endif
+ lm_message_handler_invalidate (activity_reply_handler);
+ lm_message_handler_unref (activity_reply_handler);
+
+ g_free (activity_major);
+ g_free (activity_minor);
+ g_free (activity_text);
+}
+
+/* vim: se ts=4 sw=4: */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pep_geoloc.c Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,474 @@
+/*
+ * pep_geoloc.c -- Pep geographical location events
+ *
+ * Copyright (C) 2009-2012 Myhailo Danylenko <isbear@ukrpost.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <glib.h>
+#include <loudmouth/loudmouth.h>
+#include <stdlib.h> // atoi
+#include <string.h>
+#include <time.h>
+
+#include <mcabber/logprint.h>
+#include <mcabber/utils.h>
+#include <mcabber/xmpp.h>
+#include <mcabber/xmpp_helper.h>
+#include <mcabber/hooks.h>
+#include <mcabber/settings.h>
+#include <mcabber/modules.h>
+
+#include "pep.h"
+#include "geoloc.h"
+
+#include "config.h"
+
+//
+// module description
+//
+
+void pep_geoloc_init (void);
+void pep_geoloc_uninit (void);
+
+#define DESCRIPTION ( \
+ "PEP geoloc event handling\n" \
+ "Recognizes option geoloc_interval" )
+
+static const gchar *deps[] = { "pep", NULL };
+
+static module_info_t info_geoloc_dev = {
+ .branch = "dev",
+ .api = 20,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = pep_geoloc_init,
+ .uninit = pep_geoloc_uninit,
+ .next = NULL,
+};
+
+module_info_t info_pep_geoloc = {
+ .branch = "0.10.1",
+ .api = 1,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = pep_geoloc_init,
+ .uninit = pep_geoloc_uninit,
+ .next = &info_geoloc_dev,
+};
+
+//
+// globals
+//
+
+#define MAX_NO ( 21 )
+
+static geoloc_pair_t info[] = {
+ { "accuracy", NULL },
+ { "alt", NULL },
+ { "area", NULL },
+ { "bearing", NULL },
+ { "building", NULL },
+ { "country", NULL },
+ { "countrycode", NULL },
+ { "datum", NULL },
+ { "description", NULL },
+ { "error", NULL },
+ { "floor", NULL },
+ { "lat", NULL },
+ { "locality", NULL },
+ { "lon", NULL },
+ { "postalcode", NULL },
+ { "region", NULL },
+ { "room", NULL },
+ { "speed", NULL },
+ { "street", NULL },
+ { "text", NULL },
+ { "timestamp", NULL },
+ { "uri", NULL },
+ { NULL, NULL },
+};
+
+static GQuark geoloc_gerror_quark = 0;
+static gboolean publish_delayed = FALSE;
+static guint geoloc_hid_connect = 0;
+static guint geoloc_hid_disconnect = 0;
+static guint geoloc_hid_geolocout = 0;
+static guint geoloc_interval = 0;
+static time_t geoloc_timestamp = 0;
+static LmMessageHandler *geoloc_reply_handler = NULL;
+static guint geoloc_source = 0;
+static gboolean geoloc_guard_installed = FALSE;
+
+//
+// predeclarations
+//
+
+static void geoloc_publish_info (void);
+
+//
+// code
+//
+
+static LmHandlerResult geoloc_publish_reply_handler (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer userdata)
+{
+ switch (lm_message_get_sub_type (message)) {
+ case LM_MESSAGE_SUB_TYPE_RESULT:
+ break;
+
+ case LM_MESSAGE_SUB_TYPE_ERROR:
+
+ {
+ LmMessageNode *node = lm_message_get_node (message);
+ const gchar *type;
+ const gchar *reason;
+
+ node = lm_message_node_get_child (node, "error");
+ type = lm_message_node_get_attribute (node, "type");
+ if (node->children)
+ reason = node->children->name;
+ else
+ reason = "undefined";
+
+ scr_log_print (LPRINT_LOGNORM, "geoloc: Publish failed: %s - %s.", type, reason);
+ }
+
+ break;
+
+ default:
+ return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+ break;
+ }
+
+ return LM_HANDLER_RESULT_REMOVE_MESSAGE;
+}
+
+static gboolean geoloc_delayed_publish_cb (gpointer data)
+{
+ geoloc_source = 0;
+ geoloc_publish_info ();
+ return FALSE;
+}
+
+static void geoloc_publish_info (void)
+{
+ if (!xmpp_is_online ()) {
+ scr_log_print (LPRINT_DEBUG, "geoloc: Not online, delaying publish.");
+ publish_delayed = TRUE;
+ return;
+ }
+
+ // check for frequency of publishes
+ if (geoloc_interval) {
+ time_t now = time (NULL);
+
+ if (now - geoloc_timestamp < geoloc_interval) {
+
+ scr_log_print (LPRINT_DEBUG, "geoloc: Publish interval not passed, delaying.");
+ if (!geoloc_source)
+ geoloc_source = g_timeout_add_seconds ( geoloc_interval - ( now - geoloc_timestamp ), geoloc_delayed_publish_cb, NULL );
+ return;
+
+ } else
+ geoloc_timestamp = now;
+ }
+
+ LmMessage *request = lm_message_new_with_sub_type (NULL, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET);
+ LmMessageNode *node = lm_message_get_node (request);
+ lm_message_node_set_attribute (node, "from", lm_connection_get_jid (lconnection));
+
+ node = lm_message_node_add_child (node, "pubsub", NULL);
+ lm_message_node_set_attribute (node, "xmlns", NS_PUBSUB);
+
+ node = lm_message_node_add_child (node, "publish", NULL);
+ lm_message_node_set_attribute (node, "node", NS_GEOLOC);
+
+ node = lm_message_node_add_child (node, "item", NULL);
+
+ node = lm_message_node_add_child (node, "geoloc", NULL);
+ lm_message_node_set_attribute (node, "xmlns", NS_GEOLOC);
+
+ { // put data inside
+ int i;
+
+ for ( i = 0; i <= MAX_NO; ++ i )
+ if ( info[i].value )
+ lm_message_node_add_child ( node, info[i].name, info[i].value );
+ }
+
+ { // send
+ GError *error = NULL;
+
+ lm_connection_send_with_reply (lconnection, request, geoloc_reply_handler, &error);
+
+ if (error) {
+ scr_log_print (LPRINT_DEBUG, "geoloc: Publishing error: %s.", error -> message);
+ g_error_free (error);
+ }
+ }
+
+ lm_message_unref (request);
+ //publish_delayed = FALSE; XXX
+}
+
+void geoloc_publish (const geoloc_pair_t *pairs)
+{
+ gboolean publish = FALSE;
+ const geoloc_pair_t *tag;
+ static geoloc_pair_t new_info[] = {
+ { "accuracy", NULL },
+ { "alt", NULL },
+ { "area", NULL },
+ { "bearing", NULL },
+ { "building", NULL },
+ { "country", NULL },
+ { "countrycode", NULL },
+ { "datum", NULL },
+ { "description", NULL },
+ { "error", NULL },
+ { "floor", NULL },
+ { "lat", NULL },
+ { "locality", NULL },
+ { "lon", NULL },
+ { "postalcode", NULL },
+ { "region", NULL },
+ { "room", NULL },
+ { "speed", NULL },
+ { "street", NULL },
+ { "text", NULL },
+ { "timestamp", NULL },
+ { "uri", NULL },
+ { NULL, NULL },
+ };
+
+ // populate new_info with new values
+ for (tag = pairs; tag->name; ++tag) {
+ int i;
+ for (i = 0; i <= MAX_NO; ++i)
+ if (!g_strcmp0 (tag->name, new_info[i].name))
+ new_info[i].value = tag->value;
+ }
+
+ { // check, if it differ from info
+ int i;
+ for (i = 0; i <= MAX_NO; ++i)
+ if (g_strcmp0 (new_info[i].value, info[i].value)) {
+ publish = TRUE;
+ break;
+ }
+ }
+
+ if (publish) {
+
+ { // copy new vaules to info
+ int i;
+ for (i = 0; i <= MAX_NO; ++i) {
+ if (info[i].value)
+ g_free (info[i].value);
+ info[i].value = g_strdup (new_info[i].value);
+ }
+ }
+
+ geoloc_publish_info ();
+ }
+}
+
+gboolean geoloc_request ( const gchar *to, GError **err )
+{
+
+ LmMessage *request;
+ LmMessageNode *node;
+
+ if (!xmpp_is_online ()) {
+ g_set_error ( err, geoloc_gerror_quark, GEOLOC_ERROR_NOTCONNECTED, "You are not connected" );
+ return FALSE;
+ }
+
+ request = lm_message_new_with_sub_type (to, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET);
+ node = lm_message_get_node (request);
+ lm_message_node_set_attribute (node, "from", lm_connection_get_jid (lconnection));
+
+ node = lm_message_node_add_child (node, "pubsub", NULL);
+ lm_message_node_set_attribute (node, "xmlns", NS_PUBSUB);
+
+ node = lm_message_node_add_child (node, "items", NULL);
+ lm_message_node_set_attribute (node, "node", NS_GEOLOC);
+
+ { // send, result will be handled by pep
+ GError *error = NULL;
+
+ lm_connection_send (lconnection, request, &error);
+
+ if (error) {
+ g_propagate_error ( err, error );
+ return FALSE;
+ }
+ }
+
+ lm_message_unref (request);
+
+ return TRUE;
+}
+
+static void geoloc_handler (const gchar *from, const gchar *node, LmMessageNode *n, const gchar *id, gpointer ignore)
+{
+ LmMessageNode *tag;
+ hk_arg_t args[] = {
+ { "accuracy", NULL },
+ { "alt", NULL },
+ { "area", NULL },
+ { "bearing", NULL },
+ { "building", NULL },
+ { "country", NULL },
+ { "countrycode", NULL },
+ { "datum", NULL },
+ { "description", NULL },
+ { "error", NULL },
+ { "floor", NULL },
+ { "lat", NULL },
+ { "locality", NULL },
+ { "lon", NULL },
+ { "postalcode", NULL },
+ { "region", NULL },
+ { "room", NULL },
+ { "speed", NULL },
+ { "street", NULL },
+ { "text", NULL },
+ { "timestamp", NULL },
+ { "uri", NULL },
+ { "from", from },
+ { NULL, NULL },
+ };
+
+ for ( tag = n -> children; tag; tag = tag -> next ) {
+ const gchar *name = tag -> name;
+ if ( name ) {
+ int i;
+ for ( i = 0; i <= MAX_NO; ++ i )
+ if ( ! strcmp ( name, args[i].name ) ) {
+ const gchar *value = lm_message_node_get_value ( tag );
+ if ( value )
+ args[i].value = value;
+ }
+ }
+ }
+
+ hk_run_handlers ( HOOK_GEOLOC_IN, args );
+}
+
+static guint geoloc_hch (const gchar *hid, hk_arg_t *args, gpointer userdata)
+{
+ if (publish_delayed) {
+ scr_log_print (LPRINT_DEBUG, "geoloc: Publishing delayed data.");
+
+ publish_delayed = FALSE;
+ geoloc_publish_info ();
+ }
+
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+static guint geoloc_hdh (const gchar *hid, hk_arg_t *args, gpointer userdata)
+{
+#ifdef HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER
+ if (lconnection)
+ lm_connection_unregister_reply_handler (lconnection, geoloc_reply_handler);
+#endif
+
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+static guint geoloc_hgoh ( const gchar *hid, hk_arg_t *args, gpointer userdata )
+{
+ geoloc_publish ( (const geoloc_pair_t *) args );
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+static gchar *geoloc_guard (const char *key, const char *new_value)
+{
+ if (new_value)
+ geoloc_interval = atoi (new_value);
+ else
+ geoloc_interval = 0;
+
+ if (geoloc_source) {
+ g_source_remove (geoloc_source);
+ geoloc_source = 0;
+ // Will reinstall source, if necessary
+ geoloc_publish_info ();
+ }
+
+ return g_strdup (new_value);
+}
+
+void pep_geoloc_init (void)
+{
+ geoloc_gerror_quark = g_quark_from_string ( "pep-geoloc-gerror-quark" );
+
+ geoloc_interval = settings_opt_get_int ("geoloc_interval");
+
+ geoloc_guard_installed = settings_set_guard ("geoloc_interval", geoloc_guard);
+ if (!geoloc_guard_installed)
+ scr_log_print (LPRINT_LOGNORM, "geoloc: Warning: cannot install option guard for 'geoloc_interval'.");
+
+ pep_register_xmlns_handler (NS_GEOLOC, geoloc_handler, NULL, NULL);
+
+ geoloc_reply_handler = lm_message_handler_new (geoloc_publish_reply_handler, NULL, NULL);
+
+ geoloc_hid_connect = hk_add_handler ( geoloc_hch, HOOK_POST_CONNECT, G_PRIORITY_DEFAULT, NULL );
+ geoloc_hid_disconnect = hk_add_handler ( geoloc_hdh, HOOK_PRE_DISCONNECT, G_PRIORITY_DEFAULT, NULL );
+ geoloc_hid_geolocout = hk_add_handler ( geoloc_hgoh, HOOK_GEOLOC_OUT, G_PRIORITY_DEFAULT, NULL );
+
+ xmpp_add_feature ( NS_GEOLOC );
+ xmpp_add_feature ( NS_GEOLOC_NOTIFY );
+}
+
+void pep_geoloc_uninit (void)
+{
+ xmpp_del_feature ( NS_GEOLOC );
+ xmpp_del_feature ( NS_GEOLOC_NOTIFY );
+
+ hk_del_handler ( HOOK_POST_CONNECT, geoloc_hid_connect );
+ hk_del_handler ( HOOK_PRE_DISCONNECT, geoloc_hid_disconnect );
+ hk_del_handler ( HOOK_GEOLOC_OUT, geoloc_hid_geolocout );
+
+ if (geoloc_source)
+ g_source_remove (geoloc_source);
+
+ pep_unregister_xmlns_handler ( NS_GEOLOC );
+
+ lm_message_handler_invalidate (geoloc_reply_handler);
+ lm_message_handler_unref (geoloc_reply_handler);
+#ifdef HAVE_LM_CONNECTION_UNREGISTE_REPLY_HANDLER
+ if (lconnection)
+ lm_connection_unregister_reply_handler (lconnection, handler);
+#endif
+
+ {
+ int i;
+ for (i = 0; i <= MAX_NO; ++i)
+ if (info[i].value)
+ g_free (info[i].value);
+ }
+
+ if (geoloc_guard_installed)
+ settings_del_guard ("geoloc_interval");
+}
+
+/* vim: se ts=4 sw=4: */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pep_mood.c Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,321 @@
+/*
+ * pep_mood.c -- Pep mood events
+ *
+ * Copyright (C) 2009-2012 Myhailo Danylenko <isbear@ukrpost.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <glib.h>
+#include <loudmouth/loudmouth.h>
+#include <string.h>
+
+#include <mcabber/utils.h>
+#include <mcabber/xmpp.h>
+#include <mcabber/xmpp_helper.h>
+#include <mcabber/logprint.h>
+#include <mcabber/hooks.h>
+#include <mcabber/modules.h>
+
+#include "pep.h"
+#include "mood.h"
+
+#include "config.h"
+
+//
+// module description
+//
+
+void pep_mood_init (void);
+void pep_mood_uninit (void);
+
+#define DESCRIPTION ( "PEP mood events handling" )
+
+static const gchar *deps[] = { "pep", NULL };
+
+static module_info_t info_mood_dev = {
+ .branch = "dev",
+ .api = 20,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = pep_mood_init,
+ .uninit = pep_mood_uninit,
+ .next = NULL,
+};
+
+module_info_t info_pep_mood = {
+ .branch = "0.10.1",
+ .api = 1,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = pep_mood_init,
+ .uninit = pep_mood_uninit,
+ .next = &info_mood_dev,
+};
+
+//
+// globals
+//
+
+static GQuark mood_gerror_quark = 0;
+static guint mood_hid_connect = 0;
+static guint mood_hid_disconnect = 0;
+static guint mood_hid_moodout = 0;
+static LmMessageHandler *mood_reply_handler = NULL;
+static gboolean publish_delayed = FALSE;
+static gchar *delayed_mood = NULL;
+static gchar *delayed_text = NULL;
+
+//
+// code
+//
+
+static LmHandlerResult mood_publish_reply_handler (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer userdata)
+{
+ switch (lm_message_get_sub_type (message)) {
+ case LM_MESSAGE_SUB_TYPE_RESULT:
+ break;
+
+ case LM_MESSAGE_SUB_TYPE_ERROR:
+
+ {
+ LmMessageNode *node = lm_message_get_node (message);
+ const gchar *type;
+ const gchar *reason;
+
+ node = lm_message_node_get_child (node, "error");
+ type = lm_message_node_get_attribute (node, "type");
+ if (node->children)
+ reason = node->children->name;
+ else
+ reason = "undefined";
+
+ scr_log_print (LPRINT_LOGNORM, "mood: Publish failed: %s - %s", type, reason);
+ }
+
+ break;
+
+ default:
+ return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+ break;
+ }
+
+ return LM_HANDLER_RESULT_REMOVE_MESSAGE;
+}
+
+void mood_publish (const gchar *mood, const gchar *text)
+{
+ if (!xmpp_is_online ()) {
+ scr_log_print (LPRINT_DEBUG, "mood: Delaying publish until online.");
+
+ g_free (delayed_mood);
+ g_free (delayed_text);
+
+ delayed_mood = g_strdup (mood);
+ delayed_text = g_strdup (text);
+ publish_delayed = TRUE;
+
+ return;
+ }
+
+ LmMessage *request = lm_message_new_with_sub_type (NULL, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET);
+ LmMessageNode *node = lm_message_get_node (request);
+ lm_message_node_set_attribute (node, "from", lm_connection_get_jid (lconnection));
+
+ node = lm_message_node_add_child (node, "pubsub", NULL);
+ lm_message_node_set_attribute (node, "xmlns", NS_PUBSUB);
+
+ node = lm_message_node_add_child (node, "publish", NULL);
+ lm_message_node_set_attribute (node, "node", NS_MOOD);
+
+ node = lm_message_node_add_child (node, "item", NULL);
+
+ node = lm_message_node_add_child (node, "mood", NULL);
+ lm_message_node_set_attribute (node, "xmlns", NS_MOOD);
+
+ if (mood)
+ lm_message_node_add_child (node, mood, NULL);
+ if (text)
+ lm_message_node_add_child (node, "text", text);
+
+ { // send
+ GError *error = NULL;
+
+ lm_connection_send_with_reply (lconnection, request, mood_reply_handler, &error);
+
+ if (error) {
+ scr_log_print (LPRINT_DEBUG, "mood: Publish sending error: %s.", error -> message);
+ g_error_free (error);
+ }
+ }
+
+ lm_message_unref (request);
+}
+
+gboolean mood_request ( const gchar *to, GError **err )
+{
+ LmMessage *request;
+ LmMessageNode *node;
+
+ if (!xmpp_is_online ()) {
+ g_set_error ( err, mood_gerror_quark, MOOD_ERROR_NOTCONNECTED, "You are not connected" );
+ return FALSE;
+ }
+
+ request = lm_message_new_with_sub_type (to, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET);
+ node = lm_message_get_node (request);
+ lm_message_node_set_attribute (node, "from", lm_connection_get_jid (lconnection));
+
+ node = lm_message_node_add_child (node, "pubsub", NULL);
+ lm_message_node_set_attribute (node, "xmlns", NS_PUBSUB);
+
+ node = lm_message_node_add_child (node, "items", NULL);
+ lm_message_node_set_attribute (node, "node", NS_MOOD);
+
+ { // send, result will be handled by pep
+ GError *error = NULL;
+
+ lm_connection_send (lconnection, request, &error);
+
+ if (error) {
+ g_propagate_error ( err, error );
+ return FALSE;
+ }
+ }
+
+ lm_message_unref (request);
+
+ return TRUE;
+}
+
+static void mood_handler ( const gchar *from, const gchar *enode, LmMessageNode *n, const gchar *id, gpointer ignore )
+{
+ LmMessageNode *node;
+ hk_arg_t args[] = {
+ { "mood", NULL },
+ { "text", NULL },
+ { "from", from },
+ { NULL, NULL },
+ };
+
+ for ( node = n -> children; node; node = node -> next ) {
+ const gchar *name = node -> name;
+
+ if ( ! strcmp ( name, "text" ) )
+ args[1].value = lm_message_node_get_value ( node );
+ else
+ args[0].value = name;
+ }
+
+ hk_run_handlers ( HOOK_MOOD_IN, args );
+}
+
+static guint mood_hch (const gchar *hid, hk_arg_t *args, gpointer userdata)
+{
+ if (publish_delayed) {
+
+ char *tmp_mood = delayed_mood;
+ char *tmp_text = delayed_text;
+
+ scr_log_print (LPRINT_DEBUG, "mood: Publishing delayed data.");
+
+ delayed_mood = delayed_text = NULL;
+ publish_delayed = FALSE;
+
+ mood_publish (tmp_mood, tmp_text);
+
+ g_free (tmp_mood);
+ g_free (tmp_text);
+ }
+
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+static guint mood_hdh (const gchar *hid, hk_arg_t *args, gpointer userdata)
+{
+#ifdef HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER
+ if (lconnection && mood_reply_handler)
+ lm_connection_unregister_reply_handler (lconnection, mood_reply_handler);
+#endif
+
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+static guint mood_hmoh ( const gchar *hid, hk_arg_t *args, gpointer userdata )
+{
+ const gchar *mood = NULL;
+ const gchar *text = NULL;
+
+ {
+ hk_arg_t *arg;
+ for ( arg = args; arg -> name; arg ++ ) {
+ const gchar *value = arg -> value;
+ if ( value ) {
+ const gchar *name = arg -> name;
+ if ( ! strcmp ( name, "mood" ) )
+ mood = value;
+ else if ( ! strcmp ( name, "text" ) )
+ text = value;
+ }
+ }
+ }
+
+ mood_publish ( mood, text );
+
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+void pep_mood_init (void)
+{
+ mood_gerror_quark = g_quark_from_string ( "pep-mood-gerror-quark" );
+
+ mood_reply_handler = lm_message_handler_new (mood_publish_reply_handler, NULL, NULL);
+
+ pep_register_xmlns_handler (NS_MOOD, mood_handler, NULL, NULL);
+
+ mood_hid_connect = hk_add_handler ( mood_hch, HOOK_POST_CONNECT, G_PRIORITY_DEFAULT, NULL );
+ mood_hid_disconnect = hk_add_handler ( mood_hdh, HOOK_PRE_DISCONNECT, G_PRIORITY_DEFAULT, NULL );
+ mood_hid_moodout = hk_add_handler ( mood_hmoh, HOOK_MOOD_OUT, G_PRIORITY_DEFAULT, NULL );
+
+ xmpp_add_feature ( NS_MOOD );
+ xmpp_add_feature ( NS_MOOD_NOTIFY );
+}
+
+void pep_mood_uninit (void)
+{
+ xmpp_del_feature ( NS_MOOD );
+ xmpp_del_feature ( NS_MOOD_NOTIFY );
+
+ hk_del_handler ( HOOK_POST_CONNECT, mood_hid_connect );
+ hk_del_handler ( HOOK_PRE_DISCONNECT, mood_hid_disconnect );
+ hk_del_handler ( HOOK_MOOD_OUT, mood_hid_moodout );
+
+ pep_unregister_xmlns_handler (NS_MOOD);
+
+#ifdef HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER
+ if (lconnection && mood_reply_handler)
+ lm_connection_unregister_reply_handler (lconnection, mood_reply_handler);
+#endif
+ lm_message_handler_invalidate (mood_reply_handler);
+ lm_message_handler_unref (mood_reply_handler);
+
+ g_free ( delayed_mood );
+ g_free ( delayed_text );
+}
+
+/* vim: se ts=4 sw=4: */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pep_tune.c Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,437 @@
+
+/* Copyright 2009-2012 Myhailo Danylenko
+ *
+ * This file is part of mcabber-pep
+ *
+ * mcabber-pep is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <glib.h>
+#include <loudmouth/loudmouth.h>
+#include <stdlib.h> // atoi
+#include <time.h>
+
+#include <mcabber/settings.h>
+#include <mcabber/utils.h>
+#include <mcabber/xmpp.h>
+#include <mcabber/xmpp_helper.h>
+#include <mcabber/logprint.h>
+#include <mcabber/hooks.h>
+#include <mcabber/modules.h>
+
+#include "pep.h"
+#include "tune.h"
+
+#include "config.h"
+
+//
+// module description
+//
+
+void pep_tune_init (void);
+void pep_tune_uninit (void);
+
+#define DESCRIPTION ( \
+ "PEP tune event handler\n" \
+ "Recognizes option tune_interval" )
+
+static const gchar *deps[] = { "pep", NULL };
+
+static module_info_t info_tune_dev = {
+ .branch = "dev",
+ .api = 20,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = pep_tune_init,
+ .uninit = pep_tune_uninit,
+ .next = NULL,
+};
+
+static module_info_t info_tune_0_10_0 = {
+ .branch = "0.10.0",
+ .api = 1,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = pep_tune_init,
+ .uninit = pep_tune_uninit,
+ .next = &info_tune_dev,
+};
+
+module_info_t info_pep_tune = {
+ .branch = "0.10.1",
+ .api = 1,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = pep_tune_init,
+ .uninit = pep_tune_uninit,
+ .next = &info_tune_0_10_0,
+};
+
+//
+// globals
+//
+
+#define MAX_NO ( 6 )
+
+static tune_pair_t info[] = {
+ { "artist", NULL },
+ { "length", NULL },
+ { "rating", NULL },
+ { "source", NULL },
+ { "title", NULL },
+ { "track", NULL },
+ { "uri", NULL },
+ { NULL, NULL },
+};
+
+static GQuark tune_gerror_quark = 0;
+static gboolean publish_delayed = FALSE;
+static guint tune_hid_connect = 0;
+static guint tune_hid_disconnect = 0;
+static guint tune_hid_tuneout = 0;
+static guint tune_interval = 0;
+static time_t tune_timestamp = 0;
+static LmMessageHandler *tune_reply_handler = NULL;
+static guint tune_source = 0;
+static gboolean tune_guard_installed = FALSE;
+
+//
+// predeclarations
+//
+
+static void tune_publish_info (void);
+
+//
+// code
+//
+
+static LmHandlerResult tune_publish_reply_handler (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer userdata)
+{
+ switch (lm_message_get_sub_type (message)) {
+ case LM_MESSAGE_SUB_TYPE_RESULT:
+ break;
+
+ case LM_MESSAGE_SUB_TYPE_ERROR:
+
+ {
+ LmMessageNode *node = lm_message_get_node (message);
+ const gchar *type;
+ const gchar *reason;
+
+ node = lm_message_node_get_child (node, "error");
+ type = lm_message_node_get_attribute (node, "type");
+ if (node->children)
+ reason = node->children->name;
+ else
+ reason = "undefined";
+
+ scr_log_print (LPRINT_LOGNORM, "tune: Publish failed: %s - %s", type, reason);
+ }
+
+ break;
+
+ default:
+ return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+ break;
+ }
+
+ return LM_HANDLER_RESULT_REMOVE_MESSAGE;
+}
+
+static gboolean tune_delayed_publish_cb (gpointer data)
+{
+ tune_source = 0;
+ tune_publish_info ();
+ return FALSE;
+}
+
+static void tune_publish_info (void)
+{
+ if (!xmpp_is_online ()) {
+ scr_log_print (LPRINT_DEBUG, "tune: Not online, delaying publish.");
+ publish_delayed = TRUE;
+ return;
+ }
+
+ // check for frequency of publihes
+ if (tune_interval) {
+ time_t now = time (NULL);
+
+ if (now - tune_timestamp < tune_interval) {
+
+ scr_log_print (LPRINT_DEBUG, "tune: Publish interval not passed, delaying publish.");
+ if (!tune_source)
+ tune_source = g_timeout_add_seconds ( tune_interval - ( now - tune_timestamp ), tune_delayed_publish_cb, NULL );
+ return;
+
+ } else
+ tune_timestamp = now;
+ }
+
+ // publish
+ LmMessage *request = lm_message_new_with_sub_type (NULL, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET);
+ LmMessageNode *node = lm_message_get_node (request);
+ lm_message_node_set_attribute (node, "from", lm_connection_get_jid (lconnection));
+
+ node = lm_message_node_add_child (node, "pubsub", NULL);
+ lm_message_node_set_attribute (node, "xmlns", NS_PUBSUB);
+
+ node = lm_message_node_add_child (node, "publish", NULL);
+ lm_message_node_set_attribute (node, "node", NS_TUNE);
+
+ node = lm_message_node_add_child (node, "item", NULL);
+
+ node = lm_message_node_add_child (node, "tune", NULL);
+ lm_message_node_set_attribute (node, "xmlns", NS_TUNE);
+
+ { // put data inside
+ int i;
+
+ for (i = 0; i <= MAX_NO; ++i)
+ if (info[i].value)
+ lm_message_node_add_child (node, info[i].name, info[i].value);
+ }
+
+ { // send
+ GError *error = NULL;
+
+ lm_connection_send_with_reply (lconnection, request, tune_reply_handler, &error);
+
+ if (error) {
+ scr_log_print (LPRINT_DEBUG, "tune: Publishing error: %s.", error -> message);
+ g_error_free (error);
+ }
+ }
+
+ lm_message_unref (request);
+}
+
+void tune_publish (const tune_pair_t *pairs)
+{
+ gboolean publish = FALSE;
+ const tune_pair_t *tag;
+ tune_pair_t new_info[] = {
+ { "artist", NULL },
+ { "length", NULL },
+ { "rating", NULL },
+ { "source", NULL },
+ { "title", NULL },
+ { "track", NULL },
+ { "uri", NULL },
+ { NULL, NULL },
+ };
+
+ // populate new_info with new values
+ for (tag = pairs; tag->name; ++tag) {
+ int i;
+ for (i = 0; i <= MAX_NO; ++i)
+ if (!g_strcmp0 (tag->name, new_info[i].name))
+ new_info[i].value = tag->value;
+ }
+
+ { // check, if it differ from info
+ int i;
+ for (i = 0; i <= MAX_NO; ++i)
+ if (g_strcmp0 (new_info[i].value, info[i].value)) {
+ publish = TRUE;
+ break;
+ }
+ }
+
+ if (publish) {
+
+ { // copy new values to info
+ int i;
+ for (i = 0; i <= MAX_NO; ++i) {
+ if (info[i].value)
+ g_free (info[i].value);
+ info[i].value = g_strdup (new_info[i].value);
+ }
+ }
+
+ tune_publish_info ();
+ }
+}
+
+gboolean tune_request ( const gchar *to, GError **err )
+{
+ LmMessage *request;
+ LmMessageNode *node;
+
+ if (!xmpp_is_online ()) {
+ g_set_error ( err, tune_gerror_quark, TUNE_ERROR_NOTCONNECTED, "You are not connected" );
+ return FALSE;
+ }
+
+ request = lm_message_new_with_sub_type ( to, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET );
+ node = lm_message_get_node (request);
+ lm_message_node_set_attribute (node, "from", lm_connection_get_jid (lconnection));
+
+ node = lm_message_node_add_child (node, "pubsub", NULL);
+ lm_message_node_set_attribute (node, "xmlns", NS_PUBSUB);
+
+ node = lm_message_node_add_child (node, "items", NULL);
+ lm_message_node_set_attribute (node, "node", NS_TUNE);
+
+ { // send, result will be handled by pep
+ GError *error = NULL;
+
+ lm_connection_send ( lconnection, request, &error );
+
+ if ( error ) {
+ g_propagate_error ( err, error );
+ return FALSE;
+ }
+ }
+
+ lm_message_unref (request);
+
+ return TRUE;
+}
+
+static void tune_handler ( const gchar *from, const gchar *node, LmMessageNode *n, const gchar *id, gpointer ignore )
+{
+ LmMessageNode *tag;
+ hk_arg_t args[] = {
+ { "artist", NULL },
+ { "length", NULL },
+ { "rating", NULL },
+ { "source", NULL },
+ { "title", NULL },
+ { "track", NULL },
+ { "uri", NULL },
+ { "from", from },
+ { NULL, NULL },
+ };
+
+ for ( tag = n -> children; tag; tag = tag -> next ) {
+ const gchar *name = tag -> name;
+ if ( name ) {
+ int i;
+ for ( i = 0; i <= MAX_NO; ++i )
+ if ( ! g_strcmp0 ( name, args[i].name ) ) {
+ const gchar *value = lm_message_node_get_value ( tag );
+ if ( value )
+ args[i].value = value;
+ }
+ }
+ }
+
+ hk_run_handlers ( HOOK_TUNE_IN, args );
+}
+
+static guint tune_hch (const gchar *htype, hk_arg_t *args, gpointer udata)
+{
+ if (publish_delayed) {
+ scr_log_print (LPRINT_DEBUG, "tune: Publishing delayed data.");
+
+ publish_delayed = FALSE;
+ tune_publish_info ();
+ }
+
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+static guint tune_hdh (const gchar *htype, hk_arg_t *args, gpointer udata)
+{
+#ifdef HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER
+ if (lconnection && tune_reply_handler)
+ lm_connection_unregister_reply_handler (lconnection, tune_reply_handler);
+#endif
+
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+static guint tune_htoh ( const gchar *htype, hk_arg_t *args, gpointer udata )
+{
+ tune_publish ( (const tune_pair_t *) args );
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+static gchar *tune_guard (const char *key, const char *new_value)
+{
+ if (new_value)
+ tune_interval = atoi (new_value);
+ else
+ tune_interval = 0;
+
+ if (tune_source) {
+ g_source_remove (tune_source);
+ tune_source = 0;
+ // this will reinstall source with proper timeout, if necessary
+ tune_publish_info ();
+ }
+
+ return g_strdup (new_value);
+}
+
+void pep_tune_init(void)
+{
+ tune_gerror_quark = g_quark_from_string ( "pep-tune-gerror-quark" );
+
+ tune_interval = settings_opt_get_int ("tune_interval");
+
+ tune_guard_installed = settings_set_guard ("tune_interval", tune_guard);
+ if (!tune_guard_installed)
+ scr_log_print (LPRINT_LOGNORM, "tune: Warning: cannot install option guard for 'tune_interval'");
+
+ pep_register_xmlns_handler (NS_TUNE, tune_handler, NULL, NULL);
+
+ tune_reply_handler = lm_message_handler_new ( tune_publish_reply_handler, NULL, NULL );
+
+ tune_hid_connect = hk_add_handler ( tune_hch, HOOK_POST_CONNECT, G_PRIORITY_DEFAULT, NULL );
+ tune_hid_disconnect = hk_add_handler ( tune_hdh, HOOK_PRE_DISCONNECT, G_PRIORITY_DEFAULT, NULL );
+ tune_hid_tuneout = hk_add_handler ( tune_htoh, HOOK_TUNE_OUT, G_PRIORITY_DEFAULT, NULL );
+
+ xmpp_add_feature ( NS_TUNE );
+ xmpp_add_feature ( NS_TUNE_NOTIFY );
+}
+
+void pep_tune_uninit ( void )
+{
+ xmpp_del_feature ( NS_TUNE );
+ xmpp_del_feature ( NS_TUNE_NOTIFY );
+
+ hk_del_handler ( HOOK_POST_CONNECT, tune_hid_connect );
+ hk_del_handler ( HOOK_PRE_DISCONNECT, tune_hid_disconnect );
+ hk_del_handler ( HOOK_TUNE_OUT, tune_hid_tuneout );
+
+ if ( tune_source )
+ g_source_remove ( tune_source );
+
+ pep_unregister_xmlns_handler ( NS_TUNE );
+
+ if ( tune_reply_handler ) {
+#ifdef HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER
+ if ( lconnection )
+ lm_connection_unregister_reply_handler ( lconnection, tune_reply_handler );
+#endif
+
+ lm_message_handler_invalidate ( tune_reply_handler );
+ lm_message_handler_unref ( tune_reply_handler );
+ }
+
+ {
+ int i;
+ for ( i = 0; i <= MAX_NO; i ++ )
+ g_free ( info[i].value );
+ }
+
+ if ( tune_guard_installed )
+ settings_del_guard ( "tune_interval" );
+}
+
+/* vim: se ts=4 sw=4: */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tune.c Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,302 @@
+
+/* Copyright 2009-2012 Myhailo Danylenko
+ *
+ * This file is part of mcabber-pep
+ *
+ * mcabber-pep is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <glib.h>
+#include <string.h>
+
+#include <mcabber/commands.h>
+#include <mcabber/compl.h>
+#include <mcabber/utils.h>
+#include <mcabber/screen.h>
+#include <mcabber/logprint.h>
+#include <mcabber/roster.h>
+#include <mcabber/hbuf.h> // HBUF_PREFIX_*
+#include <mcabber/hooks.h>
+#include <mcabber/modules.h>
+
+#include "tune.h"
+
+#include "config.h"
+
+//
+// module description
+//
+
+void tune_init (void);
+void tune_uninit (void);
+
+#define DESCRIPTION ( \
+ "User interface for PEP tune events\n" \
+ "Prints incoming notifications into buddies buffers\n" \
+ "Provides command /tune" )
+
+static const gchar *deps[] = { "pep_tune", NULL };
+
+static module_info_t info_tune_dev = {
+ .branch = "dev",
+ .api = 20,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = tune_init,
+ .uninit = tune_uninit,
+ .next = NULL,
+};
+
+static module_info_t info_tune_0_10_0 = {
+ .branch = "0.10.0",
+ .api = 1,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = tune_init,
+ .uninit = tune_uninit,
+ .next = &info_tune_dev,
+};
+
+module_info_t info_tune = {
+ .branch = "0.10.1",
+ .api = 1,
+ .version = PROJECT_VERSION,
+ .description = DESCRIPTION,
+ .requires = deps,
+ .init = tune_init,
+ .uninit = tune_uninit,
+ .next = &info_tune_0_10_0,
+};
+
+//
+// globals
+//
+
+#ifdef MCABBER_API_HAVE_CMD_ID
+static gpointer tune_cmid = NULL;
+static gboolean tune_set_safe = FALSE;
+#endif
+
+static guint tune_cid = 0;
+static guint tune_hid_tunein = 0;
+
+//
+// code
+//
+
+static void do_tune (char *arg)
+{
+ hk_arg_t tags[] = {
+ { "artist", NULL },
+ { "length", NULL },
+ { "rating", NULL },
+ { "source", NULL },
+ { "title", NULL },
+ { "track", NULL },
+ { "uri", NULL },
+ { NULL, NULL },
+ };
+
+ if (!*arg) { // request
+
+ GError *error = NULL;
+
+ tune_request ( CURRENT_JID, &error );
+ if ( error ) {
+ scr_log_print ( LPRINT_NORMAL, "Error sending request: %s.", error -> message );
+ g_error_free ( error );
+ } else
+ scr_log_print ( LPRINT_NORMAL, "Request sent." ); // XXX
+
+ return;
+
+ } else if (arg[0] != '-' || arg[1] != '\0') {
+
+ char *p;
+ char *argstart = NULL;
+ char *argstop = NULL;
+ char *tagstart = NULL;
+ char *tagstop = NULL;
+ char *wordstart = arg;
+ gboolean proceed = TRUE;
+
+// pt = p, ws = wordstart, ts = tagstart, tt = tagstop, as = argstart, at = argstop
+// tag=value value tag=value
+// w p
+// s t
+// t ta
+// s t*
+// tag=value value tag=value
+// t ta p
+// s t* t
+// t ta aw
+// s ts ts
+// tag=value value tag=value
+// t ta aw p
+// s ts ts t
+// t ta aw
+// s ts ts
+// tag=value value tag=value
+// t ta aw p
+// s ts ts t
+// t ta
+// s t*
+// tag=value value tag=value
+// t ta p
+// s t* t
+// t ta a
+// s ts t
+
+ for (p = arg; proceed; ++p) {
+ switch (*p) {
+ case '=':
+ if (tagstart && tagstop - tagstart) {
+ // process previous args
+ hk_arg_t *tag;
+
+ for (tag = tags; tag->name; ++tag) {
+ if (!strncmp (tag->name, tagstart, tagstop - tagstart)) {
+ g_free ( (gchar *) tag->value );
+ if (argstop - argstart) {
+ *argstop = '\0';
+ tag->value = to_utf8 (argstart);
+ }
+ break;
+ }
+ }
+ }
+
+ tagstart = wordstart;
+ tagstop = p;
+ argstop = p+1;
+ argstart = p+1;
+ break;
+
+ case '\0':
+ argstop = p;
+
+ if (tagstop - tagstart) {
+ // process previous args
+ hk_arg_t *tag;
+
+ for (tag = tags; tag->name; ++tag) {
+ if (!strncmp (tag->name, tagstart, tagstop - tagstart)) {
+ g_free ( (gchar *) tag->value );
+ if (argstop - argstart)
+ tag->value = to_utf8 (argstart);
+ break;
+ }
+ }
+ }
+
+ proceed = FALSE;
+ break;
+
+ case ' ':
+ argstop = p;
+ wordstart = p+1;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ hk_run_handlers ( HOOK_TUNE_OUT, tags );
+
+ {
+ hk_arg_t *tag;
+
+ for (tag = tags; tag->name; ++tag)
+ g_free ( (gchar *) tag->value );
+ }
+}
+
+static guint tune_htih ( const gchar *htype, hk_arg_t *args, gpointer udata )
+{
+ GString *mesg = g_string_new ( NULL );
+ const gchar *from = NULL;
+
+ {
+ hk_arg_t *arg;
+ for ( arg = args; arg -> name; arg ++ )
+ if ( arg -> value ) {
+ if ( ! strcmp ( arg -> name, "from" ) )
+ from = arg -> value;
+ else
+ g_string_append_printf ( mesg, "\n - %s: %s", arg -> name, arg -> value );
+ }
+ }
+
+ if (mesg->len)
+ g_string_prepend (mesg, "Now listens to:");
+ else
+ g_string_overwrite (mesg, 0, "Now listening to nothing");
+
+ { // print to buddy's buffer
+ gchar *jid = jidtodisp ( from );
+
+ scr_write_incoming_message ( jid, mesg->str, 0, HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0 ); // NO conversion from utf-8
+
+ g_free ( jid );
+ }
+
+ g_string_free ( mesg, TRUE );
+
+ return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+}
+
+void tune_init(void)
+{
+ tune_cid = compl_new_category ();
+ if (tune_cid) {
+ compl_add_category_word (tune_cid, "artist=");
+ compl_add_category_word (tune_cid, "length=");
+ compl_add_category_word (tune_cid, "rating=");
+ compl_add_category_word (tune_cid, "source=");
+ compl_add_category_word (tune_cid, "title=");
+ compl_add_category_word (tune_cid, "track=");
+ compl_add_category_word (tune_cid, "uri=");
+ }
+
+#ifndef MCABBER_API_HAVE_CMD_ID
+ cmd_add ("tune", "", tune_cid, tune_cid, do_tune, NULL);
+#else
+ tune_cmid = cmd_add ("tune", "", tune_cid, tune_cid, do_tune, NULL);
+ tune_set_safe = cmd_set_safe ("tune", TRUE);
+#endif
+
+ tune_hid_tunein = hk_add_handler (tune_htih, HOOK_TUNE_IN, G_PRIORITY_DEFAULT, NULL);
+}
+
+void tune_uninit(void)
+{
+ hk_del_handler (HOOK_TUNE_IN, tune_hid_tunein);
+
+#ifndef MCABBER_API_HAVE_CMD_ID
+ cmd_del ("tune");
+#else
+ if (tune_cmid)
+ cmd_del (tune_cmid);
+ if (tune_set_safe)
+ cmd_set_safe ("tune", FALSE);
+#endif
+
+ if (tune_cid)
+ compl_del_category (tune_cid);
+}
+
+/* vim: se ts=4 sw=4: */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tune.h Sun May 20 22:15:51 2012 +0300
@@ -0,0 +1,45 @@
+
+#ifndef MCABBER_TUNE_H
+#define MCABBER_TUNE_H
+
+/*
+ * tune.h -- Pep tune events
+ *
+ * Copyright (C) 2009-2012 Myhailo Danylenko <isbear@ukrpost.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <glib.h>
+
+#define NS_TUNE ( "http:/" "/jabber.org/protocol/tune" )
+#define NS_TUNE_NOTIFY ( "http:/" "/jabber.org/protocol/tune+notify" )
+
+#define HOOK_TUNE_IN ( "tune-in" )
+#define HOOK_TUNE_OUT ( "tune-out" )
+
+#define TUNE_ERROR_NOTCONNECTED ( 0x01 )
+
+typedef struct {
+ const gchar *name;
+ gchar *value;
+} tune_pair_t;
+
+void tune_publish ( const tune_pair_t *pairs );
+gboolean tune_request ( const gchar *to, GError **err );
+
+#endif
+