# HG changeset patch # User Marcus Lundblad # Date 1239081052 0 # Node ID 7fba18b43da35697e6ca19f08e5a284931c4655a # Parent 12089d993a0cdbd09c4f05ef2d100f9c95ddb68c# Parent fb44acfae44144284e0ca41932ad3e1d8ac2e6c6 propagate from branch 'im.pidgin.pidgin' (head eed0598058a6e7cc5da7ad99f06bfe136291d2f9) to branch 'im.pidgin.cpw.malu.xmpp.idle' (head 6e86275961530024d108fa7f061327fd01a92969) diff -r 12089d993a0c -r 7fba18b43da3 COPYRIGHT --- a/COPYRIGHT Sat Apr 04 10:33:33 2009 +0000 +++ b/COPYRIGHT Tue Apr 07 05:10:52 2009 +0000 @@ -19,6 +19,7 @@ Christopher Ayoup Alex Badea John Bailey +Arunan Balasubramaniam R. Tyler Ballance Chris Banal Luca Barbato @@ -332,10 +333,9 @@ Joao Luís Marques Pinto Aleksander Piotrowski Julien Pivotto +Robey Pointer Eric Polino Ari Pollak -Robey Pointer -Eric Polino Stephen Pope Nathan Poznick Jory A. Pratt diff -r 12089d993a0c -r 7fba18b43da3 ChangeLog --- a/ChangeLog Sat Apr 04 10:33:33 2009 +0000 +++ b/ChangeLog Tue Apr 07 05:10:52 2009 +0000 @@ -13,8 +13,10 @@ * Add voice & video support with Jingle (XEP-0166, 0167, 0176, & 0177), and voice support with GTalk and GMail. (Mike "Maiku" Ruprecht) * Add support for in-band bytestreams for file transfers (XEP-0047). - * Add support for sending attentions (equivalent to "buzz" and "nudge") - using the command /buzz (XEP-0224). + * Add support for sending and receiving attentions (equivalent to "buzz" + and "nudge") using the command /buzz (XEP-0224). + * A buddy's local time is displayed in the Get Info dialog if the remote + client supports it. IRC: * Correctly handle WHOIS for users who are joined to a large number of @@ -35,6 +37,11 @@ * The New Account dialog is now broken into three tabs. Proxy configuration has been moved from the Advanced tab to the new tab. + Finch: + * The hardware cursor is updated correctly. This will be useful + especially for users of braille terminals, screen readers etc. + * Added a TinyURL plugin, which aids copying longer URLs. + version 2.5.5 (03/01/2009): libpurple: * Fix a crash when removing an account with an unknown protocol id. diff -r 12089d993a0c -r 7fba18b43da3 configure.ac --- a/configure.ac Sat Apr 04 10:33:33 2009 +0000 +++ b/configure.ac Tue Apr 07 05:10:52 2009 +0000 @@ -748,13 +748,33 @@ fi dnl ####################################################################### +dnl # Check for GStreamer Interfaces +dnl ####################################################################### +if test "x$enable_gst" != "xno"; then + AC_ARG_ENABLE(gstreamer-interfaces, + [AC_HELP_STRING([--disable-gstreamer-interfaces], [compile without GStreamer interface support])], + enable_gstinterfaces="$enableval", enable_gstinterfaces="yes") + if test "x$enable_gstinterfaces" != "xno"; then + PKG_CHECK_MODULES(GSTINTERFACES, [gstreamer-interfaces-0.10], [ + AC_DEFINE(USE_GSTINTERFACES, 1, [Use GStreamer interfaces for X overlay support]) + AC_SUBST(GSTINTERFACES_CFLAGS) + AC_SUBST(GSTINTERFACES_LIBS) + ], [ + enable_gstinterfaces="no" + ]) + fi +else + enable_gstinterfaces="no" +fi + +dnl ####################################################################### dnl # Check for Farsight dnl ####################################################################### AC_ARG_ENABLE(farsight, [AC_HELP_STRING([--disable-farsight], [compile without farsight support])], enable_farsight="$enableval", enable_farsight="yes") if test "x$enable_farsight" != "xno"; then - PKG_CHECK_MODULES(FARSIGHT, [farsight2-0.10 >= 0.0.8 gstreamer-0.10 gstreamer-plugins-base-0.10 libxml-2.0], [ + PKG_CHECK_MODULES(FARSIGHT, [farsight2-0.10 >= 0.0.8], [ AC_DEFINE(USE_FARSIGHT, 1, [Use Farsight for voice and video]) AC_SUBST(FARSIGHT_CFLAGS) AC_SUBST(FARSIGHT_LIBS) @@ -764,36 +784,23 @@ fi dnl ####################################################################### -dnl # Check for GStreamer-properties -dnl ####################################################################### -AC_ARG_ENABLE(gstprops, - [AC_HELP_STRING([--disable-gstprops], [compile without gstreamer props])], - enable_gstprops="$enableval", enable_gstprops="yes") -if test "x$enable_gstprops" != "xno"; -then - dnl gstreamer-libs-$GST_MAJORMINOR - dnl gstreamer-gconf-$GST_MAJORMINOR - PKG_CHECK_MODULES(GSTPROPS, [gstreamer-0.10 gstreamer-plugins-base-0.10 libxml-2.0], [ - GSTPROPS_LIBS="$GSTPROPS_LIBS -lgstinterfaces-0.10" - AC_DEFINE(USE_GSTPROPS, 1, [Use GStreamer property probe for finding devices]) - AC_SUBST(GSTPROPS_LIBS) - AC_SUBST(GSTPROPS_CFLAGS) - ], [ - enable_gstprops="no" - ]) -fi - -dnl ####################################################################### dnl # Check for Voice and Video support dnl ####################################################################### AC_ARG_ENABLE(vv, [AC_HELP_STRING([--disable-vv], [compile without voice and video support])], - enable_vv="$enableval", enable_vv="yes") + [enable_vv="$enableval" force_vv=$enableval], [enable_vv="yes" force_vv=no]) if test "x$enable_vv" != "xno"; then - if test "x$enable_farsight" != "xno" -a "x$enable_gstprops" != "xno"; then + if test "x$enable_gstreamer" != "xno" -a "x$enable_gstinterfaces" != "xno" -a "x$enable_farsight" != "xno"; then AC_DEFINE(USE_VV, 1, [Use voice and video]) else enable_vv="no" + if test "x$force_vv" = "xyes"; then + AC_MSG_ERROR([ +Dependencies for voice/video were not met. +Install the necessary gstreamer and farsight packages first. +Or use --disable-vv if you do not need voice/video support. + ]) + fi fi fi diff -r 12089d993a0c -r 7fba18b43da3 doc/finch.1.in --- a/doc/finch.1.in Sat Apr 04 10:33:33 2009 +0000 +++ b/doc/finch.1.in Tue Apr 07 05:10:52 2009 +0000 @@ -59,7 +59,7 @@ Display the version information window. .SH GNT Shortcuts -You can use the following shortcuts: +You can use the following shortcuts (see the "\*QWidget Actions\*U" section for a more complete list): .TP .B Alt \+ a Bring up a list of available actions. You can use this list to access the @@ -378,6 +378,8 @@ [GntWidget::binding] .br f11 = context-menu +.br +c-x = context-menu [GntWindow::binding] .br diff -r 12089d993a0c -r 7fba18b43da3 finch/gntaccount.c --- a/finch/gntaccount.c Sat Apr 04 10:33:33 2009 +0000 +++ b/finch/gntaccount.c Tue Apr 07 05:10:52 2009 +0000 @@ -669,8 +669,13 @@ account_toggled(GntWidget *widget, void *key, gpointer null) { PurpleAccount *account = key; + gboolean enabled = gnt_tree_get_choice(GNT_TREE(widget), key); - purple_account_set_enabled(account, FINCH_UI, gnt_tree_get_choice(GNT_TREE(widget), key)); + if (enabled) + purple_savedstatus_activate_for_account(purple_savedstatus_get_current(), + account); + + purple_account_set_enabled(account, FINCH_UI, enabled); } static gboolean diff -r 12089d993a0c -r 7fba18b43da3 finch/gntblist.c --- a/finch/gntblist.c Sat Apr 04 10:33:33 2009 +0000 +++ b/finch/gntblist.c Tue Apr 07 05:10:52 2009 +0000 @@ -61,7 +61,7 @@ #include #define PREF_ROOT "/finch/blist" -#define TYPING_TIMEOUT 4000 +#define TYPING_TIMEOUT_S 4 #define SHOW_EMPTY_GROUP_TIMEOUT 60 @@ -2016,7 +2016,7 @@ } if (ggblist->typing) - g_source_remove(ggblist->typing); + purple_timeout_remove(ggblist->typing); remove_peripherals(ggblist); if (ggblist->tagged) g_list_free(ggblist->tagged); @@ -2253,7 +2253,7 @@ end: g_free(escnewmessage); if (ggblist->typing) - g_source_remove(ggblist->typing); + purple_timeout_remove(ggblist->typing); ggblist->typing = 0; return FALSE; } @@ -2272,7 +2272,7 @@ /* Move the focus to the entry box */ /* XXX: Make sure the selected status can have a message */ gnt_box_move_focus(GNT_BOX(ggblist->window), 1); - ggblist->typing = g_timeout_add(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, NULL); + ggblist->typing = purple_timeout_add_seconds(TYPING_TIMEOUT_S, (GSourceFunc)remove_typing_cb, NULL); } else if (now->type == STATUS_SAVED_ALL) { @@ -2298,7 +2298,7 @@ return FALSE; if (ggblist->typing) - g_source_remove(ggblist->typing); + purple_timeout_remove(ggblist->typing); ggblist->typing = 0; if (text[0] == '\r' && text[1] == 0) @@ -2308,7 +2308,7 @@ return TRUE; } - ggblist->typing = g_timeout_add(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, NULL); + ggblist->typing = purple_timeout_add_seconds(TYPING_TIMEOUT_S, (GSourceFunc)remove_typing_cb, NULL); return FALSE; } diff -r 12089d993a0c -r 7fba18b43da3 finch/gntmedia.c --- a/finch/gntmedia.c Sat Apr 04 10:33:33 2009 +0000 +++ b/finch/gntmedia.c Tue Apr 07 05:10:52 2009 +0000 @@ -272,7 +272,7 @@ alias); } else { message = g_strdup_printf( - _("%s is trying to start an unsuppoted media session type with you."), + _("%s is trying to start an unsupported media session type with you."), alias); } finch_media_emit_message(gntmedia, message); diff -r 12089d993a0c -r 7fba18b43da3 finch/libgnt/gnt.h --- a/finch/libgnt/gnt.h Sat Apr 04 10:33:33 2009 +0000 +++ b/finch/libgnt/gnt.h Tue Apr 07 05:10:52 2009 +0000 @@ -48,6 +48,10 @@ #define G_PARAM_STATIC_BLURB G_PARAM_PRIVATE #endif +#if !GLIB_CHECK_VERSION(2,14,0) + #define g_timeout_add_seconds(time, callback, data) g_timeout_add(time * 1000, callback, data) +#endif + /** * Initialize GNT. */ diff -r 12089d993a0c -r 7fba18b43da3 finch/libgnt/gntbox.c --- a/finch/libgnt/gntbox.c Sat Apr 04 10:33:33 2009 +0000 +++ b/finch/libgnt/gntbox.c Tue Apr 07 05:10:52 2009 +0000 @@ -78,13 +78,11 @@ g_list_foreach(box->list, (GFunc)gnt_widget_draw, NULL); - gnt_box_sync_children(box); - if (box->title && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) { int pos, right; char *title = g_strdup(box->title); - + get_title_thingies(box, title, &pos, &right); if (gnt_widget_has_focus(widget)) @@ -96,8 +94,8 @@ mvwaddch(widget->window, 0, right, ACS_LTEE | gnt_color_pair(GNT_COLOR_NORMAL)); g_free(title); } - - GNTDEBUG; + + gnt_box_sync_children(box); } static void @@ -723,6 +721,9 @@ if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) pos = 0; + if (!box->active) + find_focusable_widget(box); + for (iter = box->list; iter; iter = iter->next) { GntWidget *w = GNT_WIDGET(iter->data); @@ -764,6 +765,9 @@ copywin(w->window, widget->window, 0, 0, y, x, y + height - 1, x + width - 1, FALSE); gnt_widget_set_position(w, x + widget->priv.x, y + widget->priv.y); + if (w == box->active) { + wmove(widget->window, y + getcury(w->window), x + getcurx(w->window)); + } } } diff -r 12089d993a0c -r 7fba18b43da3 finch/libgnt/gntcheckbox.c --- a/finch/libgnt/gntcheckbox.c Sat Apr 04 10:33:33 2009 +0000 +++ b/finch/libgnt/gntcheckbox.c Tue Apr 07 05:10:52 2009 +0000 @@ -42,7 +42,7 @@ type = GNT_COLOR_HIGHLIGHT; else type = GNT_COLOR_NORMAL; - + wbkgdset(widget->window, '\0' | gnt_color_pair(type)); text = g_strdup_printf("[%c]", cb->checked ? 'X' : ' '); @@ -51,7 +51,8 @@ wbkgdset(widget->window, '\0' | gnt_color_pair(GNT_COLOR_NORMAL)); mvwaddstr(widget->window, 0, 4, GNT_BUTTON(cb)->priv->text); - + wmove(widget->window, 0, 1); + GNTDEBUG; } diff -r 12089d993a0c -r 7fba18b43da3 finch/libgnt/gntcombobox.c --- a/finch/libgnt/gntcombobox.c Sat Apr 04 10:33:33 2009 +0000 +++ b/finch/libgnt/gntcombobox.c Tue Apr 07 05:10:52 2009 +0000 @@ -73,7 +73,7 @@ char *text = NULL, *s; GntColorType type; int len; - + if (box->dropdown && box->selected) text = gnt_tree_get_selection_text(GNT_TREE(box->dropdown)); @@ -94,6 +94,7 @@ whline(widget->window, ' ' | gnt_color_pair(type), widget->priv.width - 4 - len); mvwaddch(widget->window, 1, widget->priv.width - 3, ACS_VLINE | gnt_color_pair(GNT_COLOR_NORMAL)); mvwaddch(widget->window, 1, widget->priv.width - 2, ACS_DARROW | gnt_color_pair(GNT_COLOR_NORMAL)); + wmove(widget->window, 1, 1); g_free(text); GNTDEBUG; diff -r 12089d993a0c -r 7fba18b43da3 finch/libgnt/gntentry.c --- a/finch/libgnt/gntentry.c Sat Apr 04 10:33:33 2009 +0000 +++ b/finch/libgnt/gntentry.c Tue Apr 07 05:10:52 2009 +0000 @@ -271,6 +271,7 @@ GntEntry *entry = GNT_ENTRY(widget); int stop; gboolean focus; + int curpos; if ((focus = gnt_widget_has_focus(widget))) wbkgdset(widget->window, '\0' | gnt_color_pair(GNT_COLOR_TEXT_NORMAL)); @@ -289,9 +290,10 @@ if (stop < widget->priv.width) mvwhline(widget->window, 0, stop, ENTRY_CHAR, widget->priv.width - stop); + curpos = gnt_util_onscreen_width(entry->scroll, entry->cursor); if (focus) - mvwchgat(widget->window, 0, gnt_util_onscreen_width(entry->scroll, entry->cursor), - 1, A_REVERSE, GNT_COLOR_TEXT_NORMAL, NULL); + mvwchgat(widget->window, 0, curpos, 1, A_REVERSE, GNT_COLOR_TEXT_NORMAL, NULL); + wmove(widget->window, 0, curpos); GNTDEBUG; } diff -r 12089d993a0c -r 7fba18b43da3 finch/libgnt/gnttextview.c --- a/finch/libgnt/gnttextview.c Sat Apr 04 10:33:33 2009 +0000 +++ b/finch/libgnt/gnttextview.c Tue Apr 07 05:10:52 2009 +0000 @@ -177,7 +177,7 @@ gnt_color_pair(GNT_COLOR_HIGHLIGHT_D)); } - GNTDEBUG; + wmove(widget->window, 0, 0); } static void @@ -799,6 +799,7 @@ break; } } + gnt_widget_draw(GNT_WIDGET(view)); return count; } diff -r 12089d993a0c -r 7fba18b43da3 finch/libgnt/gnttree.c --- a/finch/libgnt/gnttree.c Sat Apr 04 10:33:33 2009 +0000 +++ b/finch/libgnt/gnttree.c Tue Apr 07 05:10:52 2009 +0000 @@ -28,7 +28,7 @@ #include #include -#define SEARCH_TIMEOUT 4000 /* 4 secs */ +#define SEARCH_TIMEOUT_S 4 /* 4 secs */ #define SEARCHING(tree) (tree->priv->search && tree->priv->search->len > 0) #define COLUMN_INVISIBLE(tree, index) (tree->columns[index].flags & GNT_TREE_COLUMN_INVISIBLE) @@ -420,6 +420,7 @@ GntTreeRow *row; int pos, up, down = 0; int rows, scrcol; + int current = 0; if (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_MAPPED)) return; @@ -518,6 +519,7 @@ if (row == tree->current) { + current = i; attr |= A_BOLD; if (gnt_widget_has_focus(widget)) attr |= gnt_color_pair(GNT_COLOR_HIGHLIGHT); @@ -606,6 +608,7 @@ mvwaddnstr(widget->window, widget->priv.height - pos - 1, pos, tree->priv->search->str, str - tree->priv->search->str); } + wmove(widget->window, current, pos); gnt_widget_queue_update(widget); } @@ -818,7 +821,7 @@ gnt_bindable_perform_action_key(GNT_BINDABLE(tree), text); } g_source_remove(tree->priv->search_timeout); - tree->priv->search_timeout = g_timeout_add(SEARCH_TIMEOUT, search_timeout, tree); + tree->priv->search_timeout = g_timeout_add_seconds(SEARCH_TIMEOUT_S, search_timeout, tree); return TRUE; } else if (text[0] == ' ' && text[1] == 0) { /* Space pressed */ @@ -930,7 +933,7 @@ return FALSE; GNT_WIDGET_SET_FLAGS(GNT_WIDGET(tree), GNT_WIDGET_DISABLE_ACTIONS); tree->priv->search = g_string_new(NULL); - tree->priv->search_timeout = g_timeout_add(SEARCH_TIMEOUT, search_timeout, tree); + tree->priv->search_timeout = g_timeout_add_seconds(SEARCH_TIMEOUT_S, search_timeout, tree); return TRUE; } diff -r 12089d993a0c -r 7fba18b43da3 finch/libgnt/gntwm.c --- a/finch/libgnt/gntwm.c Sat Apr 04 10:33:33 2009 +0000 +++ b/finch/libgnt/gntwm.c Tue Apr 07 05:10:52 2009 +0000 @@ -135,6 +135,17 @@ src = widget->window; dst = node->window; copywin(src, dst, node->scroll, 0, 0, 0, getmaxy(dst) - 1, getmaxx(dst) - 1, 0); + + /* Update the hardware cursor */ + if (GNT_IS_WINDOW(widget) || GNT_IS_BOX(widget)) { + GntWidget *active = GNT_BOX(widget)->active; + if (active) { + int curx = active->priv.x + getcurx(active->window); + int cury = active->priv.y + getcury(active->window); + if (wmove(node->window, cury - widget->priv.y, curx - widget->priv.x) != OK) + wmove(node->window, 0, 0); + } + } } /** @@ -397,7 +408,7 @@ wm->positions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); if (gnt_style_get_bool(GNT_STYLE_REMPOS, TRUE)) read_window_positions(wm); - g_timeout_add(IDLE_CHECK_INTERVAL * 1000, check_idle, NULL); + g_timeout_add_seconds(IDLE_CHECK_INTERVAL, check_idle, NULL); time(&last_active_time); gnt_wm_switch_workspace(wm, 0); } @@ -1101,8 +1112,8 @@ g_hash_table_foreach(wm->nodes, (GHFunc)refresh_node, GINT_TO_POINTER(TRUE)); g_signal_emit(wm, signals[SIG_TERMINAL_REFRESH], 0); + gnt_ws_draw_taskbar(wm->cws, TRUE); update_screen(wm); - gnt_ws_draw_taskbar(wm->cws, TRUE); curs_set(0); /* endwin resets the cursor to normal */ return TRUE; @@ -1872,8 +1883,8 @@ } } + gnt_ws_draw_taskbar(wm->cws, FALSE); update_screen(wm); - gnt_ws_draw_taskbar(wm->cws, FALSE); } void gnt_wm_window_decorate(GntWM *wm, GntWidget *widget) @@ -1885,6 +1896,7 @@ { GntWS *s; int pos; + gboolean transient = !!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT); s = gnt_wm_widget_find_workspace(wm, widget); @@ -1908,10 +1920,12 @@ if (s->ordered && wm->cws == s) gnt_wm_raise_window(wm, s->ordered->data); } + } else if (transient && wm->cws && wm->cws->ordered) { + gnt_wm_update_window(wm, wm->cws->ordered->data); } + gnt_ws_draw_taskbar(wm->cws, FALSE); update_screen(wm); - gnt_ws_draw_taskbar(wm->cws, FALSE); } time_t gnt_wm_get_idle_time() @@ -2119,7 +2133,7 @@ if (write_timeout) { g_source_remove(write_timeout); } - write_timeout = g_timeout_add(10000, write_already, wm); + write_timeout = g_timeout_add_seconds(10, write_already, wm); } void gnt_wm_move_window(GntWM *wm, GntWidget *widget, int x, int y) @@ -2181,8 +2195,8 @@ GntNode *nd = g_hash_table_lookup(wm->nodes, wm->_list.window); top_panel(nd->panel); } + gnt_ws_draw_taskbar(wm->cws, FALSE); update_screen(wm); - gnt_ws_draw_taskbar(wm->cws, FALSE); } void gnt_wm_update_window(GntWM *wm, GntWidget *widget) @@ -2207,8 +2221,8 @@ if (ws == wm->cws || GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT)) { gnt_wm_copy_win(widget, node); + gnt_ws_draw_taskbar(wm->cws, FALSE); update_screen(wm); - gnt_ws_draw_taskbar(wm->cws, FALSE); } else if (ws && ws != wm->cws && GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_URGENT)) { if (!act || (act && !g_list_find(act, ws))) act = g_list_prepend(act, ws); diff -r 12089d993a0c -r 7fba18b43da3 finch/plugins/Makefile.am --- a/finch/plugins/Makefile.am Sat Apr 04 10:33:33 2009 +0000 +++ b/finch/plugins/Makefile.am Tue Apr 07 05:10:52 2009 +0000 @@ -2,6 +2,7 @@ gntgf_la_LDFLAGS = -module -avoid-version gnthistory_la_LDFLAGS = -module -avoid-version gntlastlog_la_LDFLAGS = -module -avoid-version +gnttinyurl_la_LDFLAGS = -module -avoid-version grouping_la_LDFLAGS = -module -avoid-version if PLUGINS @@ -11,6 +12,7 @@ gntgf.la \ gnthistory.la \ gntlastlog.la \ + gnttinyurl.la \ grouping.la plugindir = $(libdir)/finch @@ -19,6 +21,7 @@ gntgf_la_SOURCES = gntgf.c gnthistory_la_SOURCES = gnthistory.c gntlastlog_la_SOURCES = lastlog.c +gnttinyurl_la_SOURCES = gnttinyurl.c grouping_la_SOURCES = grouping.c gntclipboard_la_CFLAGS = $(X11_CFLAGS) @@ -28,6 +31,7 @@ gntgf_la_LIBADD = $(GLIB_LIBS) $(X11_LIBS) $(top_builddir)/finch/libgnt/libgnt.la gnthistory_la_LIBADD = $(GLIB_LIBS) gntlastlog_la_LIBADD = $(GLIB_LIBS) +gnttinyurl_la_LIBADD = $(GLIB_LIBS) grouping_la_LIBADD = $(GLIB_LIBS) $(top_builddir)/finch/libgnt/libgnt.la endif # PLUGINS diff -r 12089d993a0c -r 7fba18b43da3 finch/plugins/gntgf.c --- a/finch/plugins/gntgf.c Sat Apr 04 10:33:33 2009 +0000 +++ b/finch/plugins/gntgf.c Tue Apr 07 05:10:52 2009 +0000 @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -75,7 +76,7 @@ { toasters = g_list_remove(toasters, toast); gnt_widget_destroy(toast->window); - g_source_remove(toast->timer); + purple_timeout_remove(toast->timer); g_free(toast); } @@ -220,7 +221,7 @@ } gnt_widget_draw(window); - toast->timer = g_timeout_add(4000, (GSourceFunc)remove_toaster, toast); + toast->timer = purple_timeout_add_seconds(4, (GSourceFunc)remove_toaster, toast); toasters = g_list_prepend(toasters, toast); } diff -r 12089d993a0c -r 7fba18b43da3 finch/plugins/gnttinyurl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/plugins/gnttinyurl.c Tue Apr 07 05:10:52 2009 +0000 @@ -0,0 +1,415 @@ +/** + * @file gnttinyurl.c + * + * Copyright (C) 2009 Richard Nelson + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + + +#include "internal.h" +#include + +#define PLUGIN_STATIC_NAME TinyURL +#define PREFS_BASE "/plugins/gnt/tinyurl" +#define PREF_LENGTH PREFS_BASE "/length" +#define PREF_URL PREFS_BASE "/url" + + +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include + +static int tag_num = 0; + +typedef struct +{ + PurpleConversation *conv; + gchar *tag; + int num; +} CbInfo; + +/* 3 functions from util.c */ +static gboolean +badchar(char c) +{ + switch (c) { + case ' ': + case ',': + case '\0': + case '\n': + case '\r': + case '<': + case '>': + case '"': + case '\'': + return TRUE; + default: + return FALSE; + } +} + +static gboolean +badentity(const char *c) +{ + if (!g_ascii_strncasecmp(c, "<", 4) || + !g_ascii_strncasecmp(c, ">", 4) || + !g_ascii_strncasecmp(c, """, 6)) { + return TRUE; + } + return FALSE; +} + +static GList *extract_urls(char *text) { + const char *t, *c, *q = NULL; + char *url_buf; + GList *ret = NULL; + gboolean inside_html = FALSE; + int inside_paren = 0; + c = text; + while (*c) { + if (*c == '(' && !inside_html) { + inside_paren++; + c++; + } + if (inside_html) { + if (*c == '>') { + inside_html = FALSE; + } else if (!q && (*c == '\"' || *c == '\'')) { + q = c; + } else if(q) { + if(*c == *q) + q = NULL; + } + } else if (*c == '<') { + inside_html = TRUE; + if (!g_ascii_strncasecmp(c, "') { + inside_html = FALSE; + break; + } + c++; + if (!(*c)) + break; + } + } + } else if ((*c=='h') && (!g_ascii_strncasecmp(c, "http://", 7) || + (!g_ascii_strncasecmp(c, "https://", 8)))) { + t = c; + while (1) { + if (badchar(*t) || badentity(t)) { + + if ((!g_ascii_strncasecmp(c, "http://", 7) && (t - c == 7)) || + (!g_ascii_strncasecmp(c, "https://", 8) && (t - c == 8))) { + break; + } + + if (*(t) == ',' && (*(t + 1) != ' ')) { + t++; + continue; + } + + if (*(t - 1) == '.') + t--; + if ((*(t - 1) == ')' && (inside_paren > 0))) { + t--; + } + + url_buf = g_strndup(c, t - c); + if (!g_list_find_custom(ret, url_buf, (GCompareFunc)strcmp)) { + purple_debug_info("TinyURL", "Added URL %s\n", url_buf); + ret = g_list_append(ret, g_strdup(url_buf)); + } + c = t; + break; + } + t++; + + } + } else if (!g_ascii_strncasecmp(c, "www.", 4) && (c == text || badchar(c[-1]) || badentity(c-1))) { + if (c[4] != '.') { + t = c; + while (1) { + if (badchar(*t) || badentity(t)) { + if (t - c == 4) { + break; + } + + if (*(t) == ',' && (*(t + 1) != ' ')) { + t++; + continue; + } + + if (*(t - 1) == '.') + t--; + if ((*(t - 1) == ')' && (inside_paren > 0))) { + t--; + } + url_buf = g_strndup(c, t - c); + if (!g_list_find_custom(ret, url_buf, (GCompareFunc)strcmp)) { + purple_debug_info("TinyURL", "Added URL %s\n", url_buf); + ret = g_list_append(ret, url_buf); + } + c = t; + break; + } + t++; + } + } + } + if (*c == ')' && !inside_html) { + inside_paren--; + c++; + } + if (*c == 0) + break; + c++; + } + return ret; +} + +static void url_fetched(PurpleUtilFetchUrlData *url_data, gpointer cb_data, + const gchar *url_text, gsize len, const gchar *error_message) +{ + CbInfo *data = (CbInfo *)cb_data; + PurpleConversation *conv = data->conv; + GList *convs = purple_get_conversations(); + /* ensure the conversation still exists */ + for (; convs; convs = convs->next) { + if ((PurpleConversation *)(convs->data) == conv) { + FinchConv *fconv = FINCH_CONV(conv); + gchar *str = g_strdup_printf("[%d] %s", data->num, url_text); + GntTextView *tv = GNT_TEXT_VIEW(fconv->tv); + gnt_text_view_tag_change(tv, data->tag, str, FALSE); + g_free(str); + g_free(data->tag); + return; + } + } + g_free(data->tag); + purple_debug_info("TinyURL", "Conversation no longer exists... :(\n"); +} + +static void free_urls(gpointer data, gpointer null) +{ + g_free(data); +} + +static gboolean receiving_msg(PurpleAccount *account, char **sender, char **message, + PurpleConversation *conv, PurpleMessageFlags *flags) { + GString *t; + GList *iter, *urls; + int c = 0; + + if (!(*flags & PURPLE_MESSAGE_RECV) || *flags & PURPLE_MESSAGE_INVISIBLE) + return FALSE; + + t = g_string_new(*message); + urls = purple_conversation_get_data(conv, "TinyURLs"); + if (urls != NULL) /* message was cancelled somewhere? Reset. */ + g_list_foreach(urls, free_urls, NULL); + g_list_free(urls); + urls = extract_urls(t->str); + g_free(*message); + for (iter = urls; iter; iter = iter->next) { + if (g_utf8_strlen((char *)iter->data, -1) >= purple_prefs_get_int(PREF_LENGTH)) { + int pos, x = 0; + gchar *j, *s, *str, *orig; + glong len = g_utf8_strlen(iter->data, -1); + s = g_strdup(t->str); + orig = s; + str = g_strdup_printf("[%d]", ++c); + while ((j = strstr(s, iter->data))) { /* replace all occurrences */ + pos = j - orig + (x++ * 3); + s = j + len; + t = g_string_insert(t, pos + len, str); + if (*s == '\0') break; + } + g_free(orig); + g_free(str); + continue; + } else { + if (iter->prev) { + iter = iter->prev; + g_free(iter->next->data); + urls = g_list_delete_link(urls, iter->next); + } else { + g_free(iter->data); + g_list_free(urls); + urls = NULL; + } + } + } + *message = t->str; + g_string_free(t, FALSE); + if (conv == NULL) + conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, *sender); + purple_conversation_set_data(conv, "TinyURLs", urls); + return FALSE; +} + +static void received_msg(PurpleAccount *account, char *sender, char *message, + PurpleConversation *conv, PurpleMessageFlags flags) { + int c; + GList *urls, *iter; + FinchConv *fconv = FINCH_CONV(conv); + GntTextView *tv = GNT_TEXT_VIEW(fconv->tv); + + urls = purple_conversation_get_data(conv, "TinyURLs"); + if (!(flags & PURPLE_MESSAGE_RECV) || urls == NULL) + return; + + for (iter = urls, c = 0; iter; iter = iter->next) { + int i; + CbInfo *cbdata; + gchar *url, *str, *tmp; + cbdata = g_new(CbInfo, 1); + cbdata->num = ++c; + cbdata->tag = g_strdup_printf("%s%d", "tiny_", tag_num++); + cbdata->conv = conv; + tmp = purple_unescape_html((char *)iter->data); + if (g_ascii_strncasecmp(tmp, "http://", 7) && g_ascii_strncasecmp(tmp, "https://", 8)) { + url = g_strdup_printf("%shttp://%s", purple_prefs_get_string(PREF_URL), tmp); + } else { + url = g_strdup_printf("%s%s", purple_prefs_get_string(PREF_URL), tmp); + } + g_free(tmp); + purple_util_fetch_url(url, TRUE, "finch", FALSE, url_fetched, cbdata); + i = gnt_text_view_get_lines_below(tv); + str = g_strdup_printf(_("\nFetching TinyURL...")); + gnt_text_view_append_text_with_tag((tv), str, GNT_TEXT_FLAG_DIM, cbdata->tag); + g_free(str); + if (i == 0) + gnt_text_view_scroll(tv, 0); + g_free(iter->data); + g_free(url); + } + g_list_free(urls); + purple_conversation_set_data(conv, "TinyURLs", NULL); +} + +static void +free_conv_urls(PurpleConversation *conv) +{ + GList *urls = purple_conversation_get_data(conv, "TinyURLs"); + if (urls) + g_list_foreach(urls, free_urls, NULL); + g_list_free(urls); +} + +static gboolean +plugin_load(PurplePlugin *plugin) { + purple_signal_connect(purple_conversations_get_handle(), + "wrote-im-msg", + plugin, PURPLE_CALLBACK(received_msg), NULL); + purple_signal_connect(purple_conversations_get_handle(), + "wrote-chat-msg", + plugin, PURPLE_CALLBACK(received_msg), NULL); + purple_signal_connect(purple_conversations_get_handle(), + "receiving-im-msg", + plugin, PURPLE_CALLBACK(receiving_msg), NULL); + purple_signal_connect(purple_conversations_get_handle(), + "receiving-chat-msg", + plugin, PURPLE_CALLBACK(receiving_msg), NULL); + purple_signal_connect(purple_conversations_get_handle(), + "deleting-conversation", + plugin, PURPLE_CALLBACK(free_conv_urls), NULL); + + return TRUE; +} + +static PurplePluginPrefFrame * +get_plugin_pref_frame(PurplePlugin *plugin) { + + PurplePluginPrefFrame *frame; + PurplePluginPref *pref; + + frame = purple_plugin_pref_frame_new(); + + pref = purple_plugin_pref_new_with_name(PREF_LENGTH); + purple_plugin_pref_set_label(pref, _("Only create TinyURL for urls" + " of this length or greater")); + purple_plugin_pref_frame_add(frame, pref); + pref = purple_plugin_pref_new_with_name(PREF_URL); + purple_plugin_pref_set_label(pref, _("TinyURL (or other) address prefix")); + purple_plugin_pref_frame_add(frame, pref); + + return frame; +} + +static PurplePluginUiInfo prefs_info = { + get_plugin_pref_frame, + 0, /* page_num (Reserved) */ + NULL, /* frame (Reserved) */ + + /* padding */ + NULL, + NULL, + NULL, + NULL +}; + +static PurplePluginInfo info = +{ + PURPLE_PLUGIN_MAGIC, + PURPLE_MAJOR_VERSION, + PURPLE_MINOR_VERSION, + PURPLE_PLUGIN_STANDARD, + FINCH_PLUGIN_TYPE, + 0, + NULL, + PURPLE_PRIORITY_DEFAULT, + "TinyURL", + N_("TinyURL"), + DISPLAY_VERSION, + N_("TinyURL plugin"), + N_("When receiving a message with URL(s), TinyURL for easier copying"), + "Richard Nelson ", + PURPLE_WEBSITE, + plugin_load, + NULL, + NULL, + NULL, + NULL, + &prefs_info, /**< prefs_info */ + NULL, + + /* padding */ + NULL, + NULL, + NULL, + NULL +}; + +static void +init_plugin(PurplePlugin *plugin) { + purple_prefs_add_none(PREFS_BASE); + purple_prefs_add_int(PREF_LENGTH, 30); + purple_prefs_add_string(PREF_URL, "http://tinyurl.com/api-create.php?url="); +} + +PURPLE_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info) diff -r 12089d993a0c -r 7fba18b43da3 libpurple/Makefile.am --- a/libpurple/Makefile.am Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/Makefile.am Tue Apr 07 05:10:52 2009 +0000 @@ -280,8 +280,8 @@ $(NETWORKMANAGER_LIBS) \ $(INTLLIBS) \ $(FARSIGHT_LIBS) \ - $(GSTPROPS_LIBS) \ $(GSTREAMER_LIBS) \ + $(GSTINTERFACES_LIBS) \ -lm AM_CPPFLAGS = \ @@ -295,8 +295,8 @@ $(DBUS_CFLAGS) \ $(LIBXML_CFLAGS) \ $(FARSIGHT_CFLAGS) \ - $(GSTPROPS_CFLAGS) \ $(GSTREAMER_CFLAGS) \ + $(GSTINTERFACES_CFLAGS) \ $(NETWORKMANAGER_CFLAGS) # INSTALL_SSL_CERTIFICATES is true when SSL_CERTIFICATES_DIR is empty. diff -r 12089d993a0c -r 7fba18b43da3 libpurple/media-gst.h --- a/libpurple/media-gst.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/media-gst.h Tue Apr 07 05:10:52 2009 +0000 @@ -24,8 +24,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __MEDIA_GST_H_ -#define __MEDIA_GST_H_ +#ifndef _PURPLE_MEDIA_GST_H_ +#define _PURPLE_MEDIA_GST_H_ #include "media.h" #include "mediamanager.h" @@ -81,6 +81,8 @@ * Gets the element type's GType. * * @return The element type's GType. + * + * @since 2.6.0 */ GType purple_media_element_type_get_type(void); @@ -88,6 +90,8 @@ * Gets the element info's GType. * * @return The element info's GType. + * + * @since 2.6.0 */ GType purple_media_element_info_get_type(void); @@ -98,6 +102,8 @@ * @param sess_id The session id of the session to get the source from. * * @return The source retrieved. + * + * @since 2.6.0 */ GstElement *purple_media_get_src(PurpleMedia *media, const gchar *sess_id); @@ -109,6 +115,8 @@ * @param participant Optionally, the participant of the stream to get the tee from. * * @return The GstTee element from the chosen session/stream. + * + * @since 2.6.0 */ GstElement *purple_media_get_tee(PurpleMedia *media, const gchar *session_id, const gchar *participant); @@ -120,6 +128,8 @@ * @param manager The media manager to get the pipeline from. * * @return The pipeline. + * + * @since 2.6.0 */ GstElement *purple_media_manager_get_pipeline(PurpleMediaManager *manager); @@ -128,6 +138,8 @@ * * @param manager The media manager to use to obtain the source/sink. * @param type The type of source/sink to get. + * + * @since 2.6.0 */ GstElement *purple_media_manager_get_element(PurpleMediaManager *manager, PurpleMediaSessionType type, PurpleMedia *media, @@ -158,4 +170,4 @@ G_END_DECLS -#endif /* __MEDIA_GST_H_ */ +#endif /* _PURPLE_MEDIA_GST_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/media.h --- a/libpurple/media.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/media.h Tue Apr 07 05:10:52 2009 +0000 @@ -24,11 +24,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __MEDIA_H_ -#define __MEDIA_H_ - -#include "signals.h" -#include "util.h" +#ifndef _PURPLE_MEDIA_H_ +#define _PURPLE_MEDIA_H_ #include #include @@ -129,6 +126,9 @@ PURPLE_MEDIA_NETWORK_PROTOCOL_TCP, } PurpleMediaNetworkProtocol; +#include "signals.h" +#include "util.h" + #ifdef __cplusplus extern "C" { #endif @@ -137,6 +137,8 @@ * Gets the media session type's GType * * @return The media session type's GType. + * + * @since 2.6.0 */ GType purple_media_session_type_get_type(void); @@ -144,6 +146,8 @@ * Gets the media candidate type's GType * * @return The media candidate type's GType. + * + * @since 2.6.0 */ GType purple_media_candidate_type_get_type(void); @@ -151,6 +155,8 @@ * Gets the media network protocol's GType * * @return The media network protocol's GType. + * + * @since 2.6.0 */ GType purple_media_network_protocol_get_type(void); @@ -158,6 +164,8 @@ * Gets the media class's GType * * @return The media class's GType. + * + * @since 2.6.0 */ GType purple_media_get_type(void); @@ -165,6 +173,8 @@ * Gets the type of the state-changed enum * * @return The state-changed enum's GType + * + * @since 2.6.0 */ GType purple_media_state_changed_get_type(void); @@ -172,6 +182,8 @@ * Gets the type of the info type enum * * @return The info type enum's GType + * + * @since 2.6.0 */ GType purple_media_info_type_get_type(void); @@ -179,6 +191,8 @@ * Gets the type of the media candidate structure. * * @return The media canditate's GType + * + * @since 2.6.0 */ GType purple_media_candidate_get_type(void); @@ -193,6 +207,8 @@ * @param port The network port. * * @return The newly created PurpleMediaCandidate instance. + * + * @since 2.6.0 */ PurpleMediaCandidate *purple_media_candidate_new( const gchar *foundation, guint component_id, @@ -206,6 +222,8 @@ * @param candidates The list of candidates to be copied. * * @return The copy of the GList. + * + * @since 2.6.0 */ GList *purple_media_candidate_list_copy(GList *candidates); @@ -213,6 +231,8 @@ * Frees a GList of PurpleMediaCandidate and its contents. * * @param candidates The list of candidates to be freed. + * + * @since 2.6.0 */ void purple_media_candidate_list_free(GList *candidates); @@ -235,6 +255,8 @@ * Gets the type of the media codec structure. * * @return The media codec's GType + * + * @since 2.6.0 */ GType purple_media_codec_get_type(void); @@ -247,6 +269,8 @@ * @param clock_rate The clock rate this codec encodes at, if applicable. * * @return The newly created PurpleMediaCodec. + * + * @since 2.6.0 */ PurpleMediaCodec *purple_media_codec_new(int id, const char *encoding_name, PurpleMediaSessionType media_type, guint clock_rate); @@ -263,6 +287,8 @@ * @param codec The codec to create the string of. * * @return The new string representation. + * + * @since 2.6.0 */ gchar *purple_media_codec_to_string(const PurpleMediaCodec *codec); @@ -272,6 +298,8 @@ * @param codec The codec to add the parameter to. * @param name The name of the parameter to add. * @param value The value of the parameter to add. + * + * @since 2.6.0 */ void purple_media_codec_add_optional_parameter(PurpleMediaCodec *codec, const gchar *name, const gchar *value); @@ -281,6 +309,8 @@ * * @param codec The codec to remove the parameter from. * @param param A pointer to the parameter to remove. + * + * @since 2.6.0 */ void purple_media_codec_remove_optional_parameter(PurpleMediaCodec *codec, PurpleKeyValuePair *param); @@ -293,6 +323,8 @@ * @param value The value to search for or NULL. * * @return The value found or NULL. + * + * @since 2.6.0 */ PurpleKeyValuePair *purple_media_codec_get_optional_parameter( PurpleMediaCodec *codec, const gchar *name, @@ -304,6 +336,8 @@ * @param codecs The list of codecs to be copied. * * @return The copy of the GList. + * + * @since 2.6.0 */ GList *purple_media_codec_list_copy(GList *codecs); @@ -311,6 +345,8 @@ * Frees a GList of PurpleMediaCodec and its contents. * * @param codecs The list of codecs to be freed. + * + * @since 2.6.0 */ void purple_media_codec_list_free(GList *codecs); @@ -320,6 +356,8 @@ * @param media The media session to retrieve session names from. * * @return GList of session names. + * + * @since 2.6.0 */ GList *purple_media_get_session_names(PurpleMedia *media); @@ -329,6 +367,8 @@ * @param media The media session to retrieve the connection from. * * @return The connection retrieved. + * + * @since 2.6.0 */ PurpleConnection *purple_media_get_connection(PurpleMedia *media); @@ -338,6 +378,8 @@ * @param media The media session to retrieve the prpl data from. * * @return The prpl data retrieved. + * + * @since 2.6.0 */ gpointer purple_media_get_prpl_data(PurpleMedia *media); @@ -346,6 +388,8 @@ * * @param media The media session to set the prpl data on. * @param prpl_data The data to set on the media session. + * + * @since 2.6.0 */ void purple_media_set_prpl_data(PurpleMedia *media, gpointer prpl_data); @@ -355,6 +399,8 @@ * @param media The media object to set the state on. * @param error The format of the error message to send in the signal. * @param ... The arguments to plug into the format. + * + * @since 2.6.0 */ void purple_media_error(PurpleMedia *media, const gchar *error, ...); @@ -364,6 +410,8 @@ * @param media The media object with which to end streams. * @param session_id The session to end streams on. * @param participant The participant to end streams with. + * + * @since 2.6.0 */ void purple_media_end(PurpleMedia *media, const gchar *session_id, const gchar *participant); @@ -376,6 +424,8 @@ * @param session_id The id of the session of the stream being signaled. * @param participant The participant of the stream being signaled. * @param local TRUE if the info originated locally, FALSE if on the remote end. + * + * @since 2.6.0 */ void purple_media_stream_info(PurpleMedia *media, PurpleMediaInfoType type, const gchar *session_id, const gchar *participant, @@ -397,6 +447,8 @@ * @param params The parameters to pass to Farsight. * * @return @c TRUE The stream was added successfully, @c FALSE otherwise. + * + * @since 2.6.0 */ gboolean purple_media_add_stream(PurpleMedia *media, const gchar *sess_id, const gchar *who, PurpleMediaSessionType type, @@ -410,6 +462,8 @@ * @param sess_id The session id of the session to get the type from. * * @return The retreived session type. + * + * @since 2.6.0 */ PurpleMediaSessionType purple_media_get_session_type(PurpleMedia *media, const gchar *sess_id); @@ -419,6 +473,8 @@ * @param media The media object to get the manager instance from. * * @return The PurpleMediaManager instance retrieved. + * + * @since 2.6.0 */ struct _PurpleMediaManager *purple_media_get_manager(PurpleMedia *media); @@ -429,6 +485,8 @@ * @param sess_id The session id of the session to get the codecs from. * * @return The retreieved codecs. + * + * @since 2.6.0 */ GList *purple_media_get_codecs(PurpleMedia *media, const gchar *sess_id); @@ -439,6 +497,8 @@ * @param sess_id The session id of the session find the stream in. * @param name The name of the remote user to add the candidates for. * @param remote_candidates The remote candidates to add. + * + * @since 2.6.0 */ void purple_media_add_remote_candidates(PurpleMedia *media, const gchar *sess_id, @@ -451,6 +511,8 @@ * @param media The media object to find the session in. * @param sess_id The session id of the session to find the stream in. * @param name The name of the remote user to get the candidates from. + * + * @since 2.6.0 */ GList *purple_media_get_local_candidates(PurpleMedia *media, const gchar *sess_id, @@ -495,6 +557,8 @@ * @param name The name of the remote user to get the candidates from. * * @return @c TRUE The codecs were set successfully, or @c FALSE otherwise. + * + * @since 2.6.0 */ gboolean purple_media_set_remote_codecs(PurpleMedia *media, const gchar *sess_id, const gchar *name, GList *codecs); @@ -507,6 +571,8 @@ * @param participant The remote user to check for. * * @return @c TRUE All streams for the given session_id/participant combination have candidates prepared, @c FALSE otherwise. + * + * @since 2.6.0 */ gboolean purple_media_candidates_prepared(PurpleMedia *media, const gchar *session_id, const gchar *participant); @@ -519,6 +585,8 @@ * @param codec The codec to set the session to stream. * * @return @c TRUE The codec was successfully changed, or @c FALSE otherwise. + * + * @since 2.6.0 */ gboolean purple_media_set_send_codec(PurpleMedia *media, const gchar *sess_id, PurpleMediaCodec *codec); @@ -529,6 +597,8 @@ * @param sess_id The session id of the session to check. * * @return @c TRUE The codecs are ready, or @c FALSE otherwise. + * + * @since 2.6.0 */ gboolean purple_media_codecs_ready(PurpleMedia *media, const gchar *sess_id); @@ -540,6 +610,8 @@ * @param participant The participant of the stream to check. * * @return TRUE if the local user is the stream's initator, else FALSE. + * + * @since 2.6.0 */ gboolean purple_media_is_initiator(PurpleMedia *media, const gchar *sess_id, const gchar *participant); @@ -552,6 +624,8 @@ * @param participant The participant to check. * * @return @c TRUE The selected streams have been accepted, or @c FALSE otherwise. + * + * @since 2.6.0 */ gboolean purple_media_accepted(PurpleMedia *media, const gchar *sess_id, const gchar *participant); @@ -562,6 +636,8 @@ * @param media The media object the sessions are in. * @param session_id The session to select (if any). * @param level The level to set the volume to. + * + * @since 2.6.0 */ void purple_media_set_input_volume(PurpleMedia *media, const gchar *session_id, double level); @@ -572,6 +648,8 @@ * @param session_id The session to limit the streams to (if any). * @param participant The participant to limit the streams to (if any). * @param level The level to set the volume to. + * + * @since 2.6.0 */ void purple_media_set_output_volume(PurpleMedia *media, const gchar *session_id, const gchar *participant, double level); @@ -585,6 +663,8 @@ * @param window_id The window id use for embedding the video in. * * @return An id to reference the output window. + * + * @since 2.6.0 */ gulong purple_media_set_output_window(PurpleMedia *media, const gchar *session_id, const gchar *participant, @@ -594,6 +674,8 @@ * Removes all output windows from a given media session. * * @param media The instance to remove all output windows from. + * + * @since 2.6.0 */ void purple_media_remove_output_windows(PurpleMedia *media); @@ -603,4 +685,4 @@ G_END_DECLS -#endif /* __MEDIA_H_ */ +#endif /* _PURPLE_MEDIA_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/mediamanager.h --- a/libpurple/mediamanager.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/mediamanager.h Tue Apr 07 05:10:52 2009 +0000 @@ -24,12 +24,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __MEDIA_MANAGER_H_ -#define __MEDIA_MANAGER_H_ +#ifndef _PURPLE_MEDIA_MANAGER_H_ +#define _PURPLE_MEDIA_MANAGER_H_ #include #include +/** @copydoc _PurpleMediaManager */ +typedef struct _PurpleMediaManager PurpleMediaManager; +/** @copydoc _PurpleMediaManagerClass */ +typedef struct _PurpleMediaManagerClass PurpleMediaManagerClass; + #include "connection.h" #include "media.h" @@ -42,11 +47,6 @@ #define PURPLE_IS_MEDIA_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_MEDIA_MANAGER)) #define PURPLE_MEDIA_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MEDIA_MANAGER, PurpleMediaManagerClass)) -/** @copydoc _PurpleMediaManager */ -typedef struct _PurpleMediaManager PurpleMediaManager; -/** @copydoc _PurpleMediaManagerClass */ -typedef struct _PurpleMediaManagerClass PurpleMediaManagerClass; - #ifdef __cplusplus extern "C" { #endif @@ -60,6 +60,8 @@ * Gets the media manager's GType. * * @return The media manager's GType. + * + * @since 2.6.0 */ GType purple_media_manager_get_type(void); @@ -67,6 +69,8 @@ * Gets the "global" media manager object. It's created if it doesn't already exist. * * @return The "global" instance of the media manager object. + * + * @since 2.6.0 */ PurpleMediaManager *purple_media_manager_get(void); @@ -79,6 +83,8 @@ * @param remote_user The remote user to initiate the session with. * * @return A newly created media session. + * + * @since 2.6.0 */ PurpleMedia *purple_media_manager_create_media(PurpleMediaManager *manager, PurpleConnection *gc, @@ -92,6 +98,8 @@ * @param manager The media manager to get all of the sessions from. * * @return A list of all the media sessions. + * + * @since 2.6.0 */ GList *purple_media_manager_get_media(PurpleMediaManager *manager); @@ -102,6 +110,8 @@ * @param pc The connection the sessions are on. * * @return A list of the media sessions on the given connection. + * + * @since 2.6.0 */ GList *purple_media_manager_get_media_by_connection( PurpleMediaManager *manager, PurpleConnection *pc); @@ -111,6 +121,8 @@ * * @param manager The media manager to remove the media session from. * @param media The media session to remove. + * + * @since 2.6.0 */ void purple_media_manager_remove_media(PurpleMediaManager *manager, @@ -127,6 +139,8 @@ * @param participant The participant the output windows are registered with. * * @return TRUE if it succeeded, FALSE if it failed. + * + * @since 2.6.0 */ gboolean purple_media_manager_create_output_window( PurpleMediaManager *manager, PurpleMedia *media, @@ -142,6 +156,8 @@ * @param window_id The window ID to embed the video in. * * @return A unique ID to the registered output window, 0 if it failed. + * + * @since 2.6.0 */ gulong purple_media_manager_set_output_window(PurpleMediaManager *manager, PurpleMedia *media, const gchar *session_id, @@ -154,6 +170,8 @@ * @param output_window_id The ID of the output window. * * @return TRUE if it found the output window and was successful, else FALSE. + * + * @since 2.6.0 */ gboolean purple_media_manager_remove_output_window( PurpleMediaManager *manager, gulong output_window_id); @@ -165,6 +183,8 @@ * @param media The media instance the output windows were registered for. * @param session_id The session the output windows were registered for. * @param participant The participant the output windows were registered for. + * + * @since 2.6.0 */ void purple_media_manager_remove_output_windows( PurpleMediaManager *manager, PurpleMedia *media, @@ -175,6 +195,8 @@ * * @param manager The manager to set the caps on. * @param caps The caps to set. + * + * @since 2.6.0 */ void purple_media_manager_set_ui_caps(PurpleMediaManager *manager, PurpleMediaCaps caps); @@ -185,6 +207,8 @@ * @param manager The manager to get caps from. * * @return caps The caps retrieved. + * + * @since 2.6.0 */ PurpleMediaCaps purple_media_manager_get_ui_caps(PurpleMediaManager *manager); @@ -196,4 +220,4 @@ G_END_DECLS -#endif /* __MEDIA_MANAGER_H_ */ +#endif /* _PURPLE_MEDIA_MANAGER_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/adhoccommands.c --- a/libpurple/protocols/jabber/adhoccommands.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/adhoccommands.c Tue Apr 07 05:10:52 2009 +0000 @@ -39,16 +39,17 @@ GList *actionslist; } JabberAdHocActionInfo; -void jabber_adhoc_disco_result_cb(JabberStream *js, xmlnode *packet, gpointer data) { - const char *from = xmlnode_get_attrib(packet, "from"); - const char *type = xmlnode_get_attrib(packet, "type"); +void jabber_adhoc_disco_result_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) +{ const char *node; xmlnode *query, *item; JabberID *jabberid; JabberBuddy *jb; JabberBuddyResource *jbr = NULL; - if(strcmp(type, "result")) + if (type == JABBER_IQ_ERROR) return; query = xmlnode_get_child_with_namespace(packet,"query","http://jabber.org/protocol/disco#items"); @@ -95,7 +96,10 @@ } } -static void jabber_adhoc_parse(JabberStream *js, xmlnode *packet, gpointer data); +static void jabber_adhoc_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data); + static void do_adhoc_action_cb(JabberStream *js, xmlnode *result, const char *actionhandle, gpointer user_data) { xmlnode *command; @@ -131,13 +135,16 @@ jabber_iq_send(iq); } -static void jabber_adhoc_parse(JabberStream *js, xmlnode *packet, gpointer data) { +static void +jabber_adhoc_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) +{ xmlnode *command = xmlnode_get_child_with_namespace(packet, "command", "http://jabber.org/protocol/commands"); const char *status = xmlnode_get_attrib(command,"status"); xmlnode *xdata = xmlnode_get_child_with_namespace(command,"x","jabber:x:data"); - const char *type = xmlnode_get_attrib(packet,"type"); - if(type && !strcmp(type,"error")) { + if (type == JABBER_IQ_ERROR) { char *msg = jabber_parse_error(js, packet, NULL); if(!msg) msg = g_strdup(_("Unknown Error")); @@ -147,8 +154,6 @@ g_free(msg); return; } - if(!type || strcmp(type,"result")) - return; if(!status) return; @@ -159,7 +164,7 @@ if(note) { char *data = xmlnode_get_data(note); - purple_notify_info(NULL, xmlnode_get_attrib(packet, "from"), data, NULL); + purple_notify_info(NULL, from, data, NULL); g_free(data); } @@ -199,7 +204,7 @@ actionInfo = g_new0(JabberAdHocActionInfo, 1); actionInfo->sessionid = g_strdup(xmlnode_get_attrib(command,"sessionid")); - actionInfo->who = g_strdup(xmlnode_get_attrib(packet,"from")); + actionInfo->who = g_strdup(from); actionInfo->node = g_strdup(xmlnode_get_attrib(command,"node")); actionInfo->actionslist = actionslist; @@ -218,7 +223,11 @@ } } -static void jabber_adhoc_server_got_list_cb(JabberStream *js, xmlnode *packet, gpointer data) { +static void +jabber_adhoc_server_got_list_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) +{ xmlnode *query = xmlnode_get_child_with_namespace(packet, "query", "http://jabber.org/protocol/disco#items"); xmlnode *item; diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/adhoccommands.h --- a/libpurple/protocols/jabber/adhoccommands.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/adhoccommands.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,14 +19,16 @@ * */ -#ifndef _PURPLE_JABBER_ADHOCCOMMANDS_H_ -#define _PURPLE_JABBER_ADHOCCOMMANDS_H_ +#ifndef PURPLE_JABBER_ADHOCCOMMANDS_H_ +#define PURPLE_JABBER_ADHOCCOMMANDS_H_ #include "jabber.h" /* Implementation of XEP-0050 */ -void jabber_adhoc_disco_result_cb(JabberStream *js, xmlnode *packet, gpointer data); +void jabber_adhoc_disco_result_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data); void jabber_adhoc_execute(JabberStream *js, JabberAdHocCommands *cmd); @@ -36,4 +38,4 @@ void jabber_adhoc_init_server_commands(JabberStream *js, GList **m); -#endif /* _PURPLE_JABBER_ADHOCCOMMANDS_H_ */ +#endif /* PURPLE_JABBER_ADHOCCOMMANDS_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/auth.c --- a/libpurple/protocols/jabber/auth.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/auth.c Tue Apr 07 05:10:52 2009 +0000 @@ -36,8 +36,9 @@ #include "iq.h" #include "notify.h" -static void auth_old_result_cb(JabberStream *js, xmlnode *packet, - gpointer data); +static void auth_old_result_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data); gboolean jabber_process_starttls(JabberStream *js, xmlnode *packet) @@ -566,11 +567,11 @@ #endif } -static void auth_old_result_cb(JabberStream *js, xmlnode *packet, gpointer data) +static void auth_old_result_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { - const char *type = xmlnode_get_attrib(packet, "type"); - - if(type && !strcmp(type, "result")) { + if (type == JABBER_IQ_RESULT) { jabber_stream_set_state(js, JABBER_STREAM_CONNECTED); } else { PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; @@ -593,24 +594,20 @@ } } -static void auth_old_cb(JabberStream *js, xmlnode *packet, gpointer data) +static void auth_old_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { JabberIq *iq; xmlnode *query, *x; - const char *type = xmlnode_get_attrib(packet, "type"); const char *pw = purple_connection_get_password(js->gc); - if(!type) { - purple_connection_error_reason (js->gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Invalid response from server.")); - return; - } else if(!strcmp(type, "error")) { + if (type == JABBER_IQ_ERROR) { PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; char *msg = jabber_parse_error(js, packet, &reason); purple_connection_error_reason (js->gc, reason, msg); g_free(msg); - } else if(!strcmp(type, "result")) { + } else if (type == JABBER_IQ_RESULT) { query = xmlnode_get_child(packet, "query"); if(js->stream_id && xmlnode_get_child(query, "digest")) { char *s, *hash; diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/auth.h --- a/libpurple/protocols/jabber/auth.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/auth.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,8 +19,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef _PURPLE_JABBER_AUTH_H_ -#define _PURPLE_JABBER_AUTH_H_ +#ifndef PURPLE_JABBER_AUTH_H_ +#define PURPLE_JABBER_AUTH_H_ #include "jabber.h" #include "xmlnode.h" @@ -32,4 +32,4 @@ void jabber_auth_handle_success(JabberStream *js, xmlnode *packet); void jabber_auth_handle_failure(JabberStream *js, xmlnode *packet); -#endif /* _PURPLE_JABBER_AUTH_H_ */ +#endif /* PURPLE_JABBER_AUTH_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/buddy.c --- a/libpurple/protocols/jabber/buddy.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/buddy.c Tue Apr 07 05:10:52 2009 +0000 @@ -160,6 +160,7 @@ jbr->jb = jb; jbr->name = g_strdup(resource); jbr->capabilities = JABBER_CAP_XHTML; + jbr->tz_off = PURPLE_NO_TZ_OFF; jb->resources = g_list_append(jb->resources, jbr); } jbr->priority = priority; @@ -802,6 +803,21 @@ purple_notify_user_info_prepend_pair(user_info, _("Operating System"), jbr->client.os); } } + if (jbr && jbr->tz_off != PURPLE_NO_TZ_OFF) { + time_t now_t; + struct tm *now; + char *timestamp; + time(&now_t); + now_t += jbr->tz_off; + now = gmtime(&now_t); + + timestamp = g_strdup_printf("%s %c%02d%02d", purple_time_format(now), + jbr->tz_off < 0 ? '-' : '+', + abs(jbr->tz_off / (60*60)), + abs((jbr->tz_off % (60*60)) / 60)); + purple_notify_user_info_prepend_pair(user_info, _("Local Time"), timestamp); + g_free(timestamp); + } if(jbir) { if(jbir->idle_seconds > 0) { char *idle = purple_str_seconds_to_string(jbir->idle_seconds); @@ -920,7 +936,7 @@ feature = _("User Gaming"); else if(!strcmp(feature, "http://jabber.org/protocol/viewing")) feature = _("User Viewing"); - else if(!strcmp(feature, "urn:xmpp:ping") || !strcmp(feature, "http://www.xmpp.org/extensions/xep-0199.html#ns")) + else if(!strcmp(feature, "urn:xmpp:ping")) feature = _("Ping"); else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0200.html#ns")) feature = _("Stanza Encryption"); @@ -972,6 +988,22 @@ } } + if (jbr->tz_off != PURPLE_NO_TZ_OFF) { + time_t now_t; + struct tm *now; + char *timestamp; + time(&now_t); + now_t += jbr->tz_off; + now = gmtime(&now_t); + + timestamp = g_strdup_printf("%s %c%02d%02d", purple_time_format(now), + jbr->tz_off < 0 ? '-' : '+', + abs(jbr->tz_off / (60*60)), + abs((jbr->tz_off % (60*60)) / 60)); + purple_notify_user_info_prepend_pair(user_info, _("Local Time"), timestamp); + g_free(timestamp); + } + if(jbr->name && (jbir = g_hash_table_lookup(jbi->resources, jbr->name))) { if(jbir->idle_seconds > 0) { char *idle = purple_str_seconds_to_string(jbir->idle_seconds); @@ -1090,7 +1122,7 @@ feature = _("User Gaming"); else if(!strcmp(feature, "http://jabber.org/protocol/viewing")) feature = _("User Viewing"); - else if(!strcmp(feature, "urn:xmpp:ping") || !strcmp(feature, "http://www.xmpp.org/extensions/xep-0199.html#ns")) + else if(!strcmp(feature, "urn:xmpp:ping")) feature = _("Ping"); else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0200.html#ns")) feature = _("Stanza Encryption"); @@ -1156,12 +1188,19 @@ } } -static void jabber_vcard_save_mine(JabberStream *js, xmlnode *packet, gpointer data) +static void jabber_vcard_save_mine(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { xmlnode *vcard; char *txt; PurpleStoredImage *img; + if (type == JABBER_IQ_ERROR) { + purple_debug_warning("jabber", "Server returned error while retrieving vCard"); + return; + } + if((vcard = xmlnode_get_child(packet, "vCard")) || (vcard = xmlnode_get_child_with_namespace(packet, "query", "vcard-temp"))) { @@ -1192,9 +1231,10 @@ jabber_iq_send(iq); } -static void jabber_vcard_parse(JabberStream *js, xmlnode *packet, gpointer data) +static void jabber_vcard_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { - const char *id, *from; char *bare_jid; char *text; char *serverside_alias = NULL; @@ -1203,9 +1243,6 @@ JabberBuddyInfo *jbi = data; PurpleNotifyUserInfo *user_info; - from = xmlnode_get_attrib(packet, "from"); - id = xmlnode_get_attrib(packet, "id"); - if(!jbi) return; @@ -1555,19 +1592,16 @@ g_free(jbri); } -static void jabber_version_parse(JabberStream *js, xmlnode *packet, gpointer data) +static void jabber_version_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { JabberBuddyInfo *jbi = data; - const char *type, *id, *from; xmlnode *query; char *resource_name; g_return_if_fail(jbi != NULL); - type = xmlnode_get_attrib(packet, "type"); - id = xmlnode_get_attrib(packet, "id"); - from = xmlnode_get_attrib(packet, "from"); - jabber_buddy_info_remove_id(jbi, id); if(!from) @@ -1576,7 +1610,7 @@ resource_name = jabber_get_resource(from); if(resource_name) { - if(type && !strcmp(type, "result")) { + if (type == JABBER_IQ_RESULT) { if((query = xmlnode_get_child(packet, "query"))) { JabberBuddyResource *jbr = jabber_buddy_find_resource(jbi->jb, resource_name); if(jbr) { @@ -1599,19 +1633,17 @@ jabber_buddy_info_show_if_ready(jbi); } -static void jabber_last_parse(JabberStream *js, xmlnode *packet, gpointer data) +static void jabber_last_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { JabberBuddyInfo *jbi = data; xmlnode *query; char *resource_name; - const char *type, *id, *from, *seconds; + const char *seconds; g_return_if_fail(jbi != NULL); - type = xmlnode_get_attrib(packet, "type"); - id = xmlnode_get_attrib(packet, "id"); - from = xmlnode_get_attrib(packet, "from"); - jabber_buddy_info_remove_id(jbi, id); if(!from) @@ -1620,7 +1652,7 @@ resource_name = jabber_get_resource(from); if(resource_name) { - if(type && !strcmp(type, "result")) { + if (type == JABBER_IQ_RESULT) { if((query = xmlnode_get_child(packet, "query"))) { seconds = xmlnode_get_attrib(query, "seconds"); if(seconds) { @@ -1678,6 +1710,56 @@ jabber_buddy_info_show_if_ready(jbi); } +static void jabber_time_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) +{ + JabberBuddyInfo *jbi = data; + JabberBuddyResource *jbr; + char *resource_name; + + g_return_if_fail(jbi != NULL); + + jabber_buddy_info_remove_id(jbi, id); + + if (!from) + return; + + resource_name = jabber_get_resource(from); + jbr = resource_name ? jabber_buddy_find_resource(jbi->jb, resource_name) : NULL; + g_free(resource_name); + if (jbr) { + if (type == JABBER_IQ_RESULT) { + xmlnode *time = xmlnode_get_child(packet, "time"); + xmlnode *tzo = time ? xmlnode_get_child(time, "tzo") : NULL; + char *tzo_data = tzo ? xmlnode_get_data(tzo) : NULL; + if (tzo_data) { + char *c = tzo_data; + int hours, minutes; + if (tzo_data[0] == 'Z' && tzo_data[1] == '\0') { + jbr->tz_off = 0; + } else { + gboolean offset_positive = (tzo_data[0] == '+'); + /* [+-]HH:MM */ + if (((*c == '+' || *c == '-') && (c = c + 1)) && + sscanf(c, "%02d:%02d", &hours, &minutes) == 2) { + jbr->tz_off = 60*60*hours + 60*minutes; + if (!offset_positive) + jbr->tz_off *= -1; + } else { + purple_debug_info("jabber", "Ignoring malformed timezone %s", + tzo_data); + } + } + + g_free(tzo_data); + } + } + } + + jabber_buddy_info_show_if_ready(jbi); +} + void jabber_buddy_remove_all_pending_buddy_info_requests(JabberStream *js) { if (js->pending_buddy_info_requests) @@ -1809,6 +1891,19 @@ jabber_iq_send(iq); } + if (jbr->tz_off == PURPLE_NO_TZ_OFF && + (!jbr->caps || + jabber_resource_has_capability(jbr, "urn:xmpp:time"))) { + xmlnode *child; + iq = jabber_iq_new(js, JABBER_IQ_GET); + xmlnode_set_attrib(iq->node, "to", full_jid); + child = xmlnode_new_child(iq->node, "time"); + xmlnode_set_namespace(child, "urn:xmpp:time"); + jabber_iq_set_callback(iq, jabber_time_parse, jbi); + jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id)); + jabber_iq_send(iq); + } + g_free(full_jid); } @@ -2205,7 +2300,9 @@ g_list_nth_data(row, 0), NULL, NULL); } -static void user_search_result_cb(JabberStream *js, xmlnode *packet, gpointer data) +static void user_search_result_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { PurpleNotifySearchResults *results; PurpleNotifySearchColumn *column; @@ -2401,15 +2498,16 @@ }; #endif -static void user_search_fields_result_cb(JabberStream *js, xmlnode *packet, gpointer data) +static void user_search_fields_result_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { xmlnode *query, *x; - const char *from, *type; - - if(!(from = xmlnode_get_attrib(packet, "from"))) + + if (!from) return; - if(!(type = xmlnode_get_attrib(packet, "type")) || !strcmp(type, "error")) { + if (type == JABBER_IQ_ERROR) { char *msg = jabber_parse_error(js, packet, NULL); if(!msg) diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/buddy.h --- a/libpurple/protocols/jabber/buddy.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/buddy.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,8 +19,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef _PURPLE_JABBER_BUDDY_H_ -#define _PURPLE_JABBER_BUDDY_H_ +#ifndef PURPLE_JABBER_BUDDY_H_ +#define PURPLE_JABBER_BUDDY_H_ typedef enum { JABBER_BUDDY_STATE_UNKNOWN = -2, @@ -82,6 +82,8 @@ char *name; char *os; } client; + /* tz_off == PURPLE_NO_TZ_OFF when unset */ + long tz_off; JabberCapsClientInfo *caps; GList *commands; } JabberBuddyResource; @@ -122,4 +124,4 @@ const gchar *cap); gboolean jabber_buddy_has_capability(const JabberBuddy *jb, const gchar *cap); -#endif /* _PURPLE_JABBER_BUDDY_H_ */ +#endif /* PURPLE_JABBER_BUDDY_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/caps.c --- a/libpurple/protocols/jabber/caps.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/caps.c Tue Apr 07 05:10:52 2009 +0000 @@ -369,7 +369,10 @@ } } -static void jabber_caps_ext_iqcb(JabberStream *js, xmlnode *packet, gpointer data) { +static void jabber_caps_ext_iqcb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) +{ /* collect data and fetch all exts */ xmlnode *query = xmlnode_get_child_with_namespace(packet, "query", "http://jabber.org/protocol/disco#info"); jabber_ext_userdata *extuserdata = data; @@ -433,7 +436,10 @@ jabber_caps_get_info_check_completion(userdata); } -static void jabber_caps_client_iqcb(JabberStream *js, xmlnode *packet, gpointer data) { +static void jabber_caps_client_iqcb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) +{ /* collect data and fetch all exts */ xmlnode *query = xmlnode_get_child_with_namespace(packet, "query", "http://jabber.org/protocol/disco#info"); diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/caps.h --- a/libpurple/protocols/jabber/caps.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/caps.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,8 +19,8 @@ * */ -#ifndef _PURPLE_JABBER_CAPS_H_ -#define _PURPLE_JABBER_CAPS_H_ +#ifndef PURPLE_JABBER_CAPS_H_ +#define PURPLE_JABBER_CAPS_H_ typedef struct _JabberCapsClientInfo JabberCapsClientInfo; @@ -46,4 +46,4 @@ void jabber_caps_get_info(JabberStream *js, const char *who, const char *node, const char *ver, const char *ext, jabber_caps_get_info_cb cb, gpointer user_data); void jabber_caps_free_clientinfo(JabberCapsClientInfo *clientinfo); -#endif /* _PURPLE_JABBER_CAPS_H_ */ +#endif /* PURPLE_JABBER_CAPS_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/chat.c --- a/libpurple/protocols/jabber/chat.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/chat.c Tue Apr 07 05:10:52 2009 +0000 @@ -376,21 +376,19 @@ jabber_iq_send(iq); } -static void jabber_chat_room_configure_cb(JabberStream *js, xmlnode *packet, gpointer data) +static void jabber_chat_room_configure_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { xmlnode *query, *x; - const char *type = xmlnode_get_attrib(packet, "type"); - const char *from = xmlnode_get_attrib(packet, "from"); char *msg; JabberChat *chat; JabberID *jid; - if(!type || !from) + if (!from) return; - - - if(!strcmp(type, "result")) { + if (type == JABBER_IQ_RESULT) { jid = jabber_id_new(from); if(!jid) @@ -416,7 +414,7 @@ return; } } - } else if(!strcmp(type, "error")) { + } else if (type == JABBER_IQ_ERROR) { char *msg = jabber_parse_error(js, packet, NULL); purple_notify_error(js->gc, _("Configuration error"), _("Configuration error"), msg); @@ -486,11 +484,12 @@ g_free(room_jid); } -static void jabber_chat_register_x_data_result_cb(JabberStream *js, xmlnode *packet, gpointer data) +static void +jabber_chat_register_x_data_result_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { - const char *type = xmlnode_get_attrib(packet, "type"); - - if(type && !strcmp(type, "error")) { + if (type == JABBER_IQ_ERROR) { char *msg = jabber_parse_error(js, packet, NULL); purple_notify_error(js->gc, _("Registration error"), _("Registration error"), msg); @@ -521,19 +520,19 @@ jabber_iq_send(iq); } -static void jabber_chat_register_cb(JabberStream *js, xmlnode *packet, gpointer data) +static void jabber_chat_register_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { xmlnode *query, *x; - const char *type = xmlnode_get_attrib(packet, "type"); - const char *from = xmlnode_get_attrib(packet, "from"); char *msg; JabberChat *chat; JabberID *jid; - if(!type || !from) + if (!from) return; - if(!strcmp(type, "result")) { + if (type == JABBER_IQ_RESULT) { jid = jabber_id_new(from); if(!jid) @@ -559,7 +558,7 @@ return; } } - } else if(!strcmp(type, "error")) { + } else if (type == JABBER_IQ_ERROR) { char *msg = jabber_parse_error(js, packet, NULL); purple_notify_error(js->gc, _("Registration error"), _("Registration error"), msg); @@ -690,16 +689,17 @@ g_free(room_jid); } -static void roomlist_disco_result_cb(JabberStream *js, xmlnode *packet, gpointer data) +static void roomlist_disco_result_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { xmlnode *query; xmlnode *item; - const char *type; if(!js->roomlist) return; - if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) { + if (type == JABBER_IQ_ERROR) { char *err = jabber_parse_error(js, packet, NULL); purple_notify_error(js->gc, _("Error"), _("Error retrieving room list"), err); @@ -988,13 +988,17 @@ return TRUE; } -static void jabber_chat_disco_traffic_cb(JabberStream *js, xmlnode *packet, gpointer data) +static void jabber_chat_disco_traffic_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { JabberChat *chat; - /*xmlnode *query;*/ - int id = GPOINTER_TO_INT(data); +#if 0 + xmlnode *query, *x; +#endif + int chat_id = GPOINTER_TO_INT(data); - if(!(chat = jabber_chat_find_by_id(js, id))) + if(!(chat = jabber_chat_find_by_id(js, chat_id))) return; /* defaults, in case the conference server doesn't @@ -1002,8 +1006,9 @@ chat->xhtml = TRUE; /* disabling this until more MUC servers support - * announcing this - if(xmlnode_get_child(packet, "error")) { + * announcing this */ +#if 0 + if (type == JABBER_IQ_ERROR) { return; } @@ -1019,7 +1024,7 @@ chat->xhtml = TRUE; } } - */ +#endif } void jabber_chat_disco_traffic(JabberChat *chat) diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/chat.h --- a/libpurple/protocols/jabber/chat.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/chat.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,8 +19,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef _PURPLE_JABBER_CHAT_H_ -#define _PURPLE_JABBER_CHAT_H_ +#ifndef PURPLE_JABBER_CHAT_H_ +#define PURPLE_JABBER_CHAT_H_ #include "internal.h" #include "connection.h" @@ -94,4 +94,4 @@ char *jabber_roomlist_room_serialize(PurpleRoomlistRoom *room); -#endif /* _PURPLE_JABBER_CHAT_H_ */ +#endif /* PURPLE_JABBER_CHAT_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/data.c --- a/libpurple/protocols/jabber/data.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/data.c Tue Apr 07 05:10:52 2009 +0000 @@ -200,25 +200,26 @@ } void -jabber_data_parse(JabberStream *js, xmlnode *packet) +jabber_data_parse(JabberStream *js, const char *who, JabberIqType type, + const char *id, xmlnode *data_node) { JabberIq *result = NULL; - const char *who = xmlnode_get_attrib(packet, "from"); - xmlnode *data_node = xmlnode_get_child(packet, "data"); - const JabberData *data = - jabber_data_find_local_by_cid(xmlnode_get_attrib(data_node, "cid")); + const char *cid = xmlnode_get_attrib(data_node, "cid"); + const JabberData *data = cid ? jabber_data_find_local_by_cid(cid) : NULL; if (!data) { xmlnode *item_not_found = xmlnode_new("item-not-found"); result = jabber_iq_new(js, JABBER_IQ_ERROR); - xmlnode_set_attrib(result->node, "to", who); - xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id")); + if (who) + xmlnode_set_attrib(result->node, "to", who); + xmlnode_set_attrib(result->node, "id", id); xmlnode_insert_child(result->node, item_not_found); } else { result = jabber_iq_new(js, JABBER_IQ_RESULT); - xmlnode_set_attrib(result->node, "to", who); - xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id")); + if (who) + xmlnode_set_attrib(result->node, "to", who); + xmlnode_set_attrib(result->node, "id", id); xmlnode_insert_child(result->node, jabber_data_get_xml_definition(data)); } @@ -235,6 +236,8 @@ g_free, jabber_data_delete); remote_data_by_cid = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, jabber_data_delete); + + jabber_iq_register_handler("data", XEP_0231_NAMESPACE, jabber_data_parse); } void diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/data.h --- a/libpurple/protocols/jabber/data.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/data.h Tue Apr 07 05:10:52 2009 +0000 @@ -14,8 +14,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA */ -#ifndef JABBER_DATA_H -#define JABBER_DATA_H +#ifndef PURPLE_JABBER_DATA_H +#define PURPLE_JABBER_DATA_H #include "xmlnode.h" #include "jabber.h" @@ -65,9 +65,10 @@ void jabber_data_associate_remote(JabberData *data); /* handles iq requests */ -void jabber_data_parse(JabberStream *js, xmlnode *packet); +void jabber_data_parse(JabberStream *js, const char *who, JabberIqType type, + const char *id, xmlnode *data_node); void jabber_data_init(void); void jabber_data_uninit(void); -#endif /* JABBER_DATA_H */ +#endif /* PURPLE_JABBER_DATA_H */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/disco.c --- a/libpurple/protocols/jabber/disco.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/disco.c Tue Apr 07 05:10:52 2009 +0000 @@ -46,9 +46,11 @@ } static void -jabber_disco_bytestream_server_cb(JabberStream *js, xmlnode *packet, gpointer data) { +jabber_disco_bytestream_server_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) +{ JabberBytestreamsStreamhost *sh = data; - const char *from = xmlnode_get_attrib(packet, "from"); xmlnode *query = xmlnode_get_child_with_namespace(packet, "query", "http://jabber.org/protocol/bytestreams"); @@ -86,29 +88,22 @@ } -void jabber_disco_info_parse(JabberStream *js, xmlnode *packet) { - const char *from = xmlnode_get_attrib(packet, "from"); - const char *type = xmlnode_get_attrib(packet, "type"); +void jabber_disco_info_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *in_query) { - if(!from || !type) + if(!from) return; - if(!strcmp(type, "get")) { + if(type == JABBER_IQ_GET) { xmlnode *query, *identity, *feature; JabberIq *iq; - - xmlnode *in_query; - const char *node = NULL; - - if((in_query = xmlnode_get_child(packet, "query"))) { - node = xmlnode_get_attrib(in_query, "node"); - } - + const char *node = xmlnode_get_attrib(in_query, "node"); iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "http://jabber.org/protocol/disco#info"); - jabber_iq_set_id(iq, xmlnode_get_attrib(packet, "id")); + jabber_iq_set_id(iq, id); xmlnode_set_attrib(iq->node, "to", from); query = xmlnode_get_child(iq->node, "query"); @@ -127,7 +122,7 @@ SUPPORT_FEATURE("jabber:iq:last") SUPPORT_FEATURE("jabber:iq:oob") SUPPORT_FEATURE("jabber:iq:time") - SUPPORT_FEATURE("xmpp:urn:time") + SUPPORT_FEATURE("urn:xmpp:time") SUPPORT_FEATURE("jabber:iq:version") SUPPORT_FEATURE("jabber:x:conference") SUPPORT_FEATURE("http://jabber.org/protocol/bytestreams") @@ -140,7 +135,6 @@ SUPPORT_FEATURE("http://jabber.org/protocol/si/profile/file-transfer") SUPPORT_FEATURE("http://jabber.org/protocol/xhtml-im") SUPPORT_FEATURE("urn:xmpp:ping") - SUPPORT_FEATURE("http://www.xmpp.org/extensions/xep-0199.html#ns") if(!node) { /* non-caps disco#info, add all enabled extensions */ GList *features; @@ -209,8 +203,7 @@ } jabber_iq_send(iq); - } else if(!strcmp(type, "result")) { - xmlnode *query = xmlnode_get_child(packet, "query"); + } else if(type == JABBER_IQ_RESULT) { xmlnode *child; JabberID *jid; JabberBuddy *jb; @@ -227,7 +220,7 @@ if(jbr) capabilities = jbr->capabilities; - for(child = query->child; child; child = child->next) { + for(child = in_query->child; child; child = child->next) { if(child->type != XMLNODE_TYPE_TAG) continue; @@ -277,7 +270,7 @@ capabilities |= JABBER_CAP_IQ_SEARCH; else if(!strcmp(var, "jabber:iq:register")) capabilities |= JABBER_CAP_IQ_REGISTER; - else if(!strcmp(var, "http://www.xmpp.org/extensions/xep-0199.html#ns")) + else if(!strcmp(var, "urn:xmpp:ping")) capabilities |= JABBER_CAP_PING; else if(!strcmp(var, "http://jabber.org/protocol/commands")) { capabilities |= JABBER_CAP_ADHOC; @@ -298,7 +291,7 @@ jdicd->callback(js, from, capabilities, jdicd->data); g_hash_table_remove(js->disco_callbacks, from); } - } else if(!strcmp(type, "error")) { + } else if(type == JABBER_IQ_ERROR) { JabberID *jid; JabberBuddy *jb; JabberBuddyResource *jbr = NULL; @@ -322,28 +315,23 @@ } } -void jabber_disco_items_parse(JabberStream *js, xmlnode *packet) { - const char *from = xmlnode_get_attrib(packet, "from"); - const char *type = xmlnode_get_attrib(packet, "type"); - - if(type && !strcmp(type, "get")) { +void jabber_disco_items_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *query) { + if(type == JABBER_IQ_GET) { JabberIq *iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "http://jabber.org/protocol/disco#items"); /* preserve node */ - xmlnode *iq_query = xmlnode_get_child_with_namespace(iq->node,"query","http://jabber.org/protocol/disco#items"); - if(iq_query) { - xmlnode *query = xmlnode_get_child_with_namespace(packet,"query","http://jabber.org/protocol/disco#items"); - if(query) { - const char *node = xmlnode_get_attrib(query,"node"); - if(node) - xmlnode_set_attrib(iq_query,"node",node); - } - } + xmlnode *iq_query = xmlnode_get_child(iq->node, "query"); + const char *node = xmlnode_get_attrib(query, "node"); + if(node) + xmlnode_set_attrib(iq_query,"node",node); - jabber_iq_set_id(iq, xmlnode_get_attrib(packet, "id")); + jabber_iq_set_id(iq, id); - xmlnode_set_attrib(iq->node, "to", from); + if (from) + xmlnode_set_attrib(iq->node, "to", from); jabber_iq_send(iq); } } @@ -408,19 +396,18 @@ } static void -jabber_disco_server_info_result_cb(JabberStream *js, xmlnode *packet, gpointer data) +jabber_disco_server_info_result_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { xmlnode *query, *child; - const char *from = xmlnode_get_attrib(packet, "from"); - const char *type = xmlnode_get_attrib(packet, "type"); - if((!from || !type) || - (strcmp(from, js->user->domain))) { + if (!from || strcmp(from, js->user->domain)) { jabber_disco_finish_server_info_result_cb(js); return; } - if(strcmp(type, "result")) { + if (type == JABBER_IQ_ERROR) { /* A common way to get here is for the server not to support xmlns http://jabber.org/protocol/disco#info */ jabber_disco_finish_server_info_result_cb(js); return; @@ -486,19 +473,16 @@ } static void -jabber_disco_server_items_result_cb(JabberStream *js, xmlnode *packet, gpointer data) +jabber_disco_server_items_result_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { xmlnode *query, *child; - const char *from = xmlnode_get_attrib(packet, "from"); - const char *type = xmlnode_get_attrib(packet, "type"); - if(!from || !type) + if (!from || strcmp(from, js->user->domain) != 0) return; - if(strcmp(from, js->user->domain)) - return; - - if(strcmp(type, "result")) + if (type == JABBER_IQ_ERROR) return; while(js->chat_servers) { diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/disco.h --- a/libpurple/protocols/jabber/disco.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/disco.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,20 +19,22 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef _PURPLE_JABBER_DISCO_H_ -#define _PURPLE_JABBER_DISCO_H_ +#ifndef PURPLE_JABBER_DISCO_H_ +#define PURPLE_JABBER_DISCO_H_ #include "jabber.h" typedef void (JabberDiscoInfoCallback)(JabberStream *js, const char *who, JabberCapabilities capabilities, gpointer data); -void jabber_disco_info_parse(JabberStream *js, xmlnode *packet); -void jabber_disco_items_parse(JabberStream *js, xmlnode *packet); +void jabber_disco_info_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, xmlnode *in_query); +void jabber_disco_items_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, xmlnode *query); void jabber_disco_items_server(JabberStream *js); void jabber_disco_info_do(JabberStream *js, const char *who, JabberDiscoInfoCallback *callback, gpointer data); -#endif /* _PURPLE_JABBER_DISCO_H_ */ +#endif /* PURPLE_JABBER_DISCO_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/google.c --- a/libpurple/protocols/jabber/google.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/google.c Tue Apr 07 05:10:52 2009 +0000 @@ -374,7 +374,7 @@ } static void -google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess) +google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id) { JabberIq *result; GList *codecs = NULL; @@ -440,13 +440,13 @@ purple_media_codec_list_free(codecs); result = jabber_iq_new(js, JABBER_IQ_RESULT); - jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id")); + jabber_iq_set_id(result, iq_id); xmlnode_set_attrib(result->node, "to", session->remote_jid); jabber_iq_send(result); } static void -google_session_handle_candidates(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess) +google_session_handle_candidates(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id) { JabberIq *result; GList *list = NULL; @@ -480,13 +480,13 @@ purple_media_candidate_list_free(list); result = jabber_iq_new(js, JABBER_IQ_RESULT); - jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id")); + jabber_iq_set_id(result, iq_id); xmlnode_set_attrib(result->node, "to", session->remote_jid); jabber_iq_send(result); } static void -google_session_handle_accept(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess) +google_session_handle_accept(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id) { xmlnode *desc_element = xmlnode_get_child(sess, "description"); xmlnode *codec_element = xmlnode_get_child(desc_element, "payload-type"); @@ -514,58 +514,54 @@ NULL, NULL, FALSE); result = jabber_iq_new(js, JABBER_IQ_RESULT); - jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id")); + jabber_iq_set_id(result, iq_id); xmlnode_set_attrib(result->node, "to", session->remote_jid); jabber_iq_send(result); } static void -google_session_handle_reject(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess) +google_session_handle_reject(JabberStream *js, GoogleSession *session, xmlnode *sess) { purple_media_end(session->media, NULL, NULL); } static void -google_session_handle_terminate(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess) +google_session_handle_terminate(JabberStream *js, GoogleSession *session, xmlnode *sess) { purple_media_end(session->media, NULL, NULL); } static void -google_session_parse_iq(JabberStream *js, GoogleSession *session, xmlnode *packet) +google_session_parse_iq(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id) { - xmlnode *sess = xmlnode_get_child(packet, "session"); const char *type = xmlnode_get_attrib(sess, "type"); if (!strcmp(type, "initiate")) { - google_session_handle_initiate(js, session, packet, sess); + google_session_handle_initiate(js, session, sess, iq_id); } else if (!strcmp(type, "accept")) { - google_session_handle_accept(js, session, packet, sess); + google_session_handle_accept(js, session, sess, iq_id); } else if (!strcmp(type, "reject")) { - google_session_handle_reject(js, session, packet, sess); + google_session_handle_reject(js, session, sess); } else if (!strcmp(type, "terminate")) { - google_session_handle_terminate(js, session, packet, sess); + google_session_handle_terminate(js, session, sess); } else if (!strcmp(type, "candidates")) { - google_session_handle_candidates(js, session, packet, sess); + google_session_handle_candidates(js, session, sess, iq_id); } } void -jabber_google_session_parse(JabberStream *js, xmlnode *packet) +jabber_google_session_parse(JabberStream *js, const char *from, + JabberIqType type, const char *iq_id, + xmlnode *session_node) { GoogleSession *session = NULL; GoogleSessionId id; - xmlnode *session_node; xmlnode *desc_node; GList *iter = NULL; - if (strcmp(xmlnode_get_attrib(packet, "type"), "set")) - return; - - session_node = xmlnode_get_child(packet, "session"); - if (!session_node) + if (type != JABBER_IQ_SET) return; id.id = (gchar*)xmlnode_get_attrib(session_node, "id"); @@ -591,7 +587,7 @@ } if (session) { - google_session_parse_iq(js, session, packet); + google_session_parse_iq(js, session, session_node, iq_id); return; } @@ -608,18 +604,18 @@ session->js = js; session->remote_jid = g_strdup(session->id.initiator); - google_session_parse_iq(js, session, packet); + google_session_parse_iq(js, session, session_node, iq_id); } #endif /* USE_VV */ static void -jabber_gmail_parse(JabberStream *js, xmlnode *packet, gpointer nul) +jabber_gmail_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer nul) { - const char *type = xmlnode_get_attrib(packet, "type"); xmlnode *child; - xmlnode *message, *sender_node, *subject_node; - const char *from, *to, *url, *tid; - char *subject; + xmlnode *message; + const char *to, *url; const char *in_str; char *to_name; char *default_tos[1]; @@ -629,7 +625,7 @@ const char **tos, **froms, **urls; char **subjects; - if (strcmp(type, "result")) + if (type == JABBER_IQ_ERROR) return; child = xmlnode_get_child(packet, "mailbox"); @@ -670,6 +666,10 @@ message= xmlnode_get_child(child, "mail-thread-info"); for (i=0; message; message = xmlnode_get_next_twin(message), i++) { + xmlnode *sender_node, *subject_node; + const char *from, *tid; + char *subject; + subject_node = xmlnode_get_child(message, "subject"); sender_node = xmlnode_get_child(message, "senders"); sender_node = xmlnode_get_child(sender_node, "sender"); @@ -727,9 +727,9 @@ } void -jabber_gmail_poke(JabberStream *js, xmlnode *packet) +jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type, + const char *id, xmlnode *new_mail) { - const char *type; xmlnode *query; JabberIq *iq; @@ -737,11 +737,8 @@ if (!purple_account_get_check_mail(js->gc->account)) return; - type = xmlnode_get_attrib(packet, "type"); - - /* Is this an initial incoming mail notification? If so, send a request for more info */ - if (strcmp(type, "set") || !xmlnode_get_child(packet, "new-mail")) + if (type != JABBER_IQ_SET) return; purple_debug(PURPLE_DEBUG_MISC, "jabber", @@ -1159,48 +1156,77 @@ } static void -jabber_google_jingle_info_cb(JabberStream *js, xmlnode *result, - gpointer nullus) -{ - if (result) { - const xmlnode *query = - xmlnode_get_child_with_namespace(result, "query", - GOOGLE_JINGLE_INFO_NAMESPACE); +jabber_google_jingle_info_common(JabberStream *js, const char *from, + JabberIqType type, xmlnode *query) +{ + const xmlnode *stun = xmlnode_get_child(query, "stun"); + gchar *my_bare_jid; - if (query) { - const xmlnode *stun = xmlnode_get_child(query, "stun"); + /* + * Make sure that random people aren't sending us STUN servers. Per + * http://code.google.com/apis/talk/jep_extensions/jingleinfo.html, these + * stanzas are stamped from our bare JID. + */ + if (from) { + my_bare_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain); + if (!purple_strequal(from, my_bare_jid)) { + purple_debug_warning("jabber", "got google:jingleinfo with invalid from (%s)\n", + from); + g_free(my_bare_jid); + return; + } - purple_debug_info("jabber", "got google:jingleinfo\n"); - - if (stun) { - xmlnode *server = xmlnode_get_child(stun, "server"); + g_free(my_bare_jid); + } - if (server) { - const gchar *host = xmlnode_get_attrib(server, "host"); - const gchar *udp = xmlnode_get_attrib(server, "udp"); + if (type == JABBER_IQ_ERROR || type == JABBER_IQ_GET) + return; + + purple_debug_info("jabber", "got google:jingleinfo\n"); + + if (stun) { + xmlnode *server = xmlnode_get_child(stun, "server"); - if (host && udp) { - int port = atoi(udp); - /* if there, would already be an ongoing query, - cancel it */ - if (js->stun_query) - purple_dnsquery_destroy(js->stun_query); + if (server) { + const gchar *host = xmlnode_get_attrib(server, "host"); + const gchar *udp = xmlnode_get_attrib(server, "udp"); - js->stun_query = purple_dnsquery_a(host, port, - jabber_google_stun_lookup_cb, js); - } - } + if (host && udp) { + int port = atoi(udp); + /* if there, would already be an ongoing query, + cancel it */ + if (js->stun_query) + purple_dnsquery_destroy(js->stun_query); + + js->stun_query = purple_dnsquery_a(host, port, + jabber_google_stun_lookup_cb, js); } - /* should perhaps handle relays later on, or maybe wait until - Google supports a common standard... */ } } + /* should perhaps handle relays later on, or maybe wait until + Google supports a common standard... */ +} + +static void +jabber_google_jingle_info_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) +{ + xmlnode *query = xmlnode_get_child_with_namespace(packet, "query", + GOOGLE_JINGLE_INFO_NAMESPACE); + + if (query) + jabber_google_jingle_info_common(js, from, type, query); + else + purple_debug_warning("jabber", "Got invalid google:jingleinfo\n"); } void -jabber_google_handle_jingle_info(JabberStream *js, xmlnode *packet) +jabber_google_handle_jingle_info(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *child) { - jabber_google_jingle_info_cb(js, packet, NULL); + jabber_google_jingle_info_common(js, from, type, child); } void diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/google.h --- a/libpurple/protocols/jabber/google.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/google.h Tue Apr 07 05:10:52 2009 +0000 @@ -18,8 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef _PURPLE_GOOGLE_H_ -#define _PURPLE_GOOGLE_H_ +#ifndef PURPLE_JABBER_GOOGLE_H_ +#define PURPLE_JABBER_GOOGLE_H_ /* This is a place for Google Talk-specific XMPP extensions to live * such that they don't intermingle with code for the XMPP RFCs and XEPs :) */ @@ -31,7 +31,8 @@ #define GOOGLE_JINGLE_INFO_NAMESPACE "google:jingleinfo" void jabber_gmail_init(JabberStream *js); -void jabber_gmail_poke(JabberStream *js, xmlnode *node); +void jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type, + const char *id, xmlnode *new_mail); void jabber_google_roster_init(JabberStream *js); void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item); @@ -50,9 +51,11 @@ char *jabber_google_format_to_html(const char *text); gboolean jabber_google_session_initiate(JabberStream *js, const gchar *who, PurpleMediaSessionType type); -void jabber_google_session_parse(JabberStream *js, xmlnode *node); +void jabber_google_session_parse(JabberStream *js, const char *from, JabberIqType type, const char *iq, xmlnode *session); -void jabber_google_handle_jingle_info(JabberStream *js, xmlnode *packet); +void jabber_google_handle_jingle_info(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *child); void jabber_google_send_jingle_info(JabberStream *js); -#endif /* _PURPLE_GOOGLE_H_ */ +#endif /* PURPLE_JABBER_GOOGLE_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/ibb.c --- a/libpurple/protocols/jabber/ibb.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/ibb.c Tue Apr 07 05:10:52 2009 +0000 @@ -46,12 +46,10 @@ } JabberIBBSession * -jabber_ibb_session_create_from_xmlnode(JabberStream *js, xmlnode *packet, - gpointer user_data) +jabber_ibb_session_create_from_xmlnode(JabberStream *js, const char *from, + const char *id, xmlnode *open, gpointer user_data) { JabberIBBSession *sess = NULL; - xmlnode *open = xmlnode_get_child_with_namespace(packet, "open", - XEP_0047_NAMESPACE); const gchar *sid = xmlnode_get_attrib(open, "sid"); const gchar *block_size = xmlnode_get_attrib(open, "block-size"); @@ -66,9 +64,8 @@ return NULL; } - sess = jabber_ibb_session_create(js, sid, - xmlnode_get_attrib(packet, "from"), user_data); - sess->id = g_strdup(xmlnode_get_attrib(packet, "id")); + sess = jabber_ibb_session_create(js, sid, from, user_data); + sess->id = g_strdup(id); sess->block_size = atoi(block_size); /* if we create a session from an incoming request, it means the session is immediatly open... */ @@ -198,11 +195,13 @@ } static void -jabber_ibb_session_opened_cb(JabberStream *js, xmlnode *packet, gpointer data) +jabber_ibb_session_opened_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { JabberIBBSession *sess = (JabberIBBSession *) data; - if (strcmp(xmlnode_get_attrib(packet, "type"), "error") == 0) { + if (type == JABBER_IQ_ERROR) { sess->state = JABBER_IBB_SESSION_ERROR; } else { sess->state = JABBER_IBB_SESSION_OPENED; @@ -274,10 +273,11 @@ } static void -jabber_ibb_session_send_acknowledge_cb(JabberStream *js, xmlnode *packet, gpointer data) +jabber_ibb_session_send_acknowledge_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { JabberIBBSession *sess = (JabberIBBSession *) data; - xmlnode *error = xmlnode_get_child(packet, "error"); if (sess) { /* reset callback */ @@ -286,7 +286,7 @@ sess->last_iq_id = NULL; } - if (error) { + if (type == JABBER_IQ_ERROR) { jabber_ibb_session_close(sess); sess->state = JABBER_IBB_SESSION_ERROR; @@ -351,7 +351,7 @@ } static void -jabber_ibb_send_error_response(JabberStream *js, xmlnode *packet) +jabber_ibb_send_error_response(JabberStream *js, const char *to, const char *id) { JabberIq *result = jabber_iq_new(js, JABBER_IQ_ERROR); xmlnode *error = xmlnode_new("error"); @@ -361,9 +361,8 @@ "urn:ietf:params:xml:ns:xmpp-stanzas"); xmlnode_set_attrib(error, "code", "440"); xmlnode_set_attrib(error, "type", "cancel"); - jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id")); - xmlnode_set_attrib(result->node, "to", - xmlnode_get_attrib(packet, "from")); + jabber_iq_set_id(result, id); + xmlnode_set_attrib(result->node, "to", to); xmlnode_insert_child(error, item_not_found); xmlnode_insert_child(result->node, error); @@ -371,20 +370,17 @@ } void -jabber_ibb_parse(JabberStream *js, xmlnode *packet) +jabber_ibb_parse(JabberStream *js, const char *who, JabberIqType type, + const char *id, xmlnode *child) { - xmlnode *data = xmlnode_get_child_with_namespace(packet, "data", - XEP_0047_NAMESPACE); - xmlnode *close = xmlnode_get_child_with_namespace(packet, "close", - XEP_0047_NAMESPACE); - xmlnode *open = xmlnode_get_child_with_namespace(packet, "open", - XEP_0047_NAMESPACE); - const gchar *sid = - data ? xmlnode_get_attrib(data, "sid") : - close ? xmlnode_get_attrib(close, "sid") : NULL; + const char *name = child->name; + gboolean data = g_str_equal(name, "data"); + gboolean close = g_str_equal(name, "close"); + gboolean open = g_str_equal(name, "open"); + const gchar *sid = (data || close) ? + xmlnode_get_attrib(child, "sid") : NULL; JabberIBBSession *sess = sid ? g_hash_table_lookup(jabber_ibb_sessions, sid) : NULL; - const gchar *who = xmlnode_get_attrib(packet, "from"); if (sess) { @@ -394,7 +390,7 @@ purple_debug_error("jabber", "Got IBB iq from wrong JID, ignoring\n"); } else if (data) { - const gchar *seq_attr = xmlnode_get_attrib(data, "seq"); + const gchar *seq_attr = xmlnode_get_attrib(child, "seq"); guint16 seq = (seq_attr ? atoi(seq_attr) : 0); /* reject the data, and set the session in error if we get an @@ -403,12 +399,11 @@ /* sequence # is the expected... */ JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT); - jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id")); - xmlnode_set_attrib(result->node, "to", - xmlnode_get_attrib(packet, "from")); + jabber_iq_set_id(result, id); + xmlnode_set_attrib(result->node, "to", who); if (sess->data_received_cb) { - gchar *base64 = xmlnode_get_data(data); + gchar *base64 = xmlnode_get_data(child); gsize size; gpointer rawdata = purple_base64_decode(base64, &size); @@ -475,20 +470,19 @@ iterator = g_list_next(iterator)) { JabberIBBOpenHandler *handler = iterator->data; - if (handler(js, packet)) { + if (handler(js, who, id, child)) { result = jabber_iq_new(js, JABBER_IQ_RESULT); - xmlnode_set_attrib(result->node, "to", - xmlnode_get_attrib(packet, "from")); - jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id")); + xmlnode_set_attrib(result->node, "to", who); + jabber_iq_set_id(result, id); jabber_iq_send(result); return; } } /* no open callback returned success, reject */ - jabber_ibb_send_error_response(js, packet); + jabber_ibb_send_error_response(js, who, id); } else { /* send error reply */ - jabber_ibb_send_error_response(js, packet); + jabber_ibb_send_error_response(js, who, id); } } @@ -508,6 +502,10 @@ jabber_ibb_init(void) { jabber_ibb_sessions = g_hash_table_new(g_str_hash, g_str_equal); + + jabber_iq_register_handler("close", XEP_0047_NAMESPACE, jabber_ibb_parse); + jabber_iq_register_handler("data", XEP_0047_NAMESPACE, jabber_ibb_parse); + jabber_iq_register_handler("open", XEP_0047_NAMESPACE, jabber_ibb_parse); } void diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/ibb.h --- a/libpurple/protocols/jabber/ibb.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/ibb.h Tue Apr 07 05:10:52 2009 +0000 @@ -14,8 +14,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA */ -#ifndef _PURPLE_JABBER_IBB_H_ -#define _PURPLE_JABBER_IBB_H_ +#ifndef PURPLE_JABBER_IBB_H_ +#define PURPLE_JABBER_IBB_H_ #include "jabber.h" #include "iq.h" @@ -32,7 +32,8 @@ typedef void (JabberIBBErrorCallback)(JabberIBBSession *); typedef void (JabberIBBSentCallback)(JabberIBBSession *); -typedef gboolean (JabberIBBOpenHandler)(JabberStream *js, xmlnode *packet); +typedef gboolean (JabberIBBOpenHandler)(JabberStream *js, const char *from, + const char *id, xmlnode *open); typedef enum { JABBER_IBB_SESSION_NOT_OPENED, @@ -71,7 +72,7 @@ JabberIBBSession *jabber_ibb_session_create(JabberStream *js, const gchar *sid, const gchar *who, gpointer user_data); JabberIBBSession *jabber_ibb_session_create_from_xmlnode(JabberStream *js, - xmlnode *packet, gpointer user_data); + const gchar *from, const gchar *id, xmlnode *open, gpointer user_data); void jabber_ibb_session_destroy(JabberIBBSession *sess); @@ -107,7 +108,8 @@ gpointer jabber_ibb_session_get_user_data(JabberIBBSession *sess); /* handle incoming packet */ -void jabber_ibb_parse(JabberStream *js, xmlnode *packet); +void jabber_ibb_parse(JabberStream *js, const char *who, JabberIqType type, + const char *id, xmlnode *child); /* add a handler for open session */ void jabber_ibb_register_open_handler(JabberIBBOpenHandler *cb); @@ -116,4 +118,4 @@ void jabber_ibb_init(void); void jabber_ibb_uninit(void); -#endif /* _PURPLE_JABBER_IBB_H_ */ +#endif /* PURPLE_JABBER_IBB_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/iq.c --- a/libpurple/protocols/jabber/iq.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/iq.c Tue Apr 07 05:10:52 2009 +0000 @@ -144,23 +144,19 @@ g_free(iq); } -static void jabber_iq_last_parse(JabberStream *js, xmlnode *packet) +static void jabber_iq_last_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet) { JabberIq *iq; - const char *type; - const char *from; - const char *id; xmlnode *query; char *idle_time; - type = xmlnode_get_attrib(packet, "type"); - from = xmlnode_get_attrib(packet, "from"); - id = xmlnode_get_attrib(packet, "id"); - - if(type && !strcmp(type, "get")) { + if(type == JABBER_IQ_GET) { iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:last"); jabber_iq_set_id(iq, id); - xmlnode_set_attrib(iq->node, "to", from); + if (from) + xmlnode_set_attrib(iq->node, "to", from); query = xmlnode_get_child(iq->node, "query"); @@ -172,88 +168,67 @@ } } -static void jabber_iq_time_parse(JabberStream *js, xmlnode *packet) +static void jabber_iq_time_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *child) { - const char *type, *from, *id, *xmlns; + const char *xmlns; JabberIq *iq; - xmlnode *query; time_t now_t; + struct tm now_local; + struct tm now_utc; struct tm *now; time(&now_t); now = localtime(&now_t); - - type = xmlnode_get_attrib(packet, "type"); - from = xmlnode_get_attrib(packet, "from"); - id = xmlnode_get_attrib(packet, "id"); + memcpy(&now_local, now, sizeof(struct tm)); + now = gmtime(&now_t); + memcpy(&now_utc, now, sizeof(struct tm)); - /* we're gonna throw this away in a moment, but we need it - * to get the xmlns, so we can figure out if this is - * jabber:iq:time or urn:xmpp:time */ - query = xmlnode_get_child(packet, "query"); - xmlns = xmlnode_get_namespace(query); + xmlns = xmlnode_get_namespace(child); - if(type && !strcmp(type, "get")) { + if(type == JABBER_IQ_GET) { xmlnode *utc; - const char *date; + const char *date, *tz, *display; - iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, xmlns); + iq = jabber_iq_new(js, JABBER_IQ_RESULT); jabber_iq_set_id(iq, id); - xmlnode_set_attrib(iq->node, "to", from); - - query = xmlnode_get_child(iq->node, "query"); + if (from) + xmlnode_set_attrib(iq->node, "to", from); - date = purple_utf8_strftime("%Y%m%dT%T", now); - utc = xmlnode_new_child(query, "utc"); - xmlnode_insert_data(utc, date, -1); + child = xmlnode_new_child(iq->node, child->name); + xmlnode_set_namespace(child, xmlns); + utc = xmlnode_new_child(child, "utc"); if(!strcmp("urn:xmpp:time", xmlns)) { - xmlnode_insert_data(utc, "Z", 1); /* of COURSE the thing that is the same is different */ + tz = purple_get_tzoff_str(&now_local, TRUE); + xmlnode_insert_data(xmlnode_new_child(child, "tzo"), tz, -1); - date = purple_get_tzoff_str(now, TRUE); - xmlnode_insert_data(xmlnode_new_child(query, "tzo"), date, -1); + date = purple_utf8_strftime("%FT%TZ", &now_utc); + xmlnode_insert_data(utc, date, -1); } else { /* jabber:iq:time */ - date = purple_utf8_strftime("%Z", now); - xmlnode_insert_data(xmlnode_new_child(query, "tz"), date, -1); + tz = purple_utf8_strftime("%Z", &now_local); + xmlnode_insert_data(xmlnode_new_child(child, "tz"), tz, -1); - date = purple_utf8_strftime("%d %b %Y %T", now); - xmlnode_insert_data(xmlnode_new_child(query, "display"), date, -1); + date = purple_utf8_strftime("%Y%m%dT%T", &now_utc); + xmlnode_insert_data(utc, date, -1); + + display = purple_utf8_strftime("%d %b %Y %T", &now_local); + xmlnode_insert_data(xmlnode_new_child(child, "display"), display, -1); } jabber_iq_send(iq); } } -static void urn_xmpp_ping_parse(JabberStream *js, xmlnode *packet) -{ - const char *type, *id, *from; - JabberIq *iq; - - type = xmlnode_get_attrib(packet, "type"); - from = xmlnode_get_attrib(packet, "from"); - id = xmlnode_get_attrib(packet, "id"); - - if(type && !strcmp(type, "get")) { - iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "urn:xmpp:ping"); - - jabber_iq_set_id(iq, id); - xmlnode_set_attrib(iq->node, "to", from); - - jabber_iq_send(iq); - } else { - /* XXX: error */ - } -} - -static void jabber_iq_version_parse(JabberStream *js, xmlnode *packet) +static void jabber_iq_version_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet) { JabberIq *iq; - const char *type, *from, *id; xmlnode *query; - type = xmlnode_get_attrib(packet, "type"); - - if(type && !strcmp(type, "get")) { + if(type == JABBER_IQ_GET) { GHashTable *ui_info; const char *ui_name = NULL, *ui_version = NULL; #if 0 @@ -266,11 +241,10 @@ osinfo.machine); } #endif - from = xmlnode_get_attrib(packet, "from"); - id = xmlnode_get_attrib(packet, "id"); iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:version"); - xmlnode_set_attrib(iq->node, "to", from); + if (from) + xmlnode_set_attrib(iq->node, "to", from); jabber_iq_set_id(iq, id); query = xmlnode_get_child(iq->node, "query"); @@ -311,33 +285,56 @@ void jabber_iq_parse(JabberStream *js, xmlnode *packet) { JabberCallbackData *jcd; - xmlnode *query, *error, *x; + xmlnode *child, *error, *x; const char *xmlns; - const char *type, *id, *from; - JabberIqHandler *jih; + const char *iq_type, *id, *from; + JabberIqType type = JABBER_IQ_NONE; - query = xmlnode_get_child(packet, "query"); - type = xmlnode_get_attrib(packet, "type"); + /* + * child will be either the first tag child or NULL if there is no child. + * Historically, we used just the 'query' subchild, but newer XEPs use + * differently named children. Grabbing the first child is (for the time + * being) sufficient. + */ + for (child = packet->child; child; child = child->next) { + if (child->type == XMLNODE_TYPE_TAG) + break; + } + + iq_type = xmlnode_get_attrib(packet, "type"); from = xmlnode_get_attrib(packet, "from"); id = xmlnode_get_attrib(packet, "id"); - if(type == NULL || !(!strcmp(type, "get") || !strcmp(type, "set") - || !strcmp(type, "result") || !strcmp(type, "error"))) { + if (iq_type) { + if (!strcmp(iq_type, "get")) + type = JABBER_IQ_GET; + else if (!strcmp(iq_type, "set")) + type = JABBER_IQ_SET; + else if (!strcmp(iq_type, "result")) + type = JABBER_IQ_RESULT; + else if (!strcmp(iq_type, "error")) + type = JABBER_IQ_ERROR; + } + + if (type == JABBER_IQ_NONE) { purple_debug_error("jabber", "IQ with invalid type ('%s') - ignoring.\n", - type ? type : "(null)"); + iq_type ? iq_type : "(null)"); return; } /* All IQs must have an ID, so send an error for a set/get that doesn't */ if(!id || !*id) { - if(!strcmp(type, "set") || !strcmp(type, "get")) { + if(type == JABBER_IQ_SET || type == JABBER_IQ_GET) { JabberIq *iq = jabber_iq_new(js, JABBER_IQ_ERROR); xmlnode_free(iq->node); iq->node = xmlnode_copy(packet); - xmlnode_set_attrib(iq->node, "to", from); - xmlnode_remove_attrib(iq->node, "from"); + if (from) { + xmlnode_set_attrib(iq->node, "to", from); + xmlnode_remove_attrib(iq->node, "from"); + } + xmlnode_set_attrib(iq->node, "type", "error"); /* This id is clearly not useful, but we must put something there for a valid stanza */ iq->id = jabber_get_next_id(js); @@ -349,79 +346,46 @@ jabber_iq_send(iq); } else - purple_debug_error("jabber", "IQ of type '%s' missing id - ignoring.\n", type); + purple_debug_error("jabber", "IQ of type '%s' missing id - ignoring.\n", + iq_type); return; } /* First, lets see if a special callback got registered */ - - if(!strcmp(type, "result") || !strcmp(type, "error")) { - if(id && *id && (jcd = g_hash_table_lookup(js->iq_callbacks, id))) { - jcd->callback(js, packet, jcd->data); + if(type == JABBER_IQ_RESULT || type == JABBER_IQ_ERROR) { + if((jcd = g_hash_table_lookup(js->iq_callbacks, id))) { + jcd->callback(js, from, type, id, packet, jcd->data); jabber_iq_remove_callback_by_id(js, id); return; } } /* Apparently not, so lets see if we have a pre-defined handler */ + if(child && (xmlns = xmlnode_get_namespace(child))) { + char *key = g_strdup_printf("%s %s", child->name, xmlns); + JabberIqHandler *jih = g_hash_table_lookup(iq_handlers, key); + g_free(key); - if(query && (xmlns = xmlnode_get_namespace(query))) { - if((jih = g_hash_table_lookup(iq_handlers, xmlns))) { - jih(js, packet); + if(jih) { + jih(js, from, type, id, child); return; } } -#ifdef USE_VV - if (xmlnode_get_child_with_namespace(packet, "session", "http://www.google.com/session")) { - jabber_google_session_parse(js, packet); - return; - } -#endif - - if(xmlnode_get_child_with_namespace(packet, "si", "http://jabber.org/protocol/si")) { - jabber_si_parse(js, packet); - return; - } - - if(xmlnode_get_child_with_namespace(packet, "new-mail", "google:mail:notify")) { - jabber_gmail_poke(js, packet); - return; - } - purple_debug_info("jabber", "jabber_iq_parse\n"); - if(xmlnode_get_child_with_namespace(packet, "ping", "urn:xmpp:ping")) { - jabber_ping_parse(js, packet); - return; - } - - if (xmlnode_get_child_with_namespace(packet, "data", XEP_0231_NAMESPACE)) { - jabber_data_parse(js, packet); - return; - } - - if (xmlnode_get_child_with_namespace(packet, "data", XEP_0047_NAMESPACE) - || xmlnode_get_child_with_namespace(packet, "close", XEP_0047_NAMESPACE) - || xmlnode_get_child_with_namespace(packet, "open", XEP_0047_NAMESPACE)) { - jabber_ibb_parse(js, packet); - return; - } - - if (xmlnode_get_child_with_namespace(packet, "jingle", JINGLE)) { - jingle_parse(js, packet); - return; - } - /* If we get here, send the default error reply mandated by XMPP-CORE */ - if(!strcmp(type, "set") || !strcmp(type, "get")) { + if(type == JABBER_IQ_SET || type == JABBER_IQ_GET) { JabberIq *iq = jabber_iq_new(js, JABBER_IQ_ERROR); xmlnode_free(iq->node); iq->node = xmlnode_copy(packet); - xmlnode_set_attrib(iq->node, "to", from); - xmlnode_remove_attrib(iq->node, "from"); + if (from) { + xmlnode_set_attrib(iq->node, "to", from); + xmlnode_remove_attrib(iq->node, "from"); + } + xmlnode_set_attrib(iq->node, "type", "error"); error = xmlnode_new_child(iq->node, "error"); xmlnode_set_attrib(error, "type", "cancel"); @@ -433,31 +397,50 @@ } } -void jabber_iq_register_handler(const char *xmlns, JabberIqHandler *handlerfunc) +void jabber_iq_register_handler(const char *node, const char *xmlns, JabberIqHandler *handlerfunc) { - g_hash_table_replace(iq_handlers, g_strdup(xmlns), handlerfunc); + /* + * This is valid because nodes nor namespaces cannot have spaces in them + * (see http://www.w3.org/TR/2006/REC-xml-20060816/ and + * http://www.w3.org/TR/REC-xml-names/) + */ + char *key = g_strdup_printf("%s %s", node, xmlns); + g_hash_table_replace(iq_handlers, key, handlerfunc); } void jabber_iq_init(void) { iq_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); - jabber_iq_register_handler("jabber:iq:roster", jabber_roster_parse); - jabber_iq_register_handler("jabber:iq:oob", jabber_oob_parse); - jabber_iq_register_handler("http://jabber.org/protocol/bytestreams", jabber_bytestreams_parse); - jabber_iq_register_handler("jabber:iq:last", jabber_iq_last_parse); - jabber_iq_register_handler("jabber:iq:time", jabber_iq_time_parse); - jabber_iq_register_handler("urn:xmpp:time", jabber_iq_time_parse); - jabber_iq_register_handler("jabber:iq:version", jabber_iq_version_parse); - jabber_iq_register_handler("http://jabber.org/protocol/disco#info", jabber_disco_info_parse); - jabber_iq_register_handler("http://jabber.org/protocol/disco#items", jabber_disco_items_parse); - jabber_iq_register_handler("jabber:iq:register", jabber_register_parse); - jabber_iq_register_handler("urn:xmpp:ping", urn_xmpp_ping_parse); - jabber_iq_register_handler(JINGLE, jingle_parse); + jabber_iq_register_handler("jingle", JINGLE, jingle_parse); + jabber_iq_register_handler("mailbox", "google:mail:notify", + jabber_gmail_poke); + jabber_iq_register_handler("new-mail", "google:mail:notify", + jabber_gmail_poke); + jabber_iq_register_handler("ping", "urn:xmpp:ping", jabber_ping_parse); + jabber_iq_register_handler("query", GOOGLE_JINGLE_INFO_NAMESPACE, + jabber_google_handle_jingle_info); + jabber_iq_register_handler("query", "http://jabber.org/protocol/bytestreams", + jabber_bytestreams_parse); + jabber_iq_register_handler("query", "http://jabber.org/protocol/disco#info", + jabber_disco_info_parse); + jabber_iq_register_handler("query", "http://jabber.org/protocol/disco#items", + jabber_disco_items_parse); + jabber_iq_register_handler("query", "jabber:iq:last", jabber_iq_last_parse); + jabber_iq_register_handler("query", "jabber:iq:oob", jabber_oob_parse); + jabber_iq_register_handler("query", "jabber:iq:register", + jabber_register_parse); + jabber_iq_register_handler("query", "jabber:iq:roster", + jabber_roster_parse); + jabber_iq_register_handler("query", "jabber:iq:time", jabber_iq_time_parse); + jabber_iq_register_handler("query", "jabber:iq:version", + jabber_iq_version_parse); +#ifdef USE_VV + jabber_iq_register_handler("session", "http://www.google.com/session", + jabber_google_session_parse); +#endif + jabber_iq_register_handler("time", "urn:xmpp:time", jabber_iq_time_parse); - /* handle Google jingleinfo */ - jabber_iq_register_handler(GOOGLE_JINGLE_INFO_NAMESPACE, - jabber_google_handle_jingle_info); } void jabber_iq_uninit(void) @@ -465,4 +448,3 @@ g_hash_table_destroy(iq_handlers); iq_handlers = NULL; } - diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/iq.h --- a/libpurple/protocols/jabber/iq.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/iq.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,12 +19,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef _PURPLE_JABBER_IQ_H_ -#define _PURPLE_JABBER_IQ_H_ - -#include "jabber.h" - -typedef struct _JabberIq JabberIq; +#ifndef PURPLE_JABBER_IQ_H_ +#define PURPLE_JABBER_IQ_H_ typedef enum { JABBER_IQ_SET, @@ -34,9 +30,51 @@ JABBER_IQ_NONE } JabberIqType; -typedef void (JabberIqHandler)(JabberStream *js, xmlnode *packet); +#include "jabber.h" + +typedef struct _JabberIq JabberIq; -typedef void (JabberIqCallback)(JabberStream *js, xmlnode *packet, gpointer data); +/** + * A JabberIqHandler is called to process an incoming IQ stanza. + * Handlers typically process unsolicited incoming GETs or SETs for their + * registered namespace, but may be called to handle the results of a + * GET or SET that we generated if no JabberIqCallback was generated + * The handler may be called for the results of a GET or SET (RESULT or ERROR) + * that we generated + * if the generating function did not register a JabberIqCallback. + * + * @param js The JabberStream object. + * @param from The remote entity (the from attribute on the stanza) + * @param type The IQ type. + * @param id The IQ id (the id attribute on the stanza) + * @param child The child element of the stanza that matches the name + * and namespace registered with jabber_iq_register_handler. + * + * @see jabber_iq_register_handler() + * @see JabberIqCallback + */ +typedef void (JabberIqHandler)(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *child); + +/** + * A JabberIqCallback is called to process the results of a GET or SET that + * we send to a remote entity. The callback is matched based on the id + * of the incoming stanza (which matches the one on the initial stanza). + * + * @param js The JabberStream object. + * @param from The remote entity (the from attribute on the stanza) + * @param type The IQ type. The only possible values are JABBER_IQ_RESULT + * and JABBER_IQ_ERROR. + * @param id The IQ id (the id attribute on the stanza) + * @param packet The stanza + * @param data The callback data passed to jabber_iq_set_callback() + * + * @see jabber_iq_set_callback() + */ +typedef void (JabberIqCallback)(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data); struct _JabberIq { JabberIqType type; @@ -65,6 +103,7 @@ void jabber_iq_init(void); void jabber_iq_uninit(void); -void jabber_iq_register_handler(const char *xmlns, JabberIqHandler *func); +void jabber_iq_register_handler(const char *node, const char *xmlns, + JabberIqHandler *func); -#endif /* _PURPLE_JABBER_IQ_H_ */ +#endif /* PURPLE_JABBER_IQ_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/jabber.c --- a/libpurple/protocols/jabber/jabber.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/jabber.c Tue Apr 07 05:10:52 2009 +0000 @@ -88,10 +88,11 @@ } static void -jabber_session_initialized_cb(JabberStream *js, xmlnode *packet, gpointer data) +jabber_session_initialized_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { - const char *type = xmlnode_get_attrib(packet, "type"); - if(type && !strcmp(type, "result")) { + if (type == JABBER_IQ_RESULT) { jabber_stream_set_state(js, JABBER_STREAM_CONNECTED); if(js->unregistration) jabber_unregister_account_cb(js); @@ -115,13 +116,13 @@ jabber_iq_send(iq); } -static void jabber_bind_result_cb(JabberStream *js, xmlnode *packet, - gpointer data) +static void jabber_bind_result_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { - const char *type = xmlnode_get_attrib(packet, "type"); xmlnode *bind; - if(type && !strcmp(type, "result") && + if (type == JABBER_IQ_RESULT && (bind = xmlnode_get_child_with_namespace(packet, "bind", "urn:ietf:params:xml:ns:xmpp-bind"))) { xmlnode *jid; char *full_jid; @@ -449,13 +450,7 @@ g_free(txt); } -static void jabber_pong_cb(JabberStream *js, xmlnode *packet, gpointer unused) -{ - purple_timeout_remove(js->keepalive_timeout); - js->keepalive_timeout = -1; -} - -static gboolean jabber_pong_timeout(PurpleConnection *gc) +static gboolean jabber_keepalive_timeout(PurpleConnection *gc) { JabberStream *js = gc->proto_data; purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, @@ -469,14 +464,9 @@ JabberStream *js = gc->proto_data; if (js->keepalive_timeout == -1) { - JabberIq *iq = jabber_iq_new(js, JABBER_IQ_GET); - - xmlnode *ping = xmlnode_new_child(iq->node, "ping"); - xmlnode_set_namespace(ping, "urn:xmpp:ping"); - - js->keepalive_timeout = purple_timeout_add_seconds(120, (GSourceFunc)(jabber_pong_timeout), gc); - jabber_iq_set_callback(iq, jabber_pong_cb, NULL); - jabber_iq_send(iq); + jabber_ping_jid(js, NULL); + js->keepalive_timeout = purple_timeout_add_seconds(120, + (GSourceFunc)(jabber_keepalive_timeout), gc); } } @@ -812,14 +802,15 @@ } static void -jabber_registration_result_cb(JabberStream *js, xmlnode *packet, gpointer data) +jabber_registration_result_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { PurpleAccount *account = purple_connection_get_account(js->gc); - const char *type = xmlnode_get_attrib(packet, "type"); char *buf; char *to = data; - if(!strcmp(type, "result")) { + if (type == JABBER_IQ_RESULT) { if(js->registration) { buf = g_strdup_printf(_("Registration of %s@%s successful"), js->user->node, js->user->domain); @@ -847,13 +838,14 @@ } g_free(to); if(js->registration) - jabber_connection_schedule_close(js); + jabber_connection_schedule_close(js); } static void -jabber_unregistration_result_cb(JabberStream *js, xmlnode *packet, gpointer data) +jabber_unregistration_result_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { - const char *type = xmlnode_get_attrib(packet, "type"); char *buf; char *to = data; @@ -861,7 +853,7 @@ * the server, so there should always be a 'to' address. */ g_return_if_fail(to != NULL); - if(!strcmp(type, "result")) { + if (type == JABBER_IQ_RESULT) { buf = g_strdup_printf(_("Registration from %s successfully removed"), to); purple_notify_info(NULL, _("Unregistration Successful"), @@ -1010,31 +1002,30 @@ jabber_iq_send(iq); } -void jabber_register_parse(JabberStream *js, xmlnode *packet) +void jabber_register_parse(JabberStream *js, const char *from, JabberIqType type, + const char *id, xmlnode *query) { PurpleAccount *account = purple_connection_get_account(js->gc); - const char *type; - const char *from; PurpleRequestFields *fields; PurpleRequestFieldGroup *group; PurpleRequestField *field; - xmlnode *query, *x, *y; + xmlnode *x, *y; char *instructions; JabberRegisterCBData *cbdata; gboolean registered = FALSE; - if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) + if (type != JABBER_IQ_RESULT) return; - from = xmlnode_get_attrib(packet, "from"); + if (!from) + from = js->serverFQDN; + g_return_if_fail(from != NULL); if(js->registration) { /* get rid of the login thingy */ purple_connection_set_state(js->gc, PURPLE_CONNECTED); } - query = xmlnode_get_child(packet, "query"); - if(xmlnode_get_child(query, "registered")) { registered = TRUE; @@ -1272,10 +1263,14 @@ } } -static void jabber_unregister_account_iq_cb(JabberStream *js, xmlnode *packet, gpointer data) { +static void +jabber_unregister_account_iq_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) +{ PurpleAccount *account = purple_connection_get_account(js->gc); - const char *type = xmlnode_get_attrib(packet,"type"); - if(!strcmp(type,"error")) { + + if (type == JABBER_IQ_ERROR) { char *msg = jabber_parse_error(js, packet, NULL); purple_notify_error(js->gc, _("Error unregistering account"), @@ -1283,7 +1278,7 @@ g_free(msg); if(js->unregistration_cb) js->unregistration_cb(account, FALSE, js->unregistration_user_data); - } else if(!strcmp(type,"result")) { + } else { purple_notify_info(js->gc, _("Account successfully unregistered"), _("Account successfully unregistered"), NULL); if(js->unregistration_cb) @@ -1530,7 +1525,9 @@ jabber_presence_send(account, status); } -static void jabber_blocklist_parse(JabberStream *js, xmlnode *packet, gpointer data) +static void jabber_blocklist_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { xmlnode *blocklist, *item; PurpleAccount *account; @@ -1982,14 +1979,11 @@ } static void -jabber_password_change_result_cb(JabberStream *js, xmlnode *packet, - gpointer data) +jabber_password_change_result_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { - const char *type; - - type = xmlnode_get_attrib(packet, "type"); - - if(type && !strcmp(type, "result")) { + if (type == JABBER_IQ_RESULT) { purple_notify_info(js->gc, _("Password Changed"), _("Password Changed"), _("Your password has been changed.")); @@ -2521,10 +2515,16 @@ static PurpleCmdRet jabber_cmd_ping(PurpleConversation *conv, const char *cmd, char **args, char **error, void *data) { + PurpleAccount *account; + PurpleConnection *pc; + if(!args || !args[0]) return PURPLE_CMD_RET_FAILED; - if(!jabber_ping_jid(conv, args[0])) { + account = purple_conversation_get_account(conv); + pc = purple_account_get_connection(account); + + if(!jabber_ping_jid(purple_connection_get_protocol_data(pc), args[0])) { *error = g_strdup_printf(_("Unable to ping user %s"), args[0]); return PURPLE_CMD_RET_FAILED; } @@ -2656,6 +2656,39 @@ return TRUE; } +#ifdef USE_VV +typedef struct { + PurpleConnection *pc; + gchar *who; + PurpleMediaSessionType type; + +} JabberMediaRequest; + +static void +jabber_media_cancel_cb(JabberMediaRequest *request, + PurpleRequestFields *fields) +{ + g_free(request->who); + g_free(request); +} + +static void +jabber_media_ok_cb(JabberMediaRequest *request, PurpleRequestFields *fields) +{ + PurpleRequestField *field = + purple_request_fields_get_field(fields, "resource"); + int selected_id = purple_request_field_choice_get_value(field); + GList *labels = purple_request_field_choice_get_labels(field); + gchar *who = g_strdup_printf("%s/%s", request->who, + (gchar*)g_list_nth_data(labels, selected_id)); + jabber_initiate_media(request->pc, who, request->type); + + g_free(who); + g_free(request->who); + g_free(request); +} +#endif + gboolean jabber_initiate_media(PurpleConnection *gc, const char *who, PurpleMediaSessionType type) @@ -2663,6 +2696,8 @@ #ifdef USE_VV JabberStream *js = (JabberStream *) gc->proto_data; JabberBuddy *jb; + JabberBuddyResource *jbr = NULL; + char *resource; if (!js) { purple_debug_error("jabber", @@ -2670,23 +2705,135 @@ return FALSE; } - jb = jabber_buddy_find(js, who, FALSE); - - if (!jb) { - purple_debug_error("jabber", "Could not find buddy\n"); - return FALSE; + + if((resource = jabber_get_resource(who)) != NULL) { + /* they've specified a resource, no need to ask or + * default or anything, just do it */ + + jb = jabber_buddy_find(js, who, FALSE); + jbr = jabber_buddy_find_resource(jb, resource); + g_free(resource); + + if (type & PURPLE_MEDIA_AUDIO && + !jabber_resource_has_capability(jbr, + JINGLE_APP_RTP_SUPPORT_AUDIO) && + jabber_resource_has_capability(jbr, + GOOGLE_VOICE_CAP)) + return jabber_google_session_initiate( + gc->proto_data, who, type); + else + return jingle_rtp_initiate_media( + gc->proto_data, who, type); } - if (type & PURPLE_MEDIA_AUDIO && - !jabber_buddy_has_capability(jb, - JINGLE_APP_RTP_SUPPORT_AUDIO) && - jabber_buddy_has_capability(jb, GOOGLE_VOICE_CAP)) - return jabber_google_session_initiate(gc->proto_data, who, type); - else - return jingle_rtp_initiate_media(gc->proto_data, who, type); -#else + jb = jabber_buddy_find(js, who, FALSE); + + if(!jb || !jb->resources) { + /* no resources online, we're trying to initiate with someone + * whose presence we're not subscribed to, or + * someone who is offline. Let's inform the user */ + char *msg; + + if(!jb) { + msg = g_strdup_printf(_("Unable to initiate media with %s: invalid JID"), who); + } else if(jb->subscription & JABBER_SUB_TO) { + msg = g_strdup_printf(_("Unable to initiate media with %s: user is not online"), who); + } else { + msg = g_strdup_printf(_("Unable to initiate media with %s: not subscribed to user presence"), who); + } + + purple_notify_error(js->gc, _("Media Initiation Failed"), + _("Media Initiation Failed"), msg); + g_free(msg); + return FALSE; + } else if(!jb->resources->next) { + /* only 1 resource online (probably our most common case) + * so no need to ask who to initiate with */ + gchar *name; + gboolean result; + jbr = jb->resources->data; + name = g_strdup_printf("%s/%s", who, jbr->name); + result = jabber_initiate_media(gc, name, type); + g_free(name); + return result; + } else { + /* we've got multiple resources, + * we need to pick one to initiate with */ + GList *l; + char *msg; + PurpleRequestFields *fields; + PurpleRequestField *field = purple_request_field_choice_new( + "resource", _("Resource"), 0); + PurpleRequestFieldGroup *group; + JabberMediaRequest *request; + + for(l = jb->resources; l; l = l->next) + { + JabberBuddyResource *ljbr = l->data; + PurpleMediaCaps caps; + gchar *name; + name = g_strdup_printf("%s/%s", who, ljbr->name); + caps = jabber_get_media_caps(gc, name); + g_free(name); + + if ((type & PURPLE_MEDIA_AUDIO) && + (type & PURPLE_MEDIA_VIDEO)) { + if (caps & PURPLE_MEDIA_CAPS_AUDIO_VIDEO) { + jbr = ljbr; + purple_request_field_choice_add( + field, jbr->name); + } + } else if (type & (PURPLE_MEDIA_AUDIO) && + (caps & PURPLE_MEDIA_CAPS_AUDIO)) { + jbr = ljbr; + purple_request_field_choice_add( + field, jbr->name); + }else if (type & (PURPLE_MEDIA_VIDEO) && + (caps & PURPLE_MEDIA_CAPS_VIDEO)) { + jbr = ljbr; + purple_request_field_choice_add( + field, jbr->name); + } + } + + if (jbr == NULL) { + purple_debug_error("jabber", + "No resources available\n"); + return FALSE; + } + + if (g_list_length(purple_request_field_choice_get_labels( + field)) <= 1) { + gchar *name; + gboolean result; + purple_request_field_destroy(field); + name = g_strdup_printf("%s/%s", who, jbr->name); + result = jabber_initiate_media(gc, name, type); + g_free(name); + return result; + } + + msg = g_strdup_printf(_("Please select the resource of %s with which you would like to start a media session."), who); + fields = purple_request_fields_new(); + group = purple_request_field_group_new(NULL); + request = g_new0(JabberMediaRequest, 1); + request->pc = gc; + request->who = g_strdup(who); + request->type = type; + + purple_request_field_group_add_field(group, field); + purple_request_fields_add_group(fields, group); + purple_request_fields(gc, _("Select a Resource"), msg, NULL, + fields, _("Initiate Media"), + G_CALLBACK(jabber_media_ok_cb), _("Cancel"), + G_CALLBACK(jabber_media_cancel_cb), + gc->account, who, NULL, request); + + g_free(msg); + return TRUE; + } +#endif return FALSE; -#endif } PurpleMediaCaps jabber_get_media_caps(PurpleConnection *gc, const char *who) @@ -2694,7 +2841,9 @@ #ifdef USE_VV JabberStream *js = (JabberStream *) gc->proto_data; JabberBuddy *jb; + JabberBuddyResource *jbr; PurpleMediaCaps caps = PURPLE_MEDIA_CAPS_NONE; + gchar *resource; if (!js) { purple_debug_info("jabber", @@ -2702,35 +2851,75 @@ return FALSE; } - jb = jabber_buddy_find(js, who, FALSE); - - if (!jb) { - purple_debug_error("jabber", "Could not find buddy\n"); - return FALSE; + if ((resource = jabber_get_resource(who)) != NULL) { + /* they've specified a resource, no need to ask or + * default or anything, just do it */ + + jb = jabber_buddy_find(js, who, FALSE); + jbr = jabber_buddy_find_resource(jb, resource); + g_free(resource); + + if (!jbr) { + purple_debug_error("jabber", "jabber_get_media_caps:" + " Can't find resource %s\n", who); + return caps; + } + + if (jabber_resource_has_capability(jbr, + JINGLE_APP_RTP_SUPPORT_AUDIO)) + caps |= PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION | + PURPLE_MEDIA_CAPS_AUDIO; + if (jabber_resource_has_capability(jbr, + JINGLE_APP_RTP_SUPPORT_VIDEO)) + caps |= PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION | + PURPLE_MEDIA_CAPS_VIDEO; + if (caps & PURPLE_MEDIA_CAPS_AUDIO && caps & + PURPLE_MEDIA_CAPS_VIDEO) + caps |= PURPLE_MEDIA_CAPS_AUDIO_VIDEO; + if (caps != PURPLE_MEDIA_CAPS_NONE) { + if (!jabber_resource_has_capability(jbr, + JINGLE_TRANSPORT_ICEUDP) && + !jabber_resource_has_capability(jbr, + JINGLE_TRANSPORT_RAWUDP)) { + purple_debug_info("jingle-rtp", "Buddy doesn't " + "support the same transport types\n"); + caps = PURPLE_MEDIA_CAPS_NONE; + } else + caps |= PURPLE_MEDIA_CAPS_MODIFY_SESSION | + PURPLE_MEDIA_CAPS_CHANGE_DIRECTION; + } + if (jabber_resource_has_capability(jbr, GOOGLE_VOICE_CAP)) + caps |= PURPLE_MEDIA_CAPS_AUDIO; + return caps; } - if (jabber_buddy_has_capability(jb, JINGLE_APP_RTP_SUPPORT_AUDIO)) - caps |= PURPLE_MEDIA_CAPS_AUDIO | - PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION; - if (jabber_buddy_has_capability(jb, JINGLE_APP_RTP_SUPPORT_VIDEO)) - caps |= PURPLE_MEDIA_CAPS_VIDEO | - PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION; - if (caps & PURPLE_MEDIA_CAPS_AUDIO && caps & PURPLE_MEDIA_CAPS_VIDEO) - caps |= PURPLE_MEDIA_CAPS_AUDIO_VIDEO; - if (caps != PURPLE_MEDIA_CAPS_NONE) { - if (!jabber_buddy_has_capability(jb, - JINGLE_TRANSPORT_ICEUDP) && - !jabber_buddy_has_capability(jb, - JINGLE_TRANSPORT_RAWUDP)) { - purple_debug_info("jingle-rtp", "Buddy doesn't " - "support the same transport types\n"); - caps = PURPLE_MEDIA_CAPS_NONE; - } else - caps |= PURPLE_MEDIA_CAPS_MODIFY_SESSION | - PURPLE_MEDIA_CAPS_CHANGE_DIRECTION; + jb = jabber_buddy_find(js, who, FALSE); + + if(!jb || !jb->resources) { + /* no resources online, we're trying to get caps for someone + * whose presence we're not subscribed to, or + * someone who is offline. */ + return caps; + } else if(!jb->resources->next) { + /* only 1 resource online (probably our most common case) */ + gchar *name; + jbr = jb->resources->data; + name = g_strdup_printf("%s/%s", who, jbr->name); + caps = jabber_get_media_caps(gc, name); + g_free(name); + } else { + /* we've got multiple resources, combine their caps */ + GList *l; + + for(l = jb->resources; l; l = l->next) + { + gchar *name; + jbr = l->data; + name = g_strdup_printf("%s/%s", who, jbr->name); + caps |= jabber_get_media_caps(gc, name); + g_free(name); + } } - if (jabber_buddy_has_capability(jb, GOOGLE_VOICE_CAP)) - caps |= PURPLE_MEDIA_CAPS_AUDIO; return caps; #else diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/jabber.h --- a/libpurple/protocols/jabber/jabber.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/jabber.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,8 +19,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef _PURPLE_JABBER_H_ -#define _PURPLE_JABBER_H_ +#ifndef PURPLE_JABBER_H_ +#define PURPLE_JABBER_H_ typedef enum { JABBER_CAP_NONE = 0, @@ -60,6 +60,7 @@ #include "sslconn.h" #include "dnsquery.h" +#include "iq.h" #include "jutil.h" #include "xmlnode.h" #include "buddy.h" @@ -282,7 +283,8 @@ void jabber_stream_set_state(JabberStream *js, JabberStreamState state); -void jabber_register_parse(JabberStream *js, xmlnode *packet); +void jabber_register_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, xmlnode *query); void jabber_register_start(JabberStream *js); char *jabber_get_next_id(JabberStream *js); @@ -328,4 +330,4 @@ void jabber_register_commands(void); void jabber_init_plugin(PurplePlugin *plugin); -#endif /* _PURPLE_JABBER_H_ */ +#endif /* PURPLE_JABBER_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/jingle/content.h --- a/libpurple/protocols/jabber/jingle/content.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/jingle/content.h Tue Apr 07 05:10:52 2009 +0000 @@ -18,8 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef JINGLE_CONTENT_H -#define JINGLE_CONTENT_H +#ifndef PURPLE_JABBER_JINGLE_CONTENT_H +#define PURPLE_JABBER_JINGLE_CONTENT_H #include "jabber.h" @@ -113,5 +113,5 @@ G_END_DECLS -#endif /* JINGLE_CONTENT_H */ +#endif /* PURPLE_JABBER_JINGLE_CONTENT_H */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/jingle/iceudp.h --- a/libpurple/protocols/jabber/jingle/iceudp.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/jingle/iceudp.h Tue Apr 07 05:10:52 2009 +0000 @@ -18,8 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef JINGLE_ICEUDP_H -#define JINGLE_ICEUDP_H +#ifndef PURPLE_JABBER_JINGLE_ICEUDP_H +#define PURPLE_JABBER_JINGLE_ICEUDP_H #include #include @@ -110,5 +110,5 @@ G_END_DECLS -#endif /* JINGLE_ICEUDP_H */ +#endif /* PURPLE_JABBER_JINGLE_ICEUDP_H */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/jingle/jingle.c --- a/libpurple/protocols/jabber/jingle/jingle.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/jingle/jingle.c Tue Apr 07 05:10:52 2009 +0000 @@ -359,28 +359,21 @@ } void -jingle_parse(JabberStream *js, xmlnode *packet) +jingle_parse(JabberStream *js, const char *from, JabberIqType type, + const char *id, xmlnode *jingle) { - const gchar *type = xmlnode_get_attrib(packet, "type"); - xmlnode *jingle; const gchar *action; const gchar *sid; JingleActionType action_type; JingleSession *session; - if (!type || strcmp(type, "set")) { - /* send iq error here */ - return; - } - - /* is this a Jingle package? */ - if (!(jingle = xmlnode_get_child(packet, "jingle"))) { - /* send iq error here */ + if (type != JABBER_IQ_SET) { + /* TODO: send iq error here */ return; } if (!(action = xmlnode_get_attrib(jingle, "action"))) { - /* send iq error here */ + /* TODO: send iq error here */ return; } @@ -409,9 +402,10 @@ /* send iq error */ return; } else { - session = jingle_session_create(js, sid, - xmlnode_get_attrib(packet, "to"), - xmlnode_get_attrib(packet, "from"), FALSE); + char *own_jid = g_strdup_printf("%s@%s/%s", js->user->node, + js->user->domain, js->user->resource); + session = jingle_session_create(js, sid, own_jid, from, FALSE); + g_free(own_jid); } } diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/jingle/jingle.h --- a/libpurple/protocols/jabber/jingle/jingle.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/jingle/jingle.h Tue Apr 07 05:10:52 2009 +0000 @@ -16,8 +16,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA */ -#ifndef JINGLE_H -#define JINGLE_H +#ifndef PURPLE_JABBER_JINGLE_H +#define PURPLE_JABBER_JINGLE_H #include "jabber.h" @@ -69,7 +69,8 @@ GType jingle_get_type(const gchar *type); -void jingle_parse(JabberStream *js, xmlnode *packet); +void jingle_parse(JabberStream *js, const char *from, JabberIqType type, + const char *id, xmlnode *child); void jingle_terminate_sessions(JabberStream *js); @@ -83,4 +84,4 @@ G_END_DECLS -#endif /* JINGLE_H */ +#endif /* PURPLE_JABBER_JINGLE_H */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/jingle/rawudp.h --- a/libpurple/protocols/jabber/jingle/rawudp.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/jingle/rawudp.h Tue Apr 07 05:10:52 2009 +0000 @@ -18,8 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef JINGLE_RAWUDP_H -#define JINGLE_RAWUDP_H +#ifndef PURPLE_JABBER_JINGLE_RAWUDP_H +#define PURPLE_JABBER_JINGLE_RAWUDP_H #include #include @@ -97,5 +97,5 @@ G_END_DECLS -#endif /* JINGLE_RAWUDP_H */ +#endif /* PURPLE_JABBER_JINGLE_RAWUDP_H */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/jingle/rtp.c --- a/libpurple/protocols/jabber/jingle/rtp.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/jingle/rtp.c Tue Apr 07 05:10:52 2009 +0000 @@ -438,12 +438,13 @@ } static void -jingle_rtp_initiate_ack_cb(JabberStream *js, xmlnode *packet, gpointer data) +jingle_rtp_initiate_ack_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { JingleSession *session = data; - if (!strcmp(xmlnode_get_attrib(packet, "type"), "error") || - xmlnode_get_child(packet, "error")) { + if (type == JABBER_IQ_ERROR || xmlnode_get_child(packet, "error")) { purple_media_end(jingle_rtp_get_media(session), NULL, NULL); g_object_unref(session); return; @@ -834,7 +835,7 @@ JabberBuddyResource *jbr; const gchar *transport_type; - gchar *jid = NULL, *me = NULL, *sid = NULL; + gchar *resource = NULL, *me = NULL, *sid = NULL; /* construct JID to send to */ jb = jabber_buddy_find(js, who, FALSE); @@ -842,7 +843,11 @@ purple_debug_error("jingle-rtp", "Could not find Jabber buddy\n"); return FALSE; } - jbr = jabber_buddy_find_resource(jb, NULL); + + resource = jabber_get_resource(who); + jbr = jabber_buddy_find_resource(jb, resource); + g_free(resource); + if (!jbr) { purple_debug_error("jingle-rtp", "Could not find buddy's resource\n"); } @@ -857,17 +862,11 @@ return FALSE; } - if ((strchr(who, '/') == NULL) && jbr && (jbr->name != NULL)) { - jid = g_strdup_printf("%s/%s", who, jbr->name); - } else { - jid = g_strdup(who); - } - /* set ourselves as initiator */ me = g_strdup_printf("%s@%s/%s", js->user->node, js->user->domain, js->user->resource); sid = jabber_get_next_id(js); - session = jingle_session_create(js, sid, me, jid, TRUE); + session = jingle_session_create(js, sid, me, who, TRUE); g_free(sid); @@ -888,7 +887,6 @@ jingle_rtp_init_media(content); } - g_free(jid); g_free(me); if (jingle_rtp_get_media(session) == NULL) { diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/jingle/rtp.h --- a/libpurple/protocols/jabber/jingle/rtp.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/jingle/rtp.h Tue Apr 07 05:10:52 2009 +0000 @@ -18,8 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef JINGLE_RTP_H -#define JINGLE_RTP_H +#ifndef PURPLE_JABBER_JINGLE_RTP_H +#define PURPLE_JABBER_JINGLE_RTP_H #include "config.h" @@ -88,5 +88,5 @@ #endif /* USE_VV */ -#endif /* JINGLE_RTP_H */ +#endif /* PURPLE_JABBER_JINGLE_RTP_H */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/jingle/session.h --- a/libpurple/protocols/jabber/jingle/session.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/jingle/session.h Tue Apr 07 05:10:52 2009 +0000 @@ -18,8 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef JINGLE_SESSION_H -#define JINGLE_SESSION_H +#ifndef PURPLE_JABBER_JINGLE_SESSION_H +#define PURPLE_JABBER_JINGLE_SESSION_H #include "iq.h" #include "jabber.h" @@ -111,5 +111,5 @@ G_END_DECLS -#endif /* JINGLE_SESSION_H */ +#endif /* PURPLE_JABBER_JINGLE_SESSION_H */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/jingle/transport.h --- a/libpurple/protocols/jabber/jingle/transport.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/jingle/transport.h Tue Apr 07 05:10:52 2009 +0000 @@ -18,8 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef JINGLE_TRANSPORT_H -#define JINGLE_TRANSPORT_H +#ifndef PURPLE_JABBER_JINGLE_TRANSPORT_H +#define PURPLE_JABBER_JINGLE_TRANSPORT_H #include #include @@ -84,5 +84,5 @@ G_END_DECLS -#endif /* JINGLE_TRANSPORT_H */ +#endif /* PURPLE_JABBER_JINGLE_TRANSPORT_H */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/jutil.h --- a/libpurple/protocols/jabber/jutil.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/jutil.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,8 +19,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef _PURPLE_JABBER_JUTIL_H_ -#define _PURPLE_JABBER_JUTIL_H_ +#ifndef PURPLE_JABBER_JUTIL_H_ +#define PURPLE_JABBER_JUTIL_H_ typedef struct _JabberID { char *node; @@ -43,4 +43,4 @@ PurpleConversation *jabber_find_unnormalized_conv(const char *name, PurpleAccount *account); char *jabber_calculate_data_sha1sum(gconstpointer data, size_t len); -#endif /* _PURPLE_JABBER_JUTIL_H_ */ +#endif /* PURPLE_JABBER_JUTIL_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/message.c --- a/libpurple/protocols/jabber/message.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/message.c Tue Apr 07 05:10:52 2009 +0000 @@ -477,7 +477,9 @@ } JabberDataRef; static void -jabber_message_get_data_cb(JabberStream *js, xmlnode *packet, gpointer data) +jabber_message_get_data_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { JabberDataRef *ref = (JabberDataRef *) data; PurpleConversation *conv = ref->conv; diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/message.h --- a/libpurple/protocols/jabber/message.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/message.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,8 +19,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef _PURPLE_JABBER_MESSAGE_H_ -#define _PURPLE_JABBER_MESSAGE_H_ +#ifndef PURPLE_JABBER_MESSAGE_H_ +#define PURPLE_JABBER_MESSAGE_H_ #include "buddy.h" #include "jabber.h" @@ -85,4 +85,4 @@ gboolean jabber_custom_smileys_isenabled(JabberStream *js, const gchar *shortname, const gchar *namespace); -#endif /* _PURPLE_JABBER_MESSAGE_H_ */ +#endif /* PURPLE_JABBER_MESSAGE_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/oob.c --- a/libpurple/protocols/jabber/oob.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/oob.c Tue Apr 07 05:10:52 2009 +0000 @@ -187,18 +187,18 @@ jabber_oob_xfer_recv_error(xfer, "404"); } -void jabber_oob_parse(JabberStream *js, xmlnode *packet) { +void jabber_oob_parse(JabberStream *js, const char *from, JabberIqType type, + const char *id, xmlnode *querynode) { JabberOOBXfer *jox; PurpleXfer *xfer; char *filename; char *url; - const char *type; - xmlnode *querynode, *urlnode; + xmlnode *urlnode; - if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "set")) + if(type != JABBER_IQ_SET) return; - if(!(querynode = xmlnode_get_child(packet, "query"))) + if(!from) return; if(!(urlnode = xmlnode_get_child(querynode, "url"))) @@ -211,10 +211,9 @@ g_free(url); jox->js = js; jox->headers = g_string_new(""); - jox->iq_id = g_strdup(xmlnode_get_attrib(packet, "id")); + jox->iq_id = g_strdup(id); - xfer = purple_xfer_new(js->gc->account, PURPLE_XFER_RECEIVE, - xmlnode_get_attrib(packet, "from")); + xfer = purple_xfer_new(js->gc->account, PURPLE_XFER_RECEIVE, from); if (xfer) { xfer->data = jox; diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/oob.h --- a/libpurple/protocols/jabber/oob.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/oob.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,9 +19,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef _PURPLE_JABBER_OOB_H_ -#define _PURPLE_JABBER_OOB_H_ +#ifndef PURPLE_JABBER_OOB_H_ +#define PURPLE_JABBER_OOB_H_ + +#include "jabber.h" -void jabber_oob_parse(JabberStream *js, xmlnode *packet); +void jabber_oob_parse(JabberStream *js, const char *from, JabberIqType type, + const char *id, xmlnode *querynode); -#endif /* _PURPLE_JABBER_OOB_H_ */ +#endif /* PURPLE_JABBER_OOB_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/parser.h --- a/libpurple/protocols/jabber/parser.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/parser.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,8 +19,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef _PURPLE_JABBER_PARSER_H_ -#define _PURPLE_JABBER_PARSER_H_ +#ifndef PURPLE_JABBER_PARSER_H_ +#define PURPLE_JABBER_PARSER_H_ #include "jabber.h" @@ -28,4 +28,4 @@ void jabber_parser_free(JabberStream *js); void jabber_parser_process(JabberStream *js, const char *buf, int len); -#endif /* _PURPLE_JABBER_PARSER_H_ */ +#endif /* PURPLE_JABBER_PARSER_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/pep.c --- a/libpurple/protocols/jabber/pep.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/pep.c Tue Apr 07 05:10:52 2009 +0000 @@ -52,8 +52,11 @@ g_hash_table_replace(pep_handlers, g_strdup(xmlns), handlerfunc); } -static void do_pep_iq_request_item_callback(JabberStream *js, xmlnode *packet, gpointer data) { - const char *from = xmlnode_get_attrib(packet,"from"); +static void +do_pep_iq_request_item_callback(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) +{ xmlnode *pubsub = xmlnode_get_child_with_namespace(packet,"pubsub","http://jabber.org/protocol/pubsub"); xmlnode *items = NULL; JabberPEPHandler *cb = data; diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/pep.h --- a/libpurple/protocols/jabber/pep.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/pep.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,8 +19,8 @@ * */ -#ifndef _PURPLE_JABBER_PEP_H_ -#define _PURPLE_JABBER_PEP_H_ +#ifndef PURPLE_JABBER_PEP_H_ +#define PURPLE_JABBER_PEP_H_ #include "jabber.h" #include "message.h" @@ -82,4 +82,4 @@ */ void jabber_pep_publish(JabberStream *js, xmlnode *publish); -#endif /* _PURPLE_JABBER_PEP_H_ */ +#endif /* PURPLE_JABBER_PEP_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/ping.c --- a/libpurple/protocols/jabber/ping.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/ping.c Tue Apr 07 05:10:52 2009 +0000 @@ -23,50 +23,63 @@ #include "internal.h" #include "debug.h" -#include "xmlnode.h" #include "jabber.h" #include "ping.h" #include "iq.h" -void -jabber_ping_parse(JabberStream *js, xmlnode *packet) +static void jabber_keepalive_pong_cb(JabberStream *js) { - JabberIq *iq; - - purple_debug_info("jabber", "jabber_ping_parse\n"); - - iq = jabber_iq_new(js, JABBER_IQ_RESULT); - - xmlnode_set_attrib(iq->node, "to", xmlnode_get_attrib(packet, "from") ); - - jabber_iq_set_id(iq, xmlnode_get_attrib(packet, "id")); - - jabber_iq_send(iq); + purple_timeout_remove(js->keepalive_timeout); + js->keepalive_timeout = -1; } -static void jabber_ping_result_cb(JabberStream *js, xmlnode *packet, - gpointer data) +void +jabber_ping_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, xmlnode *ping) { - const char *type = xmlnode_get_attrib(packet, "type"); + if (type == JABBER_IQ_GET) { + JabberIq *iq = jabber_iq_new(js, JABBER_IQ_RESULT); + + if (from) + xmlnode_set_attrib(iq->node, "to", from); + xmlnode_set_attrib(iq->node, "id", id); + + jabber_iq_send(iq); + } else if (type == JABBER_IQ_SET) { + /* XXX: error */ + } +} - purple_debug_info("jabber", "jabber_ping_result_cb\n"); - if(type && !strcmp(type, "result")) { +static void jabber_ping_result_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) +{ + char *own_bare_jid = g_strdup_printf("%s@%s", js->user->node, + js->user->domain); + + if (!from || !strcmp(from, own_bare_jid)) { + /* If the pong is from our bare JID, treat it as a return from the + * keepalive functions */ + jabber_keepalive_pong_cb(js); + } + g_free(own_bare_jid); + + if (type == JABBER_IQ_RESULT) { purple_debug_info("jabber", "PONG!\n"); } else { purple_debug_info("jabber", "(not supported)\n"); } } -gboolean jabber_ping_jid(PurpleConversation *conv, const char *jid) +gboolean jabber_ping_jid(JabberStream *js, const char *jid) { JabberIq *iq; xmlnode *ping; - purple_debug_info("jabber", "jabber_ping_jid\n"); - - iq = jabber_iq_new(conv->account->gc->proto_data, JABBER_IQ_GET); - xmlnode_set_attrib(iq->node, "to", jid); + iq = jabber_iq_new(js, JABBER_IQ_GET); + if (jid) + xmlnode_set_attrib(iq->node, "to", jid); ping = xmlnode_new_child(iq->node, "ping"); xmlnode_set_namespace(ping, "urn:xmpp:ping"); @@ -74,7 +87,5 @@ jabber_iq_set_callback(iq, jabber_ping_result_cb, NULL); jabber_iq_send(iq); - - return TRUE; } diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/ping.h --- a/libpurple/protocols/jabber/ping.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/ping.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,17 +19,15 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _PURPLE_JABBER_PING_H_ -#define _PURPLE_JABBER_PING_H_ +#ifndef PURPLE_JABBER_PING_H_ +#define PURPLE_JABBER_PING_H_ #include "jabber.h" -#include "conversation.h" - -void jabber_ping_parse(JabberStream *js, - xmlnode *packet); +#include "iq.h" +#include "xmlnode.h" - -gboolean jabber_ping_jid(PurpleConversation *conv, const char *jid); +void jabber_ping_parse(JabberStream *js, const char *from, + JabberIqType, const char *id, xmlnode *child); +gboolean jabber_ping_jid(JabberStream *js, const char *jid); - -#endif /* _PURPLE_JABBER_PING_H_ */ +#endif /* PURPLE_JABBER_PING_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/presence.c --- a/libpurple/protocols/jabber/presence.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/presence.c Tue Apr 07 05:10:52 2009 +0000 @@ -343,14 +343,16 @@ g_free(jap); } -static void jabber_vcard_parse_avatar(JabberStream *js, xmlnode *packet, gpointer blah) +static void +jabber_vcard_parse_avatar(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer blah) { JabberBuddy *jb = NULL; xmlnode *vcard, *photo, *binval; char *text; guchar *data; gsize size; - const char *from = xmlnode_get_attrib(packet, "from"); if(!from) return; diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/presence.h --- a/libpurple/protocols/jabber/presence.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/presence.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,8 +19,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef _PURPLE_JABBER_PRESENCE_H_ -#define _PURPLE_JABBER_PRESENCE_H_ +#ifndef PURPLE_JABBER_PRESENCE_H_ +#define PURPLE_JABBER_PRESENCE_H_ #include "buddy.h" #include "jabber.h" @@ -35,4 +35,4 @@ void jabber_presence_fake_to_self(JabberStream *js, const PurpleStatus *status); void purple_status_to_jabber(const PurpleStatus *status, JabberBuddyState *state, char **msg, int *priority); -#endif /* _PURPLE_JABBER_PRESENCE_H_ */ +#endif /* PURPLE_JABBER_PRESENCE_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/roster.c --- a/libpurple/protocols/jabber/roster.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/roster.c Tue Apr 07 05:10:52 2009 +0000 @@ -145,10 +145,10 @@ g_slist_free(buddies); } -void jabber_roster_parse(JabberStream *js, xmlnode *packet) +void jabber_roster_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, xmlnode *query) { - xmlnode *query, *item, *group; - const char *from = xmlnode_get_attrib(packet, "from"); + xmlnode *item, *group; if(from) { char *from_norm; @@ -169,10 +169,6 @@ return; } - query = xmlnode_get_child(packet, "query"); - if(!query) - return; - js->currently_parsing_roster_push = TRUE; for(item = xmlnode_get_child(query, "item"); item; item = xmlnode_get_next_twin(item)) diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/roster.h --- a/libpurple/protocols/jabber/roster.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/roster.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,14 +19,15 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef _PURPLE_JABBER_ROSTER_H_ -#define _PURPLE_JABBER_ROSTER_H_ +#ifndef PURPLE_JABBER_ROSTER_H_ +#define PURPLE_JABBER_ROSTER_H_ #include "jabber.h" void jabber_roster_request(JabberStream *js); -void jabber_roster_parse(JabberStream *js, xmlnode *packet); +void jabber_roster_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, xmlnode *query); void jabber_roster_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); @@ -39,4 +40,4 @@ void jabber_roster_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); -#endif /* _PURPLE_JABBER_ROSTER_H_ */ +#endif /* PURPLE_JABBER_ROSTER_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/si.c --- a/libpurple/protocols/jabber/si.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/si.c Tue Apr 07 05:10:52 2009 +0000 @@ -311,20 +311,18 @@ } } -void jabber_bytestreams_parse(JabberStream *js, xmlnode *packet) +void jabber_bytestreams_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, xmlnode *query) { PurpleXfer *xfer; JabberSIXfer *jsx; - xmlnode *query, *streamhost; - const char *sid, *from, *type; + xmlnode *streamhost; + const char *sid; - if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "set")) + if(type != JABBER_IQ_SET) return; - if(!(from = xmlnode_get_attrib(packet, "from"))) - return; - - if(!(query = xmlnode_get_child(packet, "query"))) + if(!from) return; if(!(sid = xmlnode_get_attrib(query, "sid"))) @@ -340,7 +338,7 @@ if(jsx->iq_id) g_free(jsx->iq_id); - jsx->iq_id = g_strdup(xmlnode_get_attrib(packet, "id")); + jsx->iq_id = g_strdup(id); for(streamhost = xmlnode_get_child(query, "streamhost"); streamhost; streamhost = xmlnode_get_next_twin(streamhost)) { @@ -685,13 +683,14 @@ } static void -jabber_si_connect_proxy_cb(JabberStream *js, xmlnode *packet, - gpointer data) +jabber_si_connect_proxy_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { PurpleXfer *xfer = data; JabberSIXfer *jsx; xmlnode *query, *streamhost_used; - const char *from, *type, *jid; + const char *jid; GList *matched; /* TODO: This need to send errors if we don't see what we're looking for */ @@ -708,37 +707,34 @@ jsx = xfer->data; - if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) { - purple_debug_info("jabber", - "jabber_si_xfer_connect_proxy_cb: type = %s\n", - type); - if (type && !strcmp(type, "error")) { - /* if IBB is available, open IBB session */ - purple_debug_info("jabber", - "jabber_si_xfer_connect_proxy_cb: got error, method: %d\n", - jsx->stream_method); - if (jsx->stream_method & STREAM_METHOD_IBB) { - purple_debug_info("jabber", "IBB is possible, try it\n"); - /* if we are the sender and haven't already opened an IBB - session, do so now (we might already have failed to open - the bytestream proxy ourselves when receiving this */ - if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND - && !jsx->ibb_session) { - jabber_si_xfer_ibb_send_init(js, xfer); - } else { - jsx->ibb_timeout_handle = purple_timeout_add_seconds(30, - jabber_si_bytestreams_ibb_timeout_cb, xfer); - } - /* if we are receiver, just wait for IBB open stanza, callback - is already set up */ + if(type != JABBER_IQ_RESULT) { + purple_debug_info("jabber", + "jabber_si_xfer_connect_proxy_cb: type = error\n"); + /* if IBB is available, open IBB session */ + purple_debug_info("jabber", + "jabber_si_xfer_connect_proxy_cb: got error, method: %d\n", + jsx->stream_method); + if (jsx->stream_method & STREAM_METHOD_IBB) { + purple_debug_info("jabber", "IBB is possible, try it\n"); + /* if we are the sender and haven't already opened an IBB + session, do so now (we might already have failed to open + the bytestream proxy ourselves when receiving this */ + if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND + && !jsx->ibb_session) { + jabber_si_xfer_ibb_send_init(js, xfer); } else { - purple_xfer_cancel_remote(xfer); + jsx->ibb_timeout_handle = purple_timeout_add_seconds(30, + jabber_si_bytestreams_ibb_timeout_cb, xfer); } + /* if we are receiver, just wait for IBB open stanza, callback + is already set up */ + } else { + purple_xfer_cancel_remote(xfer); } return; } - if(!(from = xmlnode_get_attrib(packet, "from"))) + if (!from) return; if(!(query = xmlnode_get_child(packet, "query"))) @@ -1019,16 +1015,15 @@ } static gboolean -jabber_si_xfer_ibb_open_cb(JabberStream *js, xmlnode *packet) +jabber_si_xfer_ibb_open_cb(JabberStream *js, const char *who, const char *id, + xmlnode *open) { - const gchar *who = xmlnode_get_attrib(packet, "from"); - xmlnode *open = xmlnode_get_child(packet, "open"); const gchar *sid = xmlnode_get_attrib(open, "sid"); PurpleXfer *xfer = jabber_si_xfer_find(js, sid, who); if (xfer) { JabberSIXfer *jsx = (JabberSIXfer *) xfer->data; JabberIBBSession *sess = - jabber_ibb_session_create_from_xmlnode(js, packet, xfer); + jabber_ibb_session_create_from_xmlnode(js, who, id, open, xfer); const char *filename; jabber_si_bytestreams_ibb_timeout_remove(jsx); @@ -1183,8 +1178,9 @@ } } -static void jabber_si_xfer_send_method_cb(JabberStream *js, xmlnode *packet, - gpointer data) +static void jabber_si_xfer_send_method_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) { PurpleXfer *xfer = data; xmlnode *si, *feature, *x, *field, *value; @@ -1585,17 +1581,15 @@ purple_xfer_request(xfer); } -void jabber_si_parse(JabberStream *js, xmlnode *packet) +void jabber_si_parse(JabberStream *js, const char *from, JabberIqType type, + const char *id, xmlnode *si) { JabberSIXfer *jsx; PurpleXfer *xfer; - xmlnode *si, *file, *feature, *x, *field, *option, *value; - const char *stream_id, *filename, *filesize_c, *profile, *from; + xmlnode *file, *feature, *x, *field, *option, *value; + const char *stream_id, *filename, *filesize_c, *profile; size_t filesize = 0; - if(!(si = xmlnode_get_child(packet, "si"))) - return; - if(!(profile = xmlnode_get_attrib(si, "profile")) || strcmp(profile, "http://jabber.org/protocol/si/profile/file-transfer")) return; @@ -1618,7 +1612,7 @@ if(!(x = xmlnode_get_child_with_namespace(feature, "x", "jabber:x:data"))) return; - if(!(from = xmlnode_get_attrib(packet, "from"))) + if(!from) return; /* if they've already sent us this file transfer with the same damn id @@ -1659,7 +1653,7 @@ jsx->js = js; jsx->stream_id = g_strdup(stream_id); - jsx->iq_id = g_strdup(xmlnode_get_attrib(packet, "id")); + jsx->iq_id = g_strdup(id); xfer = purple_xfer_new(js->gc->account, PURPLE_XFER_RECEIVE, from); g_return_if_fail(xfer != NULL); @@ -1683,6 +1677,8 @@ void jabber_si_init(void) { + jabber_iq_register_handler("si", "http://jabber.org/protocol/si", jabber_si_parse); + jabber_ibb_register_open_handler(jabber_si_xfer_ibb_open_cb); } diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/si.h --- a/libpurple/protocols/jabber/si.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/si.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,18 +19,20 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef _PURPLE_JABBER_SI_H_ -#define _PURPLE_JABBER_SI_H_ +#ifndef PURPLE_JABBER_SI_H_ +#define PURPLE_JABBER_SI_H_ #include "ft.h" #include "jabber.h" -void jabber_bytestreams_parse(JabberStream *js, xmlnode *packet); -void jabber_si_parse(JabberStream *js, xmlnode *packet); +void jabber_bytestreams_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, xmlnode *query); +void jabber_si_parse(JabberStream *js, const char *from, JabberIqType type, + const char *id, xmlnode *si); PurpleXfer *jabber_si_new_xfer(PurpleConnection *gc, const char *who); void jabber_si_xfer_send(PurpleConnection *gc, const char *who, const char *file); void jabber_si_init(void); void jabber_si_uninit(void); -#endif /* _PURPLE_JABBER_SI_H_ */ +#endif /* PURPLE_JABBER_SI_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/usermood.h --- a/libpurple/protocols/jabber/usermood.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/usermood.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,8 +19,8 @@ * */ -#ifndef _PURPLE_JABBER_USERMOOD_H_ -#define _PURPLE_JABBER_USERMOOD_H_ +#ifndef PURPLE_JABBER_USERMOOD_H_ +#define PURPLE_JABBER_USERMOOD_H_ #include "jabber.h" @@ -34,4 +34,4 @@ const char *mood, /* must be one of the valid strings defined in the XEP */ const char *text /* might be NULL */); -#endif /* _PURPLE_JABBER_USERMOOD_H_ */ +#endif /* PURPLE_JABBER_USERMOOD_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/usernick.h --- a/libpurple/protocols/jabber/usernick.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/usernick.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,8 +19,8 @@ * */ -#ifndef _PURPLE_JABBER_USERNICK_H_ -#define _PURPLE_JABBER_USERNICK_H_ +#ifndef PURPLE_JABBER_USERNICK_H_ +#define PURPLE_JABBER_USERNICK_H_ #include "jabber.h" @@ -29,4 +29,4 @@ void jabber_nick_init(void); void jabber_nick_init_action(GList **m); -#endif /* _PURPLE_JABBER_USERNICK_H_ */ +#endif /* PURPLE_JABBER_USERNICK_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/usertune.h --- a/libpurple/protocols/jabber/usertune.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/usertune.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,8 +19,8 @@ * */ -#ifndef _PURPLE_JABBER_USERTUNE_H_ -#define _PURPLE_JABBER_USERTUNE_H_ +#ifndef PURPLE_JABBER_USERTUNE_H_ +#define PURPLE_JABBER_USERTUNE_H_ #include "jabber.h" @@ -40,4 +40,4 @@ void jabber_tune_set(PurpleConnection *gc, const PurpleJabberTuneInfo *tuneinfo); -#endif /* _PURPLE_JABBER_USERTUNE_H_ */ +#endif /* PURPLE_JABBER_USERTUNE_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/protocols/jabber/xdata.h --- a/libpurple/protocols/jabber/xdata.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/protocols/jabber/xdata.h Tue Apr 07 05:10:52 2009 +0000 @@ -19,8 +19,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifndef _PURPLE_JABBER_XDATA_H_ -#define _PURPLE_JABBER_XDATA_H_ +#ifndef PURPLE_JABBER_XDATA_H_ +#define PURPLE_JABBER_XDATA_H_ #include "jabber.h" #include "xmlnode.h" @@ -35,4 +35,4 @@ void *jabber_x_data_request(JabberStream *js, xmlnode *packet, jabber_x_data_cb cb, gpointer user_data); void *jabber_x_data_request_with_actions(JabberStream *js, xmlnode *packet, GList *actions, int defaultaction, jabber_x_data_action_cb cb, gpointer user_data); -#endif /* _PURPLE_JABBER_XDATA_H_ */ +#endif /* PURPLE_JABBER_XDATA_H_ */ diff -r 12089d993a0c -r 7fba18b43da3 libpurple/server.c --- a/libpurple/server.c Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/server.c Tue Apr 07 05:10:52 2009 +0000 @@ -587,6 +587,11 @@ account = purple_connection_get_account(gc); + /* + * XXX: Should we be setting this here, or relying on prpls to set it? + */ + flags |= PURPLE_MESSAGE_RECV; + if (PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc))->set_permit_deny == NULL) { /* protocol does not support privacy, handle it ourselves */ if (!purple_privacy_check(account, who)) { @@ -630,11 +635,6 @@ if (conv == NULL) conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, gc->account); - /* - * XXX: Should we be setting this here, or relying on prpls to set it? - */ - flags |= PURPLE_MESSAGE_RECV; - if (conv == NULL) conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name); @@ -939,6 +939,14 @@ if (!conv) return; + /* Did I send the message? */ + if (purple_strequal(purple_conv_chat_get_nick(chat), who)) { + flags |= PURPLE_MESSAGE_SEND; + flags &= ~PURPLE_MESSAGE_RECV; /* Just in case some prpl sets it! */ + } else { + flags |= PURPLE_MESSAGE_RECV; + } + /* * Make copies of the message and the sender in case plugins want * to free these strings and replace them with a modifed version. diff -r 12089d993a0c -r 7fba18b43da3 libpurple/util.h --- a/libpurple/util.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/util.h Tue Apr 07 05:10:52 2009 +0000 @@ -31,23 +31,26 @@ #include +typedef struct _PurpleUtilFetchUrlData PurpleUtilFetchUrlData; +typedef struct _PurpleMenuAction PurpleMenuAction; +typedef struct _PurpleKeyValuePair PurpleKeyValuePair; + #include "account.h" #include "xmlnode.h" #include "notify.h" + #ifdef __cplusplus extern "C" { #endif -typedef struct _PurpleUtilFetchUrlData PurpleUtilFetchUrlData; - -typedef struct _PurpleMenuAction +struct _PurpleMenuAction { char *label; PurpleCallback callback; gpointer data; GList *children; -} PurpleMenuAction; +}; typedef char *(*PurpleInfoFieldFormatCallback)(const char *field, size_t len); @@ -57,12 +60,12 @@ * This is used by, among other things, purple_gtk_combo* functions to pass in a * list of key-value pairs so it can display a user-friendly value. */ -typedef struct _PurpleKeyValuePair +struct _PurpleKeyValuePair { gchar *key; void *value; -} PurpleKeyValuePair; +}; /** * Creates a new PurpleMenuAction. diff -r 12089d993a0c -r 7fba18b43da3 libpurple/xmlnode.h --- a/libpurple/xmlnode.h Sat Apr 04 10:33:33 2009 +0000 +++ b/libpurple/xmlnode.h Tue Apr 07 05:10:52 2009 +0000 @@ -273,6 +273,8 @@ * @param child The child node. * * @return The parent or NULL. + * + * @since 2.6.0 */ xmlnode *xmlnode_get_parent(const xmlnode *child); diff -r 12089d993a0c -r 7fba18b43da3 pidgin/gtkimhtml.c --- a/pidgin/gtkimhtml.c Sat Apr 04 10:33:33 2009 +0000 +++ b/pidgin/gtkimhtml.c Tue Apr 07 05:10:52 2009 +0000 @@ -3320,7 +3320,8 @@ pos++; } else if ((pos == 0 || wpos == 0 || isspace(*(c - 1))) && (len_protocol = gtk_imhtml_is_protocol(c)) > 0 && - c[len_protocol] && !isspace(c[len_protocol])) { + c[len_protocol] && !isspace(c[len_protocol]) && + (c[len_protocol] != '<' || !gtk_imhtml_is_tag(c + 1, NULL, NULL, NULL))) { br = FALSE; if (wpos > 0) { gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); diff -r 12089d993a0c -r 7fba18b43da3 pidgin/gtkmedia.c --- a/pidgin/gtkmedia.c Sat Apr 04 10:33:33 2009 +0000 +++ b/pidgin/gtkmedia.c Tue Apr 07 05:10:52 2009 +0000 @@ -495,25 +495,6 @@ gtk_widget_show(GTK_WIDGET(gtkmedia)); } -static gboolean -plug_delete_event_cb(GtkWidget *widget, gpointer data) -{ - return TRUE; -} - -static gboolean -plug_removed_cb(GtkWidget *widget, gpointer data) -{ - return TRUE; -} - -static void -socket_realize_cb(GtkWidget *widget, gpointer data) -{ - gtk_socket_add_id(GTK_SOCKET(widget), - gtk_plug_get_id(GTK_PLUG(data))); -} - static void pidgin_media_accept_cb(PurpleMedia *media, int index) { @@ -619,27 +600,12 @@ PidginMediaRealizeData *data; GtkWidget *aspect; GtkWidget *remote_video; - GtkWidget *plug; - GtkWidget *socket; GdkColor color = {0, 0, 0, 0}; aspect = gtk_aspect_frame_new(NULL, 0.5, 0.5, 4.0/3.0, FALSE); gtk_frame_set_shadow_type(GTK_FRAME(aspect), GTK_SHADOW_IN); gtk_box_pack_start(GTK_BOX(recv_widget), aspect, TRUE, TRUE, 0); - plug = gtk_plug_new(0); - g_signal_connect(G_OBJECT(plug), "delete-event", - G_CALLBACK(plug_delete_event_cb), plug); - gtk_widget_show(plug); - - socket = gtk_socket_new(); - g_signal_connect(G_OBJECT(socket), "realize", - G_CALLBACK(socket_realize_cb), plug); - g_signal_connect(G_OBJECT(socket), "plug-removed", - G_CALLBACK(plug_removed_cb), NULL); - gtk_container_add(GTK_CONTAINER(aspect), socket); - gtk_widget_show(socket); - data = g_new0(PidginMediaRealizeData, 1); data->gtkmedia = gtkmedia; data->session_id = g_strdup(sid); @@ -649,7 +615,7 @@ gtk_widget_modify_bg(remote_video, GTK_STATE_NORMAL, &color); g_signal_connect(G_OBJECT(remote_video), "realize", G_CALLBACK(realize_cb), data); - gtk_container_add(GTK_CONTAINER(plug), remote_video); + gtk_container_add(GTK_CONTAINER(aspect), remote_video); gtk_widget_set_size_request (GTK_WIDGET(remote_video), 320, 240); gtk_widget_show(remote_video); gtk_widget_show(aspect); @@ -660,27 +626,12 @@ PidginMediaRealizeData *data; GtkWidget *aspect; GtkWidget *local_video; - GtkWidget *plug; - GtkWidget *socket; GdkColor color = {0, 0, 0, 0}; aspect = gtk_aspect_frame_new(NULL, 0.5, 0.5, 4.0/3.0, FALSE); gtk_frame_set_shadow_type(GTK_FRAME(aspect), GTK_SHADOW_IN); gtk_box_pack_start(GTK_BOX(send_widget), aspect, TRUE, TRUE, 0); - plug = gtk_plug_new(0); - g_signal_connect(G_OBJECT(plug), "delete-event", - G_CALLBACK(plug_delete_event_cb), plug); - gtk_widget_show(plug); - - socket = gtk_socket_new(); - g_signal_connect(G_OBJECT(socket), "realize", - G_CALLBACK(socket_realize_cb), plug); - g_signal_connect(G_OBJECT(socket), "plug-removed", - G_CALLBACK(plug_removed_cb), NULL); - gtk_container_add(GTK_CONTAINER(aspect), socket); - gtk_widget_show(socket); - data = g_new0(PidginMediaRealizeData, 1); data->gtkmedia = gtkmedia; data->session_id = g_strdup(sid); @@ -690,7 +641,7 @@ gtk_widget_modify_bg(local_video, GTK_STATE_NORMAL, &color); g_signal_connect(G_OBJECT(local_video), "realize", G_CALLBACK(realize_cb), data); - gtk_container_add(GTK_CONTAINER(plug), local_video); + gtk_container_add(GTK_CONTAINER(aspect), local_video); gtk_widget_set_size_request (GTK_WIDGET(local_video), 160, 120); gtk_widget_show(local_video); diff -r 12089d993a0c -r 7fba18b43da3 pidgin/gtkprefs.h --- a/pidgin/gtkprefs.h Sat Apr 04 10:33:33 2009 +0000 +++ b/pidgin/gtkprefs.h Tue Apr 07 05:10:52 2009 +0000 @@ -92,6 +92,8 @@ * @return An hbox containing both the label and the entry. Can be used to set * the widgets to sensitive or insensitive based on the value of a * checkbox. + * + * @since 2.6.0 */ GtkWidget *pidgin_prefs_labeled_password(GtkWidget *page, const gchar *title, const char *key, GtkSizeGroup *sg); diff -r 12089d993a0c -r 7fba18b43da3 po/POTFILES.in --- a/po/POTFILES.in Sat Apr 04 10:33:33 2009 +0000 +++ b/po/POTFILES.in Tue Apr 07 05:10:52 2009 +0000 @@ -37,6 +37,7 @@ finch/plugins/gnthistory.c finch/plugins/grouping.c finch/plugins/lastlog.c +finch/plugins/gnttinyurl.c libpurple/account.c libpurple/blist.c libpurple/certificate.c @@ -88,7 +89,6 @@ libpurple/protocols/jabber/buddy.c libpurple/protocols/jabber/chat.c libpurple/protocols/jabber/jabber.c -libpurple/protocols/jabber/jingle.c libpurple/protocols/jabber/libxmpp.c libpurple/protocols/jabber/message.c libpurple/protocols/jabber/parser.c