# HG changeset patch # User Marcus Lundblad # Date 1238259570 0 # Node ID ea0494a3a2994809aaf1afa03fa74a090136e937 # Parent 9407348dc714b388d892e45943612b4d62379b5a# Parent c422c7b1bde7cbf4f7cdaca62e4cf8aad866f0ae propagate from branch 'im.pidgin.pidgin' (head 81bb2e1582a2222b36e57c29ccb573dac27f2a44) to branch 'im.pidgin.cpw.attention_ui' (head 6d0c340ea0021535d623146846cc275b0b6aa5ea) diff -r 9407348dc714 -r ea0494a3a299 COPYRIGHT --- a/COPYRIGHT Mon Mar 16 21:45:24 2009 +0000 +++ b/COPYRIGHT Sat Mar 28 16:59:30 2009 +0000 @@ -8,6 +8,7 @@ Dave Ahlswede Manuel Amador Matt Amato +Josef Andrysek Geoffrey Antos Daniel Atallah Paul Aurich diff -r 9407348dc714 -r ea0494a3a299 ChangeLog --- a/ChangeLog Mon Mar 16 21:45:24 2009 +0000 +++ b/ChangeLog Sat Mar 28 16:59:30 2009 +0000 @@ -4,10 +4,15 @@ General: * Theme support in libpurple thanks to Justin Rodriguez's summer of code project. With some minor additions and clean ups from Paul Aurich. + * It should no longer be possible to end up with duplicates of buddies + in a group on the buddy list. + * Removed the unmaintained and unneeded toc protocol plugin. + * Fixed NTLM authentication on big-endian systems. XMPP: - * Add support for in-band bytestreams (XEP-0047). - * Add support for attention (XEP-0224). + * 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). Pidgin: * Added -f command line option to tell Pidgin to ignore NetworkManager @@ -21,6 +26,8 @@ * Created a unified Buddy Pounce notification window for all pounces where "Pop up a notification" is selected, which avoids having a new dialog box every time a pounce is triggered. (Jorge Villaseñor) + * The New Account dialog is now broken into three tabs. Proxy + configuration has been moved from the Advanced tab to the new tab. version 2.5.5 (03/01/2009): libpurple: diff -r 9407348dc714 -r ea0494a3a299 ChangeLog.API --- a/ChangeLog.API Mon Mar 16 21:45:24 2009 +0000 +++ b/ChangeLog.API Sat Mar 28 16:59:30 2009 +0000 @@ -30,10 +30,10 @@ Changed: * xmlnode_remove_attrib now removes all attributes with the - same name. Previously, it would remove the first one found, - which was completely non-deterministic. If you want to remove - the attribute with no namespace, then use NULL with - xmlnode_remove_with_namespace. + same name. Previously, it would remove the first one found, + which was completely non-deterministic. If you want to remove + the attribute with no namespace, then use NULL with + xmlnode_remove_with_namespace. Deprecated: * purple_buddy_get_local_alias diff -r 9407348dc714 -r ea0494a3a299 configure.ac --- a/configure.ac Mon Mar 16 21:45:24 2009 +0000 +++ b/configure.ac Sat Mar 28 16:59:30 2009 +0000 @@ -1048,7 +1048,6 @@ silc) static_silc=yes ;; silc10) static_silc=yes ;; simple) static_simple=yes ;; - toc) static_toc=yes ;; yahoo) static_yahoo=yes ;; zephyr) static_zephyr=yes ;; *) echo "Invalid static protocol $i!!" ; exit ;; @@ -1066,7 +1065,6 @@ AM_CONDITIONAL(STATIC_SAMETIME, test "x$static_sametime" = "xyes" -a "x$have_meanwhile" = "xyes") AM_CONDITIONAL(STATIC_SILC, test "x$static_silc" = "xyes" -a "x$have_silc" = "xyes") AM_CONDITIONAL(STATIC_SIMPLE, test "x$static_simple" = "xyes") -AM_CONDITIONAL(STATIC_TOC, test "x$static_toc" = "xyes") AM_CONDITIONAL(STATIC_YAHOO, test "x$static_yahoo" = "xyes") AM_CONDITIONAL(STATIC_ZEPHYR, test "x$static_zephyr" = "xyes") AC_SUBST(STATIC_LINK_LIBS) @@ -1112,7 +1110,6 @@ silc) dynamic_silc=yes ;; silc10) dynamic_silc=yes ;; simple) dynamic_simple=yes ;; - toc) dynamic_toc=yes ;; yahoo) dynamic_yahoo=yes ;; zephyr) dynamic_zephyr=yes ;; *) echo "Invalid dynamic protocol $i!!" ; exit ;; @@ -2450,7 +2447,6 @@ libpurple/protocols/silc/Makefile libpurple/protocols/silc10/Makefile libpurple/protocols/simple/Makefile - libpurple/protocols/toc/Makefile libpurple/protocols/yahoo/Makefile libpurple/protocols/zephyr/Makefile libpurple/tests/Makefile diff -r 9407348dc714 -r ea0494a3a299 doc/account-signals.dox --- a/doc/account-signals.dox Mon Mar 16 21:45:24 2009 +0000 +++ b/doc/account-signals.dox Sat Mar 28 16:59:30 2009 +0000 @@ -109,7 +109,7 @@ @signaldef account-authorization-requested @signalproto -void (*account_authorization_requested)(PurpleAccount *account, const char *user); +int (*account_authorization_requested)(PurpleAccount *account, const char *user); @endsignalproto @signaldesc Emitted when a user requests authorization. diff -r 9407348dc714 -r ea0494a3a299 finch/gntblist.c --- a/finch/gntblist.c Mon Mar 16 21:45:24 2009 +0000 +++ b/finch/gntblist.c Sat Mar 28 16:59:30 2009 +0000 @@ -643,10 +643,14 @@ purple_blist_add_group(grp, NULL); } - /* XXX: Ask if there's already the same buddy in the same group (#4553) */ - - buddy = purple_buddy_new(account, username, alias); - purple_blist_add_buddy(buddy, NULL, grp, NULL); + /* XXX: Ask to merge if there's already a buddy with the same alias in the same group (#4553) */ + + if ((buddy = purple_find_buddy_in_group(account, username, grp)) == NULL) + { + buddy = purple_buddy_new(account, username, alias); + purple_blist_add_buddy(buddy, NULL, grp, NULL); + } + purple_account_add_buddy(account, buddy); } diff -r 9407348dc714 -r ea0494a3a299 finch/gntlog.c --- a/finch/gntlog.c Mon Mar 16 21:45:24 2009 +0000 +++ b/finch/gntlog.c Sat Mar 28 16:59:30 2009 +0000 @@ -66,7 +66,7 @@ g_str_hash(purple_account_get_username(viewer->account)); } - return (guint)viewer; + return g_direct_hash(viewer); } static gboolean log_viewer_equal(gconstpointer y, gconstpointer z) diff -r 9407348dc714 -r ea0494a3a299 finch/gntplugin.c --- a/finch/gntplugin.c Mon Mar 16 21:45:24 2009 +0000 +++ b/finch/gntplugin.c Sat Mar 28 16:59:30 2009 +0000 @@ -484,10 +484,10 @@ char *value = NULL; switch(type) { case PURPLE_PREF_BOOLEAN: - value = g_strdup_printf("%d", (int)list->next->data); + value = g_strdup_printf("%d", GPOINTER_TO_INT(list->next->data)); break; case PURPLE_PREF_INT: - value = g_strdup_printf("%d", (int)list->next->data); + value = g_strdup_printf("%d", GPOINTER_TO_INT(list->next->data)); break; case PURPLE_PREF_STRING: value = g_strdup(list->next->data); diff -r 9407348dc714 -r ea0494a3a299 finch/gntroomlist.c --- a/finch/gntroomlist.c Mon Mar 16 21:45:24 2009 +0000 +++ b/finch/gntroomlist.c Sat Mar 28 16:59:30 2009 +0000 @@ -190,7 +190,7 @@ label = g_strdup(iter->data ? "True" : "False"); break; case PURPLE_ROOMLIST_FIELD_INT: - label = g_strdup_printf("%d", (int)iter->data); + label = g_strdup_printf("%d", GPOINTER_TO_INT(iter->data)); break; case PURPLE_ROOMLIST_FIELD_STRING: label = g_strdup(iter->data); diff -r 9407348dc714 -r ea0494a3a299 libpurple/blist.h --- a/libpurple/blist.h Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/blist.h Sat Mar 28 16:59:30 2009 +0000 @@ -595,7 +595,7 @@ * @param contact The optional contact to place the buddy in. * @param group The group to add the new buddy to. * @param node The insertion point. Pass in NULL to add the node as - * the last child in the given group. + * the first child in the given group. */ void purple_blist_add_buddy(PurpleBuddy *buddy, PurpleContact *contact, PurpleGroup *group, PurpleBlistNode *node); diff -r 9407348dc714 -r ea0494a3a299 libpurple/circbuffer.c --- a/libpurple/circbuffer.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/circbuffer.c Sat Mar 28 16:59:30 2009 +0000 @@ -68,7 +68,8 @@ /* If the fill pointer is wrapped to before the remove * pointer, we need to shift the data */ - if (in_offset < out_offset) { + if (in_offset < out_offset + || (in_offset == out_offset && buf->bufused > 0)) { int shift_n = MIN(buf->buflen - start_buflen, in_offset); memcpy(buf->buffer + start_buflen, buf->buffer, diff -r 9407348dc714 -r ea0494a3a299 libpurple/desktopitem.c --- a/libpurple/desktopitem.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/desktopitem.c Sat Mar 28 16:59:30 2009 +0000 @@ -823,7 +823,11 @@ } } -/* fallback to find something suitable for C locale */ +/** + * Fallback to find something suitable for C locale. + * + * @return A newly allocated string which should be g_freed by the caller. + */ static char * try_english_key (PurpleDesktopItem *item, const char *key) { diff -r 9407348dc714 -r ea0494a3a299 libpurple/dnssrv.c --- a/libpurple/dnssrv.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/dnssrv.c Sat Mar 28 16:59:30 2009 +0000 @@ -175,9 +175,11 @@ end: size = g_list_length(ret); + /* TODO: Check return value */ write(out, &size, sizeof(int)); while (ret != NULL) { + /* TODO: Check return value */ write(out, ret->data, sizeof(PurpleSrvResponse)); g_free(ret->data); ret = g_list_remove(ret, ret->data); diff -r 9407348dc714 -r ea0494a3a299 libpurple/ntlm.c --- a/libpurple/ntlm.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/ntlm.c Sat Mar 28 16:59:30 2009 +0000 @@ -41,12 +41,12 @@ guint32 type; /* 0x00000001 */ guint32 flags; /* 0x0000b203 */ - short dom_len1; /* domain string length */ - short dom_len2; /* domain string length */ + guint16 dom_len1; /* domain string length */ + guint16 dom_len2; /* domain string length */ guint32 dom_off; /* domain string offset */ - short host_len1; /* host string length */ - short host_len2; /* host string length */ + guint16 host_len1; /* host string length */ + guint16 host_len2; /* host string length */ guint32 host_off; /* host string offset (always 0x00000020) */ #if 0 @@ -59,47 +59,47 @@ guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/ guint32 type; /* 0x00000002 */ - short msg_len1; /* target name length */ - short msg_len2; /* target name length */ - guint32 msg_off; /* target name offset (always 0x00000048) */ + guint32 zero; + guint16 msg_len1; /* target name length */ + guint16 msg_len2; /* target name length */ guint32 flags; /* 0x00008201 */ guint8 nonce[8]; /* nonce */ - guint8 context[8]; + guint8 context[8]; }; struct type3_message { guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/ guint32 type; /* 0x00000003 */ - short lm_resp_len1; /* LanManager response length (always 0x18)*/ - short lm_resp_len2; /* LanManager response length (always 0x18)*/ + guint16 lm_resp_len1; /* LanManager response length (always 0x18)*/ + guint16 lm_resp_len2; /* LanManager response length (always 0x18)*/ guint32 lm_resp_off; /* LanManager response offset */ - short nt_resp_len1; /* NT response length (always 0x18) */ - short nt_resp_len2; /* NT response length (always 0x18) */ + guint16 nt_resp_len1; /* NT response length (always 0x18) */ + guint16 nt_resp_len2; /* NT response length (always 0x18) */ guint32 nt_resp_off; /* NT response offset */ - short dom_len1; /* domain string length */ - short dom_len2; /* domain string length */ + guint16 dom_len1; /* domain string length */ + guint16 dom_len2; /* domain string length */ guint32 dom_off; /* domain string offset (always 0x00000040) */ - short user_len1; /* username string length */ - short user_len2; /* username string length */ + guint16 user_len1; /* username string length */ + guint16 user_len2; /* username string length */ guint32 user_off; /* username string offset */ - short host_len1; /* host string length */ - short host_len2; /* host string length */ + guint16 host_len1; /* host string length */ + guint16 host_len2; /* host string length */ guint32 host_off; /* host string offset */ - short sess_len1; - short sess_len2; + guint16 sess_len1; + guint16 sess_len2; guint32 sess_off; /* message length */ guint32 flags; /* 0x00008201 */ /* guint32 flags2; */ /* unknown, used in windows messenger */ - /* guint32 flags3; */ + /* guint32 flags3; */ #if 0 guint8 dom[*]; /* domain string (unicode UTF-16LE) */ @@ -110,7 +110,6 @@ #endif }; -/* TODO: Will this work on both little-endian and big-endian machines? */ gchar * purple_ntlm_gen_type1(const gchar *hostname, const gchar *domain) { @@ -132,12 +131,12 @@ tmsg->protocol[5] = 'S'; tmsg->protocol[6] = 'P'; tmsg->protocol[7] = '\0'; - tmsg->type = 0x00000001; - tmsg->flags = 0x0000b203; - tmsg->dom_len1 = tmsg->dom_len2 = domainlen; - tmsg->dom_off = sizeof(struct type1_message) + hostnamelen; - tmsg->host_len1 = tmsg->host_len2 = hostnamelen; - tmsg->host_off = sizeof(struct type1_message); + tmsg->type = GUINT32_TO_LE(0x00000001); + tmsg->flags = GUINT32_TO_LE(0x0000b203); + tmsg->dom_len1 = tmsg->dom_len2 = GUINT16_TO_LE(domainlen); + tmsg->dom_off = GUINT32_TO_LE(sizeof(struct type1_message) + hostnamelen); + tmsg->host_len1 = tmsg->host_len2 = GUINT16_TO_LE(hostnamelen); + tmsg->host_off = GUINT32_TO_LE(sizeof(struct type1_message)); memcpy(msg + tmsg->host_off, hostname, hostnamelen); memcpy(msg + tmsg->dom_off, domain, domainlen); @@ -157,7 +156,7 @@ tmsg = (struct type2_message*)purple_base64_decode(type2, &retlen); memcpy(nonce, tmsg->nonce, 8); if (flags != NULL) - *flags = tmsg->flags; + *flags = GUINT16_FROM_LE(tmsg->flags); g_free(tmsg); return nonce; @@ -268,27 +267,27 @@ tmsg->protocol[4] = 'S'; tmsg->protocol[5] = 'S'; tmsg->protocol[6] = 'P'; - tmsg->type = 0x00000003; - tmsg->lm_resp_len1 = tmsg->lm_resp_len2 = 0x18; - tmsg->lm_resp_off = sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen; - tmsg->nt_resp_len1 = tmsg->nt_resp_len2 = 0x18; - tmsg->nt_resp_off = sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen + 0x18; + tmsg->type = GUINT32_TO_LE(0x00000003); + tmsg->lm_resp_len1 = tmsg->lm_resp_len2 = GUINT16_TO_LE(0x18); + tmsg->lm_resp_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen); + tmsg->nt_resp_len1 = tmsg->nt_resp_len2 = GUINT16_TO_LE(0x18); + tmsg->nt_resp_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen + 0x18); - tmsg->dom_len1 = tmsg->dom_len2 = domainlen; - tmsg->dom_off = sizeof(struct type3_message); + tmsg->dom_len1 = tmsg->dom_len2 = GUINT16_TO_LE(domainlen); + tmsg->dom_off = GUINT32_TO_LE(sizeof(struct type3_message)); - tmsg->user_len1 = tmsg->user_len2 = usernamelen; - tmsg->user_off = sizeof(struct type3_message) + domainlen; + tmsg->user_len1 = tmsg->user_len2 = GUINT16_TO_LE(usernamelen); + tmsg->user_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen); - tmsg->host_len1 = tmsg->host_len2 = hostnamelen; - tmsg->host_off = sizeof(struct type3_message) + domainlen + usernamelen; + tmsg->host_len1 = tmsg->host_len2 = GUINT16_TO_LE(hostnamelen); + tmsg->host_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen); if(flags) { - tmsg->sess_off = sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen + 0x18 + 0x18; - tmsg->sess_len1 = tmsg->sess_len2 = 0x0010; + tmsg->sess_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen + 0x18 + 0x18); + tmsg->sess_len1 = tmsg->sess_len2 = GUINT16_TO_LE(0x0010); } - tmsg->flags = 0x00008201; + tmsg->flags = GUINT32_TO_LE(0x00008201); tmp = (char *)tmsg + sizeof(struct type3_message); @@ -361,7 +360,7 @@ /* LCS Stuff */ if (flags) { - tmsg->flags = 0x409082d4; + tmsg->flags = GUINT32_TO_LE(0x409082d4); gensesskey(sesskey, NULL); memcpy(tmp, sesskey, 0x10); } diff -r 9407348dc714 -r ea0494a3a299 libpurple/plugins/mono/loader/debug-glue.c --- a/libpurple/plugins/mono/loader/debug-glue.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/plugins/mono/loader/debug-glue.c Sat Mar 28 16:59:30 2009 +0000 @@ -9,7 +9,7 @@ ccat = mono_string_to_utf8(cat); cstr = mono_string_to_utf8(str); - purple_debug(type, ccat, cstr); + purple_debug(type, ccat, "%s", cstr); g_free(ccat); g_free(cstr); diff -r 9407348dc714 -r ea0494a3a299 libpurple/plugins/mono/loader/mono.c --- a/libpurple/plugins/mono/loader/mono.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/plugins/mono/loader/mono.c Sat Mar 28 16:59:30 2009 +0000 @@ -39,18 +39,18 @@ if (!assm) { return FALSE; - } + } purple_debug(PURPLE_DEBUG_INFO, "mono", "Probing plugin\n"); if (ml_is_api_dll(mono_assembly_get_image(assm))) { - purple_debug(PURPLE_DEBUG_INFO, "mono", "Found our PurpleAPI.dll\n"); + purple_debug_info("mono", "Found our PurpleAPI.dll\n"); + mono_assembly_close(assm); return FALSE; } - info = g_new0(PurplePluginInfo, 1); mplug = g_new0(PurpleMonoPlugin, 1); - + mplug->signal_data = NULL; mplug->assm = assm; @@ -58,12 +58,16 @@ mplug->klass = ml_find_plugin_class(mono_assembly_get_image(mplug->assm)); if (!mplug->klass) { purple_debug(PURPLE_DEBUG_ERROR, "mono", "no plugin class in \'%s\'\n", file); + mono_assembly_close(assm); + g_free(mplug); return FALSE; } mplug->obj = mono_object_new(ml_get_domain(), mplug->klass); if (!mplug->obj) { purple_debug(PURPLE_DEBUG_ERROR, "mono", "obj not valid\n"); + mono_assembly_close(assm); + g_free(mplug); return FALSE; } @@ -85,14 +89,17 @@ if (!(found_load && found_unload && found_destroy)) { purple_debug(PURPLE_DEBUG_ERROR, "mono", "did not find the required methods\n"); + mono_assembly_close(assm); + g_free(mplug); return FALSE; } - + plugin_info = ml_get_info_prop(mplug->obj); /* now that the methods are filled out we can populate the info struct with all the needed info */ + info = g_new0(PurplePluginInfo, 1); info->id = ml_get_prop_string(plugin_info, "Id"); info->name = ml_get_prop_string(plugin_info, "Name"); info->version = ml_get_prop_string(plugin_info, "Version"); @@ -109,7 +116,7 @@ /* this plugin depends on us; duh */ info->dependencies = g_list_append(info->dependencies, MONO_PLUGIN_ID); mplug->plugin = plugin; - + plugin->info = info; info->extra_info = mplug; @@ -238,7 +245,7 @@ static void init_plugin(PurplePlugin *plugin) { ml_init(); - + loader_info.exts = g_list_append(loader_info.exts, "dll"); } diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/Makefile.am --- a/libpurple/protocols/Makefile.am Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/Makefile.am Sat Mar 28 16:59:30 2009 +0000 @@ -1,5 +1,5 @@ EXTRA_DIST = Makefile.mingw -DIST_SUBDIRS = bonjour gg irc jabber msn msnp9 myspace novell null oscar qq sametime silc silc10 toc simple yahoo zephyr +DIST_SUBDIRS = bonjour gg irc jabber msn msnp9 myspace novell null oscar qq sametime silc silc10 simple yahoo zephyr SUBDIRS = $(DYNAMIC_PRPLS) $(STATIC_PRPLS) diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/bonjour/mdns_win32.c --- a/libpurple/protocols/bonjour/mdns_win32.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/bonjour/mdns_win32.c Sat Mar 28 16:59:30 2009 +0000 @@ -169,14 +169,17 @@ gboolean delete_buddy = FALSE; PurpleBuddy *pb = NULL; + if ((pb = purple_find_buddy(args->account, args->res_data->name))) { + if (pb->proto_data != args->bb) { + purple_debug_error("bonjour", "Found purple buddy for %s not matching bonjour buddy record.", + args->res_data->name); + goto cleanup; + } /* Make sure that the BonjourBuddy associated with this request is still around */ - if (g_slist_find(pending_buddies, args->bb) == NULL) + } else if (g_slist_find(pending_buddies, args->bb) == NULL) { + purple_debug_error("bonjour", "host resolution - complete, but buddy no longer pending.\n"); goto cleanup; - - if ((pb = purple_find_buddy(args->account, args->bb->name))) - if (pb->proto_data != args->bb) - purple_debug_error("bonjour", "Found purple buddy for %s not matching bonjour buddy record. " - "This is going to be ugly!.\n", args->bb->name); + } if (!hosts || !hosts->data) { purple_debug_error("bonjour", "host resolution - callback error.\n"); diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/irc/irc.c --- a/libpurple/protocols/irc/irc.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/irc/irc.c Sat Mar 28 16:59:30 2009 +0000 @@ -565,7 +565,7 @@ struct irc_conn *irc = (struct irc_conn *)gc->proto_data; struct irc_buddy *ib = g_new0(struct irc_buddy, 1); ib->name = g_strdup(purple_buddy_get_name(buddy)); - g_hash_table_insert(irc->buddies, ib->name, ib); + g_hash_table_replace(irc->buddies, ib->name, ib); /* if the timer isn't set, this is during signon, so we don't want to flood * ourself off with ISON's, so we don't, but after that we want to know when diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/jabber/buddy.c --- a/libpurple/protocols/jabber/buddy.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/jabber/buddy.c Sat Mar 28 16:59:30 2009 +0000 @@ -301,36 +301,32 @@ struct vcard_template { char *label; /* label text pointer */ - char *text; /* entry text pointer */ - int visible; /* should entry field be "visible?" */ - int editable; /* should entry field be editable? */ char *tag; /* tag text */ char *ptag; /* parent tag "path" text */ - char *url; /* vCard display format if URL */ } const vcard_template_data[] = { - {N_("Full Name"), NULL, TRUE, TRUE, "FN", NULL, NULL}, - {N_("Family Name"), NULL, TRUE, TRUE, "FAMILY", "N", NULL}, - {N_("Given Name"), NULL, TRUE, TRUE, "GIVEN", "N", NULL}, - {N_("Nickname"), NULL, TRUE, TRUE, "NICKNAME", NULL, NULL}, - {N_("URL"), NULL, TRUE, TRUE, "URL", NULL, "%s"}, - {N_("Street Address"), NULL, TRUE, TRUE, "STREET", "ADR", NULL}, - {N_("Extended Address"), NULL, TRUE, TRUE, "EXTADD", "ADR", NULL}, - {N_("Locality"), NULL, TRUE, TRUE, "LOCALITY", "ADR", NULL}, - {N_("Region"), NULL, TRUE, TRUE, "REGION", "ADR", NULL}, - {N_("Postal Code"), NULL, TRUE, TRUE, "PCODE", "ADR", NULL}, - {N_("Country"), NULL, TRUE, TRUE, "CTRY", "ADR", NULL}, - {N_("Telephone"), NULL, TRUE, TRUE, "NUMBER", "TEL", NULL}, - {N_("Email"), NULL, TRUE, TRUE, "USERID", "EMAIL", "%s"}, - {N_("Organization Name"), NULL, TRUE, TRUE, "ORGNAME", "ORG", NULL}, - {N_("Organization Unit"), NULL, TRUE, TRUE, "ORGUNIT", "ORG", NULL}, - {N_("Title"), NULL, TRUE, TRUE, "TITLE", NULL, NULL}, - {N_("Role"), NULL, TRUE, TRUE, "ROLE", NULL, NULL}, - {N_("Birthday"), NULL, TRUE, TRUE, "BDAY", NULL, NULL}, - {N_("Description"), NULL, TRUE, TRUE, "DESC", NULL, NULL}, - {"", NULL, TRUE, TRUE, "N", NULL, NULL}, - {"", NULL, TRUE, TRUE, "ADR", NULL, NULL}, - {"", NULL, TRUE, TRUE, "ORG", NULL, NULL}, - {NULL, NULL, 0, 0, NULL, NULL, NULL} + {N_("Full Name"), "FN", NULL}, + {N_("Family Name"), "FAMILY", "N"}, + {N_("Given Name"), "GIVEN", "N"}, + {N_("Nickname"), "NICKNAME", NULL}, + {N_("URL"), "URL", NULL}, + {N_("Street Address"), "STREET", "ADR"}, + {N_("Extended Address"), "EXTADD", "ADR"}, + {N_("Locality"), "LOCALITY", "ADR"}, + {N_("Region"), "REGION", "ADR"}, + {N_("Postal Code"), "PCODE", "ADR"}, + {N_("Country"), "CTRY", "ADR"}, + {N_("Telephone"), "NUMBER", "TEL"}, + {N_("Email"), "USERID", "EMAIL"}, + {N_("Organization Name"), "ORGNAME", "ORG"}, + {N_("Organization Unit"), "ORGUNIT", "ORG"}, + {N_("Title"), "TITLE", NULL}, + {N_("Role"), "ROLE", NULL}, + {N_("Birthday"), "BDAY", NULL}, + {N_("Description"), "DESC", NULL}, + {"", "N", NULL}, + {"", "ADR", NULL}, + {"", "ORG", NULL}, + {NULL, NULL, NULL} }; /* diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/jabber/si.c --- a/libpurple/protocols/jabber/si.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/jabber/si.c Sat Mar 28 16:59:30 2009 +0000 @@ -1662,23 +1662,22 @@ jsx->iq_id = g_strdup(xmlnode_get_attrib(packet, "id")); xfer = purple_xfer_new(js->gc->account, PURPLE_XFER_RECEIVE, from); - if (xfer) - { - xfer->data = jsx; + g_return_if_fail(xfer != NULL); + + xfer->data = jsx; - purple_xfer_set_filename(xfer, filename); - if(filesize > 0) - purple_xfer_set_size(xfer, filesize); + purple_xfer_set_filename(xfer, filename); + if(filesize > 0) + purple_xfer_set_size(xfer, filesize); - purple_xfer_set_init_fnc(xfer, jabber_si_xfer_init); - purple_xfer_set_request_denied_fnc(xfer, jabber_si_xfer_request_denied); - purple_xfer_set_cancel_recv_fnc(xfer, jabber_si_xfer_cancel_recv); - purple_xfer_set_end_fnc(xfer, jabber_si_xfer_end); + purple_xfer_set_init_fnc(xfer, jabber_si_xfer_init); + purple_xfer_set_request_denied_fnc(xfer, jabber_si_xfer_request_denied); + purple_xfer_set_cancel_recv_fnc(xfer, jabber_si_xfer_cancel_recv); + purple_xfer_set_end_fnc(xfer, jabber_si_xfer_end); - js->file_transfers = g_list_append(js->file_transfers, xfer); + js->file_transfers = g_list_append(js->file_transfers, xfer); - purple_xfer_request(xfer); - } + purple_xfer_request(xfer); } void diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/jabber/xdata.c --- a/libpurple/protocols/jabber/xdata.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/jabber/xdata.c Sat Mar 28 16:59:30 2009 +0000 @@ -153,11 +153,12 @@ } g_free(data); - if (hasActions) { + if (hasActions) cb(js, result, actionhandle, user_data); - g_free(actionhandle); - } else + else ((jabber_x_data_cb)cb)(js, result, user_data); + + g_free(actionhandle); } static void jabber_x_data_cancel_cb(struct jabber_x_data_data *data, PurpleRequestFields *fields) { diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/msn/cmdproc.c --- a/libpurple/protocols/msn/cmdproc.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/msn/cmdproc.c Sat Mar 28 16:59:30 2009 +0000 @@ -117,8 +117,10 @@ servconn = cmdproc->servconn; - if (!servconn->connected) + if (!servconn->connected) { + /* TODO: Need to free trans */ return; + } msn_history_add(cmdproc->history, trans); diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/msn/contact.c --- a/libpurple/protocols/msn/contact.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/msn/contact.c Sat Mar 28 16:59:30 2009 +0000 @@ -1482,8 +1482,6 @@ const gchar *passport, const MsnListId list) { gchar *body = NULL, *member = NULL; - const char *type = "PassportMember"; - gchar *federate = NULL; MsnSoapPartnerScenario partner_scenario; MsnUser *user; @@ -1501,23 +1499,28 @@ msn_callback_state_set_who(state, passport); user = msn_userlist_find_user(session->userlist, passport); - if (user && user->networkid != MSN_NETWORK_PASSPORT) { - type = "EmailMember"; - federate = g_strdup_printf(MSN_MEMBER_FEDERATED_ANNOTATION_XML, - user->networkid); - } if (list == MSN_LIST_PL) { partner_scenario = MSN_PS_CONTACT_API; - member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML, - type, user->membership_id[MSN_LIST_PL], - federate ? federate : ""); + if (user && user->networkid != MSN_NETWORK_PASSPORT) + member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML, + "EmailMember", "Email", + user->membership_id[MSN_LIST_PL]); + else + member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML, + "PassportMember", "Passport", + user->membership_id[MSN_LIST_PL]); } else { /* list == MSN_LIST_AL || list == MSN_LIST_BL */ partner_scenario = MSN_PS_BLOCK_UNBLOCK; - member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, - type, passport, - federate ? federate : ""); + if (user && user->networkid != MSN_NETWORK_PASSPORT) + member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, + "EmailMember", "Email", + "Email", passport, "Email"); + else + member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, + "PassportMember", "Passport", + "PassportName", passport, "PassportName"); } body = g_strdup_printf(MSN_CONTACT_DELETE_FROM_LIST_TEMPLATE, @@ -1530,7 +1533,6 @@ state->cb = msn_del_contact_from_list_read_cb; msn_contact_request(state); - g_free(federate); g_free(member); g_free(body); } @@ -1578,8 +1580,6 @@ const gchar *passport, const MsnListId list) { gchar *body = NULL, *member = NULL; - const char *type = "PassportMember"; - gchar *federate = NULL; MsnSoapPartnerScenario partner_scenario; MsnUser *user; @@ -1596,15 +1596,16 @@ msn_callback_state_set_who(state, passport); user = msn_userlist_find_user(session->userlist, passport); - if (user && user->networkid != MSN_NETWORK_PASSPORT) { - type = "EmailMember"; - federate = g_strdup_printf(MSN_MEMBER_FEDERATED_ANNOTATION_XML, - user->networkid); - } partner_scenario = (list == MSN_LIST_RL) ? MSN_PS_CONTACT_API : MSN_PS_BLOCK_UNBLOCK; - member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, - type, state->who, federate ? federate : ""); + if (user && user->networkid != MSN_NETWORK_PASSPORT) + member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, + "EmailMember", "Email", + "Email", state->who, "Email"); + else + member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, + "PassportMember", "Passport", + "PassportName", state->who, "PassportName"); body = g_strdup_printf(MSN_CONTACT_ADD_TO_LIST_TEMPLATE, MsnSoapPartnerScenarioText[partner_scenario], @@ -1616,7 +1617,6 @@ state->cb = msn_add_contact_to_list_read_cb; msn_contact_request(state); - g_free(federate); g_free(member); g_free(body); } diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/msn/contact.h --- a/libpurple/protocols/msn/contact.h Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/msn/contact.h Sat Mar 28 16:59:30 2009 +0000 @@ -397,28 +397,18 @@ #define MSN_MEMBER_PASSPORT_XML \ ""\ - "Passport"\ + "%s"\ "Accepted"\ - "%s"\ - "%s"\ + "<%s>%s"\ "" #define MSN_MEMBER_MEMBERSHIPID_XML \ ""\ - "Passport"\ + "%s"\ "%u"\ "Accepted"\ - "%s"\ "" -#define MSN_MEMBER_FEDERATED_ANNOTATION_XML \ - ""\ - ""\ - "MSN.IM.BuddyType"\ - "%02d:"\ - ""\ - "" - /* first delete contact from allow list */ #define MSN_CONTACT_DELETE_FROM_LIST_TEMPLATE ""\ diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/msn/notification.c --- a/libpurple/protocols/msn/notification.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/msn/notification.c Sat Mar 28 16:59:30 2009 +0000 @@ -630,7 +630,7 @@ } else { purple_debug_error("msn", - "Got FQY update for unkwown user %s on network %d.\n", + "Got FQY update for unknown user %s on network %d.\n", passport, network); } } @@ -686,6 +686,9 @@ if (++adl_count % 150 == 0) { payload = xmlnode_to_str(adl_node, &payload_len); + /* ADL's are returned all-together */ + session->adl_fqy++; + msn_notification_post_adl(session->notification->cmdproc, payload, payload_len); @@ -697,6 +700,9 @@ xmlnode_set_attrib(adl_node, "l", "1"); } } else { + /* FQY's are returned one-at-a-time */ + session->adl_fqy++; + msn_add_contact_xml(session, fqy_node, user->passport, 0, user->networkid); @@ -718,6 +724,9 @@ if (adl_count == 0 || adl_count % 150 != 0) { payload = xmlnode_to_str(adl_node, &payload_len); + /* ADL's are returned all-together */ + session->adl_fqy++; + msn_notification_post_adl(session->notification->cmdproc, payload, payload_len); g_free(payload); @@ -804,7 +813,8 @@ if (!strcmp(cmd->params[1], "OK")) { /* ADL ack */ - msn_session_finish_login(session); + if (--session->adl_fqy == 0) + msn_session_finish_login(session); } else { cmdproc->last_cmd->payload_cb = adl_cmd_parse; cmd->payload_len = atoi(cmd->params[1]); @@ -1609,7 +1619,7 @@ if ( (root = xmlnode_from_str(cmd->payload, cmd->payload_len)) == NULL) { - purple_debug_error("msn", "Unable to parse GCF payload into a XML tree"); + purple_debug_error("msn", "Unable to parse GCF payload into a XML tree\n"); return; } @@ -1682,7 +1692,7 @@ user = msn_userlist_find_user(session->userlist, passport); if (user == NULL) { char *str = g_strndup(payload, len); - purple_debug_info("msn", "unknown user %s, payload is %s", + purple_debug_info("msn", "unknown user %s, payload is %s\n", passport, str); g_free(str); return; diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/msn/oim.c --- a/libpurple/protocols/msn/oim.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/msn/oim.c Sat Mar 28 16:59:30 2009 +0000 @@ -174,7 +174,7 @@ gchar *faultcode_str = xmlnode_get_data(faultcode); if (faultcode_str && g_str_equal(faultcode_str, "q0:BadContextToken")) { - purple_debug_warning("msn", "OIM Request Error, Updating token now."); + purple_debug_warning("msn", "OIM Request Error, Updating token now.\n"); msn_nexus_update_token(data->oim->session->nexus, data->send ? MSN_AUTH_LIVE_SECURE : MSN_AUTH_MESSENGER_WEB, (GSourceFunc)msn_oim_request_helper, data); @@ -183,7 +183,7 @@ } else if (faultcode_str && g_str_equal(faultcode_str, "q0:AuthenticationFailed")) { if (xmlnode_get_child(fault, "detail/RequiredAuthPolicy") != NULL) { - purple_debug_warning("msn", "OIM Request Error, Updating token now."); + purple_debug_warning("msn", "OIM Request Error, Updating token now.\n"); msn_nexus_update_token(data->oim->session->nexus, data->send ? MSN_AUTH_LIVE_SECURE : MSN_AUTH_MESSENGER_WEB, (GSourceFunc)msn_oim_request_helper, data); diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/msn/session.h --- a/libpurple/protocols/msn/session.h Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/msn/session.h Sat Mar 28 16:59:30 2009 +0000 @@ -90,6 +90,7 @@ gboolean connected; gboolean logged_in; /**< A temporal flag to ignore local buddy list adds. */ + int adl_fqy; /**< A count of ADL/FQY so status is only changed once. */ gboolean destroying; /**< A flag that states if the session is being destroyed. */ gboolean http_method; diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/msn/state.c --- a/libpurple/protocols/msn/state.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/msn/state.c Sat Mar 28 16:59:30 2009 +0000 @@ -169,7 +169,7 @@ } currentmediaNode = xmlnode_get_child(payloadNode, "CurrentMedia"); if (currentmediaNode == NULL) { - purple_debug_info("msn", "No CurrentMedia Node"); + purple_debug_info("msn", "No CurrentMedia Node\n"); xmlnode_free(payloadNode); return NULL; } @@ -195,7 +195,7 @@ } psmNode = xmlnode_get_child(payloadNode, "PSM"); if (psmNode == NULL) { - purple_debug_info("msn", "No PSM status Node"); + purple_debug_info("msn", "No PSM status Node\n"); xmlnode_free(payloadNode); return NULL; } diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/msn/switchboard.c --- a/libpurple/protocols/msn/switchboard.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/msn/switchboard.c Sat Mar 28 16:59:30 2009 +0000 @@ -590,7 +590,7 @@ payload = msn_message_gen_payload(msg, &payload_len); #ifdef MSN_DEBUG_SB - purple_debug_info("msn", "SB length:{%" G_GSIZE_FORMAT "}", payload_len); + purple_debug_info("msn", "SB length:{%" G_GSIZE_FORMAT "}\n", payload_len); msn_message_show_readable(msg, "SB SEND", FALSE); #endif diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/msn/userlist.c --- a/libpurple/protocols/msn/userlist.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/msn/userlist.c Sat Mar 28 16:59:30 2009 +0000 @@ -858,7 +858,7 @@ } if ( (user = msn_userlist_find_user(userlist, who)) == NULL) { - purple_debug_error("msn", "User %s not found!", who); + purple_debug_error("msn", "User %s not found!\n", who); return FALSE; } @@ -887,7 +887,7 @@ } if ( (user = msn_userlist_find_user(userlist, who)) == NULL) { - purple_debug_error("msn", "User %s not found!", who); + purple_debug_error("msn", "User %s not found!\n", who); return FALSE; } diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/myspace/myspace.c --- a/libpurple/protocols/myspace/myspace.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/myspace/myspace.c Sat Mar 28 16:59:30 2009 +0000 @@ -388,7 +388,7 @@ g_return_val_if_fail(buddy != NULL, NULL); - user = msim_get_user_from_buddy(buddy); + user = msim_get_user_from_buddy(buddy, TRUE); account = purple_buddy_get_account(buddy); gc = purple_account_get_connection(account); @@ -436,7 +436,7 @@ g_return_if_fail(buddy != NULL); g_return_if_fail(user_info != NULL); - user = msim_get_user_from_buddy(buddy); + user = msim_get_user_from_buddy(buddy, TRUE); if (PURPLE_BUDDY_IS_ONLINE(buddy)) { MsimSession *session; @@ -1053,7 +1053,7 @@ g_free(display_name); /* 3. Update buddy information */ - user = msim_get_user_from_buddy(buddy); + user = msim_get_user_from_buddy(buddy, TRUE); user->id = uid; /* Keep track of the user ID across sessions */ @@ -1377,7 +1377,7 @@ buddy = purple_buddy_new(session->account, username, NULL); purple_blist_add_buddy(buddy, NULL, NULL, NULL); - user = msim_get_user_from_buddy(buddy); + user = msim_get_user_from_buddy(buddy, TRUE); user->id = msim_msg_get_integer(msg, "f"); /* Keep track of the user ID across sessions */ @@ -2641,6 +2641,9 @@ name = purple_buddy_get_name(buddy); gname = group ? purple_group_get_name(group) : NULL; + if (msim_get_user_from_buddy(buddy, FALSE) != NULL) + return; + purple_debug_info("msim", "msim_add_buddy: want to add %s to %s\n", name, gname ? gname : "(no group)"); diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/myspace/user.c --- a/libpurple/protocols/myspace/user.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/myspace/user.c Sat Mar 28 16:59:30 2009 +0000 @@ -41,10 +41,10 @@ } /** - * Get the MsimUser from a PurpleBuddy, creating it if needed. + * Get the MsimUser from a PurpleBuddy, optionally creating it if needed. */ MsimUser * -msim_get_user_from_buddy(PurpleBuddy *buddy) +msim_get_user_from_buddy(PurpleBuddy *buddy, gboolean create) { MsimUser *user; @@ -52,7 +52,8 @@ return NULL; } - if (!(user = purple_buddy_get_protocol_data(buddy))) { + user = purple_buddy_get_protocol_data(buddy); + if (create && !user) { /* No MsimUser for this buddy; make one. */ user = g_new0(MsimUser, 1); @@ -94,7 +95,7 @@ return NULL; } - user = msim_get_user_from_buddy(buddy); + user = msim_get_user_from_buddy(buddy, TRUE); return user; } diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/myspace/user.h --- a/libpurple/protocols/myspace/user.h Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/myspace/user.h Sat Mar 28 16:59:30 2009 +0000 @@ -46,7 +46,7 @@ * initiated from a user lookup. */ typedef void (*MSIM_USER_LOOKUP_CB)(MsimSession *session, const MsimMessage *userinfo, gpointer data); -MsimUser *msim_get_user_from_buddy(PurpleBuddy *buddy); +MsimUser *msim_get_user_from_buddy(PurpleBuddy *buddy, gboolean create); void msim_user_free(MsimUser *user); MsimUser *msim_find_user(MsimSession *session, const gchar *username); void msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full); diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/novell/nmmessage.c --- a/libpurple/protocols/novell/nmmessage.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/novell/nmmessage.c Sat Mar 28 16:59:30 2009 +0000 @@ -24,7 +24,6 @@ { NMConference *conference; char *text; - gpointer data; guint32 ref_count; }; diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/novell/novell.c --- a/libpurple/protocols/novell/novell.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/novell/novell.c Sat Mar 28 16:59:30 2009 +0000 @@ -2547,7 +2547,7 @@ if (gc == NULL || buddy == NULL || group == NULL) return; - user = (NMUser *) gc->proto_data; + user = (NMUser *) purple_connection_get_protocol_data(gc); if (user == NULL) return; @@ -2557,6 +2557,10 @@ if (!user->clist_synched) return; + /* Don't re-add a buddy that is already on our contact list */ + if (nm_find_user_record(user, purple_buddy_get_name(buddy)) != NULL) + return; + contact = nm_create_contact(); nm_contact_set_dn(contact, purple_buddy_get_name(buddy)); diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/oscar/oscar.c --- a/libpurple/protocols/oscar/oscar.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/oscar/oscar.c Sat Mar 28 16:59:30 2009 +0000 @@ -870,11 +870,11 @@ if (itmsurl) { tmp = g_strdup_printf("%s", itmsurl, message); - g_free(itmsurl); g_free(message); message = tmp; } } + g_free(itmsurl); if (is_away && message) { tmp = purple_str_sub_away_formatters(message, purple_account_get_username(account)); @@ -4917,17 +4917,24 @@ return; } - if ((od->ssi.received_data) && !(aim_ssi_itemlist_finditem(od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY))) { - purple_debug_info("oscar", - "ssi: adding buddy %s to group %s\n", bname, gname); - aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, 0); - - /* Mobile users should always be online */ - if (bname[0] == '+') { - purple_prpl_got_user_status(account, - bname, OSCAR_STATUS_ID_AVAILABLE, NULL); - purple_prpl_got_user_status(account, - bname, OSCAR_STATUS_ID_MOBILE, NULL); + if (od->ssi.received_data) { + if (!aim_ssi_itemlist_finditem(od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY)) { + purple_debug_info("oscar", + "ssi: adding buddy %s to group %s\n", bname, gname); + aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, 0); + + /* Mobile users should always be online */ + if (bname[0] == '+') { + purple_prpl_got_user_status(account, bname, + OSCAR_STATUS_ID_AVAILABLE, NULL); + purple_prpl_got_user_status(account, bname, + OSCAR_STATUS_ID_MOBILE, NULL); + } + } else if (aim_ssi_waitingforauth(od->ssi.local, + aim_ssi_itemlist_findparentname(od->ssi.local, bname), + bname)) { + /* Not authorized -- Re-request authorization */ + purple_auth_sendrequest(gc, bname); } } diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/qq/buddy_list.c --- a/libpurple/protocols/qq/buddy_list.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/qq/buddy_list.c Sat Mar 28 16:59:30 2009 +0000 @@ -47,7 +47,6 @@ #define QQ_GET_ONLINE_BUDDY_03 0x03 /* unknown function */ typedef struct _qq_buddy_online { - qq_buddy_status bs; guint16 unknown1; guint8 ext_flag; guint8 comm_flag; diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/silc/buddy.c --- a/libpurple/protocols/silc/buddy.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/silc/buddy.c Sat Mar 28 16:59:30 2009 +0000 @@ -1397,7 +1397,12 @@ void silcpurple_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { - silcpurple_add_buddy_i(gc, buddy, FALSE); + /* Don't add if the buddy is already on the list. + * + * SILC doesn't have groups, so we also don't need to do anything + * for a move. */ + if (purple_buddy_get_protocol_data(buddy) == NULL) + silcpurple_add_buddy_i(gc, buddy, FALSE); } void silcpurple_send_buddylist(PurpleConnection *gc) diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/silc10/buddy.c --- a/libpurple/protocols/silc10/buddy.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/silc10/buddy.c Sat Mar 28 16:59:30 2009 +0000 @@ -1390,7 +1390,12 @@ void silcpurple_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { - silcpurple_add_buddy_i(gc, buddy, FALSE); + /* Don't add if the buddy is already on the list. + * + * SILC doesn't have groups, so we don't need to do anything + * for a move. */ + if (purple_buddy_get_protocol_data(buddy) == NULL) + silcpurple_add_buddy_i(gc, buddy, FALSE); } void silcpurple_send_buddylist(PurpleConnection *gc) diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/toc/Makefile.am --- a/libpurple/protocols/toc/Makefile.am Mon Mar 16 21:45:24 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -EXTRA_DIST = \ - PROTOCOL \ - Makefile.mingw - -pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION) - -TOCSOURCES = toc.c - -AM_CFLAGS = $(st) - -libtoc_la_LDFLAGS = -module -avoid-version - -if STATIC_TOC - -st = -DPURPLE_STATIC_PRPL -noinst_LTLIBRARIES = libtoc.la -libtoc_la_SOURCES = $(TOCSOURCES) -libtoc_la_CFLAGS = $(AM_CFLAGS) - -else - -st = -pkg_LTLIBRARIES = libtoc.la -libtoc_la_SOURCES = $(TOCSOURCES) - -endif - -AM_CPPFLAGS = \ - -I$(top_srcdir)/libpurple \ - -I$(top_builddir)/libpurple \ - $(GLIB_CFLAGS) \ - $(DEBUG_CFLAGS) diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/toc/Makefile.mingw --- a/libpurple/protocols/toc/Makefile.mingw Mon Mar 16 21:45:24 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -# -# Makefile.mingw -# -# Description: Makefile for win32 (mingw) version of libtoc -# - -PIDGIN_TREE_TOP := ../../.. -include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak - -TARGET = libtoc -TYPE = PLUGIN - -# Static or Plugin... -ifeq ($(TYPE),STATIC) - DEFINES += -DSTATIC - DLL_INSTALL_DIR = $(PURPLE_INSTALL_DIR) -else -ifeq ($(TYPE),PLUGIN) - DLL_INSTALL_DIR = $(PURPLE_INSTALL_PLUGINS_DIR) -endif -endif - -## -## INCLUDE PATHS -## -INCLUDE_PATHS += -I$(TOC_ROOT) \ - -I$(GTK_TOP)/include \ - -I$(GTK_TOP)/include/glib-2.0 \ - -I$(GTK_TOP)/lib/glib-2.0/include \ - -I$(LIBPIDGIN_TREE_TOP) \ - -I$(LIBPIDGIN_TREE_TOP)/win32 \ - -I$(PIDGIN_TREE_TOP) - -LIB_PATHS += -L$(GTK_TOP)/lib \ - -L$(LIBPIDGIN_TREE_TOP) - -## -## SOURCES, OBJECTS -## -C_SRC = toc.c - -OBJECTS = $(C_SRC:%.c=%.o) - -## -## LIBRARIES -## -LIBS = \ - -lglib-2.0 \ - -lws2_32 \ - -lintl \ - -lpurple - -include $(PIDGIN_COMMON_RULES) - -## -## TARGET DEFINITIONS -## - -.PHONY: all install clean - -all: $(TARGET).dll - -install: all $(DLL_INSTALL_DIR) - cp $(TARGET).dll $(DLL_INSTALL_DIR) - -$(OBJECTS): $(PURPLE_CONFIG_H) - -$(TARGET).dll: $(PURPLE_DLL).a $(OBJECTS) - $(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -o $(TARGET).dll - -## -## CLEAN RULES -## -clean: - rm -f $(OBJECTS) - rm -f $(TARGET).dll - -include $(PIDGIN_COMMON_TARGETS) diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/toc/PROTOCOL --- a/libpurple/protocols/toc/PROTOCOL Mon Mar 16 21:45:24 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,499 +0,0 @@ -# Copyright (c) 1998-9 America Online, Inc. All Rights Reserved. -# -# 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. - -# Note from Jim Duchek, former libpurple maintainer -- this may not be -# the latest version of this document, I provide it as a service. -# Download a copy of TiK (http://www.aim.aol.com/tik/) for the latest -# version of this doc. - -# Note from Eric Warmenhoven, random guy -- this appears to be the last -# published version of the protocol, and AOL has stopped hosting the TiK -# program. TiK is still being maintained and is hosted on sourceforge.net; -# this appears to be the same version of the protocol they're using. - -Version: TOC1.0 - -This document describes the protocol between TOC and TOC clients. -The protocol is built on TCP. Framing is done by SFLAP, -described at the bottom of this document. Inside each -SFLAP frame is a TOC command. - -The TOC protocol is ASCII based, and special attention -must be placed argument separation. The separator and -the rules of separation are different for messages inbound -to TOC and outbound to the client. The rules of separation -are described in sections below. - -The TOC server is built mainly to service the TIC and TiK clients. Since -the TIC client is a Java applet, and downloadable, TOC will NOT support -multiple TOC protocol versions at the same time. Therefore, TiK -users will be forced to upgrade if the protocol version changes. -TOC sends down the protocol version it expects the client -to speak and understand. Note, the protocol version is a string. - -Important Notes -=============== -* TOC will drop the connection if a command exceeds the maximum - length, which is currently 2048 bytes. So the client needs to - spend special attention to im, chat, and config message lengths. - There is an 8k length maximum from TOC to the client. - -* No commands should be sent to TOC (besides toc_signon) before - a SIGN_ON is received. If you do send a command before SIGN_ON - the command will be ignored, and in some case the connection - will be dropped. - -* Initial permit/deny items should be sent after receiving SIGN_ON - but before sending toc_init_done, otherwise the user will flash - on peoples buddylist who the user has denied. You will probably - want to send the toc_add_buddies at this time also. - -* After TOC sends the PAUSE message to a client, all messages sent - to TOC will be ignored, and in some cases the connection will - be dropped. Another SIGN_ON message will be sent to the client - when it is online again. The buddy list and permit/deny items must - be sent again, followed by the toc_init_done. In most cases the - SIGN_ON message will be sent between 1-2 seconds after the - PAUSE message. Therefore a client could choose to ignore the - PAUSE message and hope nothing bad happens. - - -Client -> TOC -============== -The commands and the arguments are usually separated by whitespaces. Arguments -with whitespace characters should be enclosed in quotes. Dollar signs, -curly brackets, square brackets, parentheses, quotes, and backslashes -must all be backslashed whether in quotes or not. It is usually -a good idea just to use quotes no matter what. All user names from clients -to TOC should be normalized (spaces removed and lowercased), and therefore -are the one exception to the always use quotes rule. - -When sending commands to the server you will not get a response -back confirming that the command format was correct or not! However -in some cases if the command format was incorrect the connection -will be dropped. - - -RoastingString="Tic/Toc" - -toc_signon - - The password needs to be roasted with the Roasting String if - coming over a FLAP connection, CP connections don't use - roasted passwords. The language specified will be used - when generating web pages, such as the get info pages. - Currently the only supported language is "english". - If the language sent isn't found, the default "english" - language will be used. The version string will be used - for the client identity, and must be less then 50 - characters. - - Passwords are roasted when sent to the host. This is done so they - aren't sent in "clear text" over the wire, although they are still - trivial to decode. Roasting is performed by first xoring each byte - in the password with the equivalent modulo byte in the roasting - string. The result is then converted to ascii hex, and prepended - with "0x". So for example the password "password" roasts to - "0x2408105c23001130" - -toc_init_done - Tells TOC that we are ready to go online. TOC clients should first - send TOC the buddy list and any permit/deny lists. However toc_init_done - must be called within 30 seconds after toc_signon, or the connection - will be dropped. Remember, it can't be called until after the SIGN_ON - message is received. Calling this before or multiple times after a - SIGN_ON will cause the connection to be dropped. - -toc_send_im [auto] - Send a message to a remote user. Remember to quote and encode the - message. If the optional string "auto" is the last argument, then the - auto response flag will be turned on for the im. - -toc_add_buddy [ [ [...]]] - Add buddies to your buddy list. This does not change your - saved config. - -toc_remove_buddy [ [ [...]]] - Remove buddies from your buddy list. This does not change your - saved config. - -toc_set_config - Set the config information for this user. The config information - is line oriented with the first character being the item type, - followed by a space, with the rest of the line being the item - value. Only letters, numbers, and spaces should be used. Remember - you will have to enclose the entire config in quotes. - - Item Types: - g - Buddy Group (All Buddies until the next g or the end of config - are in this group.) - b - A Buddy - p - Person on permit list - d - Person on deny list - m - Permit/Deny Mode. Possible values are - 1 - Permit All - 2 - Deny All - 3 - Permit Some - 4 - Deny Some - -toc_evil - Evil/Warn someone else. The 2nd argument is either the string - "norm" for a normal warning, or "anon" for an anonymous - warning. You can only evil people who have recently sent you - ims. The higher someones evil level, the slower they can - send message. - -toc_add_permit [ [ [...]]] - ADD the following people to your permit mode. If - you are in deny mode it will switch you to permit - mode first. With no arguments and in deny mode - this will switch you to permit none. If already - in permit mode, no arguments does nothing - and your permit list remains the same. - -toc_add_deny [ [ [...]]] - ADD the following people to your deny mode. If - you are in permit mode it will switch you to - deny mode first. With no arguments and in permit - mode, this will switch you to deny none. If - already in deny mode, no arguments does nothing - and your deny list remains unchanged. - -toc_chat_join - Join a chat room in the given exchange. Exchange is - an integer that represents a group of chat rooms. - Different exchanges have different properties. For - example some exchanges might have room replication (ie - a room never fills up, there are just multiple - instances.) and some exchanges might have navigational - information, and some exchanges might have ... Currently - exchange should always be 4, however this may - change in the future. You will either - receive an ERROR if the room couldn't be joined - or a CHAT_JOIN message. The Chat Room Name - is case insensitive and consecutive spaces - are removed. - -toc_chat_send - Send a message in a chat room using the chat room - id from CHAT_JOIN. Since reflection is always on in - TOC, you do not need to add the message to your chat UI, - since you will get a CHAT_IN with the message. - Remember to quote and encode the message. - -toc_chat_whisper - Send a message in a chat room using the chat room - id from CHAT_JOIN. This message is directed at - only one person. (Currently you DO need to add this to - your UI.) Remember to quote and encode the message. - Chat whispering is different from IMs since it is linked - to a chat room, and should usually be displayed in the chat - room UI. - -toc_chat_evil - Evil/Warn someone else inside a chat room. The 3rd argument is either - the string "norm" for a normal warning, or "anon" for an anonymous - warning. Currently chat evil is not turned on in the chat complex. - -toc_chat_invite [ [ [...]]] - Once you are inside a chat room you can invite other people into - that room. Remember to quote and encode the invite message. - -toc_chat_leave - Leave the chat room. - -toc_chat_accept - Accept a CHAT_INVITE message from TOC. The server will send a - CHAT_JOIN in response. - -toc_get_info - Gets a user's info a GOTO_URL or ERROR message will be sent back to the - client. - -toc_set_info - Set the LOCATE user information. This is basic HTML. - Remember to encode the info. - -toc_set_away [] - if the away message is present, then the unavailable - status flag is set for the user. If the away message - is not present, then the unavailable status flag is - unset. The away message is basic HTML, remember to - encode the information. - -toc_get_dir - Gets a user's dir info a GOTO_URL or ERROR message will be sent back to the - client. - -toc_set_dir - Set the DIR user information. This is a colon separated fields as in: - "first name":"middle name":"last name":"maiden name":"city":"state":"country":"email":"allow web searches" - Should return a DIR_STATUS msg. Having anything in the "allow web searches" - field allows people to use web-searches to find your directory info. - Otherwise, they'd have to use the client. - -toc_dir_search - Perform a search of the Oscar Directory, using colon separated fields as in: - "first name":"middle name":"last name":"maiden name":"city":"state":"country":"email" - Returns either a GOTO_URL or ERROR msg. - -toc_set_idle - Set idle information. If is 0 then the user isn't idle at all. - If is greater then 0 then the user has already been idle - for number of seconds. The server will automatically - keep incrementing this number, so do not repeatedly call with new - idle times. - -toc_set_caps [ [ [...]]] - Set my capabilities. All capabilities that we support need to - be sent at the same time. Capabilities are represented by - UUIDs. - -toc_rvous_propose - Not Implemented Yet - -toc_rvous_accept - Accept a rendezvous proposal from the user . - is the cookie from the RVOUS_PROPOSE - message. is the UUID the proposal was - for. contains a list of tlv tags followed by - base64 encoded values. - -toc_rvous_cancel - Cancel a rendezvous proposal from the user . - is the cookie from the RVOUS_PROPOSE - message. is the UUID the proposal was - for. contains a list of tlv tags followed by - base64 encoded values. - -toc_format_nickname - Reformat a user's nickname. An ADMIN_NICK_STATUS or ERROR message will - be sent back to the client. - -toc_change_passwd - Change a user's password. An ADMIN_PASSWD_STATUS or ERROR message will - be sent back to the client. - - -TOC -> Client -============== -All user names from TOC to client are NOT normalized, and are -sent as they should be displayed. String are NOT encoded, instead -we use colons as separators. So that you can have colons inside -of messages, everything after the colon before : should -be considered part of the message (ie don't just "split" on colons, -instead split with a max number of results.) - - -SIGN_ON: - This is sent after a successful toc_signon command is sent to TOC. - If the command was unsuccessful either the FLAP connection will - be dropped or you will receive a ERROR message. - -CONFIG: - A user's config. Config can be empty in which case the host was not able to - retrieve it, or a config didn't exist for the user. See toc_set_config - above for the format. - -NICK: - Tells you your correct nickname (ie how it should be capitalized and - spacing) - -IM_IN::: - Receive an IM from some one. Everything after the third colon is - the incoming message, including other colons. - -UPDATE_BUDDY:::::: - This one command handles arrival/depart/updates. Evil Amount is - a percentage, Signon Time is UNIX epoc, idle time is in minutes, UC (User Class) - is a two/three character string. - uc[0]: - ' ' - Ignore - 'A' - On AOL - uc[1] - ' ' - Ignore - 'A' - Oscar Admin - 'U' - Oscar Unconfirmed - 'O' - Oscar Normal - uc[2] - '\0' - Ignore - ' ' - Ignore - 'U' - The user has set their unavailable flag. - - - -ERROR::Var args - * General Errors * - 901 - $1 not currently available - 902 - Warning of $1 not currently available - 903 - A message has been dropped, you are exceeding - the server speed limit - - * Admin Errors * - 911 - Error validating input - 912 - Invalid account - 913 - Error encountered while processing request - 914 - Service unavailable - - * Chat Errors * - 950 - Chat in $1 is unavailable. - - * IM & Info Errors * - 960 - You are sending message too fast to $1 - 961 - You missed an im from $1 because it was too big. - 962 - You missed an im from $1 because it was sent too fast. - - * Dir Errors * - 970 - Failure - 971 - Too many matches - 972 - Need more qualifiers - 973 - Dir service temporarily unavailable - 974 - Email lookup restricted - 975 - Keyword Ignored - 976 - No Keywords - 977 - Language not supported - 978 - Country not supported - 979 - Failure unknown $1 - - * Auth errors * - 980 - Incorrect nickname or password. - 981 - The service is temporarily unavailable. - 982 - Your warning level is currently too high to sign on. - 983 - You have been connecting and - disconnecting too frequently. Wait 10 minutes and try again. - If you continue to try, you will need to wait even longer. - 989 - An unknown signon error has occurred $1 - - -EVILED:: - The user was just eviled. - -CHAT_JOIN:: - We were able to join this chat room. The Chat Room Id is - internal to TOC. - -CHAT_IN:::: - A chat message was sent in a chat room. - -CHAT_UPDATE_BUDDY::::... - This one command handles arrival/departs from a chat room. The - very first message of this type for each chat room contains the - users already in the room. - -CHAT_INVITE:::: - We are being invited to a chat room. - -CHAT_LEFT: - Tells tic connection to chat room has been dropped - -GOTO_URL:: - Goto a URL. Window Name is the suggested internal name of the window - to use. (Java supports this.) - -DIR_STATUS:: - is always 0 for success status. - -ADMIN_NICK_STATUS:: - is always 0 for success status. - -ADMIN_PASSWD_STATUS:: - is always 0 for success status. - - -PAUSE - Tells TIC to pause so we can do migration - -RVOUS_PROPOSE:::::::: - [:tlv tag1:tlv value1[:tlv tag2:tlv value2[:...]]] - Another user has proposed that we rendezvous with them to - perform the service specified by . They want us - to connect to them, we have their rendezvous ip, their - proposer_ip, and their verified_ip. The tlv values are - base64 encoded. - -Typical Signon Process -====================== -Except for the section marked optional this is an sequential -process. Each line MUST occur before the following line. - -* Client connects to TOC -* Client sends "FLAPON\r\n\r\n" -* TOC sends Client FLAP SIGNON -* Client sends TOC FLAP SIGNON -* Client sends TOC "toc_signon" message -* if login fails TOC drops client's connection - else TOC sends client SIGN_ON reply -* if Client doesn't support version it drops the connection - -[BEGIN OPTIONAL] - * TOC sends Client CONFIG - * Client sends TOC permit/deny stuff - * Client sends TOC toc_add_buddy message -[END OPTIONAL] - -* Client sends TOC toc_init_done message - - -SFLAP Documentation -=================== -SFLAP is pretty much a FLAP connection except the DATA frame payload is a null -terminated string when traveling from client to host, it is NOT null -terminated when traveling from host to client. The FLAP Header is binary -data, and is in network byte order. The data portion is at offset 6, after the -header. The sequence number is sequential in each direction. So -packets from the server to client have one sequence number, while -the packets from the client to server have an independent -increasing number. - -FLAP Header (6 bytes) ------------ -Offset Size Type -0 1 ASTERISK (literal ASCII '*') -1 1 Frame Type -2 2 Sequence Number -4 2 Data Length - - -Valid Frame Type Values ------------------------ -1 SIGNON -2 DATA -3 ERROR (Not used by TOC) -4 SIGNOFF (Not used by TOC) -5 KEEP_ALIVE - - -TOC SIGNON FRAME TYPE ---------------------- -Sequence Number contains the initial sequence number used in each direction. -Data Length contains the payload length, with the payload described -below. The payload area is NOT null terminated. - -Host To Client: - 4 byte FLAP version (1) - -Client To Host: - 4 byte FLAP version (1) - 2 byte TLV Tag (1) - 2 byte Normalized User Name Length - N byte Normalized User Name (NOT null terminated) - - -TOC DATA FRAME TYPE -------------------- -Sequence Number contains the next sequence number. -Data Length is the length of the payload, including the null termination -from client to host. - diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/toc/toc.c --- a/libpurple/protocols/toc/toc.c Mon Mar 16 21:45:24 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2340 +0,0 @@ -/* - * purple - * - * Copyright (C) 1998-1999, Mark Spencer - * - * 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 "account.h" -#include "accountopt.h" -#include "conversation.h" -#include "debug.h" -#include "notify.h" -#include "privacy.h" -#include "proxy.h" -#include "prpl.h" -#include "request.h" -#include "util.h" -#include "version.h" - -static PurplePlugin *my_protocol = NULL; - -#define REVISION "penguin" - -#define TYPE_SIGNON 1 -#define TYPE_DATA 2 -#define TYPE_ERROR 3 -#define TYPE_SIGNOFF 4 -#define TYPE_KEEPALIVE 5 - -#define FLAPON "FLAPON\r\n\r\n" -#define ROAST "Tic/Toc" - -#define TOC_HOST "toc.oscar.aol.com" -#define TOC_PORT 9898 -#define AUTH_HOST "login.oscar.aol.com" -#define AUTH_PORT 5190 -#define LANGUAGE "english" - -#define STATE_OFFLINE 0 -#define STATE_FLAPON 1 -#define STATE_SIGNON_REQUEST 2 -#define STATE_ONLINE 3 -#define STATE_PAUSE 4 - -#define VOICE_UID "09461341-4C7F-11D1-8222-444553540000" -#define FILE_SEND_UID "09461343-4C7F-11D1-8222-444553540000" -#define IMAGE_UID "09461345-4C7F-11D1-8222-444553540000" -#define B_ICON_UID "09461346-4C7F-11D1-8222-444553540000" -#define STOCKS_UID "09461347-4C7F-11D1-8222-444553540000" -#define FILE_GET_UID "09461348-4C7F-11D1-8222-444553540000" -#define GAMES_UID "0946134a-4C7F-11D1-8222-444553540000" - -#define UC_UNAVAILABLE 0x01 -#define UC_AOL 0x02 -#define UC_ADMIN 0x04 -#define UC_UNCONFIRMED 0x08 -#define UC_NORMAL 0x10 -#define UC_WIRELESS 0x20 - -struct ft_request { - PurpleConnection *gc; - char *user; - char UID[2048]; - char *cookie; - char *ip; - int port; - char *message; - char *filename; - int files; - int size; -}; - -struct buddy_icon { - guint32 hash; - guint32 len; - time_t time; - void *data; -}; - -struct toc_data { - int toc_fd; - char toc_ip[20]; - int seqno; - int state; -}; - -struct sflap_hdr { - unsigned char ast; - unsigned char type; - unsigned short seqno; - unsigned short len; -}; - -struct signon { - unsigned int ver; - unsigned short tag; - unsigned short namelen; - char username[80]; -}; - -/* constants to identify proto_opts */ -#define USEROPT_AUTH 0 -#define USEROPT_AUTHPORT 1 - -#define TOC_CONNECT_STEPS 3 - -static void toc_login_callback(gpointer, gint, const gchar *); -static void toc_callback(gpointer, gint, PurpleInputCondition); - -/* ok. this function used to take username/password, and return 0 on success. - * now, it takes username/password, and returns NULL on error or a new purple_connection - * on success. */ -static void toc_login(PurpleAccount *account) -{ - PurpleConnection *gc; - struct toc_data *tdt; - char buf[80]; - - gc = purple_account_get_connection(account); - gc->proto_data = tdt = g_new0(struct toc_data, 1); - gc->flags |= PURPLE_CONNECTION_HTML; - gc->flags |= PURPLE_CONNECTION_AUTO_RESP; - - g_snprintf(buf, sizeof buf, _("Looking up %s"), - purple_account_get_string(account, "server", TOC_HOST)); - purple_connection_update_progress(gc, buf, 0, TOC_CONNECT_STEPS); - - purple_debug(PURPLE_DEBUG_INFO, "toc", "Client connects to TOC\n"); - if (purple_proxy_connect(gc, account, - purple_account_get_string(account, "server", TOC_HOST), - purple_account_get_int(account, "port", TOC_PORT), - toc_login_callback, gc) != 0 || !account->gc) { - g_snprintf(buf, sizeof(buf), _("Connect to %s failed"), - purple_account_get_string(account, "server", TOC_HOST)); - purple_connection_error(gc, buf); - return; - } -} - -static void toc_login_callback(gpointer data, gint source, const gchar *error_message) -{ - PurpleConnection *gc = data; - struct toc_data *tdt; - char buf[80]; - struct sockaddr_in name; - socklen_t namelen; - - if (!PURPLE_CONNECTION_IS_VALID(gc)) { - if (source >= 0) - close(source); - return; - } - - tdt = gc->proto_data; - - if (source == -1) { - /* we didn't successfully connect. tdt->toc_fd is valid here */ - purple_connection_error(gc, _("Unable to connect.")); - return; - } - tdt->toc_fd = source; - - /* - * Copy the IP that we're connected to. We need this because "GOTO_URL"'s - * should open on the exact server we're connected to. toc.oscar.aol.com - * doesn't work because that hostname resolves to multiple IP addresses. - */ - if (getpeername(tdt->toc_fd, (struct sockaddr *)&name, &namelen) == 0) - strncpy(tdt->toc_ip, inet_ntoa(name.sin_addr), sizeof(tdt->toc_ip)); - else - strncpy(tdt->toc_ip, purple_account_get_string(gc->account, "server", TOC_HOST), sizeof(tdt->toc_ip)); - - purple_debug(PURPLE_DEBUG_INFO, "toc", - "Client sends \"FLAPON\\r\\n\\r\\n\"\n"); - if (write(tdt->toc_fd, FLAPON, strlen(FLAPON)) < 0) { - purple_connection_error(gc, _("Disconnected.")); - return; - } - tdt->state = STATE_FLAPON; - - /* i know a lot of people like to look at purple to see how TOC works. so i'll comment - * on what this does. it's really simple. when there's data ready to be read from the - * toc_fd file descriptor, toc_callback is called, with gc passed as its data arg. */ - gc->inpa = purple_input_add(tdt->toc_fd, PURPLE_INPUT_READ, toc_callback, gc); - - g_snprintf(buf, sizeof(buf), _("Signon: %s"), purple_account_get_username(gc->account)); - purple_connection_update_progress(gc, buf, 1, TOC_CONNECT_STEPS); -} - -static void toc_close(PurpleConnection *gc) -{ - if (gc->inpa > 0) - purple_input_remove(gc->inpa); - gc->inpa = 0; - close(((struct toc_data *)gc->proto_data)->toc_fd); - g_free(gc->proto_data); -} - -static void toc_build_config(PurpleAccount *account, char *s, int len, gboolean show) -{ - PurpleBlistNode *gnode, *cnode, *bnode; - PurpleGroup *g; - PurpleBuddy *b; - GSList *plist = account->permit; - GSList *dlist = account->deny; - - int pos = 0; - - if (!account->perm_deny) - account->perm_deny = 1; - - pos += g_snprintf(&s[pos], len - pos, "m %d\n", account->perm_deny); - for(gnode = purple_get_blist()->root; gnode && len > pos; gnode = gnode->next) { - g = (PurpleGroup *)gnode; - if(!PURPLE_BLIST_NODE_IS_GROUP(gnode)) - continue; - if(purple_group_on_account(g, account)) { - pos += g_snprintf(&s[pos], len - pos, "g %s\n", g->name); - for(cnode = gnode->child; cnode; cnode = cnode->next) { - if(!PURPLE_BLIST_NODE_IS_CONTACT(cnode)) - continue; - for(bnode = gnode->child; bnode && len > pos; bnode = bnode->next) { - b = (PurpleBuddy *)bnode; - if(!PURPLE_BLIST_NODE_IS_BUDDY(bnode)) - continue; - if(b->account == account) { - pos += g_snprintf(&s[pos], len - pos, "b %s%s%s\n", - b->name, - (show && b->alias) ? ":" : "", - (show && b->alias) ? b->alias : ""); - } - } - } - } - } - - while (len > pos && plist) { - pos += g_snprintf(&s[pos], len - pos, "p %s\n", (char *)plist->data); - plist = plist->next; - } - - while (len > pos && dlist) { - pos += g_snprintf(&s[pos], len - pos, "d %s\n", (char *)dlist->data); - dlist = dlist->next; - } -} - -static char * -escape_message(const char *msg) -{ - char *ret; - int i, j; - - if (!msg) - return NULL; - - /* Calculate the length after escaping */ - for (i=0, j=0; msg[i]; i++) - switch (msg[i]) { - case '$': - case '[': - case ']': - case '(': - case ')': - j++; - default: - j++; - } - - /* Allocate a string */ - ret = (char *)g_malloc((j+1) * sizeof(char)); - - /* Copy the string */ - for (i=0, j=0; msg[i]; i++) - switch (msg[i]) { - case '$': - case '[': - case ']': - case '(': - case ')': - ret[j++] = '\\'; - default: - ret[j++] = msg[i]; - } - ret[j] = '\0'; - - return ret; -} - -/* - * Duplicates the input string, replacing each \n with a
, and - * escaping a few other characters. - */ -static char * -escape_text(const char *msg) -{ - char *ret; - int i, j; - - if (!msg) - return NULL; - - /* Calculate the length after escaping */ - for (i=0, j=0; msg[i]; i++) - switch (msg[i]) { - case '\n': - j += 4; - break; - case '{': - case '}': - case '\\': - case '"': - j += 1; - default: - j += 1; - } - - /* Allocate a string */ - ret = (char *)malloc((j+1) * sizeof(char)); - - /* Copy the string */ - for (i=0, j=0; msg[i]; i++) - switch (msg[i]) { - case '\n': - ret[j++] = '<'; - ret[j++] = 'B'; - ret[j++] = 'R'; - ret[j++] = '>'; - break; - case '{': - case '}': - case '\\': - case '"': - ret[j++] = '\\'; - default: - ret[j++] = msg[i]; - } - ret[j] = '\0'; - - return ret; -} - -static int sflap_send(PurpleConnection *gc, const char *buf, int olen, int type) -{ - struct toc_data *tdt = (struct toc_data *)gc->proto_data; - int len; - int slen = 0; - int ret; - struct sflap_hdr hdr; - char *escaped, *obuf; - - if (tdt->state == STATE_PAUSE) - /* TOC has given us the PAUSE message; sending could cause a disconnect - * so we just return here like everything went through fine */ - return 0; - - if (olen < 0) { - escaped = escape_message(buf); - len = strlen(escaped); - } else { - escaped = g_memdup(buf, olen); - len = olen; - } - - /* - * One _last_ 2048 check here! This shouldn't ever - * get hit though, hopefully. If it gets hit on an IM - * It'll lose the last " and the message won't go through, - * but this'll stop a segfault. - */ - if (len > MSG_LEN) { - purple_debug(PURPLE_DEBUG_WARNING, "toc", "message too long, truncating\n"); - escaped[MSG_LEN - 1] = '\0'; - len = MSG_LEN; - } - - if (olen < 0) - purple_debug(PURPLE_DEBUG_INFO, "toc", "C: %s\n", escaped); - - hdr.ast = '*'; - hdr.type = type; - hdr.seqno = htons(tdt->seqno++ & 0xffff); - hdr.len = htons(len + (type == TYPE_SIGNON ? 0 : 1)); - - obuf = (char *)malloc((sizeof(hdr)+len+1) * sizeof(char)); - memcpy(obuf, &hdr, sizeof(hdr)); - slen += sizeof(hdr); - - memcpy(&obuf[slen], escaped, len); - slen += len; - - if (type != TYPE_SIGNON) { - obuf[slen] = '\0'; - slen += 1; - } - - ret = write(tdt->toc_fd, obuf, slen); - free(obuf); - g_free(escaped); - - return ret; -} - -static int toc_send_raw(PurpleConnection *gc, const char *buf, int len) -{ - return sflap_send(gc, buf, len, 2); -} - -static int wait_reply(PurpleConnection *gc, char *buffer, size_t buflen) -{ - struct toc_data *tdt = (struct toc_data *)gc->proto_data; - struct sflap_hdr *hdr; - int ret; - - if (read(tdt->toc_fd, buffer, sizeof(struct sflap_hdr)) < 0) { - purple_debug(PURPLE_DEBUG_ERROR, "toc", "Couldn't read flap header\n"); - return -1; - } - - hdr = (struct sflap_hdr *)buffer; - - if (buflen < ntohs(hdr->len)) { - /* fake like there's a read error */ - purple_debug(PURPLE_DEBUG_ERROR, "toc", - "buffer too small (have %" G_GSIZE_FORMAT ", need %d)\n", - buflen, ntohs(hdr->len)); - return -1; - } - - if (ntohs(hdr->len) > 0) { - int count = 0; - ret = 0; - do { - count += ret; - ret = read(tdt->toc_fd, - buffer + sizeof(struct sflap_hdr) + count, ntohs(hdr->len) - count); - } while (count + ret < ntohs(hdr->len) && ret > 0); - buffer[sizeof(struct sflap_hdr) + count + ret] = '\0'; - return ret; - } else - return 0; -} - -static unsigned char *roast_password(const char *pass) -{ - /* Trivial "encryption" */ - static unsigned char rp[256]; - static char *roast = ROAST; - int pos = 2; - int x; - strcpy(rp, "0x"); - for (x = 0; (x < 150) && pass[x]; x++) - pos += sprintf(&rp[pos], "%02x", pass[x] ^ roast[x % strlen(roast)]); - rp[pos] = '\0'; - return rp; -} - -static void toc_got_info(void *data, const char *url_text, size_t len) -{ - if (!url_text) - return; - - purple_notify_formatted(data, NULL, _("Buddy Information"), NULL, - url_text, NULL, NULL); -} - -static char *show_error_message() -{ - int no = atoi(strtok(NULL, ":")); - char *w = strtok(NULL, ":"); - static char buf[256]; - - switch(no) { - case 69: - g_snprintf(buf, sizeof(buf), _("Unable to write file %s."), w); - break; - case 169: - g_snprintf(buf, sizeof(buf), _("Unable to read file %s."), w); - break; - case 269: - g_snprintf(buf, sizeof(buf), _("Message too long, last %s bytes truncated."), w); - break; - case 901: - g_snprintf(buf, sizeof(buf), _("%s not currently logged in."), w); - break; - case 902: - g_snprintf(buf, sizeof(buf), _("Warning of %s not allowed."), w); - break; - case 903: - g_snprintf(buf, sizeof(buf), _("A message has been dropped, you are exceeding the server speed limit.")); - break; - case 950: - g_snprintf(buf, sizeof(buf), _("Chat in %s is not available."), w); - break; - case 960: - g_snprintf(buf, sizeof(buf), _("You are sending messages too fast to %s."), w); - break; - case 961: - g_snprintf(buf, sizeof(buf), _("You missed an IM from %s because it was too big."), w); - break; - case 962: - g_snprintf(buf, sizeof(buf), _("You missed an IM from %s because it was sent too fast."), w); - break; - case 970: - g_snprintf(buf, sizeof(buf), _("Failure.")); - break; - case 971: - g_snprintf(buf, sizeof(buf), _("Too many matches.")); - break; - case 972: - g_snprintf(buf, sizeof(buf), _("Need more qualifiers.")); - break; - case 973: - g_snprintf(buf, sizeof(buf), _("Dir service temporarily unavailable.")); - break; - case 974: - g_snprintf(buf, sizeof(buf), _("Email lookup restricted.")); - break; - case 975: - g_snprintf(buf, sizeof(buf), _("Keyword ignored.")); - break; - case 976: - g_snprintf(buf, sizeof(buf), _("No keywords.")); - break; - case 977: - g_snprintf(buf, sizeof(buf), _("User has no directory information.")); - /* g_snprintf(buf, sizeof(buf), _("Language not supported.")); */ - break; - case 978: - g_snprintf(buf, sizeof(buf), _("Country not supported.")); - break; - case 979: - g_snprintf(buf, sizeof(buf), _("Failure unknown: %s."), w); - break; - case 980: - g_snprintf(buf, sizeof(buf), _("Incorrect username or password.")); - break; - case 981: - g_snprintf(buf, sizeof(buf), _("The service is temporarily unavailable.")); - break; - case 982: - g_snprintf(buf, sizeof(buf), _("Your warning level is currently too high to log in.")); - break; - case 983: - g_snprintf(buf, sizeof(buf), _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer.")); - break; - g_snprintf(buf, sizeof(buf), _("An unknown signon error has occurred: %s."), w); - break; - default: - g_snprintf(buf, sizeof(buf), _("An unknown error, %d, has occurred. Info: %s"), no, w); - } - - return buf; -} - -static void -parse_toc_buddy_list(PurpleAccount *account, char *config) -{ - char *c; - char current[256]; - GList *buddies = NULL; - - if (config == NULL) - return; - - /* skip "CONFIG:" (if it exists) */ - c = strncmp(config + 6 /* sizeof(struct sflap_hdr) */ , "CONFIG:", strlen("CONFIG:")) ? - strtok(config, "\n") : - strtok(config + 6 /* sizeof(struct sflap_hdr) */ + strlen("CONFIG:"), "\n"); - do { - if (c == NULL) - break; - if (*c == 'g') { - char *utf8 = NULL; - utf8 = purple_utf8_try_convert(c + 2); - if (utf8 == NULL) { - g_strlcpy(current, _("Invalid Groupname"), sizeof(current)); - } else { - g_strlcpy(current, utf8, sizeof(current)); - g_free(utf8); - } - if (!purple_find_group(current)) { - PurpleGroup *g = purple_group_new(current); - purple_blist_add_group(g, NULL); - } - } else if (*c == 'b') { /*&& !purple_find_buddy(user, c + 2)) {*/ - char nm[80], sw[388], *a, *utf8 = NULL; - - if ((a = strchr(c + 2, ':')) != NULL) { - *a++ = '\0'; /* nul the : */ - } - - g_strlcpy(nm, c + 2, sizeof(nm)); - if (a) { - utf8 = purple_utf8_try_convert(a); - if (utf8 == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "toc blist", - "Failed to convert alias for " - "'%s' to UTF-8\n", nm); - } - } - if (utf8 == NULL) { - sw[0] = '\0'; - } else { - /* This can leave a partial sequence at the end, - * but who cares? */ - g_strlcpy(sw, utf8, sizeof(sw)); - g_free(utf8); - } - - if (!purple_find_buddy(account, nm)) { - PurpleBuddy *b = purple_buddy_new(account, nm, sw); - PurpleGroup *g = purple_find_group(current); - purple_blist_add_buddy(b, NULL, g, NULL); - buddies = g_list_append(buddies, b); - } - } else if (*c == 'p') { - purple_privacy_permit_add(account, c + 2, TRUE); - } else if (*c == 'd') { - purple_privacy_deny_add(account, c + 2, TRUE); - } else if (!strncmp("toc", c, 3)) { - sscanf(c + strlen(c) - 1, "%d", &account->perm_deny); - purple_debug(PURPLE_DEBUG_MISC, "toc blist", - "permdeny: %d\n", account->perm_deny); - if (account->perm_deny == 0) - account->perm_deny = PURPLE_PRIVACY_ALLOW_ALL; - } else if (*c == 'm') { - sscanf(c + 2, "%d", &account->perm_deny); - purple_debug(PURPLE_DEBUG_MISC, "toc blist", - "permdeny: %d\n", account->perm_deny); - if (account->perm_deny == 0) - account->perm_deny = PURPLE_PRIVACY_ALLOW_ALL; - } - } while ((c = strtok(NULL, "\n"))); - - if (account->gc) { - if (buddies != NULL) { - purple_account_add_buddies(account, buddies); - g_list_free(buddies); - } - serv_set_permit_deny(account->gc); - } - g_list_free(buddies); -} - -static void toc_callback(gpointer data, gint source, PurpleInputCondition condition) -{ - PurpleConnection *gc = (PurpleConnection *)data; - PurpleAccount *account = purple_connection_get_account(gc); - struct toc_data *tdt = (struct toc_data *)gc->proto_data; - struct sflap_hdr *hdr; - struct signon so; - char buf[8 * 1024], *c; - char snd[BUF_LEN * 2]; - const char *username = purple_account_get_username(account); - char *password; - PurpleBuddy *buddy; - - /* there's data waiting to be read, so read it. */ - if (wait_reply(gc, buf, 8 * 1024) <= 0) { - purple_connection_error(gc, _("Connection Closed")); - return; - } - - if (tdt->state == STATE_FLAPON) { - hdr = (struct sflap_hdr *)buf; - if (hdr->type != TYPE_SIGNON) - purple_debug(PURPLE_DEBUG_ERROR, "toc", "hdr->type != TYPE_SIGNON\n"); - else - purple_debug(PURPLE_DEBUG_INFO, "toc", - "TOC sends Client FLAP SIGNON\n"); - tdt->seqno = ntohs(hdr->seqno); - tdt->state = STATE_SIGNON_REQUEST; - - purple_debug(PURPLE_DEBUG_INFO, "toc", "Client sends TOC FLAP SIGNON\n"); - g_snprintf(so.username, sizeof(so.username), "%s", username); - so.ver = htonl(1); - so.tag = htons(1); - so.namelen = htons(strlen(so.username)); - if (sflap_send(gc, (char *)&so, ntohs(so.namelen) + 8, TYPE_SIGNON) < 0) { - purple_connection_error(gc, _("Disconnected.")); - return; - } - - purple_debug(PURPLE_DEBUG_INFO, "toc", - "Client sends TOC \"toc_signon\" message\n"); - /* i hate icq. */ - if (username[0] >= '0' && username[0] <= '9') - password = g_strndup(purple_connection_get_password(gc), 8); - else - password = g_strdup(purple_connection_get_password(gc)); - g_snprintf(snd, sizeof snd, "toc_signon %s %d %s %s %s \"%s\"", - AUTH_HOST, AUTH_PORT, purple_normalize(account, username), - roast_password(password), LANGUAGE, REVISION); - g_free(password); - if (sflap_send(gc, snd, -1, TYPE_DATA) < 0) { - purple_connection_error(gc, _("Disconnected.")); - return; - } - - purple_connection_update_progress(gc, _("Waiting for reply..."), 2, TOC_CONNECT_STEPS); - return; - } - - if (tdt->state == STATE_SIGNON_REQUEST) { - purple_debug(PURPLE_DEBUG_INFO, "toc", "TOC sends client SIGN_ON reply\n"); - if (g_ascii_strncasecmp(buf + sizeof(struct sflap_hdr), "SIGN_ON", strlen("SIGN_ON"))) { - purple_debug(PURPLE_DEBUG_ERROR, "toc", - "Didn't get SIGN_ON! buf was: %s\n", - buf + sizeof(struct sflap_hdr)); - if (!g_ascii_strncasecmp(buf + sizeof(struct sflap_hdr), "ERROR", 5)) { - strtok(buf + sizeof(struct sflap_hdr), ":"); - purple_connection_error(gc, show_error_message()); - } else - purple_connection_error(gc, _("Authentication failed")); - return; - } - /* we're supposed to check that it's really TOC v1 here but we know it is ;) */ - purple_debug(PURPLE_DEBUG_INFO, "toc", - "TOC version: %s\n", buf + sizeof(struct sflap_hdr) + 8); - - /* we used to check for the CONFIG here, but we'll wait until we've sent our - * version of the config and then the toc_init_done message. we'll come back to - * the callback in a better state if we get CONFIG anyway */ - - tdt->state = STATE_ONLINE; - - purple_connection_set_state(gc, PURPLE_CONNECTED); - - /* - * Add me to my buddy list so that we know the time when - * the server thinks I signed on. - */ - buddy = purple_buddy_new(account, username, NULL); - /* XXX - Pick a group to add to */ - /* purple_blist_add(buddy, NULL, g, NULL); */ - purple_account_add_buddy(gc, buddy); - - /* Client sends TOC toc_init_done message */ - purple_debug(PURPLE_DEBUG_INFO, "toc", - "Client sends TOC toc_init_done message\n"); - g_snprintf(snd, sizeof snd, "toc_init_done"); - sflap_send(gc, snd, -1, TYPE_DATA); - - /* - g_snprintf(snd, sizeof snd, "toc_set_caps %s %s %s", - FILE_SEND_UID, FILE_GET_UID, B_ICON_UID); - */ - g_snprintf(snd, sizeof snd, "toc_set_caps %s %s", FILE_SEND_UID, FILE_GET_UID); - sflap_send(gc, snd, -1, TYPE_DATA); - - return; - } - - purple_debug(PURPLE_DEBUG_INFO, "toc", "S: %s\n", - buf + sizeof(struct sflap_hdr)); - - c = strtok(buf + sizeof(struct sflap_hdr), ":"); /* Ditch the first part */ - - if (!g_ascii_strcasecmp(c, "SIGN_ON")) { - /* we should only get here after a PAUSE */ - if (tdt->state != STATE_PAUSE) - purple_debug(PURPLE_DEBUG_ERROR, "toc", - "got SIGN_ON but not PAUSE!\n"); - else { - tdt->state = STATE_ONLINE; - g_snprintf(snd, sizeof snd, "toc_signon %s %d %s %s %s \"%s\"", - AUTH_HOST, AUTH_PORT, - purple_normalize(account, purple_account_get_username(account)), - roast_password(purple_connection_get_password(gc)), - LANGUAGE, REVISION); - if (sflap_send(gc, snd, -1, TYPE_DATA) < 0) { - purple_connection_error(gc, _("Disconnected.")); - return; - } - g_snprintf(snd, sizeof snd, "toc_init_done"); - sflap_send(gc, snd, -1, TYPE_DATA); - purple_notify_info(gc, NULL, - _("TOC has come back from its pause. You may " - "now send messages again."), NULL); - } - } else if (!g_ascii_strcasecmp(c, "CONFIG")) { - c = strtok(NULL, ":"); - parse_toc_buddy_list(account, c); - } else if (!g_ascii_strcasecmp(c, "NICK")) { - /* ignore NICK so that things get imported/exported properly - c = strtok(NULL, ":"); - g_snprintf(gc->username, sizeof(gc->username), "%s", c); - */ - } else if (!g_ascii_strcasecmp(c, "IM_IN")) { - char *away, *message; - int a = 0; - - c = strtok(NULL, ":"); - away = strtok(NULL, ":"); - - message = away; - while (*message && (*message != ':')) - message++; - message++; - - a = (away && (*away == 'T')) ? PURPLE_MESSAGE_AUTO_RESP : 0; - - serv_got_im(gc, c, message, a, time(NULL)); - } else if (!g_ascii_strcasecmp(c, "UPDATE_BUDDY")) { - char *l, *uc, *tmp; - gboolean logged_in; - int evil, idle, type = 0; - time_t signon, time_idle; - - c = strtok(NULL, ":"); /* name */ - l = strtok(NULL, ":"); /* online */ - sscanf(strtok(NULL, ":"), "%d", &evil); - sscanf(strtok(NULL, ":"), "%ld", &signon); - sscanf(strtok(NULL, ":"), "%d", &idle); - uc = strtok(NULL, ":"); - - logged_in = (l && (*l == 'T')) ? TRUE : FALSE; - - if (uc[0] == 'A') - type |= UC_AOL; - switch (uc[1]) { - case 'A': - type |= UC_ADMIN; - break; - case 'U': - type |= UC_UNCONFIRMED; - break; - case 'O': - type |= UC_NORMAL; - break; - case 'C': - type |= UC_WIRELESS; - break; - default: - break; - } - if (uc[2] == 'U') - type |= UC_UNAVAILABLE; - - if (idle) { - time(&time_idle); - time_idle -= idle * 60; - } else - time_idle = 0; - - /* - * If we have info for ourselves then set our display name, warning - * level and official time of login. - */ - tmp = g_strdup(purple_normalize(account, purple_account_get_username(gc->account))); - if (!strcmp(tmp, purple_normalize(account, c))) { - purple_connection_set_display_name(gc, c); - /* XXX - What should the second parameter be here? */ - /* purple_prpl_got_account_warning_level(account, NULL, evil);*/ - purple_prpl_got_account_login_time(account, signon); - } - g_free(tmp); - - purple_prpl_got_user_status(account, c, (logged_in ? "online" : "offline"), NULL); - purple_prpl_got_user_login_time(account, c, signon); - if (time_idle > 0) - purple_prpl_got_user_idle(account, c, TRUE, time_idle); - else - purple_prpl_got_user_idle(account, c, FALSE, 0); - } else if (!g_ascii_strcasecmp(c, "ERROR")) { - purple_notify_error(gc, NULL, show_error_message(), NULL); - } else if (!g_ascii_strcasecmp(c, "EVILED")) { - int lev; - char *name; - - sscanf(strtok(NULL, ":"), "%d", &lev); - name = strtok(NULL, ":"); - - /* purple_prpl_got_account_warning_level(account, name, lev); */ - } else if (!g_ascii_strcasecmp(c, "CHAT_JOIN")) { - char *name; - int id; - - sscanf(strtok(NULL, ":"), "%d", &id); - name = strtok(NULL, ":"); - - serv_got_joined_chat(gc, id, name); - } else if (!g_ascii_strcasecmp(c, "CHAT_IN")) { - int id; - PurpleMessageFlags flags; - char *m, *who, *whisper; - - sscanf(strtok(NULL, ":"), "%d", &id); - who = strtok(NULL, ":"); - whisper = strtok(NULL, ":"); - m = whisper; - while (*m && (*m != ':')) - m++; - m++; - - flags = (whisper && (*whisper == 'T')) ? PURPLE_MESSAGE_WHISPER : 0; - - serv_got_chat_in(gc, id, who, flags, m, time((time_t)NULL)); - } else if (!g_ascii_strcasecmp(c, "CHAT_UPDATE_BUDDY")) { - int id; - char *in, *buddy; - GSList *bcs = gc->buddy_chats; - PurpleConversation *b = NULL; - PurpleConvChat *chat; - - sscanf(strtok(NULL, ":"), "%d", &id); - in = strtok(NULL, ":"); - - chat = PURPLE_CONV_CHAT(b); - - while (bcs) { - b = (PurpleConversation *)bcs->data; - if (id == purple_conv_chat_get_id(chat)) - break; - bcs = bcs->next; - b = NULL; - } - - if (!b) - return; - - if (in && (*in == 'T')) - while ((buddy = strtok(NULL, ":")) != NULL) - purple_conv_chat_add_user(chat, buddy, NULL, PURPLE_CBFLAGS_NONE, TRUE); - else - while ((buddy = strtok(NULL, ":")) != NULL) - purple_conv_chat_remove_user(chat, buddy, NULL); - } else if (!g_ascii_strcasecmp(c, "CHAT_INVITE")) { - char *name, *who, *message; - int id; - GHashTable *components = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, g_free); - - name = strtok(NULL, ":"); - sscanf(strtok(NULL, ":"), "%d", &id); - who = strtok(NULL, ":"); - message = strtok(NULL, ":"); - - g_hash_table_replace(components, g_strdup("id"), g_strdup_printf("%d", id)); - - serv_got_chat_invite(gc, name, who, message, components); - } else if (!g_ascii_strcasecmp(c, "CHAT_LEFT")) { - GSList *bcs = gc->buddy_chats; - PurpleConversation *b = NULL; - int id; - - sscanf(strtok(NULL, ":"), "%d", &id); - - while (bcs) { - b = (PurpleConversation *)bcs->data; - if (id == purple_conv_chat_get_id(PURPLE_CONV_CHAT(b))) - break; - b = NULL; - bcs = bcs->next; - } - - if (!b) - return; - - if (b->window) { - char error_buf[BUF_LONG]; - purple_conversation_set_account(b, NULL); - g_snprintf(error_buf, sizeof error_buf, _("You have been disconnected" - " from chat room %s."), b->name); - purple_notify_error(gc, NULL, error_buf, NULL); - } else - serv_got_chat_left(gc, id); - } else if (!g_ascii_strcasecmp(c, "GOTO_URL")) { - char *name, *url, tmp[256]; - - name = strtok(NULL, ":"); - url = strtok(NULL, ":"); - - g_snprintf(tmp, sizeof(tmp), "http://%s:%d/%s", tdt->toc_ip, - purple_account_get_int(gc->account, "port", TOC_PORT), - url); - purple_url_fetch(tmp, FALSE, NULL, FALSE, toc_got_info, gc); - } else if (!g_ascii_strcasecmp(c, "DIR_STATUS")) { - } else if (!g_ascii_strcasecmp(c, "ADMIN_NICK_STATUS")) { - } else if (!g_ascii_strcasecmp(c, "ADMIN_PASSWD_STATUS")) { - purple_notify_info(gc, NULL, _("Password Change Successful"), NULL); - } else if (!g_ascii_strcasecmp(c, "PAUSE")) { - tdt->state = STATE_PAUSE; - } else if (!g_ascii_strcasecmp(c, "RVOUS_PROPOSE")) { -#if 0 - char *user, *uuid, *cookie; - int seq; - char *rip, *pip, *vip, *trillian = NULL; - int port; - - user = strtok(NULL, ":"); - uuid = strtok(NULL, ":"); - cookie = strtok(NULL, ":"); - sscanf(strtok(NULL, ":"), "%d", &seq); - rip = strtok(NULL, ":"); - pip = strtok(NULL, ":"); - vip = strtok(NULL, ":"); - sscanf(strtok(NULL, ":"), "%d", &port); - - if (!strcmp(uuid, FILE_SEND_UID)) { - /* they want us to get a file */ - int unk[4], i; - char *messages[4], *tmp, *name; - int subtype, files, totalsize = 0; - struct ft_request *ft; - - for (i = 0; i < 4; i++) { - trillian = strtok(NULL, ":"); - sscanf(trillian, "%d", &unk[i]); - if (unk[i] == 10001) - break; - /* Trillian likes to send an empty token as a message, rather than - no message at all. */ - if (*(trillian + strlen(trillian) +1) != ':') - frombase64(strtok(NULL, ":"), &messages[i], NULL); - } - - frombase64(strtok(NULL, ":"), &tmp, NULL); - - subtype = tmp[1]; - files = tmp[3]; - - totalsize |= (tmp[4] << 24) & 0xff000000; - totalsize |= (tmp[5] << 16) & 0x00ff0000; - totalsize |= (tmp[6] << 8) & 0x0000ff00; - totalsize |= (tmp[7] << 0) & 0x000000ff; - - if (!totalsize) { - g_free(tmp); - for (i--; i >= 0; i--) - g_free(messages[i]); - return; - } - - name = tmp + 8; - - ft = g_new0(struct ft_request, 1); - ft->cookie = g_strdup(cookie); - ft->ip = g_strdup(pip); - ft->port = port; - if (i) - ft->message = g_strdup(messages[0]); - else - ft->message = NULL; - ft->filename = g_strdup(name); - ft->user = g_strdup(user); - ft->size = totalsize; - ft->files = files; - g_snprintf(ft->UID, sizeof(ft->UID), "%s", FILE_SEND_UID); - ft->gc = gc; - - g_free(tmp); - for (i--; i >= 0; i--) - g_free(messages[i]); - - purple_debug(PURPLE_DEBUG_MISC, "toc", - "English translation of RVOUS_PROPOSE: %s requests " - "Send File (i.e. send a file to you); %s:%d " - "(verified_ip:port), %d files at total size of " - "%d bytes.\n", user, vip, port, files, totalsize); - accept_file_dialog(ft); - } else if (!strcmp(uuid, FILE_GET_UID)) { - /* they want us to send a file */ - int unk[4], i; - char *messages[4], *tmp; - struct ft_request *ft; - - for (i = 0; i < 4; i++) { - sscanf(strtok(NULL, ":"), "%d", unk + i); - if (unk[i] == 10001) - break; - /* Trillian likes to send an empty token as a message, rather than - no message at all. */ - if (*(trillian + strlen(trillian) +1) != ':') - frombase64(strtok(NULL, ":"), &messages[i], NULL); - } - frombase64(strtok(NULL, ":"), &tmp, NULL); - - ft = g_new0(struct ft_request, 1); - ft->cookie = g_strdup(cookie); - ft->ip = g_strdup(pip); - ft->port = port; - if (i) - ft->message = g_strdup(messages[0]); - else - ft->message = NULL; - ft->user = g_strdup(user); - g_snprintf(ft->UID, sizeof(ft->UID), "%s", FILE_GET_UID); - ft->gc = gc; - - g_free(tmp); - for (i--; i >= 0; i--) - g_free(messages[i]); - - accept_file_dialog(ft); - } else if (!strcmp(uuid, VOICE_UID)) { - /* oh goody. voice over ip. fun stuff. */ - } else if (!strcmp(uuid, B_ICON_UID)) { - int unk[4], i; - char *messages[4]; - struct buddy_icon *icon; - - for (i = 0; i < 4; i++) { - sscanf(strtok(NULL, ":"), "%d", unk + i); - if (unk[i] == 10001) - break; - frombase64(strtok(NULL, ":"), &messages[i], NULL); - } - frombase64(strtok(NULL, ":"), (char **)&icon, NULL); - - purple_debug(PURPLE_DEBUG_MISC, "toc", - "received icon of length %d\n", icon->len); - g_free(icon); - for (i--; i >= 0; i--) - g_free(messages[i]); - } else if (!strcmp(uuid, IMAGE_UID)) { - /* aka Direct IM */ - } else { - purple_debug(PURPLE_DEBUG_ERROR, "toc", - "Don't know what to do with RVOUS UUID %s\n", uuid); - /* do we have to do anything here? i think it just times out */ - } -#endif - } else { - purple_debug(PURPLE_DEBUG_ERROR, "toc", - "don't know what to do with %s\n", c); - } -} - -static int toc_send_im(PurpleConnection *gc, const char *name, const char *message, PurpleMessageFlags flags) -{ - char *buf1, *buf2; - -#if 1 - /* This is the old, non-i18n way */ - buf1 = escape_text(message); - if (strlen(buf1) + 52 > MSG_LEN) { - g_free(buf1); - return -E2BIG; - } - buf2 = g_strdup_printf("toc_send_im %s \"%s\"%s", purple_normalize(gc->account, name), buf1, - ((flags & PURPLE_MESSAGE_AUTO_RESP) ? " auto" : "")); - g_free(buf1); -#else - /* This doesn't work yet. See the comments below for details */ - buf1 = purple_strreplace(message, "\"", "\\\""); - - /* - * We still need to determine what encoding should be used and send the - * message in that encoding. This should be done the same as in - * oscar_encoding_check() in oscar.c. There is no encoding flag sent - * along with the message--the TOC to OSCAR proxy server must just - * use a lil' algorithm to determine what the actual encoding is. - * - * After that, you need to convert buf1 to that encoding, and keep track - * of the length of the resulting string. Then you need to make sure - * that length is passed to sflap_send(). - */ - - if (strlen(buf1) + 52 > MSG_LEN) { - g_free(buf1); - return -E2BIG; - } - - buf2 = g_strdup_printf("toc2_send_im_enc %s F U en \"%s\" %s", purple_normalize(gc->account, name), buf1, - ((flags & PURPLE_MESSAGE_AUTO_RESP) ? "auto" : "")); - g_free(buf1); -#endif - - sflap_send(gc, buf2, -1, TYPE_DATA); - g_free(buf2); - - return 1; -} - -static void toc_set_config(PurpleConnection *gc) -{ - char *buf = g_malloc(MSG_LEN), snd[BUF_LEN * 2]; - toc_build_config(gc->account, buf, MSG_LEN - strlen("toc_set_config \\{\\}"), FALSE); - g_snprintf(snd, MSG_LEN, "toc_set_config {%s}", buf); - sflap_send(gc, snd, -1, TYPE_DATA); - g_free(buf); -} - -static void toc_get_info(PurpleConnection *gc, const char *name) -{ - char buf[BUF_LEN * 2]; - g_snprintf(buf, MSG_LEN, "toc_get_info %s", purple_normalize(gc->account, name)); - sflap_send(gc, buf, -1, TYPE_DATA); -} - -/* Should be implemented as an Account Action? */ -static void toc_get_dir(PurpleBlistNode *node, gpointer data) -{ - PurpleBuddy *buddy; - PurpleConnection *gc; - char buf[BUF_LEN * 2]; - - g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); - - buddy = (PurpleBuddy *) node; - gc = purple_account_get_connection(buddy->account); - - g_snprintf(buf, MSG_LEN, "toc_get_dir %s", - purple_normalize(buddy->account, buddy->name)); - sflap_send(gc, buf, -1, TYPE_DATA); -} - -#if 0 -/* Should be implemented as an Account Action */ -static void toc_set_dir(PurpleConnection *g, const char *first, const char *middle, const char *last, - const char *maiden, const char *city, const char *state, const char *country, int web) -{ - char *buf3, buf2[BUF_LEN * 4], buf[BUF_LEN]; - g_snprintf(buf2, sizeof(buf2), "%s:%s:%s:%s:%s:%s:%s:%s", first, - middle, last, maiden, city, state, country, (web == 1) ? "Y" : ""); - buf3 = escape_text(buf2); - g_snprintf(buf, sizeof(buf), "toc_set_dir %s", buf3); - g_free(buf3); - sflap_send(g, buf, -1, TYPE_DATA); -} -#endif - -#if 0 -/* Should be implemented as an Account Action */ -static void toc_dir_search(PurpleConnection *g, const char *first, const char *middle, const char *last, - const char *maiden, const char *city, const char *state, const char *country, const char *email) -{ - char buf[BUF_LONG]; - g_snprintf(buf, sizeof(buf) / 2, "toc_dir_search %s:%s:%s:%s:%s:%s:%s:%s", first, middle, - last, maiden, city, state, country, email); - purple_debug(PURPLE_DEBUG_INFO, "toc", - "Searching for: %s,%s,%s,%s,%s,%s,%s\n", - first, middle, last, maiden, - city, state, country); - sflap_send(g, buf, -1, TYPE_DATA); -} -#endif - -static void toc_set_status(PurpleAccount *account, PurpleStatus *status) -{ -#if 0 /* do we care about TOC any more? */ - char buf[BUF_LEN * 2]; - if (gc->away) { - g_free(gc->away); - gc->away = NULL; - } - if (message) { - char *tmp; - gc->away = g_strdup(message); - tmp = escape_text(message); - g_snprintf(buf, MSG_LEN, "toc_set_away \"%s\"", tmp); - g_free(tmp); - } else - g_snprintf(buf, MSG_LEN, "toc_set_away \"\""); - sflap_send(g, buf, -1, TYPE_DATA); -#endif -} - -static void toc_set_info(PurpleConnection *g, const char *info) -{ - char buf[BUF_LEN * 2], *buf2; - buf2 = escape_text(info); - g_snprintf(buf, sizeof(buf), "toc_set_info \"%s\n\"", buf2); - g_free(buf2); - sflap_send(g, buf, -1, TYPE_DATA); -} - -static void toc_change_passwd(PurpleConnection *g, const char *orig, const char *new) -{ - char buf[BUF_LEN * 2]; - g_snprintf(buf, BUF_LONG, "toc_change_passwd %s %s", orig, new); - sflap_send(g, buf, -1, TYPE_DATA); -} - -static void -toc_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) -{ - char buf[BUF_LEN * 2]; - g_snprintf(buf, sizeof(buf), "toc_add_buddy %s", purple_normalize(gc->account, buddy->name)); - sflap_send(gc, buf, -1, TYPE_DATA); - toc_set_config(gc); -} - -static void toc_add_buddies(PurpleConnection *gc, GList *buddies, GList *groups) -{ - char buf[BUF_LEN * 2]; - int n; - GList *cur; - - n = g_snprintf(buf, sizeof(buf), "toc_add_buddy"); - for (cur = buddies; cur != NULL; cur = cur->next) { - PurpleBuddy *buddy = cur->data; - - if (strlen(purple_normalize(gc->account, buddy->name)) + n + 32 > MSG_LEN) { - sflap_send(gc, buf, -1, TYPE_DATA); - n = g_snprintf(buf, sizeof(buf), "toc_add_buddy"); - } - n += g_snprintf(buf + n, sizeof(buf) - n, " %s", purple_normalize(gc->account, buddy->name)); - } - sflap_send(gc, buf, -1, TYPE_DATA); -} - -static void toc_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) -{ - char buf[BUF_LEN * 2]; - g_snprintf(buf, sizeof(buf), "toc_remove_buddy %s", purple_normalize(gc->account, buddy->name)); - sflap_send(gc, buf, -1, TYPE_DATA); - toc_set_config(gc); -} - -static void toc_remove_buddies(PurpleConnection *gc, GList *buddies, GList *groups) -{ - char buf[BUF_LEN * 2]; - int n; - GList *cur; - - n = g_snprintf(buf, sizeof(buf), "toc_remove_buddy"); - for (cur = buddies; cur != NULL; cur = cur->next) { - PurpleBuddy *buddy = cur->data; - - if (strlen(purple_normalize(gc->account, buddy->name)) + n + 32 > MSG_LEN) { - sflap_send(gc, buf, -1, TYPE_DATA); - n = g_snprintf(buf, sizeof(buf), "toc_remove_buddy"); - } - n += g_snprintf(buf + n, sizeof(buf) - n, " %s", purple_normalize(gc->account, buddy->name)); - } - sflap_send(gc, buf, -1, TYPE_DATA); - toc_set_config(gc); -} - -static void toc_set_idle(PurpleConnection *g, int time) -{ - char buf[BUF_LEN * 2]; - g_snprintf(buf, sizeof(buf), "toc_set_idle %d", time); - sflap_send(g, buf, -1, TYPE_DATA); -} - -static void toc_warn(PurpleConnection *g, const char *name, int anon) -{ - char send[BUF_LEN * 2]; - g_snprintf(send, 255, "toc_evil %s %s", name, ((anon) ? "anon" : "norm")); - sflap_send(g, send, -1, TYPE_DATA); -} - -static GList *toc_chat_info(PurpleConnection *gc) -{ - GList *m = NULL; - struct proto_chat_entry *pce; - - pce = g_new0(struct proto_chat_entry, 1); - pce->label = _("_Group:"); - pce->identifier = "room"; - m = g_list_append(m, pce); - - pce = g_new0(struct proto_chat_entry, 1); - pce->label = _("_Exchange:"); - pce->identifier = "exchange"; - pce->is_int = TRUE; - pce->min = 4; - pce->max = 20; - m = g_list_append(m, pce); - - return m; -} - -GHashTable *toc_chat_info_defaults(PurpleConnection *gc, const char *chat_name) -{ - GHashTable *defaults; - - defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); - - if (chat_name != NULL) - g_hash_table_insert(defaults, "room", g_strdup(chat_name)); - - return defaults; -} - -static void toc_join_chat(PurpleConnection *g, GHashTable *data) -{ - char buf[BUF_LONG]; - char *name, *exchange; - char *id; - - name = g_hash_table_lookup(data, "room"); - exchange = g_hash_table_lookup(data, "exchange"); - id = g_hash_table_lookup(data, "id"); - - if (id) { - g_snprintf(buf, 255, "toc_chat_accept %d", atoi(id)); - } else { - g_snprintf(buf, sizeof(buf) / 2, "toc_chat_join %d \"%s\"", atoi(exchange), name); - } - - sflap_send(g, buf, -1, TYPE_DATA); -} - -static void toc_chat_invite(PurpleConnection *gc, int id, const char *message, const char *name) -{ - char buf[BUF_LONG]; - g_snprintf(buf, sizeof(buf) / 2, "toc_chat_invite %d \"%s\" %s", id, - message ? message : "", purple_normalize(gc->account, name)); - sflap_send(gc, buf, -1, TYPE_DATA); -} - -static void toc_chat_leave(PurpleConnection *g, int id) -{ - GSList *bcs = g->buddy_chats; - PurpleConversation *b = NULL; - char buf[BUF_LEN * 2]; - - while (bcs) { - b = (PurpleConversation *)bcs->data; - if (id == purple_conv_chat_get_id(PURPLE_CONV_CHAT(b))) - break; - b = NULL; - bcs = bcs->next; - } - - if (!b) - return; /* can this happen? */ - - if (purple_conversation_get_account(b) == NULL) { - /* TOC already kicked us out of this room */ - serv_got_chat_left(g, id); - } - else { - g_snprintf(buf, 255, "toc_chat_leave %d", id); - sflap_send(g, buf, -1, TYPE_DATA); - } -} - -static void toc_chat_whisper(PurpleConnection *gc, int id, const char *who, const char *message) -{ - char *buf1, *buf2; - buf1 = escape_text(message); - buf2 = g_strdup_printf("toc_chat_whisper %d %s \"%s\"", id, purple_normalize(gc->account, who), buf1); - g_free(buf1); - sflap_send(gc, buf2, -1, TYPE_DATA); - g_free(buf2); -} - -static int toc_chat_send(PurpleConnection *g, int id, const char *message, PurpleMessageFlags flags) -{ - char *buf1, *buf2; - buf1 = escape_text(message); - if (strlen(buf1) > 2000) { - g_free(buf1); - return -E2BIG; - } - buf2 = g_strdup_printf("toc_chat_send %d \"%s\"", id, buf1); - g_free(buf1); - sflap_send(g, buf2, -1, TYPE_DATA); - g_free(buf2); - return 0; -} - -static void toc_keepalive(PurpleConnection *gc) -{ - sflap_send(gc, "", 0, TYPE_KEEPALIVE); -} - -static const char * -toc_normalize(const PurpleAccount *account, const char *str) -{ - static char buf[BUF_LEN]; - char *tmp1, *tmp2; - int i, j; - - g_return_val_if_fail(str != NULL, NULL); - - strncpy(buf, str, BUF_LEN); - for (i=0, j=0; buf[j]; i++, j++) - { - while (buf[j] == ' ') - j++; - buf[i] = buf[j]; - } - buf[i] = '\0'; - - tmp1 = g_utf8_strdown(buf, -1); - tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_DEFAULT); - g_snprintf(buf, sizeof(buf), "%s", tmp2); - g_free(tmp2); - g_free(tmp1); - - return buf; -} - -static const char *toc_list_icon(PurpleAccount *a, PurpleBuddy *b) -{ - if (!b || (b && b->name && b->name[0] == '+')) { - if (a != NULL && isdigit(*purple_account_get_username(a))) - return "icq"; - else - return "aim"; - } - - if (b && b->name && isdigit(b->name[0])) - return "icq"; - return "aim"; -} - -static const char* toc_list_emblem(PurpleBuddy *b) -{ - if (b->uc & UC_AOL) - return "aol"; - if (b->uc & UC_ADMIN) - return "admin"; - if (b->uc & UC_WIRELESS) - return "mobile"; - return NULL -} - -static GList *toc_blist_node_menu(PurpleBlistNode *node) -{ - GList *m = NULL; - PurpleMenuAction *act; - - if(PURPLE_BLIST_NODE_IS_BUDDY(node)) { - act = purple_menu_action_new(_("Get Dir Info"), - toc_get_dir, NULL, NULL); - m = g_list_append(m, act); - } - - return m; -} - -static void toc_add_permit(PurpleConnection *gc, const char *who) -{ - char buf2[BUF_LEN * 2]; - if (gc->account->perm_deny != 3) - return; - g_snprintf(buf2, sizeof(buf2), "toc_add_permit %s", purple_normalize(gc->account, who)); - sflap_send(gc, buf2, -1, TYPE_DATA); - toc_set_config(gc); -} - -static void toc_add_deny(PurpleConnection *gc, const char *who) -{ - char buf2[BUF_LEN * 2]; - if (gc->account->perm_deny != 4) - return; - g_snprintf(buf2, sizeof(buf2), "toc_add_deny %s", purple_normalize(gc->account, who)); - sflap_send(gc, buf2, -1, TYPE_DATA); - toc_set_config(gc); -} - -static void toc_set_permit_deny(PurpleConnection *gc) -{ - char buf2[BUF_LEN * 2]; - GSList *list; - int at; - - switch (gc->account->perm_deny) { - case 1: - /* permit all, deny none. to get here reliably we need to have been in permit - * mode, and send an empty toc_add_deny message, which will switch us to deny none */ - g_snprintf(buf2, sizeof(buf2), "toc_add_permit "); - sflap_send(gc, buf2, -1, TYPE_DATA); - g_snprintf(buf2, sizeof(buf2), "toc_add_deny "); - sflap_send(gc, buf2, -1, TYPE_DATA); - break; - case 2: - /* deny all, permit none. to get here reliably we need to have been in deny - * mode, and send an empty toc_add_permit message, which will switch us to permit none */ - g_snprintf(buf2, sizeof(buf2), "toc_add_deny "); - sflap_send(gc, buf2, -1, TYPE_DATA); - g_snprintf(buf2, sizeof(buf2), "toc_add_permit "); - sflap_send(gc, buf2, -1, TYPE_DATA); - break; - case 3: - /* permit some. we want to switch to deny mode first, then send the toc_add_permit - * message, which will clear and set our permit list. toc sucks. */ - g_snprintf(buf2, sizeof(buf2), "toc_add_deny "); - sflap_send(gc, buf2, -1, TYPE_DATA); - - at = g_snprintf(buf2, sizeof(buf2), "toc_add_permit "); - list = gc->account->permit; - while (list) { - at += g_snprintf(buf2 + at, sizeof(buf2) - at, "%s ", purple_normalize(gc->account, list->data)); - if (at > MSG_LEN + 32) { /* from out my ass comes greatness */ - sflap_send(gc, buf2, -1, TYPE_DATA); - at = g_snprintf(buf2, sizeof(buf2), "toc_add_permit "); - } - list = list->next; - } - sflap_send(gc, buf2, -1, TYPE_DATA); - break; - case 4: - /* deny some. we want to switch to permit mode first, then send the toc_add_deny - * message, which will clear and set our deny list. toc sucks. */ - g_snprintf(buf2, sizeof(buf2), "toc_add_permit "); - sflap_send(gc, buf2, -1, TYPE_DATA); - - at = g_snprintf(buf2, sizeof(buf2), "toc_add_deny "); - list = gc->account->deny; - while (list) { - at += g_snprintf(buf2 + at, sizeof(buf2) - at, "%s ", purple_normalize(gc->account, list->data)); - if (at > MSG_LEN + 32) { /* from out my ass comes greatness */ - sflap_send(gc, buf2, -1, TYPE_DATA); - at = g_snprintf(buf2, sizeof(buf2), "toc_add_deny "); - } - list = list->next; - } - sflap_send(gc, buf2, -1, TYPE_DATA); - break; - default: - break; - } - toc_set_config(gc); -} - -static void toc_rem_permit(PurpleConnection *gc, const char *who) -{ - if (gc->account->perm_deny != 3) - return; - toc_set_permit_deny(gc); -} - -static void toc_rem_deny(PurpleConnection *gc, const char *who) -{ - if (gc->account->perm_deny != 4) - return; - toc_set_permit_deny(gc); -} - -static GList *toc_away_states(PurpleAccount *account) -{ -#if 0 /* do we care about TOC any more? */ - return g_list_append(NULL, PURPLE_AWAY_CUSTOM); -#else - return NULL; -#endif -} - -static void -show_set_info(PurplePluginAction *action) -{ - PurpleConnection *gc = (PurpleConnection *) action->context; - purple_account_request_change_user_info(purple_connection_get_account(gc)); -} - -static void -change_pass(PurplePluginAction *action) -{ - PurpleConnection *gc = (PurpleConnection *) action->context; - purple_account_request_change_password(purple_connection_get_account(gc)); -} - -static GList *toc_actions(PurplePlugin *plugin, gpointer context) -{ - GList *m = NULL; - PurplePluginAction *act; - - act = purple_plugin_action_new(_("Set User Info"), - show_set_info); - m = g_list_append(m, act); - -#if 0 - act = purple_plugin_action_new(_("Set Dir Info"), - show_set_dir); - m = g_list_append(m, act); -#endif - - act = purple_plugin_action_new(_("Change Password"), - change_pass); - m = g_list_append(m, act); - - return m; -} - -#if 0 -/********* - * RVOUS ACTIONS - ********/ - -struct file_header { - char magic[4]; /* 0 */ - short hdrlen; /* 4 */ - short hdrtype; /* 6 */ - char bcookie[8]; /* 8 */ - short encrypt; /* 16 */ - short compress; /* 18 */ - short totfiles; /* 20 */ - short filesleft; /* 22 */ - short totparts; /* 24 */ - short partsleft; /* 26 */ - long totsize; /* 28 */ - long size; /* 32 */ - long modtime; /* 36 */ - long checksum; /* 40 */ - long rfrcsum; /* 44 */ - long rfsize; /* 48 */ - long cretime; /* 52 */ - long rfcsum; /* 56 */ - long nrecvd; /* 60 */ - long recvcsum; /* 64 */ - char idstring[32]; /* 68 */ - char flags; /* 100 */ - char lnameoffset; /* 101 */ - char lsizeoffset; /* 102 */ - char dummy[69]; /* 103 */ - char macfileinfo[16]; /* 172 */ - short nencode; /* 188 */ - short nlanguage; /* 190 */ - char name[64]; /* 192 */ - /* 256 */ -}; - -struct file_transfer { - struct file_header hdr; - - PurpleConnection *gc; - - char *user; - char *cookie; - char *ip; - int port; - long size; - struct stat st; - - GtkWidget *window; - int files; - char *filename; - FILE *file; - int recvsize; - - gint inpa; -}; - -static void debug_header(struct file_transfer *ft) { - struct file_header *f = (struct file_header *)ft; - purple_debug(PURPLE_DEBUG_MISC, "toc", "FT HEADER:\n" - "\t%s %d 0x%04x\n" - "\t%s %d %d\n" - "\t%d %d %d %d %d %d\n" - "\t%d %d %d %d %d %d %d %d\n" - "\t%s\n" - "\t0x%02x, 0x%02x, 0x%02x\n" - "\t%s %s\n" - "\t%d %d\n" - "\t%s\n", - f->magic, ntohs(f->hdrlen), f->hdrtype, - f->bcookie, ntohs(f->encrypt), ntohs(f->compress), - ntohs(f->totfiles), ntohs(f->filesleft), ntohs(f->totparts), - ntohs(f->partsleft), ntohl(f->totsize), ntohl(f->size), - ntohl(f->modtime), ntohl(f->checksum), ntohl(f->rfrcsum), ntohl(f->rfsize), - ntohl(f->cretime), ntohl(f->rfcsum), ntohl(f->nrecvd), - ntohl(f->recvcsum), - f->idstring, - f->flags, f->lnameoffset, f->lsizeoffset, - f->dummy, f->macfileinfo, - ntohs(f->nencode), ntohs(f->nlanguage), - f->name); -} - -static void toc_send_file_callback(gpointer data, gint source, PurpleInputCondition cond) -{ - char buf[BUF_LONG]; - int rt, i; - - struct file_transfer *ft = data; - - if (ft->hdr.hdrtype != 0x202) { - char *buf; - frombase64(ft->cookie, &buf, NULL); - - read(source, ft, 8); - read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8)); - debug_header(ft); - - ft->hdr.hdrtype = 0x202; - memcpy(ft->hdr.bcookie, buf, 8); - g_free(buf); - ft->hdr.encrypt = 0; ft->hdr.compress = 0; - debug_header(ft); - write(source, ft, 256); - - if (ft->files == 1) { - ft->file = g_fopen(ft->filename, "w"); - if (!ft->file) { - buf = g_strdup_printf(_("Could not open %s for writing!"), ft->filename); - purple_notify_error(ft->gc, NULL, buf, g_strerror(errno)); - g_free(buf); - purple_input_remove(ft->inpa); - close(source); - g_free(ft->filename); - g_free(ft->user); - g_free(ft->ip); - g_free(ft->cookie); - g_free(ft); - } - } else { - buf = g_strdup_printf("%s/%s", ft->filename, ft->hdr.name); - ft->file = g_fopen(buf, "w"); - g_free(buf); - if (!ft->file) { - buf = g_strdup_printf("Could not open %s/%s for writing!", ft->filename, - ft->hdr.name); - purple_notify_error(ft->gc, NULL, buf, g_strerror(errno)); - g_free(buf); - purple_input_remove(ft->inpa); - close(source); - g_free(ft->filename); - g_free(ft->user); - g_free(ft->ip); - g_free(ft->cookie); - g_free(ft); - } - } - - return; - } - - rt = read(source, buf, MIN(ntohl(ft->hdr.size) - ft->recvsize, 1024)); - if (rt < 0) { - purple_notify_error(ft->gc, NULL, - _("File transfer failed; other side probably " - "canceled."), NULL); - purple_input_remove(ft->inpa); - close(source); - g_free(ft->user); - g_free(ft->ip); - g_free(ft->cookie); - if (ft->file) - fclose(ft->file); - g_free(ft); - return; - } - ft->recvsize += rt; - for (i = 0; i < rt; i++) - fprintf(ft->file, "%c", buf[i]); - - if (ft->recvsize == ntohl(ft->hdr.size)) { - ft->hdr.hdrtype = htons(0x0204); - ft->hdr.filesleft = htons(ntohs(ft->hdr.filesleft) - 1); - ft->hdr.partsleft = htons(ntohs(ft->hdr.partsleft) - 1); - ft->hdr.recvcsum = ft->hdr.checksum; /* uh... */ - ft->hdr.nrecvd = htons(ntohs(ft->hdr.nrecvd) + 1); - ft->hdr.flags = 0; - write(source, ft, 256); - debug_header(ft); - ft->recvsize = 0; - fclose(ft->file); - if (ft->hdr.filesleft == 0) { - purple_input_remove(ft->inpa); - close(source); - g_free(ft->filename); - g_free(ft->user); - g_free(ft->ip); - g_free(ft->cookie); - g_free(ft); - } - } -} - -static void toc_send_file_connect(gpointer data, gint src, PurpleInputCondition cond) -{ - struct file_transfer *ft = data; - - if (src == -1) { - purple_notify_error(ft->gc, NULL, - _("Could not connect for transfer."), NULL); - g_free(ft->filename); - g_free(ft->cookie); - g_free(ft->user); - g_free(ft->ip); - g_free(ft); - return; - } - - ft->inpa = purple_input_add(src, PURPLE_INPUT_READ, toc_send_file_callback, ft); -} - -static void toc_send_file(gpointer a, struct file_transfer *old_ft) -{ - struct file_transfer *ft; - const char *dirname = gtk_file_selection_get_filename(GTK_FILE_SELECTION(old_ft->window)); - PurpleAccount *account; - char buf[BUF_LEN * 2]; - - if (purple_gtk_check_if_dir(dirname, GTK_FILE_SELECTION(old_ft->window))) - return; - ft = g_new0(struct file_transfer, 1); - if (old_ft->files == 1) - ft->filename = g_strdup(dirname); - else - ft->filename = g_path_get_dirname(dirname); - ft->cookie = g_strdup(old_ft->cookie); - ft->user = g_strdup(old_ft->user); - ft->ip = g_strdup(old_ft->ip); - ft->files = old_ft->files; - ft->port = old_ft->port; - ft->gc = old_ft->gc; - account = ft->gc->account; - gtk_widget_destroy(old_ft->window); - - g_snprintf(buf, sizeof(buf), "toc_rvous_accept %s %s %s", ft->user, ft->cookie, FILE_SEND_UID); - sflap_send(ft->gc, buf, -1, TYPE_DATA); - - if (purple_proxy_connect(ft->gc, account, ft->ip, ft->port, toc_send_file_connect, ft) != 0) { - purple_notify_error(ft->gc, NULL, - _("Could not connect for transfer."), NULL); - g_free(ft->filename); - g_free(ft->cookie); - g_free(ft->user); - g_free(ft->ip); - g_free(ft); - return; - } -} - -static void toc_get_file_callback(gpointer data, gint source, PurpleInputCondition cond) -{ - char buf[BUF_LONG]; - - struct file_transfer *ft = data; - - if (cond & PURPLE_INPUT_WRITE) { - int remain = MIN(ntohl(ft->hdr.totsize) - ft->recvsize, 1024); - int i; - for (i = 0; i < remain; i++) - fscanf(ft->file, "%c", &buf[i]); - write(source, buf, remain); - ft->recvsize += remain; - if (ft->recvsize == ntohl(ft->hdr.totsize)) { - purple_input_remove(ft->inpa); - ft->inpa = purple_input_add(source, PURPLE_INPUT_READ, - toc_get_file_callback, ft); - } - return; - } - - if (ft->hdr.hdrtype == htons(0x1108)) { - struct tm *fortime; - struct stat st; - char *basename; - - read(source, ft, 8); - read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8)); - debug_header(ft); - - g_stat(ft->filename, &st); - fortime = localtime(&st.st_mtime); - basename = g_path_get_basename(ft->filename); - g_snprintf(buf, sizeof(buf), "%2d/%2d/%4d %2d:%2d %8ld %s\r\n", - fortime->tm_mon + 1, fortime->tm_mday, fortime->tm_year + 1900, - fortime->tm_hour + 1, fortime->tm_min + 1, (long)st.st_size, - basename); - write(source, buf, ntohl(ft->hdr.size)); - g_free(basename); - return; - } - - if (ft->hdr.hdrtype == htons(0x1209)) { - read(source, ft, 8); - read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8)); - debug_header(ft); - return; - } - - if (ft->hdr.hdrtype == htons(0x120b)) { - read(source, ft, 8); - read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8)); - debug_header(ft); - - if (ft->hdr.hdrtype != htons(0x120c)) { - g_snprintf(buf, sizeof(buf), "%s decided to cancel the transfer", ft->user); - purple_notify_error(ft->gc, NULL, buf, NULL); - purple_input_remove(ft->inpa); - close(source); - g_free(ft->filename); - g_free(ft->user); - g_free(ft->ip); - g_free(ft->cookie); - if (ft->file) - fclose(ft->file); - g_free(ft); - return; - } - - ft->hdr.hdrtype = 0x0101; - ft->hdr.totfiles = htons(1); ft->hdr.filesleft = htons(1); - ft->hdr.flags = 0x20; - write(source, ft, 256); - return; - } - - if (ft->hdr.hdrtype == 0x0101) { - read(source, ft, 8); - read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8)); - debug_header(ft); - - purple_input_remove(ft->inpa); - ft->inpa = purple_input_add(source, PURPLE_INPUT_WRITE, - toc_get_file_callback, ft); - return; - } - - if (ft->hdr.hdrtype == 0x0202) { - read(source, ft, 8); - read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8)); - debug_header(ft); - - purple_input_remove(ft->inpa); - close(source); - g_free(ft->filename); - g_free(ft->user); - g_free(ft->ip); - g_free(ft->cookie); - if (ft->file) - fclose(ft->file); - g_free(ft); - return; - } -} - -static void toc_get_file_connect(gpointer data, gint src, PurpleInputCondition cond) -{ - struct file_transfer *ft = data; - struct file_header *hdr; - char *buf; - char *basename; - - if (src == -1) { - purple_notify_error(ft->gc, NULL, - _("Could not connect for transfer."), NULL); - fclose(ft->file); - g_free(ft->filename); - g_free(ft->cookie); - g_free(ft->user); - g_free(ft->ip); - g_free(ft); - return; - } - - hdr = (struct file_header *)ft; - hdr->magic[0] = 'O'; hdr->magic[1] = 'F'; hdr->magic[2] = 'T'; hdr->magic[3] = '2'; - hdr->hdrlen = htons(256); - hdr->hdrtype = htons(0x1108); - rombase64(ft->cookie, &buf, NULL); - g_snprintf(hdr->bcookie, 8, "%s", buf); - g_free(buf); - hdr->totfiles = htons(1); hdr->filesleft = htons(1); - hdr->totparts = htons(1); hdr->partsleft = htons(1); - hdr->totsize = htonl((long)ft->st.st_size); /* combined size of all files */ - /* size = strlen("mm/dd/yyyy hh:mm sizesize 'name'\r\n") */ - basename = g_path_get_basename(ft->filename); - hdr->size = htonl(28 + strlen(basename)); /* size of listing.txt */ - g_free(basename); - hdr->modtime = htonl(ft->st.st_mtime); - hdr->checksum = htonl(0x89f70000); /* uh... */ - g_snprintf(hdr->idstring, 32, "OFT_Windows ICBMFT V1.1 32"); - hdr->flags = 0x02; - hdr->lnameoffset = 0x1A; - hdr->lsizeoffset = 0x10; - g_snprintf(hdr->name, 64, "listing.txt"); - if (write(src, hdr, 256) < 0) { - purple_notify_error(ft->gc, NULL, - _("Could not write file header. The file will " - "not be transferred."), NULL); - fclose(ft->file); - g_free(ft->filename); - g_free(ft->cookie); - g_free(ft->user); - g_free(ft->ip); - g_free(ft); - return; - } - - ft->inpa = purple_input_add(src, PURPLE_INPUT_READ, toc_get_file_callback, ft); -} - -static void toc_get_file(gpointer a, struct file_transfer *old_ft) -{ - struct file_transfer *ft; - const char *dirname = gtk_file_selection_get_filename(GTK_FILE_SELECTION(old_ft->window)); - PurpleAccount *account; - char *buf, buf2[BUF_LEN * 2]; - - if (purple_gtk_check_if_dir(dirname, GTK_FILE_SELECTION(old_ft->window))) - return; - ft = g_new0(struct file_transfer, 1); - ft->filename = g_strdup(dirname); - ft->file = g_fopen(ft->filename, "r"); - if (!ft->file) { - buf = g_strdup_printf("Unable to open %s for transfer.", ft->filename); - purple_notify_error(ft->gc, NULL, buf, NULL); - g_free(buf); - g_free(ft->filename); - g_free(ft); - return; - } - if (g_stat(dirname, &ft->st)) { - buf = g_strdup_printf("Unable to examine %s.", dirname); - purple_notify_error(ft->gc, NULL, buf, NULL); - g_free(buf); - g_free(ft->filename); - g_free(ft); - return; - } - ft->cookie = g_strdup(old_ft->cookie); - ft->user = g_strdup(old_ft->user); - ft->ip = g_strdup(old_ft->ip); - ft->port = old_ft->port; - ft->gc = old_ft->gc; - account = ft->gc->account; - gtk_widget_destroy(old_ft->window); - - g_snprintf(buf2, sizeof(buf2), "toc_rvous_accept %s %s %s", ft->user, ft->cookie, FILE_GET_UID); - sflap_send(ft->gc, buf2, -1, TYPE_DATA); - - if (purple_proxy_connect(ft->gc, account, ft->ip, ft->port, toc_get_file_connect, ft) < 0) { - purple_notify_error(ft->gc, NULL, - _("Could not connect for transfer."), NULL); - fclose(ft->file); - g_free(ft->filename); - g_free(ft->cookie); - g_free(ft->user); - g_free(ft->ip); - g_free(ft); - return; - } -} - -static void cancel_callback(gpointer a, struct file_transfer *ft) { - gtk_widget_destroy(ft->window); - if (a == ft->window) { - g_free(ft->cookie); - g_free(ft->user); - g_free(ft->ip); - g_free(ft); - } -} - -static void toc_reject_ft(struct ft_request *ft) { - g_free(ft->user); - g_free(ft->filename); - g_free(ft->ip); - g_free(ft->cookie); - if (ft->message) - g_free(ft->message); - g_free(ft); -} - - -static void toc_accept_ft(struct ft_request *fr) { - if(g_list_find(purple_connections_get_all(), fr->gc)) { - GtkWidget *window; - char buf[BUF_LEN]; - - struct file_transfer *ft = g_new0(struct file_transfer, 1); - ft->gc = fr->gc; - ft->user = g_strdup(fr->user); - ft->cookie = g_strdup(fr->cookie); - ft->ip = g_strdup(fr->ip); - ft->port = fr->port; - ft->files = fr->files; - - ft->window = window = gtk_file_selection_new(_("Save As...")); - g_snprintf(buf, sizeof(buf), "%s/%s", purple_home_dir(), fr->filename ? fr->filename : ""); - gtk_file_selection_set_filename(GTK_FILE_SELECTION(window), buf); - g_signal_connect(G_OBJECT(window), "destroy", - G_CALLBACK(cancel_callback), ft); - g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(ft->window)->cancel_button), - "clicked", G_CALLBACK(cancel_callback), ft); - - if (!strcmp(fr->UID, FILE_SEND_UID)) - g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(window)->ok_button), - "clicked", G_CALLBACK(toc_send_file), ft); - else - g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(window)->ok_button), - "clicked", G_CALLBACK(toc_get_file), ft); - - gtk_widget_show(window); - } - - toc_reject_ft(fr); -} - -static void accept_file_dialog(struct ft_request *ft) { - char buf[BUF_LONG]; - if (!strcmp(ft->UID, FILE_SEND_UID)) { - /* holy crap. who the fuck would transfer gigabytes through AIM?! */ - static char *sizes[4] = { "bytes", "KB", "MB", "GB" }; - float size = ft->size; - int index = 0; - while ((index < 4) && (size > 1024)) { - size /= 1024; - index++; - } - g_snprintf(buf, sizeof(buf), - dngettext(PACKAGE, - "%s requests %s to accept %d file: %s (%.2f %s)%s%s", - "%s requests %s to accept %d files: %s (%.2f %s)%s%s", - ft->files), - ft->user, purple_account_get_username(ft->gc->account), ft->files, - ft->filename, size, sizes[index], (ft->message) ? "\n" : "", - (ft->message) ? ft->message : ""); - } else { - g_snprintf(buf, sizeof(buf), _("%s requests you to send them a file"), ft->user); - } - - purple_request_accept_cancel(ft->gc, NULL, buf, NULL, - PURPLE_DEFAULT_ACTION_NONE, ft, - G_CALLBACK(toc_accept_ft), - G_CALLBACK(toc_reject_ft)); -} -#endif - -static PurplePluginProtocolInfo prpl_info = -{ - 0, - NULL, /* user_splits */ - NULL, /* protocol_options */ - NO_BUDDY_ICONS, /* icon_spec */ - toc_list_icon, /* list_icon */ - toc_list_emblem, /* list_emblems */ - NULL, /* status_text */ - NULL, /* tooltip_text */ - toc_away_states, /* away_states */ - toc_blist_node_menu, /* blist_node_menu */ - toc_chat_info, /* chat_info */ - toc_chat_info_defaults, /* chat_info_defaults */ - toc_login, /* login */ - toc_close, /* close */ - toc_send_im, /* send_im */ - toc_set_info, /* set_info */ - NULL, /* send_typing */ - toc_get_info, /* get_info */ - toc_set_status, /* set_away */ - toc_set_idle, /* set_idle */ - toc_change_passwd, /* change_passwd */ - toc_add_buddy, /* add_buddy */ - toc_add_buddies, /* add_buddies */ - toc_remove_buddy, /* remove_buddy */ - toc_remove_buddies, /* remove_buddies */ - toc_add_permit, /* add_permit */ - toc_add_deny, /* add_deny */ - toc_rem_permit, /* rem_permit */ - toc_rem_deny, /* rem_deny */ - toc_set_permit_deny, /* set_permit_deny */ - toc_join_chat, /* join_chat */ - NULL, /* reject_chat */ - NULL, /* get_chat_name */ - toc_chat_invite, /* chat_invite */ - toc_chat_leave, /* chat_leave */ - toc_chat_whisper, /* chat_whisper */ - toc_chat_send, /* chat_send */ - toc_keepalive, /* keepalive */ - NULL, /* register_user */ - NULL, /* get_cb_info */ - NULL, /* get_cb_away */ - NULL, /* alias_buddy */ - NULL, /* group_buddy */ - NULL, /* rename_group */ - NULL, /* buddy_free */ - NULL, /* convo_closed */ - toc_normalize, /* normalize */ - NULL, /* set_buddy_icon */ - NULL, /* remove_group */ - NULL, /* get_cb_real_name */ - NULL, /* set_chat_topic */ - NULL, /* find_blist_chat */ - NULL, /* roomlist_get_list */ - NULL, /* roomlist_cancel */ - NULL, /* roomlist_expand_category */ - NULL, /* can_receive_file */ - NULL, /* send_file */ - NULL, /* new_xfer */ - NULL, /* offline_message */ - NULL, /* whiteboard_prpl_ops */ - toc_send_raw, /* send_raw */ -}; - -static PurplePluginInfo info = -{ - PURPLE_PLUGIN_MAGIC, - PURPLE_MAJOR_VERSION, - PURPLE_MINOR_VERSION, - PURPLE_PLUGIN_PROTOCOL, /**< type */ - NULL, /**< ui_requirement */ - 0, /**< flags */ - NULL, /**< dependencies */ - PURPLE_PRIORITY_DEFAULT, /**< priority */ - - "prpl-toc", /**< id */ - "TOC", /**< name */ - DISPLAY_VERSION, /**< version */ - /** summary */ - N_("TOC Protocol Plugin"), - /** description */ - N_("TOC Protocol Plugin"), - NULL, /**< author */ - PURPLE_WEBSITE, /**< homepage */ - - NULL, /**< load */ - NULL, /**< unload */ - NULL, /**< destroy */ - - NULL, /**< ui_info */ - &prpl_info, /**< extra_info */ - NULL, - toc_actions -}; - -static void -init_plugin(PurplePlugin *plugin) -{ - PurpleAccountOption *option; - - option = purple_account_option_string_new(_("Server"), "server", TOC_HOST); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, - option); - - option = purple_account_option_int_new(_("Port"), "port", TOC_PORT); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, - option); - - my_protocol = plugin; -} - -PURPLE_INIT_PLUGIN(toc, init_plugin, info); diff -r 9407348dc714 -r ea0494a3a299 libpurple/protocols/yahoo/yahoo_packet.c --- a/libpurple/protocols/yahoo/yahoo_packet.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo_packet.c Sat Mar 28 16:59:30 2009 +0000 @@ -201,6 +201,8 @@ } pos += 2; + if (pos + 1 > len) break; + /* Skip over garbage we've noticed in the mail notifications */ if (data[0] == '9' && data[pos] == 0x01) pos++; diff -r 9407348dc714 -r ea0494a3a299 libpurple/prpl.h --- a/libpurple/prpl.h Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/prpl.h Sat Mar 28 16:59:30 2009 +0000 @@ -296,6 +296,14 @@ void (*set_idle)(PurpleConnection *, int idletime); void (*change_passwd)(PurpleConnection *, const char *old_pass, const char *new_pass); + /** + * Add a buddy to a group on the server. + * + * This PRPL function may be called in situations in which the buddy is + * already in the specified group. If the protocol supports + * authorization and the user is not already authorized to see the + * status of \a buddy, \a add_buddy should request authorization. + */ void (*add_buddy)(PurpleConnection *, PurpleBuddy *buddy, PurpleGroup *group); void (*add_buddies)(PurpleConnection *, GList *buddies, GList *groups); void (*remove_buddy)(PurpleConnection *, PurpleBuddy *buddy, PurpleGroup *group); diff -r 9407348dc714 -r ea0494a3a299 libpurple/tests/test_util.c --- a/libpurple/tests/test_util.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/tests/test_util.c Sat Mar 28 16:59:30 2009 +0000 @@ -5,7 +5,7 @@ START_TEST(test_util_base16_encode) { - assert_string_equal_free("68656c6c6f2c20776f726c642100", purple_base16_encode("hello, world!", 14)); + assert_string_equal_free("68656c6c6f2c20776f726c642100", purple_base16_encode((const unsigned char *)"hello, world!", 14)); } END_TEST @@ -14,14 +14,14 @@ gsize sz = 0; guchar *out = purple_base16_decode("21646c726f77202c6f6c6c656800", &sz); fail_unless(sz == 14, NULL); - fail_unless(strcmp("!dlrow ,olleh", out) == 0, NULL); + fail_unless(strcmp("!dlrow ,olleh", (const char *)out) == 0, NULL); g_free(out); } END_TEST START_TEST(test_util_base64_encode) { - assert_string_equal_free("Zm9ydHktdHdvAA==", purple_base64_encode("forty-two", 10)); + assert_string_equal_free("Zm9ydHktdHdvAA==", purple_base64_encode((const unsigned char *)"forty-two", 10)); } END_TEST @@ -30,7 +30,7 @@ gsize sz; guchar *out = purple_base64_decode("b3d0LXl0cm9mAA==", &sz); fail_unless(sz == 10, NULL); - fail_unless(strcmp("owt-ytrof", out) == 0, NULL); + fail_unless(strcmp("owt-ytrof", (const char *)out) == 0, NULL); g_free(out); } END_TEST diff -r 9407348dc714 -r ea0494a3a299 libpurple/util.c --- a/libpurple/util.c Mon Mar 16 21:45:24 2009 +0000 +++ b/libpurple/util.c Sat Mar 28 16:59:30 2009 +0000 @@ -4044,6 +4044,13 @@ &gfud->website.page, &gfud->website.user, &gfud->website.passwd); if (purple_strcasestr(url, "https://") != NULL) { + if (!purple_ssl_is_supported()) { + purple_util_fetch_url_error(gfud, + _("Unable to connect to %s: Server requires TLS/SSL, but no TLS/SSL support was found."), + gfud->website.address); + return NULL; + } + gfud->is_ssl = TRUE; gfud->ssl_connection = purple_ssl_connect(NULL, gfud->website.address, gfud->website.port, diff -r 9407348dc714 -r ea0494a3a299 pidgin/gtkaccount.c --- a/pidgin/gtkaccount.c Mon Mar 16 21:45:24 2009 +0000 +++ b/pidgin/gtkaccount.c Sat Mar 28 16:59:30 2009 +0000 @@ -106,8 +106,8 @@ GtkSizeGroup *sg; GtkWidget *window; + GtkWidget *notebook; GtkWidget *top_vbox; - GtkWidget *bottom_vbox; GtkWidget *ok_button; GtkWidget *register_button; @@ -157,8 +157,7 @@ **************************************************************************/ static void add_login_options(AccountPrefsDialog *dialog, GtkWidget *parent); static void add_user_options(AccountPrefsDialog *dialog, GtkWidget *parent); -static void add_protocol_options(AccountPrefsDialog *dialog, - GtkWidget *parent); +static void add_protocol_options(AccountPrefsDialog *dialog); static void add_proxy_options(AccountPrefsDialog *dialog, GtkWidget *parent); static GtkWidget * @@ -237,7 +236,7 @@ add_login_options(dialog, dialog->top_vbox); add_user_options(dialog, dialog->top_vbox); - add_protocol_options(dialog, dialog->bottom_vbox); + add_protocol_options(dialog); gtk_widget_grab_focus(dialog->protocol_menu); @@ -733,11 +732,11 @@ } static void -add_protocol_options(AccountPrefsDialog *dialog, GtkWidget *parent) +add_protocol_options(AccountPrefsDialog *dialog) { PurpleAccountOption *option; PurpleAccount *account; - GtkWidget *frame, *vbox, *check, *entry, *combo; + GtkWidget *vbox, *check, *entry, *combo; GList *list, *node; gint i, idx, int_value; GtkListStore *model; @@ -752,14 +751,10 @@ ProtocolOptEntry *opt_entry; if (dialog->protocol_frame != NULL) { - gtk_widget_destroy(dialog->protocol_frame); + gtk_notebook_remove_page (GTK_NOTEBOOK(dialog->notebook), 1); dialog->protocol_frame = NULL; } - if (dialog->prpl_info == NULL || - dialog->prpl_info->protocol_options == NULL) - return; - while (dialog->protocol_opt_entries != NULL) { ProtocolOptEntry *opt_entry = dialog->protocol_opt_entries->data; g_free(opt_entry->setting); @@ -767,21 +762,17 @@ dialog->protocol_opt_entries = g_list_delete_link(dialog->protocol_opt_entries, dialog->protocol_opt_entries); } + if (dialog->prpl_info == NULL || + dialog->prpl_info->protocol_options == NULL) + return; + account = dialog->account; - /* Build the protocol options frame. */ - g_snprintf(buf, sizeof(buf), _("%s Options"), dialog->plugin->info->name); - - frame = pidgin_make_frame(parent, buf); - dialog->protocol_frame = - gtk_widget_get_parent(gtk_widget_get_parent(frame)); - - gtk_box_reorder_child(GTK_BOX(parent), dialog->protocol_frame, 0); - gtk_widget_show(dialog->protocol_frame); - /* Main vbox */ - vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - gtk_container_add(GTK_CONTAINER(frame), vbox); + dialog->protocol_frame = vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); + gtk_container_set_border_width(GTK_CONTAINER(vbox), PIDGIN_HIG_BORDER); + gtk_notebook_insert_page(GTK_NOTEBOOK(dialog->notebook), vbox, + gtk_label_new_with_mnemonic(_("_Advanced")), 1); gtk_widget_show(vbox); for (l = dialog->prpl_info->protocol_options; l != NULL; l = l->next) @@ -1046,22 +1037,15 @@ add_proxy_options(AccountPrefsDialog *dialog, GtkWidget *parent) { PurpleProxyInfo *proxy_info; - GtkWidget *frame; GtkWidget *vbox; GtkWidget *vbox2; if (dialog->proxy_frame != NULL) gtk_widget_destroy(dialog->proxy_frame); - frame = pidgin_make_frame(parent, _("Proxy Options")); - dialog->proxy_frame = gtk_widget_get_parent(gtk_widget_get_parent(frame)); - - gtk_box_reorder_child(GTK_BOX(parent), dialog->proxy_frame, 1); - gtk_widget_show(dialog->proxy_frame); - /* Main vbox */ - vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - gtk_container_add(GTK_CONTAINER(frame), vbox); + dialog->proxy_frame = vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); + gtk_container_add(GTK_CONTAINER(parent), vbox); gtk_widget_show(vbox); /* Proxy Type drop-down. */ @@ -1496,15 +1480,15 @@ dialog->prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(dialog->plugin); dialog->window = win = pidgin_create_dialog((type == PIDGIN_ADD_ACCOUNT_DIALOG) ? _("Add Account") : _("Modify Account"), - PIDGIN_HIG_BORDER, "account", FALSE); + PIDGIN_HIG_BOX_SPACE, "account", FALSE); g_signal_connect(G_OBJECT(win), "delete_event", G_CALLBACK(account_win_destroy_cb), dialog); /* Setup the vbox */ - main_vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(win), FALSE, PIDGIN_HIG_BORDER); - - notebook = gtk_notebook_new(); + main_vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(win), FALSE, PIDGIN_HIG_BOX_SPACE); + + dialog->notebook = notebook = gtk_notebook_new(); gtk_box_pack_start(GTK_BOX(main_vbox), notebook, FALSE, FALSE, 0); gtk_widget_show(GTK_WIDGET(notebook)); @@ -1530,15 +1514,15 @@ if (!dialog->prpl_info || !dialog->prpl_info->register_user) gtk_widget_hide(button); - /* Setup the page with 'Advanced'. */ - dialog->bottom_vbox = dbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER); + /* Setup the page with 'Advanced' (protocol options). */ + add_protocol_options(dialog); + + /* Setup the page with 'Proxy'. */ + dbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER); gtk_container_set_border_width(GTK_CONTAINER(dbox), PIDGIN_HIG_BORDER); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dbox, - gtk_label_new_with_mnemonic(_("_Advanced"))); + gtk_label_new_with_mnemonic(_("_Proxy"))); gtk_widget_show(dbox); - - /** Setup the bottom frames. */ - add_protocol_options(dialog, dbox); add_proxy_options(dialog, dbox); /* Cancel button */ diff -r 9407348dc714 -r ea0494a3a299 pidgin/gtkblist.c --- a/pidgin/gtkblist.c Mon Mar 16 21:45:24 2009 +0000 +++ b/pidgin/gtkblist.c Sat Mar 28 16:59:30 2009 +0000 @@ -3898,7 +3898,7 @@ presence = purple_buddy_get_presence(b); /* Name is all that is needed */ - if (aliased && biglist) { + if (!aliased || biglist) { /* Status Info */ prpl = purple_find_prpl(purple_account_get_protocol_id(b->account)); @@ -4038,7 +4038,7 @@ } /* Put it all together */ - if (aliased && biglist && (statustext || idletime)) { + if ((!aliased || biglist) && (statustext || idletime)) { /* using breaks the status, so it must be seperated into */ if (name_color) { text = g_strdup_printf("%s\n" @@ -6443,7 +6443,7 @@ gboolean biglist = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons"); PidginBlistNode *ui; PurpleConversation *conv; - gboolean hidden; + gboolean hidden = FALSE; GdkColor *bgcolor = NULL; FontColorPair *pair; PidginBlistTheme *theme; @@ -6701,14 +6701,27 @@ whoalias = NULL; g = NULL; - if ((grp != NULL) && (*grp != '\0') && ((g = purple_find_group(grp)) == NULL)) + if ((grp != NULL) && (*grp != '\0')) { - g = purple_group_new(grp); - purple_blist_add_group(g, NULL); - } - - b = purple_buddy_new(data->account, who, whoalias); - purple_blist_add_buddy(b, NULL, g, NULL); + if ((g = purple_find_group(grp)) == NULL) + { + g = purple_group_new(grp); + purple_blist_add_group(g, NULL); + } + + b = purple_find_buddy_in_group(data->account, who, g); + } + else if ((b = purple_find_buddy(data->account, who)) != NULL) + { + g = purple_buddy_get_group(b); + } + + if (b == NULL) + { + b = purple_buddy_new(data->account, who, whoalias); + purple_blist_add_buddy(b, NULL, g, NULL); + } + purple_account_add_buddy(data->account, b); /* Offer to merge people with the same alias. */ diff -r 9407348dc714 -r ea0494a3a299 pidgin/gtkdialogs.c --- a/pidgin/gtkdialogs.c Mon Mar 16 21:45:24 2009 +0000 +++ b/pidgin/gtkdialogs.c Sat Mar 28 16:59:30 2009 +0000 @@ -189,7 +189,7 @@ {N_("Italian"), "it", "Claudio Satriano", "satriano@na.infn.it"}, {N_("Japanese"), "ja", "Takashi Aihana", "aihana@gnome.gr.jp"}, {N_("Georgian"), "ka", N_("Ubuntu Georgian Translators"), "alexander.didebulidze@stusta.mhn.de"}, - {"Khmer", "km", "Khoem Sokhem", "khoemsokhem@khmeros.info"}, + {N_("Khmer"), "km", "Khoem Sokhem", "khoemsokhem@khmeros.info"}, {N_("Kannada"), "kn", N_("Kannada Translation team"), "translation@sampada.info"}, {N_("Korean"), "ko", "Sushizang", "sushizang@empal.com"}, {N_("Kurdish"), "ku", "Erdal Ronahi", "erdal.ronahi@gmail.com"}, diff -r 9407348dc714 -r ea0494a3a299 pidgin/gtkprefs.c --- a/pidgin/gtkprefs.c Mon Mar 16 21:45:24 2009 +0000 +++ b/pidgin/gtkprefs.c Sat Mar 28 16:59:30 2009 +0000 @@ -2385,14 +2385,12 @@ /* Auto-away stuff */ vbox = pidgin_make_frame(ret, _("Auto-away")); - button = pidgin_prefs_checkbox(_("Change status when _idle"), - "/purple/away/away_when_idle", vbox); - select = pidgin_prefs_labeled_spin_button(vbox, _("_Minutes before becoming idle:"), "/purple/away/mins_before_away", 1, 24 * 60, sg); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(pidgin_toggle_sensitive), select); + + button = pidgin_prefs_checkbox(_("Change status when _idle"), + "/purple/away/away_when_idle", vbox); /* TODO: Show something useful if we don't have any saved statuses. */ menu = pidgin_status_menu(purple_savedstatus_get_idleaway(), G_CALLBACK(set_idle_away)); @@ -2404,7 +2402,6 @@ if (!purple_prefs_get_bool("/purple/away/away_when_idle")) { gtk_widget_set_sensitive(GTK_WIDGET(menu), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(select), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(label), FALSE); } diff -r 9407348dc714 -r ea0494a3a299 pidgin/gtkroomlist.c --- a/pidgin/gtkroomlist.c Mon Mar 16 21:45:24 2009 +0000 +++ b/pidgin/gtkroomlist.c Sat Mar 28 16:59:30 2009 +0000 @@ -64,7 +64,6 @@ gint num_rooms, total_rooms; GtkWidget *tipwindow; GdkRectangle tip_rect; - guint timeout; PangoLayout *tip_layout; PangoLayout *tip_name_layout; int tip_height; diff -r 9407348dc714 -r ea0494a3a299 pidgin/gtkutils.c --- a/pidgin/gtkutils.c Mon Mar 16 21:45:24 2009 +0000 +++ b/pidgin/gtkutils.c Sat Mar 28 16:59:30 2009 +0000 @@ -2451,11 +2451,6 @@ dialog->callback = callback; dialog->data = data; - if (dialog->icon_filesel != NULL) { - gtk_window_present(GTK_WINDOW(dialog->icon_filesel)); - return NULL; - } - current_folder = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder"); #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ diff -r 9407348dc714 -r ea0494a3a299 pidgin/plugins/gevolution/gevo-util.c --- a/pidgin/plugins/gevolution/gevo-util.c Mon Mar 16 21:45:24 2009 +0000 +++ b/pidgin/plugins/gevolution/gevo-util.c Sat Mar 28 16:59:30 2009 +0000 @@ -41,8 +41,12 @@ purple_blist_add_group(group, NULL); } - buddy = purple_buddy_new(account, buddy_name, alias); - purple_blist_add_buddy(buddy, NULL, group, NULL); + if ((buddy = purple_find_buddy_in_group(account, buddy_name, group))) + { + buddy = purple_buddy_new(account, buddy_name, alias); + purple_blist_add_buddy(buddy, NULL, group, NULL); + } + purple_account_add_buddy(account, buddy); if (conv != NULL) diff -r 9407348dc714 -r ea0494a3a299 pidgin/plugins/gevolution/gevolution.h --- a/pidgin/plugins/gevolution/gevolution.h Mon Mar 16 21:45:24 2009 +0000 +++ b/pidgin/plugins/gevolution/gevolution.h Sat Mar 28 16:59:30 2009 +0000 @@ -75,7 +75,7 @@ GtkWidget *win; GtkWidget *accounts_menu; - GtkWidget *screenname; + GtkWidget *username; GtkWidget *firstname; GtkWidget *lastname; GtkWidget *email; diff -r 9407348dc714 -r ea0494a3a299 pidgin/win32/untar.c --- a/pidgin/win32/untar.c Mon Mar 16 21:45:24 2009 +0000 +++ b/pidgin/win32/untar.c Sat Mar 28 16:59:30 2009 +0000 @@ -212,9 +212,11 @@ * make sure the directory path exists. */ fpdst = createpath(dst); - if (!fpdst) + if (!fpdst) { /* error message already given */ + fclose(fpsrc); return; + } #ifdef _POSIX_SOURCE # ifndef _WEAK_POSIX diff -r 9407348dc714 -r ea0494a3a299 po/POTFILES.in --- a/po/POTFILES.in Mon Mar 16 21:45:24 2009 +0000 +++ b/po/POTFILES.in Sat Mar 28 16:59:30 2009 +0000 @@ -62,6 +62,7 @@ libpurple/plugins/mono/loader/mono.c libpurple/plugins/newline.c libpurple/plugins/offlinemsg.c +libpurple/plugins/one_time_password.c libpurple/plugins/perl/perl.c libpurple/plugins/psychic.c libpurple/plugins/signals-test.c @@ -165,7 +166,6 @@ libpurple/protocols/silc10/util.c libpurple/protocols/silc10/wb.c libpurple/protocols/simple/simple.c -libpurple/protocols/toc/toc.c libpurple/protocols/yahoo/yahoo.c libpurple/protocols/yahoo/yahoo_doodle.c libpurple/protocols/yahoo/yahoo_filexfer.c diff -r 9407348dc714 -r ea0494a3a299 po/de.po --- a/po/de.po Mon Mar 16 21:45:24 2009 +0000 +++ b/po/de.po Sat Mar 28 16:59:30 2009 +0000 @@ -11,8 +11,8 @@ msgstr "" "Project-Id-Version: de\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-02-25 17:28+0100\n" -"PO-Revision-Date: 2009-02-25 17:28+0100\n" +"POT-Creation-Date: 2009-03-28 16:59+0100\n" +"PO-Revision-Date: 2009-03-28 16:53+0100\n" "Last-Translator: Jochen Kemnade \n" "Language-Team: German \n" "MIME-Version: 1.0\n" @@ -2630,6 +2630,31 @@ msgid "Do not ask. Always save in pounce." msgstr "Nicht nachfragen. Immer als Alarm sichern." +msgid "One Time Password" +msgstr "" + +#. *< type +#. *< ui_requirement +#. *< flags +#. *< dependencies +#. *< priority +#. *< id +msgid "One Time Password Support" +msgstr "" + +#. *< name +#. *< version +#. * summary +msgid "Enforce that passwords are used only once." +msgstr "" + +#. * description +msgid "" +"Allows you to enforce on a per-account basis that passwords not being saved " +"are only used in a single successful connection.\n" +"Note: The account password must not be saved for this to work." +msgstr "" + #. *< type #. *< ui_requirement #. *< flags @@ -4440,16 +4465,24 @@ msgstr "Kann den Benutzer %s nicht anpingen" #, c-format -msgid "Unable to buzz, because there is nothing known about user %s." -msgstr "Kann nicht anklopfen, da nichts über den Benutzer %s bekannt ist." - -#, c-format -msgid "Unable to buzz, because user %s might be offline." -msgstr "Kann nicht anklopfen, da der Benutzer %s vielleicht offline ist." - -#, c-format -msgid "Unable to buzz, because the user %s does not support it." -msgstr "Kann nicht anklopfen, da der Benutzer %s dies nicht unterstützt." +msgid "Unable to buzz, because there is nothing known about %s." +msgstr "Kann nicht anklopfen, da nichts über %s bekannt ist." + +#, c-format +msgid "Unable to buzz, because %s might be offline." +msgstr "Kann nicht anklopfen, da %s vielleicht offline ist." + +#, c-format +msgid "" +"Unable to buzz, because %s does not support it or does not wish to receive " +"buzzes now." +msgstr "" +"Kann nicht anklopfen, da %s dies nicht unterstützt oder im Moment nicht " +"möchte." + +#, c-format +msgid "Buzzing %s..." +msgstr "%s anklopfen..." #. Yahoo only supports one attention command: the 'buzz'. #. This is index number YAHOO_BUZZ. @@ -4460,10 +4493,6 @@ msgid "%s has buzzed you!" msgstr "%s hat bei Ihnen angeklopft!" -#, c-format -msgid "Buzzing %s..." -msgstr "%s anklopfen..." - msgid "config: Configure a chat room." msgstr "config: Konfiguriere einen Chatraum." @@ -4618,6 +4647,19 @@ msgid "Error in chat %s" msgstr "Fehler im Chat %s" +#, fuzzy +msgid "An error occured on the in-band bytestream transfer\n" +msgstr "Beim Öffnen der Datei trat ein Fehler auf." + +msgid "Transfer was closed." +msgstr "Übertragung wurde geschlossen" + +msgid "Failed to open the file" +msgstr "Öffnen der Datei fehlgeschlagen" + +msgid "Failed to open in-band bytestream" +msgstr "" + #, c-format msgid "Unable to send file to %s, user does not support file transfers" msgstr "" @@ -6435,7 +6477,7 @@ "sein oder mit einem Buchstaben beginnen und nur Buchstaben, Ziffern und " "Leerzeichen enthalten oder nur aus Ziffern bestehen." -#. Unregistered screen name +#. Unregistered username #. uid is not exist msgid "Invalid username." msgstr "Ungültiger Benutzername." @@ -6451,7 +6493,7 @@ msgid "The AOL Instant Messenger service is temporarily unavailable." msgstr "Der AOL-Sofortnachrichtendienst ist zur Zeit nicht erreichbar." -#. screen name connecting too frequently +#. username connecting too frequently #. IP address connecting too frequently msgid "" "You have been connecting and disconnecting too frequently. Wait ten minutes " @@ -6652,7 +6694,7 @@ msgstr[1] "" "Sie haben %hu Nachrichten von %s aus unbekannten Gründen nicht erhalten." -#. Data is assumed to be the destination sn +#. Data is assumed to be the destination bn #, c-format msgid "Unable to send message: %s" msgstr "Kann die Nachricht nicht senden: %s" @@ -7253,6 +7295,36 @@ msgid "Could not change buddy information." msgstr "Konnte Buddy-Informationen nicht bearbeiten." +msgid "Mobile" +msgstr "Mobil" + +msgid "Note" +msgstr "Bemerkung" + +#. callback +msgid "Buddy Memo" +msgstr "Buddy-Notiz" + +msgid "Change his/her memo as you like" +msgstr "" + +#, fuzzy +msgid "_Modify" +msgstr "Bearbeiten" + +#, fuzzy +msgid "Memo Modify" +msgstr "Bearbeiten" + +msgid "Server says:" +msgstr "Server meldet:" + +msgid "Your request was accepted." +msgstr "Ihre Anfrage wurde akzeptiert." + +msgid "Your request was rejected." +msgstr "Ihre Anfrage wurde abgelehnt." + #, c-format msgid "%u requires verification" msgstr "%u erfordert Autorisierung" @@ -7701,7 +7773,6 @@ "Unbekannte Antwort bei der Anmeldung (0x%02X):\n" "%s" -#. we didn't successfully connect. tdt->toc_fd is valid here msgid "Unable to connect." msgstr "Verbindung nicht möglich." @@ -8613,9 +8684,6 @@ msgid "Unit" msgstr "Abteilung" -msgid "Note" -msgstr "Bemerkung" - msgid "Join Chat" msgstr "Chat betreten" @@ -9309,188 +9377,13 @@ msgstr "Auth-Domain" #, c-format -msgid "Looking up %s" -msgstr "Suche nach %s" - -#, c-format -msgid "Connect to %s failed" -msgstr "Verbindung mit %s fehlgeschlagen" - -#, c-format -msgid "Signon: %s" -msgstr "Anmeldung: %s" - -#, c-format -msgid "Unable to write file %s." -msgstr "Datei %s konnte nicht geschrieben werden." - -#, c-format -msgid "Unable to read file %s." -msgstr "Datei %s konnte nicht gelesen werden." - -#, c-format -msgid "Message too long, last %s bytes truncated." -msgstr "Nachricht zu lange, letzten %s Bytes abgeschnitten." - -#, c-format -msgid "%s not currently logged in." -msgstr "%s ist zur Zeit nicht online." - -#, c-format -msgid "Warning of %s not allowed." -msgstr "Verwarnung von %s nicht erlaubt." - -msgid "A message has been dropped, you are exceeding the server speed limit." -msgstr "" -"Eine Nachricht ging verloren. Sie überschreiten die Geschwindigkeitsgrenze " -"des Servers." - -#, c-format -msgid "Chat in %s is not available." -msgstr "Chat in %s ist nicht verfügbar." - -#, c-format -msgid "You are sending messages too fast to %s." -msgstr "Sie verschicken die Nachrichten an %s zu schnell." - -#, c-format -msgid "You missed an IM from %s because it was too big." -msgstr "Eine Nachricht von %s hat Sie nicht erreicht, da sie zu groß war." - -#, c-format -msgid "You missed an IM from %s because it was sent too fast." -msgstr "" -"Eine Nachricht von %s hat Sie nicht erreicht, da sie zu schnell gesendet " -"wurde." - -msgid "Failure." -msgstr "Fehler." - -msgid "Too many matches." -msgstr "Zu viele Übereinstimmungen." - -msgid "Need more qualifiers." -msgstr "Benötige mehr Angaben." - -msgid "Dir service temporarily unavailable." -msgstr "Verzeichnis-Dienst ist zur Zeit nicht verfügbar." - -msgid "Email lookup restricted." -msgstr "E-Mail-Suche eingeschränkt." - -msgid "Keyword ignored." -msgstr "Stichwort ignoriert." - -msgid "No keywords." -msgstr "Keine Stichwörter." - -msgid "User has no directory information." -msgstr "Der Benutzer hat kein Profil." - -msgid "Country not supported." -msgstr "Land nicht unterstützt." - -#, c-format -msgid "Failure unknown: %s." -msgstr "Unbekannter Fehler: %s." - -msgid "Incorrect username or password." -msgstr "Ungültiger Benutzername oder Passwort." - -msgid "The service is temporarily unavailable." -msgstr "Der Dienst ist zur Zeit nicht verfügbar." - -msgid "Your warning level is currently too high to log in." -msgstr "Ihre Warnstufe ist zur Zeit zu hoch, um sich anzumelden." - -msgid "" -"You have been connecting and disconnecting too frequently. Wait ten minutes " -"and try again. If you continue to try, you will need to wait even longer." -msgstr "" -"Sie haben Sich zu schnell an- und abgemeldet. Warten Sie 10 Minuten und " -"versuchen Sie es erneut. Wenn Sie es weiter versuchen, werden sie noch " -"länger warten müssen." - -#, c-format -msgid "An unknown signon error has occurred: %s." -msgstr "Unbekannter Anmeldungsfehler: %s." - -#, c-format -msgid "An unknown error, %d, has occurred. Info: %s" -msgstr "Unbekannter Fehler '%d' aufgetreten. Info: %s" - -msgid "Invalid Groupname" -msgstr "Ungültiger Gruppenname" - -msgid "Connection Closed" -msgstr "Verbindung geschlossen" - -msgid "Waiting for reply..." -msgstr "Warte auf Antwort..." - -msgid "TOC has come back from its pause. You may now send messages again." -msgstr "" -"TOC ist von seiner Pause zurückgekehrt. Sie können wieder Nachrichten senden." - -msgid "Password Change Successful" -msgstr "Passwortänderung erfolgreich" - -msgid "_Group:" -msgstr "_Gruppe:" - -msgid "Get Dir Info" -msgstr "Verzeichnisinformation abrufen" - -msgid "Set Dir Info" -msgstr "Verzeichnisinformation abrufen" - -#, c-format -msgid "Could not open %s for writing!" -msgstr "Kann %s nicht zum Schreiben öffnen!" - -msgid "File transfer failed; other side probably canceled." -msgstr "" -"Dateiübertragung gescheitert; die andere Seite hat die Dateiübertragung " -"wahrscheinlich abgebrochen." - -msgid "Could not connect for transfer." -msgstr "Übertragungsverbindung konnte nicht hergestellt werden." - -msgid "Could not write file header. The file will not be transferred." -msgstr "" -"Konnte keinen Datei-Header schreiben. Die Datei wurde nicht übermittelt." - -msgid "Save As..." -msgstr "Speichern unter..." - -#, c-format -msgid "%s requests %s to accept %d file: %s (%.2f %s)%s%s" -msgid_plural "%s requests %s to accept %d files: %s (%.2f %s)%s%s" -msgstr[0] "%s bittet %s %d Datei zu akzeptieren: %s (%.2f %s)%s%s" -msgstr[1] "%s bittet %s %d Dateien zu akzeptieren: %s (%.2f %s)%s%s" - -#, c-format -msgid "%s requests you to send them a file" -msgstr "%s bittet Sie eine Datei zu senden" - -#. *< type -#. *< ui_requirement -#. *< flags -#. *< dependencies -#. *< priority -#. *< id -#. *< name -#. *< version -#. * summary -#. * description -msgid "TOC Protocol Plugin" -msgstr "TOC-Protokoll-Plugin" - -#, c-format msgid "%s has sent you a webcam invite, which is not yet supported." msgstr "" "%s hat Ihnen eine Webcam-Einladung gesendet, die noch nicht unterstützt wird." +msgid "Your SMS was not delivered" +msgstr "Ihre SMS wurde nicht ausgeliefert" + msgid "Your Yahoo! message did not get sent." msgstr "Ihre Yahoo!-Nachricht wurde nicht verschickt." @@ -10099,9 +9992,6 @@ msgid "Extended away" msgstr "Abwesend (erweitert)" -msgid "Mobile" -msgstr "Mobil" - msgid "Listening to music" msgstr "Musik hören" @@ -10143,18 +10033,6 @@ msgid "%x %X" msgstr "%x %X" -#, c-format -msgid "Error Reading %s" -msgstr "Fehler beim Lesen von %s" - -#, c-format -msgid "" -"An error was encountered reading your %s. They have not been loaded, and " -"the old file has been renamed to %s~." -msgstr "" -"Beim Einlesen Ihrer %s trat ein Fehler auf. Die Liste wurde nicht geladen " -"und die alte Datei wurde in %s~ umbenannt." - msgid "Calculating..." msgstr "Berechne..." @@ -10230,6 +10108,14 @@ msgstr "Verbindung zu %s nicht möglich: %s" #, c-format +msgid "" +"Unable to connect to %s: Server requires TLS/SSL, but no TLS/SSL support was " +"found." +msgstr "" +"Verbindung zu %s fehlgeschlagen: Der Server verlangt TLS/SSL, es wurde " +"jedoch kein TLS/SSL-Support gefunden." + +#, c-format msgid " - %s" msgstr " - %s" @@ -10259,6 +10145,18 @@ msgid "Address already in use." msgstr "Adresse wird bereits benutzt." +#, c-format +msgid "Error Reading %s" +msgstr "Fehler beim Lesen von %s" + +#, c-format +msgid "" +"An error was encountered reading your %s. The file has not been loaded, and " +"the old file has been renamed to %s~." +msgstr "" +"Beim Einlesen Ihrer %s trat ein Fehler auf. Die Datei wurde nicht geladen " +"und die alte Datei wurde in %s~ umbenannt." + msgid "Internet Messenger" msgstr "Internet-Sofortnachrichtendienst" @@ -10301,10 +10199,8 @@ msgid "Use this buddy _icon for this account:" msgstr "Dieses Buddy-_Icon für dieses Konto benutzen:" -#. Build the protocol options frame. -#, c-format -msgid "%s Options" -msgstr "%s Einstellungen" +msgid "_Advanced" +msgstr "E_rweitert" msgid "Use GNOME Proxy Settings" msgstr "Benutze GNOME-Proxy-Einstellungen" @@ -10339,9 +10235,6 @@ msgid "you can see the butterflies mating" msgstr "Sie können den Schmetterlingen beim Paaren zusehen" -msgid "Proxy Options" -msgstr "Proxy-Optionen" - msgid "Proxy _type:" msgstr "Proxy-_Typ:" @@ -10369,8 +10262,8 @@ msgid "Create _this new account on the server" msgstr "Dieses _neue Konto auf dem Server anlegen" -msgid "_Advanced" -msgstr "_Erweitert" +msgid "_Proxy" +msgstr "Pr_oxy" # Aktiv msgid "Enabled" @@ -10588,6 +10481,9 @@ msgid "/Tools/_Certificates" msgstr "/Werkzeuge/_Zertifikate" +msgid "/Tools/Custom Smile_ys" +msgstr "/Werkzeuge/Benutzerdefinierte Smile_ys" + msgid "/Tools/Plu_gins" msgstr "/Werkzeuge/Plu_gins" @@ -10597,9 +10493,6 @@ msgid "/Tools/Pr_ivacy" msgstr "/Werkzeuge/Pri_vatsphäre" -msgid "/Tools/Smile_y" -msgstr "/Werkzeuge/Smile_y" - msgid "/Tools/_File Transfers" msgstr "/Werkzeuge/_Dateiübertragungen" @@ -10717,8 +10610,8 @@ msgid "By status" msgstr "Nach Status" -msgid "By log size" -msgstr "Nach Größe der Logs" +msgid "By recent log activity" +msgstr "Nach letzter Mitschnitts-Aktivität" #, c-format msgid "%s disconnected" @@ -10734,6 +10627,9 @@ msgid "Re-enable" msgstr "Reaktivieren" +msgid "SSL FAQs" +msgstr "SSL-FAQs" + msgid "Welcome back!" msgstr "Willkommen zurück!" @@ -10824,6 +10720,9 @@ msgid "A_lias:" msgstr "A_lias:" +msgid "_Group:" +msgstr "_Gruppe:" + msgid "Auto_join when account becomes online." msgstr "Automatisch _beitreten, wenn das Konto online geht." @@ -11352,6 +11251,9 @@ msgid "Ubuntu Georgian Translators" msgstr "Ubuntu-Georgisch-Übersetzer" +msgid "Khmer" +msgstr "Khmer" + msgid "Kannada" msgstr "Kannada" @@ -11825,15 +11727,6 @@ msgid "Enable typing notification" msgstr "Tipp-Benachrichtigung aktivieren" -msgid "_Copy Email Address" -msgstr "Kopiere _E-Mail-Adresse" - -msgid "_Open Link in Browser" -msgstr "Ö_ffne Link im Browser" - -msgid "_Copy Link Location" -msgstr "_Kopiere den Link" - msgid "" "Unrecognized file type\n" "\n" @@ -12086,6 +11979,7 @@ "\n" " -c, --config=DIR use DIR for config files\n" " -d, --debug print debugging messages to stdout\n" +" -f, --force-online force online, regardless of network status\n" " -h, --help display this help and exit\n" " -m, --multiple do not ensure single instance\n" " -n, --nologin don't automatically login\n" @@ -12100,6 +11994,7 @@ "\n" " -c, --config=VERZ benutze VERZ als Konfigurationsverzeichnis\n" " -d, --debug gibt Debugging-Meldungen nach stdout aus\n" +" -f, --force-online online erzwingen, ungeachtet des Netzwerk-Status\n" " -h, --help zeigt diese Hilfe und beendet das Programm\n" " -m, --multiple mehrere Instanzen erlauben\n" " -n, --nologin nicht automatisch anmelden\n" @@ -12117,6 +12012,7 @@ "\n" " -c, --config=DIR use DIR for config files\n" " -d, --debug print debugging messages to stdout\n" +" -f, --force-online force online, regardless of network status\n" " -h, --help display this help and exit\n" " -m, --multiple do not ensure single instance\n" " -n, --nologin don't automatically login\n" @@ -12130,6 +12026,7 @@ "\n" " -c, --config=VERZ benutze VERZ als Konfigurationsverzeichnis\n" " -d, --debug gibt Debugging-Meldungen nach stdout aus\n" +" -f, --force-online online erzwingen, ungeachtet des Netzwerkstatus\n" " -h, --help zeigt diese Hilfe und beendet das Programm\n" " -m, --multiple mehrere Instanzen erlauben\n" " -n, --nologin nicht automatisch anmelden\n" @@ -12176,12 +12073,6 @@ msgid "Exiting because another libpurple client is already running.\n" msgstr "Wird geschlossen, da bereits ein anderer libpurple-Client läuft\n" -msgid "Open All Messages" -msgstr "Alle Nachrichten öffnen" - -msgid "You have mail!" -msgstr "Sie haben Post!" - #, c-format msgid "%s has %d new message." msgid_plural "%s has %d new messages." @@ -12210,6 +12101,24 @@ msgstr "" "Das benutzerdefinierte Browserkommando wurde ausgewählt, aber nicht gesetzt." +msgid "Open All Messages" +msgstr "Alle Nachrichten öffnen" + +msgid "You have mail!" +msgstr "Sie haben Post!" + +msgid "New Pounces" +msgstr "Neuer Alarm" + +msgid "Dismiss" +msgstr "Verwerfen" + +msgid "You have pounced!" +msgstr "Sie haben geklopft!" + +msgid "No message" +msgstr "Keine Nachricht" + msgid "The following plugins will be unloaded." msgstr "Die folgenden Plugins werden entladen." @@ -12258,6 +12167,9 @@ msgid "Select a file" msgstr "Wählen Sie eine Datei" +msgid "Modify Buddy Pounce" +msgstr "Buddy-Alarm bearbeiten" + #. Create the "Pounce on Whom" frame. msgid "Pounce on Whom" msgstr "Bei wem alarmieren" @@ -12328,6 +12240,49 @@ msgid "Pounce Target" msgstr "Alarm-Ziel" +#, fuzzy +msgid "Started typing" +msgstr "zu tippen beginnt" + +#, fuzzy +msgid "Paused while typing" +msgstr "beim Tippen anhält" + +#, fuzzy +msgid "Signed on" +msgstr "sich anmeldet" + +#, fuzzy +msgid "Returned from being idle" +msgstr "%s ist nicht mehr inaktiv (%s)" + +#, fuzzy +msgid "Returned from being away" +msgstr "wieder anwesend ist" + +#, fuzzy +msgid "Stopped typing" +msgstr "Tippen gestoppt" + +#, fuzzy +msgid "Signed off" +msgstr "sich abmeldet" + +#, fuzzy +msgid "Became idle" +msgstr "untätig wird" + +#, fuzzy +msgid "Went away" +msgstr "Bei Abwesenheit" + +#, fuzzy +msgid "Sent a message" +msgstr "Eine Nachricht senden" + +msgid "Unknown.... Please report this!" +msgstr "Unbekannt.... Bitte berichten Sie dieses Problem!" + msgid "Smiley theme failed to unpack." msgstr "Smiley-Thema konnte nicht entpackt werden." @@ -12350,6 +12305,11 @@ msgid "Cl_ose conversations with the Escape key" msgstr "_Schließe Gespräche mit der Escape-Taste" +#. Buddy List Themes +msgid "Buddy List Theme" +msgstr "Buddy-Listen-Thema" + +#. System Tray msgid "System Tray Icon" msgstr "Kontrollleisten-Icon" @@ -12671,12 +12631,12 @@ msgid "Auto-away" msgstr "Automatisch abwesend" +msgid "_Minutes before becoming idle:" +msgstr "_Minuten, bevor auf abwesend gesetzt wird:" + msgid "Change status when _idle" msgstr "Ändere Status, wenn _inaktiv" -msgid "_Minutes before becoming idle:" -msgstr "_Minuten, bevor auf abwesend gesetzt wird:" - msgid "Change _status to:" msgstr "Ändere _Status zu:" @@ -12833,6 +12793,12 @@ msgid "Status for %s" msgstr "Status für %s" +#. +#. * TODO: We should enable/disable the add button based on +#. * whether the user has entered all required data. That +#. * would eliminate the need for this check and provide a +#. * better user experience. +#. msgid "Custom Smiley" msgstr "Benutzerdefinierter Smiley" @@ -12842,16 +12808,16 @@ msgid "Please provide a shortcut to associate with the smiley." msgstr "Bitte geben Sie eine Tastenkombination für den Smiley an." +#, c-format +msgid "" +"A custom smiley for '%s' already exists. Please use a different shortcut." +msgstr "" +"Für '%s' existiert bereits ein benutzerdefinierter Smiley. Bitten wählen Sie " +"eine andere Tastenkombination." + msgid "Duplicate Shortcut" msgstr "Doppelte Tastenkombination" -msgid "" -"A custom smiley for the selected shortcut already exists. Please specify a " -"different shortcut." -msgstr "" -"Für diese Tastenkombination existiert bereits ein benutzerdefinierter " -"Smiley. Bitten wählen Sie eine andere Tastenkombination." - msgid "Please select an image for the smiley." msgstr "Bitte wählen Sie ein Bild für den Smiley." @@ -12861,16 +12827,21 @@ msgid "Add Smiley" msgstr "Smiley hinzufügen" -msgid "Smiley _Image" -msgstr "Smiley-_Bild" - -#. Smiley shortcut -msgid "Smiley S_hortcut" -msgstr "_Tastenkombination" +msgid "_Image:" +msgstr "_Bild:" + +#. Shortcut text +#, fuzzy +msgid "S_hortcut text:" +msgstr "Tastenkombination" msgid "Smiley" msgstr "Smiley" +#, fuzzy +msgid "Shortcut Text" +msgstr "Tastenkombination" + msgid "Custom Smiley Manager" msgstr "Verwaltung für benutzerdefinierte Smileys" @@ -12996,6 +12967,15 @@ "Bild '%s' konnte nicht geladen werden: Grund unbekannt, vermutlich eine " "korrupte Bilddatei" +msgid "_Open Link" +msgstr "Ö_ffne Link" + +msgid "_Copy Link Location" +msgstr "_Kopiere den Link" + +msgid "_Copy Email Address" +msgstr "Kopiere _E-Mail-Adresse" + msgid "Save File" msgstr "Datei speichern" @@ -14023,6 +14003,3 @@ msgid "This plugin is useful for debbuging XMPP servers or clients." msgstr "" "Dieses Plugin ist nützlich zur Fehlersuche in XMPP-Servern oder -Clients." - -#~ msgid "Unable to retrieve MSN Address Book" -#~ msgstr "Konnte das MSN-Adressbuch nicht abrufen"