summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Aurich <darkrain42@pidgin.im>2009-04-20 00:05:54 +0000
committerPaul Aurich <darkrain42@pidgin.im>2009-04-20 00:05:54 +0000
commit36dd1e0e6b94fb3962080f9edfd4d5274acf1ec0 (patch)
treec7cac074ea0fbf0eaf66996eb6b595b8335cb5c4
parentb689705f25d61a99845317e8513e2c07d27d4a7d (diff)
parent9875bc4dea461732b3c3af4ff9974ac3997a635a (diff)
downloadpidgin-36dd1e0e6b94fb3962080f9edfd4d5274acf1ec0.tar.gz
merge of 'f82baafeefe310f7f70ffa19015ffcc5946e3b8f'
and '7e9d04aa7778a51f51fda71343c3116e4a2dc04a'
-rw-r--r--COPYRIGHT1
-rw-r--r--ChangeLog18
-rw-r--r--ChangeLog.API11
-rw-r--r--configure.ac4
-rw-r--r--doc/account-signals.dox2
-rw-r--r--finch/gntblist.c10
-rw-r--r--finch/gntlog.c2
-rw-r--r--finch/gntplugin.c4
-rw-r--r--finch/gntroomlist.c2
-rw-r--r--libpurple/account.h3
-rw-r--r--libpurple/blist.h52
-rw-r--r--libpurple/circbuffer.c3
-rw-r--r--libpurple/desktopitem.c6
-rw-r--r--libpurple/dnssrv.c2
-rw-r--r--libpurple/ntlm.c87
-rw-r--r--libpurple/plugins/mono/loader/debug-glue.c2
-rw-r--r--libpurple/plugins/mono/loader/mono.c21
-rw-r--r--libpurple/protocols/Makefile.am2
-rw-r--r--libpurple/protocols/bonjour/mdns_win32.c15
-rw-r--r--libpurple/protocols/bonjour/parser.c11
-rw-r--r--libpurple/protocols/irc/irc.c2
-rw-r--r--libpurple/protocols/irc/irc.h2
-rw-r--r--libpurple/protocols/irc/msgs.c10
-rw-r--r--libpurple/protocols/jabber/buddy.c50
-rw-r--r--libpurple/protocols/jabber/parser.c4
-rw-r--r--libpurple/protocols/jabber/si.c26
-rw-r--r--libpurple/protocols/jabber/xdata.c7
-rw-r--r--libpurple/protocols/msn/cmdproc.c4
-rw-r--r--libpurple/protocols/msn/contact.c77
-rw-r--r--libpurple/protocols/msn/contact.h16
-rw-r--r--libpurple/protocols/msn/notification.c18
-rw-r--r--libpurple/protocols/msn/oim.c4
-rw-r--r--libpurple/protocols/msn/session.h1
-rw-r--r--libpurple/protocols/msn/soap.c1
-rw-r--r--libpurple/protocols/msn/state.c4
-rw-r--r--libpurple/protocols/msn/switchboard.c2
-rw-r--r--libpurple/protocols/msn/userlist.c4
-rw-r--r--libpurple/protocols/myspace/myspace.c11
-rw-r--r--libpurple/protocols/myspace/user.c9
-rw-r--r--libpurple/protocols/myspace/user.h2
-rw-r--r--libpurple/protocols/novell/nmmessage.c1
-rw-r--r--libpurple/protocols/novell/novell.c6
-rw-r--r--libpurple/protocols/oscar/oscar.c32
-rw-r--r--libpurple/protocols/qq/buddy_list.c1
-rw-r--r--libpurple/protocols/silc/buddy.c7
-rw-r--r--libpurple/protocols/silc10/buddy.c7
-rw-r--r--libpurple/protocols/toc/Makefile.am32
-rw-r--r--libpurple/protocols/toc/Makefile.mingw78
-rw-r--r--libpurple/protocols/toc/PROTOCOL499
-rw-r--r--libpurple/protocols/toc/toc.c2340
-rw-r--r--libpurple/protocols/yahoo/yahoo_packet.c2
-rw-r--r--libpurple/prpl.h8
-rw-r--r--libpurple/smiley.h70
-rw-r--r--libpurple/tests/test_util.c8
-rw-r--r--libpurple/util.c13
-rw-r--r--libpurple/xmlnode.c68
-rw-r--r--libpurple/xmlnode.h20
-rw-r--r--pidgin/gtkaccount.c66
-rw-r--r--pidgin/gtkblist.c29
-rw-r--r--pidgin/gtkdialogs.c2
-rw-r--r--pidgin/gtknotify.c503
-rw-r--r--pidgin/gtknotify.h12
-rw-r--r--pidgin/gtkpounce.c40
-rw-r--r--pidgin/gtkprefs.c9
-rw-r--r--pidgin/gtkroomlist.c1
-rw-r--r--pidgin/gtkutils.c7
-rw-r--r--pidgin/plugins/gevolution/gevo-util.c8
-rw-r--r--pidgin/plugins/gevolution/gevolution.h2
-rw-r--r--pidgin/win32/untar.c4
-rw-r--r--po/POTFILES.in2
-rw-r--r--po/de.po495
71 files changed, 1179 insertions, 3705 deletions
diff --git a/COPYRIGHT b/COPYRIGHT
index c38b3f736b..613f8bf8a8 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -8,6 +8,7 @@ Saleem Abdulrasool
Dave Ahlswede
Manuel Amador
Matt Amato
+Josef Andrysek
Geoffrey Antos
Daniel Atallah
Paul Aurich
diff --git a/ChangeLog b/ChangeLog
index ef538d8b1c..bd2049464b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,10 +4,19 @@ version 2.6.0 (??/??/2009):
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).
+
+ IRC:
+ * Correctly handle WHOIS for users who are joined to a large number of
+ channels.
Pidgin:
* Added -f command line option to tell Pidgin to ignore NetworkManager
@@ -18,6 +27,11 @@ version 2.6.0 (??/??/2009):
* Pressing the Enter key in the message entry box of the New Status
dialog and various other dialogs now causes the cursor to move to
the next line.
+ * 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 --git a/ChangeLog.API b/ChangeLog.API
index ba94d7b728..6c49b978b8 100644
--- a/ChangeLog.API
+++ b/ChangeLog.API
@@ -26,6 +26,14 @@ version 2.6.0 (??/??/2009):
* purple_request_field_set_ui_data
* purple_strequal
* xmlnode_from_file
+ * xmlnode_set_attrib_full
+
+ 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.
Deprecated:
* purple_buddy_get_local_alias
@@ -40,6 +48,8 @@ version 2.6.0 (??/??/2009):
* purple_status_set_attr_string
* purple_presence_add_status
* purple_presence_add_list
+ * xmlnode_set_attrib_with_namespace
+ * xmlnode_set_attrib_with_prefix
pidgin:
Added:
@@ -52,6 +62,7 @@ version 2.6.0 (??/??/2009):
* pidgin_blist_get_theme
* pidgin_sound_is_customized
* pidgin_utils_init, pidgin_utils_uninit
+ * pidgin_notify_pounce_add
perl:
Changed:
diff --git a/configure.ac b/configure.ac
index 88de36f823..dd46c3ff9e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1048,7 +1048,6 @@ for i in $STATIC_PRPLS ; do
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_QQ, test "x$static_qq" = "xyes")
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 @@ for i in $DYNAMIC_PRPLS ; do
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 @@ AC_OUTPUT([Makefile
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 --git a/doc/account-signals.dox b/doc/account-signals.dox
index 5d24f2b53d..a3cc766cc9 100644
--- a/doc/account-signals.dox
+++ b/doc/account-signals.dox
@@ -109,7 +109,7 @@ void (*account_alias_changed)(PurpleAccount *account, const char *old);
@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 --git a/finch/gntblist.c b/finch/gntblist.c
index 949d5b76b0..0b4ff7f7bd 100644
--- a/finch/gntblist.c
+++ b/finch/gntblist.c
@@ -643,10 +643,14 @@ add_buddy_cb(void *data, PurpleRequestFields *allfields)
purple_blist_add_group(grp, NULL);
}
- /* XXX: Ask if there's already the same buddy in the same group (#4553) */
+ /* 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);
+ }
- buddy = purple_buddy_new(account, username, alias);
- purple_blist_add_buddy(buddy, NULL, grp, NULL);
purple_account_add_buddy(account, buddy);
}
diff --git a/finch/gntlog.c b/finch/gntlog.c
index 5593f73c87..9f6083a545 100644
--- a/finch/gntlog.c
+++ b/finch/gntlog.c
@@ -66,7 +66,7 @@ static guint log_viewer_hash(gconstpointer data)
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 --git a/finch/gntplugin.c b/finch/gntplugin.c
index 4c1127cbc2..7dd8e58cab 100644
--- a/finch/gntplugin.c
+++ b/finch/gntplugin.c
@@ -484,10 +484,10 @@ process_pref_frame(PurplePluginPrefFrame *frame)
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 --git a/finch/gntroomlist.c b/finch/gntroomlist.c
index bbaa3e7dad..89479a4310 100644
--- a/finch/gntroomlist.c
+++ b/finch/gntroomlist.c
@@ -190,7 +190,7 @@ roomlist_selection_changed(GntWidget *widget, gpointer old, gpointer current, gp
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 --git a/libpurple/account.h b/libpurple/account.h
index 7c6bfe9282..4d647546a9 100644
--- a/libpurple/account.h
+++ b/libpurple/account.h
@@ -42,6 +42,7 @@ typedef void (*PurpleAccountUnregistrationCb)(PurpleAccount *account, gboolean s
#include "connection.h"
#include "log.h"
+#include "privacy.h"
#include "proxy.h"
#include "prpl.h"
#include "status.h"
@@ -141,7 +142,7 @@ struct _PurpleAccount
*/
GSList *permit; /**< Permit list. */
GSList *deny; /**< Deny list. */
- int perm_deny; /**< The permit/deny setting. */
+ PurplePrivacyType perm_deny; /**< The permit/deny setting. */
GList *status_types; /**< Status types. */
diff --git a/libpurple/blist.h b/libpurple/blist.h
index 460291a886..1aaf021818 100644
--- a/libpurple/blist.h
+++ b/libpurple/blist.h
@@ -118,8 +118,8 @@ typedef enum
/**
* A Buddy list node. This can represent a group, a buddy, or anything else.
- * This is a base class for struct buddy and struct group and for anything
- * else that wants to put itself in the buddy list. */
+ * This is a base class for PurpleBuddy, PurpleContact, PurpleGroup, and for
+ * anything else that wants to put itself in the buddy list. */
struct _PurpleBlistNode {
PurpleBlistNodeType type; /**< The type of node this is */
PurpleBlistNode *prev; /**< The sibling before this buddy. */
@@ -207,7 +207,7 @@ struct _PurpleBlistUiOps
PurpleBlistNode *node); /**< This will update a node in the buddy list. */
void (*remove)(PurpleBuddyList *list,
PurpleBlistNode *node); /**< This removes a node from the list */
- void (*destroy)(PurpleBuddyList *list); /**< When the list gets destroyed, this gets called to destroy the UI. */
+ void (*destroy)(PurpleBuddyList *list); /**< When the list is destroyed, this is called to destroy the UI. */
void (*set_visible)(PurpleBuddyList *list,
gboolean show); /**< Hides or unhides the buddy list */
void (*request_add_buddy)(PurpleAccount *account, const char *username,
@@ -261,6 +261,11 @@ PurpleBlistNode *purple_blist_get_root(void);
/**
* Returns the hash table of every buddy in the list.
+ * You MUST treat this data structure as immutable. The only use should
+ * be for iterating over the values (PurpleBuddy*) in performance-critical
+ * code.
+ *
+ * @see purple_find_buddy for the recommended alternative.
*
* @return The hash table of every buddy in the list.
*
@@ -275,7 +280,7 @@ GHashTable *purple_blist_get_buddies(void);
*
* @since 2.6.0
*/
-void *purple_blist_get_ui_data(void);
+gpointer purple_blist_get_ui_data(void);
/**
* Sets the UI data for the list.
@@ -284,7 +289,7 @@ void *purple_blist_get_ui_data(void);
*
* @since 2.6.0
*/
-void purple_blist_set_ui_data(void *ui_data);
+void purple_blist_set_ui_data(gpointer ui_data);
/**
* Returns the next node of a given node. This function is to be used to iterate
@@ -359,7 +364,7 @@ PurpleBlistNode *purple_blist_node_get_sibling_prev(PurpleBlistNode *node);
* @return The UI data.
* @since 2.6.0
*/
-void *purple_blist_node_get_ui_data(const PurpleBlistNode *node);
+gpointer purple_blist_node_get_ui_data(const PurpleBlistNode *node);
/**
* Sets the UI data of a given node.
@@ -369,7 +374,7 @@ void *purple_blist_node_get_ui_data(const PurpleBlistNode *node);
*
* @since 2.6.0
*/
-void purple_blist_node_set_ui_data(PurpleBlistNode *node, void *ui_data);
+void purple_blist_node_set_ui_data(PurpleBlistNode *node, gpointer ui_data);
/**
* Shows the buddy list, creating a new one if necessary.
@@ -392,6 +397,8 @@ void purple_blist_set_visible(gboolean show);
/**
* Updates a buddy's status.
*
+ * This should only be called from within Purple.
+ *
* @param buddy The buddy whose status has changed.
* @param old_status The status from which we are changing.
*/
@@ -491,12 +498,19 @@ PurpleChat *purple_chat_new(PurpleAccount *account, const char *alias, GHashTabl
void purple_blist_add_chat(PurpleChat *chat, PurpleGroup *group, PurpleBlistNode *node);
/**
- * Creates a new buddy
+ * Creates a new buddy.
+ *
+ * This function only creates the PurpleBuddy. Use purple_blist_add_buddy
+ * to add the buddy to the list and purple_account_add_buddy to sync up
+ * with the server.
*
* @param account The account this buddy will get added to
* @param name The name of the new buddy
* @param alias The alias of the new buddy (or NULL if unaliased)
* @return A newly allocated buddy
+ *
+ * @see purple_account_add_buddy
+ * @see purple_blist_add_buddy
*/
PurpleBuddy *purple_buddy_new(PurpleAccount *account, const char *name, const char *alias);
@@ -595,7 +609,7 @@ PurplePresence *purple_buddy_get_presence(const PurpleBuddy *buddy);
* @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);
@@ -603,7 +617,7 @@ void purple_blist_add_buddy(PurpleBuddy *buddy, PurpleContact *contact, PurpleGr
* Creates a new group
*
* You can't have more than one group with the same name. Sorry. If you pass
- * this the * name of a group that already exists, it will return that group.
+ * this the name of a group that already exists, it will return that group.
*
* @param name The name of the new group
* @return A new group struct
@@ -698,19 +712,23 @@ void purple_contact_invalidate_priority_buddy(PurpleContact *contact);
/**
* Removes a buddy from the buddy list and frees the memory allocated to it.
- * This doesn't actually try to remove the buddy from the server list, nor does
- * it clean up the prpl_data.
+ * This doesn't actually try to remove the buddy from the server list.
*
* @param buddy The buddy to be removed
+ *
+ * @see purple_account_remove_buddy
*/
void purple_blist_remove_buddy(PurpleBuddy *buddy);
/**
* Removes a contact, and any buddies it contains, and frees the memory
- * allocated to it.
+ * allocated to it. This calls purple_blist_remove_buddy and therefore
+ * doesn't remove the buddies from the server list.
*
* @param contact The contact to be removed
- */
+ *
+ * @see purple_blist_remove_buddy
+ * */
void purple_blist_remove_contact(PurpleContact *contact);
/**
@@ -821,7 +839,7 @@ PurpleBuddy *purple_find_buddy_in_group(PurpleAccount *account, const char *name
* Finds all PurpleBuddy structs given a name and an account
*
* @param account The account this buddy belongs to
- * @param name The buddy's name (or NULL to return all buddies in the account)
+ * @param name The buddy's name (or NULL to return all buddies for the account)
*
* @return A GSList of buddies (which must be freed), or NULL if the buddy doesn't exist
*/
@@ -916,7 +934,7 @@ gboolean purple_group_on_account(PurpleGroup *g, PurpleAccount *account);
const char *purple_group_get_name(PurpleGroup *group);
/**
- * Called when an account gets signed on. Tells the UI to update all the
+ * Called when an account connects. Tells the UI to update all the
* buddies.
*
* @param account The account
@@ -925,7 +943,7 @@ void purple_blist_add_account(PurpleAccount *account);
/**
- * Called when an account gets signed off. Sets the presence of all the buddies to 0
+ * Called when an account disconnects. Sets the presence of all the buddies to 0
* and tells the UI to update them.
*
* @param account The account
diff --git a/libpurple/circbuffer.c b/libpurple/circbuffer.c
index 3c6af4301e..619d9c9758 100644
--- a/libpurple/circbuffer.c
+++ b/libpurple/circbuffer.c
@@ -68,7 +68,8 @@ static void grow_circ_buffer(PurpleCircBuffer *buf, gsize len) {
/* 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 --git a/libpurple/desktopitem.c b/libpurple/desktopitem.c
index 714a4b14e0..fa6d7340db 100644
--- a/libpurple/desktopitem.c
+++ b/libpurple/desktopitem.c
@@ -823,7 +823,11 @@ lookup_locale (const PurpleDesktopItem *item, const char *key, const char *local
}
}
-/* 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 --git a/libpurple/dnssrv.c b/libpurple/dnssrv.c
index 6fce86cc3d..cce7356793 100644
--- a/libpurple/dnssrv.c
+++ b/libpurple/dnssrv.c
@@ -175,9 +175,11 @@ resolve(int in, int out)
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 --git a/libpurple/ntlm.c b/libpurple/ntlm.c
index b7d3757e44..d551d02d2f 100644
--- a/libpurple/ntlm.c
+++ b/libpurple/ntlm.c
@@ -41,12 +41,12 @@ struct type1_message {
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 @@ struct type2_message {
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 @@ struct type3_message {
#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 @@ purple_ntlm_gen_type1(const gchar *hostname, const gchar *domain)
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 @@ purple_ntlm_parse_type2(const gchar *type2, guint32 *flags)
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 @@ purple_ntlm_gen_type3(const gchar *username, const gchar *passw, const gchar *ho
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 @@ purple_ntlm_gen_type3(const gchar *username, const gchar *passw, const gchar *ho
/* LCS Stuff */
if (flags) {
- tmsg->flags = 0x409082d4;
+ tmsg->flags = GUINT32_TO_LE(0x409082d4);
gensesskey(sesskey, NULL);
memcpy(tmp, sesskey, 0x10);
}
diff --git a/libpurple/plugins/mono/loader/debug-glue.c b/libpurple/plugins/mono/loader/debug-glue.c
index 01333521f8..fc07ca2289 100644
--- a/libpurple/plugins/mono/loader/debug-glue.c
+++ b/libpurple/plugins/mono/loader/debug-glue.c
@@ -9,7 +9,7 @@ void purple_debug_glue(int type, MonoString *cat, MonoString *str)
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 --git a/libpurple/plugins/mono/loader/mono.c b/libpurple/plugins/mono/loader/mono.c
index fe28bdd613..1f378e0901 100644
--- a/libpurple/plugins/mono/loader/mono.c
+++ b/libpurple/plugins/mono/loader/mono.c
@@ -39,18 +39,18 @@ static gboolean probe_mono_plugin(PurplePlugin *plugin)
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 @@ static gboolean probe_mono_plugin(PurplePlugin *plugin)
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 @@ static gboolean probe_mono_plugin(PurplePlugin *plugin)
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 @@ static gboolean probe_mono_plugin(PurplePlugin *plugin)
/* 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 PurplePluginInfo info =
static void init_plugin(PurplePlugin *plugin)
{
ml_init();
-
+
loader_info.exts = g_list_append(loader_info.exts, "dll");
}
diff --git a/libpurple/protocols/Makefile.am b/libpurple/protocols/Makefile.am
index c904076abb..97d1de9357 100644
--- a/libpurple/protocols/Makefile.am
+++ b/libpurple/protocols/Makefile.am
@@ -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 --git a/libpurple/protocols/bonjour/mdns_win32.c b/libpurple/protocols/bonjour/mdns_win32.c
index 10ee701e9f..fb94484020 100644
--- a/libpurple/protocols/bonjour/mdns_win32.c
+++ b/libpurple/protocols/bonjour/mdns_win32.c
@@ -169,14 +169,17 @@ _mdns_resolve_host_callback(GSList *hosts, gpointer data, const char *error_mess
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 --git a/libpurple/protocols/bonjour/parser.c b/libpurple/protocols/bonjour/parser.c
index 44a8e8bd99..04d6f10681 100644
--- a/libpurple/protocols/bonjour/parser.c
+++ b/libpurple/protocols/bonjour/parser.c
@@ -91,14 +91,12 @@ bonjour_parser_element_start_libxml(void *user_data,
xmlnode_set_namespace(node, (const char*) namespace);
for(i=0; i < nb_attributes * 5; i+=5) {
+ const char *name = (const char *)attributes[i];
+ const char *prefix = (const char *)attributes[i+1];
+ const char *attrib_ns = (const char *)attributes[i+2];
char *txt;
int attrib_len = attributes[i+4] - attributes[i+3];
char *attrib = g_malloc(attrib_len + 1);
- char *attrib_ns = NULL;
-
- if (attributes[i+2]) {
- attrib_ns = g_strdup((char*)attributes[i+2]);
- }
memcpy(attrib, attributes[i+3], attrib_len);
attrib[attrib_len] = '\0';
@@ -106,9 +104,8 @@ bonjour_parser_element_start_libxml(void *user_data,
txt = attrib;
attrib = purple_unescape_html(txt);
g_free(txt);
- xmlnode_set_attrib_with_namespace(node, (const char*) attributes[i], attrib_ns, attrib);
+ xmlnode_set_attrib_full(node, name, attrib_ns, prefix, attrib);
g_free(attrib);
- g_free(attrib_ns);
}
bconv->current = node;
diff --git a/libpurple/protocols/irc/irc.c b/libpurple/protocols/irc/irc.c
index 9721536931..7efd6622bb 100644
--- a/libpurple/protocols/irc/irc.c
+++ b/libpurple/protocols/irc/irc.c
@@ -565,7 +565,7 @@ static void irc_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup
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 --git a/libpurple/protocols/irc/irc.h b/libpurple/protocols/irc/irc.h
index 522405c246..09189c64fa 100644
--- a/libpurple/protocols/irc/irc.h
+++ b/libpurple/protocols/irc/irc.h
@@ -72,7 +72,7 @@ struct irc_conn {
char *name;
char *server;
char *serverinfo;
- char *channels;
+ GString *channels;
int ircop;
int identified;
int idle;
diff --git a/libpurple/protocols/irc/msgs.c b/libpurple/protocols/irc/msgs.c
index 81e107d0b1..dec148f9e7 100644
--- a/libpurple/protocols/irc/msgs.c
+++ b/libpurple/protocols/irc/msgs.c
@@ -336,7 +336,11 @@ void irc_msg_whois(struct irc_conn *irc, const char *name, const char *from, cha
if (args[3])
irc->whois.signon = (time_t)atoi(args[3]);
} else if (!strcmp(name, "319")) {
- irc->whois.channels = g_strdup(args[2]);
+ if (irc->whois.channels == NULL) {
+ irc->whois.channels = g_string_new(args[2]);
+ } else {
+ irc->whois.channels = g_string_append(irc->whois.channels, args[2]);
+ }
} else if (!strcmp(name, "320")) {
irc->whois.identified = 1;
}
@@ -391,8 +395,8 @@ void irc_msg_endwhois(struct irc_conn *irc, const char *name, const char *from,
g_free(irc->whois.serverinfo);
}
if (irc->whois.channels) {
- purple_notify_user_info_add_pair(user_info, _("Currently on"), irc->whois.channels);
- g_free(irc->whois.channels);
+ purple_notify_user_info_add_pair(user_info, _("Currently on"), irc->whois.channels->str);
+ g_string_free(irc->whois.channels, TRUE);
}
if (irc->whois.idle) {
gchar *timex = purple_str_seconds_to_string(irc->whois.idle);
diff --git a/libpurple/protocols/jabber/buddy.c b/libpurple/protocols/jabber/buddy.c
index 31f20c7e45..6f393ca4b4 100644
--- a/libpurple/protocols/jabber/buddy.c
+++ b/libpurple/protocols/jabber/buddy.c
@@ -301,36 +301,32 @@ const char *jabber_buddy_get_status_msg(JabberBuddy *jb)
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, "<A HREF=\"%s\">%s</A>"},
- {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", "<A HREF=\"mailto:%s\">%s</A>"},
- {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 --git a/libpurple/protocols/jabber/parser.c b/libpurple/protocols/jabber/parser.c
index 4e602768ce..35186ad15e 100644
--- a/libpurple/protocols/jabber/parser.c
+++ b/libpurple/protocols/jabber/parser.c
@@ -86,6 +86,8 @@ jabber_parser_element_start_libxml(void *user_data,
}
}
for(i=0; i < nb_attributes * 5; i+=5) {
+ const char *name = (const char *)attributes[i];
+ const char *prefix = (const char *)attributes[i+1];
const char *attrib_ns = (const char *)attributes[i+2];
char *txt;
int attrib_len = attributes[i+4] - attributes[i+3];
@@ -97,7 +99,7 @@ jabber_parser_element_start_libxml(void *user_data,
txt = attrib;
attrib = purple_unescape_html(txt);
g_free(txt);
- xmlnode_set_attrib_with_namespace(node, (const char*) attributes[i], attrib_ns, attrib);
+ xmlnode_set_attrib_full(node, name, attrib_ns, prefix, attrib);
g_free(attrib);
}
diff --git a/libpurple/protocols/jabber/si.c b/libpurple/protocols/jabber/si.c
index d4560a09ec..d5e050569f 100644
--- a/libpurple/protocols/jabber/si.c
+++ b/libpurple/protocols/jabber/si.c
@@ -1096,6 +1096,7 @@ jabber_si_xfer_ibb_send_data(JabberIBBSession *sess)
"jabber_si_xfer_ibb_send_data: error reading from file\n");
purple_xfer_cancel_local(xfer);
}
+ g_free(data);
}
static void
@@ -1661,23 +1662,22 @@ void jabber_si_parse(JabberStream *js, xmlnode *packet)
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);
- purple_xfer_set_filename(xfer, filename);
- if(filesize > 0)
- purple_xfer_set_size(xfer, filesize);
+ xfer->data = jsx;
- 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_filename(xfer, filename);
+ if(filesize > 0)
+ purple_xfer_set_size(xfer, filesize);
- js->file_transfers = g_list_append(js->file_transfers, xfer);
+ 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_request(xfer);
- }
+ js->file_transfers = g_list_append(js->file_transfers, xfer);
+
+ purple_xfer_request(xfer);
}
void
diff --git a/libpurple/protocols/jabber/xdata.c b/libpurple/protocols/jabber/xdata.c
index 1d2571c269..3a1914fc32 100644
--- a/libpurple/protocols/jabber/xdata.c
+++ b/libpurple/protocols/jabber/xdata.c
@@ -153,11 +153,12 @@ static void jabber_x_data_ok_cb(struct jabber_x_data_data *data, PurpleRequestFi
}
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 --git a/libpurple/protocols/msn/cmdproc.c b/libpurple/protocols/msn/cmdproc.c
index e487c77a66..49db28a3b3 100644
--- a/libpurple/protocols/msn/cmdproc.c
+++ b/libpurple/protocols/msn/cmdproc.c
@@ -117,8 +117,10 @@ msn_cmdproc_send_trans(MsnCmdProc *cmdproc, MsnTransaction *trans)
servconn = cmdproc->servconn;
- if (!servconn->connected)
+ if (!servconn->connected) {
+ /* TODO: Need to free trans */
return;
+ }
msn_history_add(cmdproc->history, trans);
diff --git a/libpurple/protocols/msn/contact.c b/libpurple/protocols/msn/contact.c
index 1310ce1b74..0e83a10242 100644
--- a/libpurple/protocols/msn/contact.c
+++ b/libpurple/protocols/msn/contact.c
@@ -697,25 +697,28 @@ msn_parse_addressbook_contacts(MsnSession *session, xmlnode *node)
/*TODO: need to support the Mobile type*/
continue;
}
- for (contactEmailNode = xmlnode_get_child(emailsNode, "ContactEmail"); contactEmailNode;
- contactEmailNode = xmlnode_get_next_twin(contactEmailNode)) {
- if (!(messengerEnabledNode = xmlnode_get_child(contactEmailNode, "isMessengerEnabled")))
- continue;
+ for (contactEmailNode = xmlnode_get_child(emailsNode, "ContactEmail");
+ contactEmailNode;
+ contactEmailNode = xmlnode_get_next_twin(contactEmailNode)) {
+ if ((messengerEnabledNode = xmlnode_get_child(contactEmailNode, "isMessengerEnabled"))) {
+
+ msnEnabled = xmlnode_get_data(messengerEnabledNode);
- msnEnabled = xmlnode_get_data(messengerEnabledNode);
+ if (msnEnabled && !strcmp(msnEnabled, "true")) {
+ if ((emailNode = xmlnode_get_child(contactEmailNode, "email")))
+ passport = xmlnode_get_data(emailNode);
- if (msnEnabled && !strcmp(msnEnabled, "true")) {
- if ((emailNode = xmlnode_get_child(contactEmailNode, "email")))
- passport = xmlnode_get_data(emailNode);
+ /* Messenger enabled, Get the Passport*/
+ purple_debug_info("msn", "AB Yahoo/Federated User %s\n", passport ? passport : "(null)");
+ g_free(msnEnabled);
+ break;
+ }
- /*Messenger enabled, Get the Passport*/
- purple_debug_info("msn", "AB Yahoo/Federated User %s\n", passport ? passport : "(null)");
g_free(msnEnabled);
- break;
}
-
- g_free(msnEnabled);
}
+ if (passport == NULL) /* Couldn't find anything */
+ continue;
} else {
xmlnode *messenger_user;
/* ignore non-messenger contacts */
@@ -1482,8 +1485,6 @@ msn_del_contact_from_list(MsnSession *session, MsnCallbackState *state,
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 +1502,28 @@ msn_del_contact_from_list(MsnSession *session, MsnCallbackState *state,
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 +1536,6 @@ msn_del_contact_from_list(MsnSession *session, MsnCallbackState *state,
state->cb = msn_del_contact_from_list_read_cb;
msn_contact_request(state);
- g_free(federate);
g_free(member);
g_free(body);
}
@@ -1578,8 +1583,6 @@ msn_add_contact_to_list(MsnSession *session, MsnCallbackState *state,
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 +1599,16 @@ msn_add_contact_to_list(MsnSession *session, MsnCallbackState *state,
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 +1620,6 @@ msn_add_contact_to_list(MsnSession *session, MsnCallbackState *state,
state->cb = msn_add_contact_to_list_read_cb;
msn_contact_request(state);
- g_free(federate);
g_free(member);
g_free(body);
}
diff --git a/libpurple/protocols/msn/contact.h b/libpurple/protocols/msn/contact.h
index 8c0f612f95..4a05ea555a 100644
--- a/libpurple/protocols/msn/contact.h
+++ b/libpurple/protocols/msn/contact.h
@@ -397,28 +397,18 @@
#define MSN_MEMBER_PASSPORT_XML \
"<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"%s\">"\
- "<Type>Passport</Type>"\
+ "<Type>%s</Type>"\
"<State>Accepted</State>"\
- "<PassportName>%s</PassportName>"\
- "%s"\
+ "<%s>%s</%s>"\
"</Member>"
#define MSN_MEMBER_MEMBERSHIPID_XML \
"<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"%s\">"\
- "<Type>Passport</Type>"\
+ "<Type>%s</Type>"\
"<MembershipId>%u</MembershipId>"\
"<State>Accepted</State>"\
- "%s"\
"</Member>"
-#define MSN_MEMBER_FEDERATED_ANNOTATION_XML \
- "<Annotations>"\
- "<Annotation>"\
- "<Name>MSN.IM.BuddyType</Name>"\
- "<Value>%02d:</Value>"\
- "</Annotation>"\
- "</Annotations>"
-
/* first delete contact from allow list */
#define MSN_CONTACT_DELETE_FROM_LIST_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\
diff --git a/libpurple/protocols/msn/notification.c b/libpurple/protocols/msn/notification.c
index d941e5f948..dfdceacd30 100644
--- a/libpurple/protocols/msn/notification.c
+++ b/libpurple/protocols/msn/notification.c
@@ -630,7 +630,7 @@ update_contact_network(MsnSession *session, const char *passport, MsnNetwork net
} 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 @@ msn_notification_dump_contact(MsnSession *session)
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 @@ msn_notification_dump_contact(MsnSession *session)
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 @@ msn_notification_dump_contact(MsnSession *session)
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 @@ adl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
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 @@ gcf_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
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 @@ ubx_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
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 --git a/libpurple/protocols/msn/oim.c b/libpurple/protocols/msn/oim.c
index 927c9376aa..9caaef8262 100644
--- a/libpurple/protocols/msn/oim.c
+++ b/libpurple/protocols/msn/oim.c
@@ -174,7 +174,7 @@ msn_oim_request_cb(MsnSoapMessage *request, MsnSoapMessage *response,
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 @@ msn_oim_request_cb(MsnSoapMessage *request, MsnSoapMessage *response,
} 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 --git a/libpurple/protocols/msn/session.h b/libpurple/protocols/msn/session.h
index 82c5a508e9..3fb42f1274 100644
--- a/libpurple/protocols/msn/session.h
+++ b/libpurple/protocols/msn/session.h
@@ -90,6 +90,7 @@ struct _MsnSession
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 --git a/libpurple/protocols/msn/soap.c b/libpurple/protocols/msn/soap.c
index b986562272..786e2f3a8e 100644
--- a/libpurple/protocols/msn/soap.c
+++ b/libpurple/protocols/msn/soap.c
@@ -667,6 +667,7 @@ msn_soap_connection_run(gpointer data)
conn->handled_len = 0;
conn->current_request = req;
+ purple_input_remove(conn->event_handle);
conn->event_handle = purple_input_add(conn->ssl->fd,
PURPLE_INPUT_WRITE, msn_soap_write_cb, conn);
if (!msn_soap_write_cb_internal(conn, conn->ssl->fd, PURPLE_INPUT_WRITE, TRUE)) {
diff --git a/libpurple/protocols/msn/state.c b/libpurple/protocols/msn/state.c
index e172d880bb..5a77a39999 100644
--- a/libpurple/protocols/msn/state.c
+++ b/libpurple/protocols/msn/state.c
@@ -169,7 +169,7 @@ msn_get_currentmedia(char *xml_str, gsize len)
}
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 @@ msn_get_psm(char *xml_str, gsize len)
}
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 --git a/libpurple/protocols/msn/switchboard.c b/libpurple/protocols/msn/switchboard.c
index 0ada2639d1..74fe0a43f3 100644
--- a/libpurple/protocols/msn/switchboard.c
+++ b/libpurple/protocols/msn/switchboard.c
@@ -590,7 +590,7 @@ release_msg(MsnSwitchBoard *swboard, MsnMessage *msg)
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 --git a/libpurple/protocols/msn/userlist.c b/libpurple/protocols/msn/userlist.c
index a98919d537..ba5cc831c2 100644
--- a/libpurple/protocols/msn/userlist.c
+++ b/libpurple/protocols/msn/userlist.c
@@ -858,7 +858,7 @@ msn_userlist_add_buddy_to_group(MsnUserList *userlist, const char *who,
}
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 @@ msn_userlist_rem_buddy_from_group(MsnUserList *userlist, const char *who,
}
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 --git a/libpurple/protocols/myspace/myspace.c b/libpurple/protocols/myspace/myspace.c
index 40ec871bd0..622bcf443b 100644
--- a/libpurple/protocols/myspace/myspace.c
+++ b/libpurple/protocols/myspace/myspace.c
@@ -388,7 +388,7 @@ msim_status_text(PurpleBuddy *buddy)
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 @@ msim_tooltip_text(PurpleBuddy *buddy, PurpleNotifyUserInfo *user_info,
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 @@ msim_add_contact_from_server_cb(MsimSession *session, const MsimMessage *user_lo
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 @@ msim_incoming_status(MsimSession *session, MsimMessage *msg)
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 @@ msim_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
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 --git a/libpurple/protocols/myspace/user.c b/libpurple/protocols/myspace/user.c
index bdd53d084c..4aa09ad08b 100644
--- a/libpurple/protocols/myspace/user.c
+++ b/libpurple/protocols/myspace/user.c
@@ -41,10 +41,10 @@ msim_format_now_playing(const gchar *band, const gchar *song)
}
/**
- * 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 @@ msim_get_user_from_buddy(PurpleBuddy *buddy)
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 @@ msim_find_user(MsimSession *session, const gchar *username)
return NULL;
}
- user = msim_get_user_from_buddy(buddy);
+ user = msim_get_user_from_buddy(buddy, TRUE);
return user;
}
diff --git a/libpurple/protocols/myspace/user.h b/libpurple/protocols/myspace/user.h
index 0f17b28c6d..d1a8b59970 100644
--- a/libpurple/protocols/myspace/user.h
+++ b/libpurple/protocols/myspace/user.h
@@ -46,7 +46,7 @@ typedef struct _MsimUser
* 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 --git a/libpurple/protocols/novell/nmmessage.c b/libpurple/protocols/novell/nmmessage.c
index aa67bfec47..70b00eed22 100644
--- a/libpurple/protocols/novell/nmmessage.c
+++ b/libpurple/protocols/novell/nmmessage.c
@@ -24,7 +24,6 @@ struct _NMMessage
{
NMConference *conference;
char *text;
- gpointer data;
guint32 ref_count;
};
diff --git a/libpurple/protocols/novell/novell.c b/libpurple/protocols/novell/novell.c
index 50ca789452..9107fee5de 100644
--- a/libpurple/protocols/novell/novell.c
+++ b/libpurple/protocols/novell/novell.c
@@ -2547,7 +2547,7 @@ novell_add_buddy(PurpleConnection * gc, PurpleBuddy *buddy, PurpleGroup * group)
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 @@ novell_add_buddy(PurpleConnection * gc, PurpleBuddy *buddy, PurpleGroup * group)
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 --git a/libpurple/protocols/oscar/oscar.c b/libpurple/protocols/oscar/oscar.c
index 4b8534e8bd..ba6769bd19 100644
--- a/libpurple/protocols/oscar/oscar.c
+++ b/libpurple/protocols/oscar/oscar.c
@@ -870,11 +870,11 @@ static void oscar_user_info_append_status(PurpleConnection *gc, PurpleNotifyUser
if (itmsurl) {
tmp = g_strdup_printf("<a href=\"%s\">%s</a>",
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));
@@ -4789,7 +4789,7 @@ oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *
status_html = purple_status_get_attr_string(status, "message");
- if (primitive == PURPLE_STATUS_AVAILABLE || primitive == PURPLE_STATUS_INVISIBLE)
+ if (status_html == NULL || primitive == PURPLE_STATUS_AVAILABLE || primitive == PURPLE_STATUS_INVISIBLE)
{
/* This is needed for us to un-set any previous away message. */
away = g_strdup("");
@@ -4847,6 +4847,7 @@ oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *
/* TODO: Combine these two calls! */
aim_srv_setextrainfo(od, FALSE, 0, TRUE, status_text, itmsurl);
oscar_set_extendedstatus(gc);
+ g_free(status_text);
}
}
@@ -4917,17 +4918,24 @@ oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {
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);
+ 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);
+ /* 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 --git a/libpurple/protocols/qq/buddy_list.c b/libpurple/protocols/qq/buddy_list.c
index e826354753..a1712f90a9 100644
--- a/libpurple/protocols/qq/buddy_list.c
+++ b/libpurple/protocols/qq/buddy_list.c
@@ -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 --git a/libpurple/protocols/silc/buddy.c b/libpurple/protocols/silc/buddy.c
index 7b2a055ff2..82972a6dc5 100644
--- a/libpurple/protocols/silc/buddy.c
+++ b/libpurple/protocols/silc/buddy.c
@@ -1397,7 +1397,12 @@ silcpurple_add_buddy_i(PurpleConnection *gc, PurpleBuddy *b, gboolean init)
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 --git a/libpurple/protocols/silc10/buddy.c b/libpurple/protocols/silc10/buddy.c
index 67e53f630f..5939ef40a0 100644
--- a/libpurple/protocols/silc10/buddy.c
+++ b/libpurple/protocols/silc10/buddy.c
@@ -1390,7 +1390,12 @@ silcpurple_add_buddy_i(PurpleConnection *gc, PurpleBuddy *b, gboolean init)
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 --git a/libpurple/protocols/toc/Makefile.am b/libpurple/protocols/toc/Makefile.am
deleted file mode 100644
index db41dfa9ad..0000000000
--- a/libpurple/protocols/toc/Makefile.am
+++ /dev/null
@@ -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 --git a/libpurple/protocols/toc/Makefile.mingw b/libpurple/protocols/toc/Makefile.mingw
deleted file mode 100644
index 4da3a3dc26..0000000000
--- a/libpurple/protocols/toc/Makefile.mingw
+++ /dev/null
@@ -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 --git a/libpurple/protocols/toc/PROTOCOL b/libpurple/protocols/toc/PROTOCOL
deleted file mode 100644
index 87672dd55f..0000000000
--- a/libpurple/protocols/toc/PROTOCOL
+++ /dev/null
@@ -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 <authorizer host> <authorizer port> <User Name> <Password>
- <language> <version>
- 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 <Destination User> <Message> [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 <Buddy User 1> [<Buddy User2> [<Buddy User 3> [...]]]
- Add buddies to your buddy list. This does not change your
- saved config.
-
-toc_remove_buddy <Buddy User 1> [<Buddy User2> [<Buddy User 3> [...]]]
- Remove buddies from your buddy list. This does not change your
- saved config.
-
-toc_set_config <Config Info>
- 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 <User> <norm|anon>
- 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 [ <User 1> [<User 2> [...]]]
- 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 [ <User 1> [<User 2> [...]]]
- 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 <Exchange> <Chat Room Name>
- 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 <Chat Room ID> <Message>
- 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 <Chat Room ID> <dst_user> <Message>
- 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 <Chat Room ID> <User> <norm|anon>
- 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 <Chat Room ID> <Invite Msg> <buddy1> [<buddy2> [<buddy3> [...]]]
- 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 <Chat Room ID>
- Leave the chat room.
-
-toc_chat_accept <Chat Room ID>
- Accept a CHAT_INVITE message from TOC. The server will send a
- CHAT_JOIN in response.
-
-toc_get_info <username>
- Gets a user's info a GOTO_URL or ERROR message will be sent back to the
- client.
-
-toc_set_info <info information>
- Set the LOCATE user information. This is basic HTML.
- Remember to encode the info.
-
-toc_set_away [<away message>]
- 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 <username>
- Gets a user's dir info a GOTO_URL or ERROR message will be sent back to the
- client.
-
-toc_set_dir <info information>
- 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 <info information>
- 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 <idle secs>
- Set idle information. If <idle secs> is 0 then the user isn't idle at all.
- If <idle secs> is greater then 0 then the user has already been idle
- for <idle secs> number of seconds. The server will automatically
- keep incrementing this number, so do not repeatedly call with new
- idle times.
-
-toc_set_caps [ <Capability 1> [<Capability 2> [...]]]
- 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 <nick> <cookie> <service> <tlvlist>
- Accept a rendezvous proposal from the user <nick>.
- <cookie> is the cookie from the RVOUS_PROPOSE
- message. <service> is the UUID the proposal was
- for. <tlvlist> contains a list of tlv tags followed by
- base64 encoded values.
-
-toc_rvous_cancel <nick> <cookie> <service> <tlvlist>
- Cancel a rendezvous proposal from the user <nick>.
- <cookie> is the cookie from the RVOUS_PROPOSE
- message. <service> is the UUID the proposal was
- for. <tlvlist> contains a list of tlv tags followed by
- base64 encoded values.
-
-toc_format_nickname <new_format>
- Reformat a user's nickname. An ADMIN_NICK_STATUS or ERROR message will
- be sent back to the client.
-
-toc_change_passwd <existing_passwd new_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 :<Message> should
-be considered part of the message (ie don't just "split" on colons,
-instead split with a max number of results.)
-
-
-SIGN_ON:<Client Version Supported>
- 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:<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:<Nickname>
- Tells you your correct nickname (ie how it should be capitalized and
- spacing)
-
-IM_IN:<Source User>:<Auto Response T/F?>:<Message>
- Receive an IM from some one. Everything after the third colon is
- the incoming message, including other colons.
-
-UPDATE_BUDDY:<Buddy User>:<Online? T/F>:<Evil Amount>:<Signon Time>:<IdleTime>:<UC>
- 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:<Error Code>: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:<new evil>:<name of eviler, blank if anonymous>
- The user was just eviled.
-
-CHAT_JOIN:<Chat Room Id>:<Chat Room Name>
- We were able to join this chat room. The Chat Room Id is
- internal to TOC.
-
-CHAT_IN:<Chat Room Id>:<Source User>:<Whisper? T/F>:<Message>
- A chat message was sent in a chat room.
-
-CHAT_UPDATE_BUDDY:<Chat Room Id>:<Inside? T/F>:<User 1>:<User 2>...
- 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:<Chat Room Name>:<Chat Room Id>:<Invite Sender>:<Message>
- We are being invited to a chat room.
-
-CHAT_LEFT:<Chat Room Id>
- Tells tic connection to chat room has been dropped
-
-GOTO_URL:<Window Name>:<Url>
- Goto a URL. Window Name is the suggested internal name of the window
- to use. (Java supports this.)
-
-DIR_STATUS:<Return Code>:<Optional args>
- <Return Code> is always 0 for success status.
-
-ADMIN_NICK_STATUS:<Return Code>:<Optional args>
- <Return Code> is always 0 for success status.
-
-ADMIN_PASSWD_STATUS:<Return Code>:<Optional args>
- <Return Code> is always 0 for success status.
-
-
-PAUSE
- Tells TIC to pause so we can do migration
-
-RVOUS_PROPOSE:<user>:<uuid>:<cookie>:<seq>:<rip>:<pip>:<vip>:<port>
- [:tlv tag1:tlv value1[:tlv tag2:tlv value2[:...]]]
- Another user has proposed that we rendezvous with them to
- perform the service specified by <uuid>. 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 --git a/libpurple/protocols/toc/toc.c b/libpurple/protocols/toc/toc.c
deleted file mode 100644
index e89a5d7bb0..0000000000
--- a/libpurple/protocols/toc/toc.c
+++ /dev/null
@@ -1,2340 +0,0 @@
-/*
- * purple
- *
- * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 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 <BR>, 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 --git a/libpurple/protocols/yahoo/yahoo_packet.c b/libpurple/protocols/yahoo/yahoo_packet.c
index c1226a4c44..86bb3c218b 100644
--- a/libpurple/protocols/yahoo/yahoo_packet.c
+++ b/libpurple/protocols/yahoo/yahoo_packet.c
@@ -201,6 +201,8 @@ void yahoo_packet_read(struct yahoo_packet *pkt, const guchar *data, int len)
}
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 --git a/libpurple/prpl.h b/libpurple/prpl.h
index c43e003759..1f9d5ac542 100644
--- a/libpurple/prpl.h
+++ b/libpurple/prpl.h
@@ -296,6 +296,14 @@ struct _PurplePluginProtocolInfo
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 --git a/libpurple/smiley.h b/libpurple/smiley.h
index ecb4385b6b..cfd2c0bb43 100644
--- a/libpurple/smiley.h
+++ b/libpurple/smiley.h
@@ -61,44 +61,41 @@ extern "C" {
/*@{*/
/**
- * GObject foo.
+ * GObject-fu.
* @internal.
*/
GType purple_smiley_get_type(void);
/**
- * Creates a new custom smiley structure and populates it.
+ * Creates a new custom smiley from a PurpleStoredImage.
*
- * If a custom smiley with the informed shortcut already exist, it
+ * If a custom smiley with the given shortcut already exists, it
* will be automaticaly returned.
*
* @param img The image associated with the smiley.
- * @param shortcut The custom smiley associated shortcut.
+ * @param shortcut The associated shortcut (e.g. "(homer)").
*
- * @return The custom smiley structure filled up.
+ * @return The custom smiley.
*/
PurpleSmiley *
purple_smiley_new(PurpleStoredImage *img, const char *shortcut);
/**
- * Creates a new custom smiley structure and populates it.
+ * Creates a new custom smiley, reading the image data from a file.
*
- * The data is retrieved from an already existent file.
- *
- * If a custom smiley with the informed shortcut already exist, it
+ * If a custom smiley with the given shortcut already exists, it
* will be automaticaly returned.
*
- * @param shortcut The custom smiley associated shortcut.
- * @param filepath The image file to be imported to a
- * new custom smiley.
+ * @param shortcut The associated shortcut (e.g. "(homer)").
+ * @param filepath The image file.
*
- * @return The custom smiley structure filled up.
+ * @return The custom smiley.
*/
PurpleSmiley *
purple_smiley_new_from_file(const char *shortcut, const char *filepath);
/**
- * Destroy the custom smiley and release the associated resources.
+ * Destroys the custom smiley and release the associated resources.
*
* @param smiley The custom smiley.
*/
@@ -109,32 +106,28 @@ purple_smiley_delete(PurpleSmiley *smiley);
* Changes the custom smiley's shortcut.
*
* @param smiley The custom smiley.
- * @param shortcut The custom smiley associated shortcut.
+ * @param shortcut The new shortcut. A custom smiley with this shortcut
+ * cannot already be in use.
*
- * @return TRUE whether the shortcut is not associated with another
- * custom smiley and the parameters are valid. FALSE otherwise.
+ * @return TRUE if the shortcut was changed. FALSE otherwise.
*/
gboolean
purple_smiley_set_shortcut(PurpleSmiley *smiley, const char *shortcut);
/**
- * Changes the custom smiley's data.
- *
- * When the filename controling is made outside this API, the param
- * #keepfilename must be TRUE.
- * Otherwise, the file and filename will be regenerated, and the
- * old one will be removed.
+ * Changes the custom smiley's image data.
*
* @param smiley The custom smiley.
- * @param smiley_data The custom smiley data.
- * @param smiley_data_len The custom smiley data length.
+ * @param smiley_data The custom smiley data, which the smiley code
+ * takes ownership of and will free.
+ * @param smiley_data_len The length of the data in @a smiley_data.
*/
void
purple_smiley_set_data(PurpleSmiley *smiley, guchar *smiley_data,
size_t smiley_data_len);
/**
- * Returns the custom smiley's associated shortcut.
+ * Returns the custom smiley's associated shortcut (e.g. "(homer)").
*
* @param smiley The custom smiley.
*
@@ -155,11 +148,11 @@ const char *purple_smiley_get_checksum(const PurpleSmiley *smiley);
* Returns the PurpleStoredImage with the reference counter incremented.
*
* The returned PurpleStoredImage reference counter must be decremented
- * after use.
+ * when the caller is done using it.
*
* @param smiley The custom smiley.
*
- * @return A PurpleStoredImage reference.
+ * @return A PurpleStoredImage.
*/
PurpleStoredImage *purple_smiley_get_stored_image(const PurpleSmiley *smiley);
@@ -167,7 +160,7 @@ PurpleStoredImage *purple_smiley_get_stored_image(const PurpleSmiley *smiley);
* Returns the custom smiley's data.
*
* @param smiley The custom smiley.
- * @param len If not @c NULL, the length of the icon data returned
+ * @param len If not @c NULL, the length of the image data returned
* will be set in the location pointed to by this.
*
* @return A pointer to the custom smiley data.
@@ -194,6 +187,8 @@ const char *purple_smiley_get_extension(const PurpleSmiley *smiley);
* directly. If you find yourself wanting to use this function, think
* very long and hard about it, and then don't.
*
+ * Think some more.
+ *
* @param smiley The custom smiley.
*
* @return A full path to the file, or @c NULL under various conditions.
@@ -210,7 +205,8 @@ char *purple_smiley_get_full_path(PurpleSmiley *smiley);
/*@{*/
/**
- * Returns a list of all custom smileys. The caller should free the list.
+ * Returns a list of all custom smileys. The caller is responsible for freeing
+ * the list.
*
* @return A list of all custom smileys.
*/
@@ -218,23 +214,21 @@ GList *
purple_smileys_get_all(void);
/**
- * Returns the custom smiley given it's shortcut.
+ * Returns a custom smiley given its shortcut.
*
* @param shortcut The custom smiley's shortcut.
*
- * @return The custom smiley (with a reference for the caller) if found,
- * or @c NULL if not found.
+ * @return The custom smiley if found, or @c NULL if not found.
*/
PurpleSmiley *
purple_smileys_find_by_shortcut(const char *shortcut);
/**
- * Returns the custom smiley given it's checksum.
+ * Returns a custom smiley given its checksum.
*
* @param checksum The custom smiley's checksum.
*
- * @return The custom smiley (with a reference for the caller) if found,
- * or @c NULL if not found.
+ * @return The custom smiley if found, or @c NULL if not found.
*/
PurpleSmiley *
purple_smileys_find_by_checksum(const char *checksum);
@@ -242,10 +236,10 @@ purple_smileys_find_by_checksum(const char *checksum);
/**
* Returns the directory used to store custom smiley cached files.
*
- * The default directory is PURPLEDIR/smileys, unless otherwise specified
+ * The default directory is PURPLEDIR/custom_smiley, unless otherwise specified
* by purple_buddy_icons_set_cache_dir().
*
- * @return The directory to store custom smyles cached files to.
+ * @return The directory in which to store custom smileys cached files.
*/
const char *purple_smileys_get_storing_dir(void);
diff --git a/libpurple/tests/test_util.c b/libpurple/tests/test_util.c
index de56591afb..9269e5e4ec 100644
--- a/libpurple/tests/test_util.c
+++ b/libpurple/tests/test_util.c
@@ -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 @@ START_TEST(test_util_base16_decode)
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 @@ START_TEST(test_util_base64_decode)
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 --git a/libpurple/util.c b/libpurple/util.c
index ac7598e317..90530589d3 100644
--- a/libpurple/util.c
+++ b/libpurple/util.c
@@ -2850,6 +2850,12 @@ purple_util_get_image_extension(gconstpointer data, size_t len)
return "icon";
}
+/*
+ * TODO: Consider using something faster than SHA-1, such as MD5, MD4
+ * or CRC32. Are there security implications to that? Would
+ * probably be a good idea to benchmark some algorithms with
+ * 3KB-10KB chunks of data (typical buddy icon sizes).
+ */
char *
purple_util_get_image_checksum(gconstpointer image_data, size_t image_len)
{
@@ -4038,6 +4044,13 @@ purple_util_fetch_url_request_len(const char *url, gboolean full,
&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 --git a/libpurple/xmlnode.c b/libpurple/xmlnode.c
index fc2fc37b36..be8a731a62 100644
--- a/libpurple/xmlnode.c
+++ b/libpurple/xmlnode.c
@@ -27,6 +27,7 @@
* libxode uses memory pools that we simply have no need for, I decided to
* write my own stuff. Also, re-writing this lets me be as lightweight
* as I want to be. Thank you libxode for giving me a good starting point */
+#define _PURPLE_XMLNODE_C_
#include "debug.h"
#include "internal.h"
@@ -126,21 +127,28 @@ xmlnode_remove_attrib(xmlnode *node, const char *attr)
g_return_if_fail(node != NULL);
g_return_if_fail(attr != NULL);
- for(attr_node = node->child; attr_node; attr_node = attr_node->next)
- {
+ attr_node = node->child;
+ while (attr_node) {
if(attr_node->type == XMLNODE_TYPE_ATTRIB &&
purple_strequal(attr_node->name, attr))
{
- if(sibling == NULL) {
+ if (node->lastchild == attr_node) {
+ node->lastchild = sibling;
+ }
+ if (sibling == NULL) {
node->child = attr_node->next;
+ xmlnode_free(attr_node);
+ attr_node = node->child;
} else {
sibling->next = attr_node->next;
+ sibling = attr_node->next;
+ xmlnode_free(attr_node);
+ attr_node = sibling;
}
- if (node->lastchild == attr_node) {
- node->lastchild = sibling;
- }
- xmlnode_free(attr_node);
- return;
+ }
+ else
+ {
+ attr_node = attr_node->next;
}
sibling = attr_node;
}
@@ -178,51 +186,36 @@ xmlnode_remove_attrib_with_namespace(xmlnode *node, const char *attr, const char
void
xmlnode_set_attrib(xmlnode *node, const char *attr, const char *value)
{
- xmlnode *attrib_node;
-
- g_return_if_fail(node != NULL);
- g_return_if_fail(attr != NULL);
- g_return_if_fail(value != NULL);
-
xmlnode_remove_attrib(node, attr);
-
- attrib_node = new_node(attr, XMLNODE_TYPE_ATTRIB);
-
- attrib_node->data = g_strdup(value);
-
- xmlnode_insert_child(node, attrib_node);
+ xmlnode_set_attrib_full(node, attr, NULL, NULL, value);
}
void
xmlnode_set_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns, const char *value)
{
- xmlnode *attrib_node;
-
- g_return_if_fail(node != NULL);
- g_return_if_fail(attr != NULL);
- g_return_if_fail(value != NULL);
-
- xmlnode_remove_attrib_with_namespace(node, attr, xmlns);
- attrib_node = new_node(attr, XMLNODE_TYPE_ATTRIB);
-
- attrib_node->data = g_strdup(value);
- attrib_node->xmlns = g_strdup(xmlns);
-
- xmlnode_insert_child(node, attrib_node);
+ xmlnode_set_attrib_full(node, attr, xmlns, NULL, value);
}
void
xmlnode_set_attrib_with_prefix(xmlnode *node, const char *attr, const char *prefix, const char *value)
{
+ xmlnode_set_attrib_full(node, attr, NULL, prefix, value);
+}
+
+void
+xmlnode_set_attrib_full(xmlnode *node, const char *attr, const char *xmlns, const char *prefix, const char *value)
+{
xmlnode *attrib_node;
g_return_if_fail(node != NULL);
g_return_if_fail(attr != NULL);
g_return_if_fail(value != NULL);
+ xmlnode_remove_attrib_with_namespace(node, attr, xmlns);
attrib_node = new_node(attr, XMLNODE_TYPE_ATTRIB);
attrib_node->data = g_strdup(value);
+ attrib_node->xmlns = g_strdup(xmlns);
attrib_node->prefix = g_strdup(prefix);
xmlnode_insert_child(node, attrib_node);
@@ -585,7 +578,8 @@ xmlnode_parser_element_start_libxml(void *user_data,
}
for(i=0; i < nb_attributes * 5; i+=5) {
- const char *prefix = (const char *)attributes[i + 1];
+ const char *name = (const char *)attributes[i];
+ const char *prefix = (const char *)attributes[i+1];
char *txt;
int attrib_len = attributes[i+4] - attributes[i+3];
char *attrib = g_malloc(attrib_len + 1);
@@ -594,11 +588,7 @@ xmlnode_parser_element_start_libxml(void *user_data,
txt = attrib;
attrib = purple_unescape_html(txt);
g_free(txt);
- if (prefix && *prefix) {
- xmlnode_set_attrib_with_prefix(node, (const char*) attributes[i], prefix, attrib);
- } else {
- xmlnode_set_attrib(node, (const char*) attributes[i], attrib);
- }
+ xmlnode_set_attrib_full(node, name, NULL, prefix, attrib);
g_free(attrib);
}
diff --git a/libpurple/xmlnode.h b/libpurple/xmlnode.h
index 3153cc66c2..364f5abd6d 100644
--- a/libpurple/xmlnode.h
+++ b/libpurple/xmlnode.h
@@ -157,6 +157,7 @@ char *xmlnode_get_data_unescaped(xmlnode *node);
*/
void xmlnode_set_attrib(xmlnode *node, const char *attr, const char *value);
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_XMLNODE_C_)
/**
* Sets a prefixed attribute for a node
*
@@ -164,6 +165,8 @@ void xmlnode_set_attrib(xmlnode *node, const char *attr, const char *value);
* @param attr The name of the attribute to set
* @param prefix The prefix of the attribute to ste
* @param value The value of the attribute
+ *
+ * @deprecated Use xmlnode_set_attrib_full instead.
*/
void xmlnode_set_attrib_with_prefix(xmlnode *node, const char *attr, const char *prefix, const char *value);
@@ -174,8 +177,25 @@ void xmlnode_set_attrib_with_prefix(xmlnode *node, const char *attr, const char
* @param attr The name of the attribute to set
* @param xmlns The namespace of the attribute to ste
* @param value The value of the attribute
+ *
+ * @deprecated Use xmlnode_set_attrib_full instead.
*/
void xmlnode_set_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns, const char *value);
+#endif /* PURPLE_DISABLE_DEPRECATED */
+
+/**
+ * Sets a namespaced attribute for a node
+ *
+ * @param node The node to set an attribute for.
+ * @param attr The name of the attribute to set
+ * @param xmlns The namespace of the attribute to ste
+ * @param prefix The prefix of the attribute to ste
+ * @param value The value of the attribute
+ *
+ * @since 2.6.0
+ */
+void xmlnode_set_attrib_full(xmlnode *node, const char *attr, const char *xmlns,
+ const char *prefix, const char *value);
/**
* Gets an attribute from a node.
diff --git a/pidgin/gtkaccount.c b/pidgin/gtkaccount.c
index a5f0a85fe9..b303b2d0b7 100644
--- a/pidgin/gtkaccount.c
+++ b/pidgin/gtkaccount.c
@@ -106,8 +106,8 @@ typedef struct
GtkSizeGroup *sg;
GtkWidget *window;
+ GtkWidget *notebook;
GtkWidget *top_vbox;
- GtkWidget *bottom_vbox;
GtkWidget *ok_button;
GtkWidget *register_button;
@@ -157,8 +157,7 @@ static void set_account(GtkListStore *store, GtkTreeIter *iter,
**************************************************************************/
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 @@ set_account_protocol_cb(GtkWidget *item, const char *id,
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 @@ add_user_options(AccountPrefsDialog *dialog, GtkWidget *parent)
}
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 @@ add_protocol_options(AccountPrefsDialog *dialog, GtkWidget *parent)
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 @@ add_protocol_options(AccountPrefsDialog *dialog, GtkWidget *parent)
dialog->protocol_opt_entries = g_list_delete_link(dialog->protocol_opt_entries, dialog->protocol_opt_entries);
}
- 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));
+ if (dialog->prpl_info == NULL ||
+ dialog->prpl_info->protocol_options == NULL)
+ return;
- gtk_box_reorder_child(GTK_BOX(parent), dialog->protocol_frame, 0);
- gtk_widget_show(dialog->protocol_frame);
+ account = dialog->account;
/* 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 @@ static void
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 @@ pidgin_account_dialog_show(PidginAccountDialogType type,
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);
+ main_vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(win), FALSE, PIDGIN_HIG_BOX_SPACE);
- notebook = gtk_notebook_new();
+ 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 @@ pidgin_account_dialog_show(PidginAccountDialogType type,
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 --git a/pidgin/gtkblist.c b/pidgin/gtkblist.c
index 3b5bce815d..62177da1eb 100644
--- a/pidgin/gtkblist.c
+++ b/pidgin/gtkblist.c
@@ -3898,7 +3898,7 @@ pidgin_blist_get_name_markup(PurpleBuddy *b, gboolean selected, gboolean aliased
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 @@ pidgin_blist_get_name_markup(PurpleBuddy *b, gboolean selected, gboolean aliased
}
/* Put it all together */
- if (aliased && biglist && (statustext || idletime)) {
+ if ((!aliased || biglist) && (statustext || idletime)) {
/* using <span size='smaller'> breaks the status, so it must be seperated into <small><span>*/
if (name_color) {
text = g_strdup_printf("<span font_desc='%s' foreground='%s'>%s</span>\n"
@@ -6443,7 +6443,7 @@ static void pidgin_blist_update_chat(PurpleBuddyList *list, PurpleBlistNode *nod
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 @@ add_buddy_cb(GtkWidget *w, int resp, PidginAddBuddyData *data)
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);
+ 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);
}
- 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 --git a/pidgin/gtkdialogs.c b/pidgin/gtkdialogs.c
index f8aa7aa755..75d5b01f28 100644
--- a/pidgin/gtkdialogs.c
+++ b/pidgin/gtkdialogs.c
@@ -189,7 +189,7 @@ static const struct translator translators[] = {
{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 --git a/pidgin/gtknotify.c b/pidgin/gtknotify.c
index 288bc83d4a..427f606e8f 100644
--- a/pidgin/gtknotify.c
+++ b/pidgin/gtknotify.c
@@ -28,6 +28,7 @@
#include <gdk/gdkkeysyms.h>
+#include "account.h"
#include "connection.h"
#include "debug.h"
#include "prefs.h"
@@ -37,6 +38,7 @@
#include "gtkblist.h"
#include "gtkimhtml.h"
#include "gtknotify.h"
+#include "gtkpounce.h"
#include "gtkutils.h"
typedef struct
@@ -57,6 +59,13 @@ typedef struct
typedef struct
{
PurpleAccount *account;
+ PurplePounce *pounce;
+} PidginNotifyPounceData;
+
+
+typedef struct
+{
+ PurpleAccount *account;
GtkListStore *model;
GtkWidget *treeview;
GtkWidget *window;
@@ -80,21 +89,44 @@ enum
COLUMNS_PIDGIN_MAIL
};
-typedef struct _PidginMailDialog PidginMailDialog;
+enum
+{
+ PIDGIN_POUNCE_ICON,
+ PIDGIN_POUNCE_ALIAS,
+ PIDGIN_POUNCE_EVENT,
+ PIDGIN_POUNCE_TEXT,
+ PIDGIN_POUNCE_DATE,
+ PIDGIN_POUNCE_DATA,
+ PIDGIN_POUNCE_COLUMNS
+};
-struct _PidginMailDialog
+typedef struct _PidginNotifyDialog PidginNotifyDialog;
+typedef PidginNotifyDialog PidginMailDialog;
+
+struct _PidginNotifyDialog
{
GtkWidget *dialog;
GtkWidget *treeview;
GtkTreeStore *treemodel;
GtkLabel *label;
GtkWidget *open_button;
+ GtkWidget *dismiss_button;
+ GtkWidget *edit_button;
int total_count;
gboolean in_use;
};
-static PidginMailDialog *mail_dialog = NULL;
+typedef enum
+{
+ PIDGIN_NOTIFY_MAIL,
+ PIDGIN_NOTIFY_POUNCE,
+ PIDGIN_NOTIFY_TYPES
+} PidginNotifyType;
+
+static PidginNotifyDialog *mail_dialog = NULL;
+static PidginNotifyDialog *pounce_dialog = NULL;
+static GtkWidget *pidgin_get_notification_dialog(PidginNotifyType type);
static void *pidgin_notify_emails(PurpleConnection *gc, size_t count, gboolean detailed,
const char **subjects,
const char **froms, const char **tos,
@@ -109,6 +141,159 @@ message_response_cb(GtkDialog *dialog, gint id, GtkWidget *widget)
}
static void
+pounce_response_close(PidginNotifyDialog *dialog)
+{
+ GtkTreeIter iter;
+ PidginNotifyPounceData *pounce_data;
+
+ while (gtk_tree_model_get_iter_first(
+ GTK_TREE_MODEL(pounce_dialog->treemodel), &iter)) {
+ gtk_tree_model_get(GTK_TREE_MODEL(pounce_dialog->treemodel), &iter,
+ PIDGIN_POUNCE_DATA, &pounce_data,
+ -1);
+ gtk_tree_store_remove(dialog->treemodel, &iter);
+
+ g_free(pounce_data);
+ }
+
+ gtk_widget_destroy(pounce_dialog->dialog);
+ g_free(pounce_dialog);
+ pounce_dialog = NULL;
+}
+
+static void
+delete_foreach(GtkTreeModel *model, GtkTreePath *path,
+ GtkTreeIter *iter, gpointer data)
+{
+ PidginNotifyPounceData *pounce_data;
+
+ gtk_tree_model_get(model, iter,
+ PIDGIN_POUNCE_DATA, &pounce_data,
+ -1);
+
+ if (pounce_data != NULL)
+ g_free(pounce_data);
+}
+
+static void
+append_to_list(GtkTreeModel *model, GtkTreePath *path,
+ GtkTreeIter *iter, gpointer data)
+{
+ GList **list = data;
+ *list = g_list_prepend(*list, gtk_tree_path_copy(path));
+}
+static void
+pounce_response_dismiss()
+{
+ GtkTreeSelection *selection;
+ GList *list = NULL;
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pounce_dialog->treeview));
+ gtk_tree_selection_selected_foreach(selection, delete_foreach, pounce_dialog);
+ gtk_tree_selection_selected_foreach(selection, append_to_list, &list);
+
+ while (list) {
+ GtkTreeIter iter;
+ if (gtk_tree_model_get_iter(GTK_TREE_MODEL(pounce_dialog->treemodel), &iter,
+ list->data)) {
+ gtk_tree_store_remove(GTK_TREE_STORE(pounce_dialog->treemodel), &iter);
+ }
+ gtk_tree_path_free(list->data);
+ list = g_list_delete_link(list, list);
+ }
+}
+
+static void
+pounce_response_edit_cb(GtkTreeModel *model, GtkTreePath *path,
+ GtkTreeIter *iter, gpointer data)
+{
+ PidginNotifyPounceData *pounce_data;
+ PidginNotifyDialog *dialog = (PidginNotifyDialog*)data;
+ PurplePounce *pounce;
+ GList *list;
+
+ list = purple_pounces_get_all();
+
+ gtk_tree_model_get(GTK_TREE_MODEL(dialog->treemodel), iter,
+ PIDGIN_POUNCE_DATA, &pounce_data,
+ -1);
+
+ for (; list != NULL; list = list->next) {
+ pounce = list->data;
+ if (pounce == pounce_data->pounce) {
+ pidgin_pounce_editor_show(pounce_data->account, NULL, pounce_data->pounce);
+ return;
+ }
+ }
+
+ purple_debug_warning("gtknotify", "Pounce was destroyed.\n");
+}
+
+static void
+pounce_response_cb(GtkDialog *dlg, gint id, PidginNotifyDialog *dialog)
+{
+ GtkTreeSelection *selection = NULL;
+
+ switch (id) {
+ case GTK_RESPONSE_CLOSE:
+ case GTK_RESPONSE_DELETE_EVENT:
+ pounce_response_close(dialog);
+ break;
+ case GTK_RESPONSE_NO:
+ pounce_response_dismiss();
+ break;
+ case GTK_RESPONSE_APPLY:
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview));
+ gtk_tree_selection_selected_foreach(selection, pounce_response_edit_cb,
+ dialog);
+ break;
+ }
+}
+
+static void
+pounce_row_selected_cb(GtkTreeView *tv, GtkTreePath *path,
+ GtkTreeViewColumn *col, gpointer data)
+{
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+ gboolean selected;
+ GList *list;
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pounce_dialog->treeview));
+
+ selected = gtk_tree_selection_get_selected(selection,
+ NULL, &iter);
+
+ if (selected) {
+ PurplePounce *pounce;
+ PidginNotifyPounceData *pounce_data;
+
+ list = purple_pounces_get_all();
+
+ gtk_tree_model_get(GTK_TREE_MODEL(pounce_dialog->treemodel), &iter,
+ PIDGIN_POUNCE_DATA, &pounce_data,
+ -1);
+
+ gtk_widget_set_sensitive(pounce_dialog->edit_button, FALSE);
+
+ for (; list != NULL; list = list->next) {
+ pounce = list->data;
+ if (pounce == pounce_data->pounce) {
+ gtk_widget_set_sensitive(pounce_dialog->edit_button, TRUE);
+ break;
+ }
+ }
+
+ gtk_widget_set_sensitive(pounce_dialog->dismiss_button, TRUE);
+ } else {
+ gtk_widget_set_sensitive(pounce_dialog->edit_button, FALSE);
+ gtk_widget_set_sensitive(pounce_dialog->dismiss_button, FALSE);
+ }
+
+
+}
+
+static void
email_response_cb(GtkDialog *dlg, gint id, PidginMailDialog *dialog)
{
PidginNotifyMailData *data = NULL;
@@ -342,89 +527,7 @@ mail_window_focus_cb(GtkWidget *widget, GdkEventFocus *focus, gpointer null)
static GtkWidget *
pidgin_get_mail_dialog(void)
{
- if (mail_dialog == NULL) {
- GtkWidget *dialog = NULL;
- GtkWidget *label;
- GtkWidget *sw;
- GtkCellRenderer *rend;
- GtkTreeViewColumn *column;
- GtkWidget *button = NULL;
- GtkWidget *vbox = NULL;
-
- dialog = gtk_dialog_new_with_buttons(_("New Mail"), NULL, 0,
- GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
- NULL);
- gtk_window_set_role(GTK_WINDOW(dialog), "new_mail_detailed");
- g_signal_connect(G_OBJECT(dialog), "focus-in-event",
- G_CALLBACK(mail_window_focus_cb), NULL);
-
- gtk_dialog_add_button(GTK_DIALOG(dialog),
- _("Open All Messages"), GTK_RESPONSE_ACCEPT);
-
- button = gtk_dialog_add_button(GTK_DIALOG(dialog),
- PIDGIN_STOCK_OPEN_MAIL, GTK_RESPONSE_YES);
-
- /* make "Open All Messages" the default response */
- gtk_dialog_set_default_response(GTK_DIALOG(dialog),
- GTK_RESPONSE_ACCEPT);
-
- /* Setup the dialog */
- gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BOX_SPACE);
- gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BOX_SPACE);
- gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
- gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER);
-
- /* Vertical box */
- vbox = GTK_DIALOG(dialog)->vbox;
-
- /* Golden ratio it up! */
- gtk_widget_set_size_request(dialog, 550, 400);
-
- sw = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
-
- mail_dialog = g_new0(PidginMailDialog, 1);
- mail_dialog->dialog = dialog;
- mail_dialog->open_button = button;
-
- mail_dialog->treemodel = gtk_tree_store_new(COLUMNS_PIDGIN_MAIL,
- GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
- mail_dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(mail_dialog->treemodel));
- g_object_unref(G_OBJECT(mail_dialog->treemodel));
- gtk_tree_view_set_search_column(GTK_TREE_VIEW(mail_dialog->treeview), PIDGIN_MAIL_TEXT);
- gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(mail_dialog->treeview),
- pidgin_tree_view_search_equal_func, NULL, NULL);
-
- g_signal_connect(G_OBJECT(dialog), "response",
- G_CALLBACK(email_response_cb), mail_dialog);
- g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(mail_dialog->treeview))),
- "changed", G_CALLBACK(selection_changed_cb), mail_dialog);
- g_signal_connect(G_OBJECT(mail_dialog->treeview), "row-activated", G_CALLBACK(email_row_activated_cb), NULL);
-
- gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(mail_dialog->treeview), FALSE);
- gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(mail_dialog->treeview), TRUE);
- gtk_container_add(GTK_CONTAINER(sw), mail_dialog->treeview);
-
- column = gtk_tree_view_column_new();
- gtk_tree_view_column_set_resizable(column, TRUE);
- rend = gtk_cell_renderer_pixbuf_new();
- gtk_tree_view_column_pack_start(column, rend, FALSE);
- gtk_tree_view_column_set_attributes(column, rend, "pixbuf", PIDGIN_MAIL_ICON, NULL);
- rend = gtk_cell_renderer_text_new();
- gtk_tree_view_column_pack_start(column, rend, TRUE);
- gtk_tree_view_column_set_attributes(column, rend, "markup", PIDGIN_MAIL_TEXT, NULL);
- gtk_tree_view_append_column(GTK_TREE_VIEW(mail_dialog->treeview), column);
-
- label = gtk_label_new(NULL);
- gtk_label_set_markup(GTK_LABEL(label), _("<span weight=\"bold\" size=\"larger\">You have mail!</span>"));
- gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
- gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
- gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
- }
-
- return mail_dialog->dialog;
+ return pidgin_get_notification_dialog(PIDGIN_NOTIFY_MAIL);
}
/* count == 0 means this is a detailed mail notification.
@@ -1001,8 +1104,10 @@ pidgin_close_notify(PurpleNotifyType type, void *ui_handle)
{
PidginNotifyMailData *data = (PidginNotifyMailData *)ui_handle;
- g_free(data->url);
- g_free(data);
+ if (data) {
+ g_free(data->url);
+ g_free(data);
+ }
}
else if (type == PURPLE_NOTIFY_SEARCHRESULTS)
{
@@ -1234,6 +1339,228 @@ pidgin_notify_uri(const char *uri)
return NULL;
}
+static GtkWidget *
+pidgin_get_dialog(PidginNotifyType type, GtkTreeStore *treemodel)
+{
+ GtkWidget *dialog = NULL;
+ GtkWidget *label = NULL;
+ GtkWidget *sw;
+ GtkCellRenderer *rend;
+ GtkTreeViewColumn *column;
+ GtkWidget *button = NULL;
+ GtkWidget *vbox = NULL;
+ GtkTreeSelection *sel;
+ PidginNotifyDialog *spec_dialog = NULL;
+
+ g_return_val_if_fail(type < PIDGIN_NOTIFY_TYPES, NULL);
+
+ dialog = gtk_dialog_new_with_buttons(NULL, NULL, 0,
+ GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+ NULL);
+
+ /* Setup the dialog */
+ gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BOX_SPACE);
+ gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BOX_SPACE);
+ gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
+ gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER);
+
+ /* Vertical box */
+ vbox = GTK_DIALOG(dialog)->vbox;
+
+ /* Golden ratio it up! */
+ gtk_widget_set_size_request(dialog, 550, 400);
+
+ sw = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+
+ spec_dialog = g_new0(PidginNotifyDialog, 1);
+ spec_dialog->dialog = dialog;
+ spec_dialog->open_button = button;
+
+ spec_dialog->treemodel = treemodel;
+ spec_dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(spec_dialog->treemodel));
+ g_object_unref(G_OBJECT(spec_dialog->treemodel));
+
+ gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(spec_dialog->treeview), TRUE);
+ gtk_container_add(GTK_CONTAINER(sw), spec_dialog->treeview);
+
+ if (type == PIDGIN_NOTIFY_MAIL) {
+ gtk_window_set_title(GTK_WINDOW(dialog), _("New Mail"));
+ gtk_window_set_role(GTK_WINDOW(dialog), "new_mail_detailed");
+ g_signal_connect(G_OBJECT(dialog), "focus-in-event",
+ G_CALLBACK(mail_window_focus_cb), NULL);
+
+ gtk_dialog_add_button(GTK_DIALOG(dialog),
+ _("Open All Messages"), GTK_RESPONSE_ACCEPT);
+
+ button = gtk_dialog_add_button(GTK_DIALOG(dialog),
+ PIDGIN_STOCK_OPEN_MAIL, GTK_RESPONSE_YES);
+
+ gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(spec_dialog->treeview), FALSE);
+
+ gtk_tree_view_set_search_column(GTK_TREE_VIEW(spec_dialog->treeview), PIDGIN_MAIL_TEXT);
+ gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(spec_dialog->treeview),
+ pidgin_tree_view_search_equal_func, NULL, NULL);
+
+ g_signal_connect(G_OBJECT(dialog), "response",
+ G_CALLBACK(email_response_cb), spec_dialog);
+ g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(spec_dialog->treeview))),
+ "changed", G_CALLBACK(selection_changed_cb), spec_dialog);
+ g_signal_connect(G_OBJECT(spec_dialog->treeview), "row-activated", G_CALLBACK(email_row_activated_cb), NULL);
+
+ column = gtk_tree_view_column_new();
+ gtk_tree_view_column_set_resizable(column, TRUE);
+ rend = gtk_cell_renderer_pixbuf_new();
+ gtk_tree_view_column_pack_start(column, rend, FALSE);
+
+ gtk_tree_view_column_set_attributes(column, rend, "pixbuf", PIDGIN_MAIL_ICON, NULL);
+ rend = gtk_cell_renderer_text_new();
+ gtk_tree_view_column_pack_start(column, rend, TRUE);
+ gtk_tree_view_column_set_attributes(column, rend, "markup", PIDGIN_MAIL_TEXT, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column);
+
+ label = gtk_label_new(NULL);
+ gtk_label_set_markup(GTK_LABEL(label), _("<span weight=\"bold\" size=\"larger\">You have mail!</span>"));
+
+ } else if (type == PIDGIN_NOTIFY_POUNCE) {
+ gtk_window_set_title(GTK_WINDOW(dialog), _("New Pounces"));
+
+ button = gtk_dialog_add_button(GTK_DIALOG(dialog),
+ _("Dismiss"), GTK_RESPONSE_NO);
+ gtk_widget_set_sensitive(button, FALSE);
+ spec_dialog->dismiss_button = button;
+
+ button = gtk_dialog_add_button(GTK_DIALOG(dialog),
+ PIDGIN_STOCK_EDIT, GTK_RESPONSE_APPLY);
+ gtk_widget_set_sensitive(button, FALSE);
+ spec_dialog->edit_button = button;
+
+ g_signal_connect(G_OBJECT(dialog), "response",
+ G_CALLBACK(pounce_response_cb), spec_dialog);
+
+ column = gtk_tree_view_column_new();
+ gtk_tree_view_column_set_title(column, _("Buddy"));
+ gtk_tree_view_column_set_resizable(column, TRUE);
+ rend = gtk_cell_renderer_pixbuf_new();
+ gtk_tree_view_column_pack_start(column, rend, FALSE);
+
+ gtk_tree_view_column_set_attributes(column, rend, "pixbuf", PIDGIN_POUNCE_ICON, NULL);
+ rend = gtk_cell_renderer_text_new();
+ gtk_tree_view_column_pack_start(column, rend, FALSE);
+ gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_ALIAS);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column);
+
+ column = gtk_tree_view_column_new();
+ gtk_tree_view_column_set_title(column, _("Event"));
+ gtk_tree_view_column_set_resizable(column, TRUE);
+ rend = gtk_cell_renderer_text_new();
+ gtk_tree_view_column_pack_start(column, rend, FALSE);
+ gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_EVENT);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column);
+
+ column = gtk_tree_view_column_new();
+ gtk_tree_view_column_set_title(column, _("Message"));
+ gtk_tree_view_column_set_resizable(column, TRUE);
+ rend = gtk_cell_renderer_text_new();
+ gtk_tree_view_column_pack_start(column, rend, FALSE);
+ gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_TEXT);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column);
+
+ column = gtk_tree_view_column_new();
+ gtk_tree_view_column_set_title(column, _("Date"));
+ gtk_tree_view_column_set_resizable(column, TRUE);
+ rend = gtk_cell_renderer_text_new();
+ gtk_tree_view_column_pack_start(column, rend, FALSE);
+ gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_DATE);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column);
+
+ label = gtk_label_new(NULL);
+ gtk_label_set_markup(GTK_LABEL(label), _("<span weight=\"bold\" size=\"larger\">You have pounced!</span>"));
+
+ sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(spec_dialog->treeview));
+ gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+ g_signal_connect(G_OBJECT(sel), "changed",
+ G_CALLBACK(pounce_row_selected_cb), NULL);
+ }
+
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 2);
+
+ if (type == PIDGIN_NOTIFY_MAIL)
+ mail_dialog = spec_dialog;
+ else if (type == PIDGIN_NOTIFY_POUNCE) {
+ pounce_dialog = spec_dialog;
+ }
+
+ return spec_dialog->dialog;
+
+}
+
+void
+pidgin_notify_pounce_add(PurpleAccount *account, PurplePounce *pounce,
+ const char *alias, const char *event, const char *message, const char *date)
+{
+ GtkWidget *dialog;
+ GdkPixbuf *icon;
+ GtkTreeIter iter;
+ PidginNotifyPounceData *pounce_data;
+
+ dialog = pidgin_get_notification_dialog(PIDGIN_NOTIFY_POUNCE);
+
+ icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL);
+
+ pounce_data = g_new(PidginNotifyPounceData, 1);
+
+ pounce_data->account = account;
+ pounce_data->pounce = pounce;
+
+ gtk_tree_store_append(pounce_dialog->treemodel, &iter, NULL);
+
+ gtk_tree_store_set(pounce_dialog->treemodel, &iter,
+ PIDGIN_POUNCE_ICON, icon,
+ PIDGIN_POUNCE_ALIAS, alias,
+ PIDGIN_POUNCE_EVENT, event,
+ PIDGIN_POUNCE_TEXT, (message != NULL)? message : _("No message"),
+ PIDGIN_POUNCE_DATE, date,
+ PIDGIN_POUNCE_DATA, pounce_data,
+ -1);
+
+ if (icon)
+ g_object_unref(icon);
+
+ gtk_widget_show_all(dialog);
+
+ return;
+}
+
+static GtkWidget *
+pidgin_get_notification_dialog(PidginNotifyType type)
+{
+ GtkTreeStore *model = NULL;
+
+ if (type == PIDGIN_NOTIFY_MAIL) {
+ if (mail_dialog != NULL)
+ return mail_dialog->dialog;
+
+ model = gtk_tree_store_new(COLUMNS_PIDGIN_MAIL,
+ GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
+
+ } else if (type == PIDGIN_NOTIFY_POUNCE) {
+
+ if (pounce_dialog != NULL)
+ return pounce_dialog->dialog;
+
+ model = gtk_tree_store_new(PIDGIN_POUNCE_COLUMNS,
+ GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_POINTER);
+ }
+
+ return pidgin_get_dialog(type, model);
+}
+
static PurpleNotifyUiOps ops =
{
pidgin_notify_message,
diff --git a/pidgin/gtknotify.h b/pidgin/gtknotify.h
index d134d9957b..8ecc762a50 100644
--- a/pidgin/gtknotify.h
+++ b/pidgin/gtknotify.h
@@ -27,6 +27,18 @@
#define _PIDGINNOTIFY_H_
#include "notify.h"
+#include "pounce.h"
+
+/**
+ * Adds a buddy pounce to the buddy pounce dialog
+ *
+ * @param alias The buddy alias
+ * @param event Event description
+ * @param message Pounce message
+ * @param date Pounce date
+ */
+void pidgin_notify_pounce_add(PurpleAccount *account, PurplePounce *pounce,
+ const char *alias, const char *event, const char *message, const char *date);
/**
* Returns the UI operations structure for GTK+ notification functions.
diff --git a/pidgin/gtkpounce.c b/pidgin/gtkpounce.c
index a8b2096014..e2ee53335c 100644
--- a/pidgin/gtkpounce.c
+++ b/pidgin/gtkpounce.c
@@ -30,7 +30,6 @@
#include "account.h"
#include "conversation.h"
#include "debug.h"
-#include "notify.h"
#include "prpl.h"
#include "request.h"
#include "server.h"
@@ -41,6 +40,7 @@
#include "gtkdialogs.h"
#include "gtkimhtml.h"
#include "gtkpounce.h"
+#include "gtknotify.h"
#include "pidginstock.h"
#include "gtkutils.h"
@@ -1275,7 +1275,6 @@ create_pounces_list(PouncesManager *dialog)
/* Handle double-clicking */
g_signal_connect(G_OBJECT(treeview), "button_press_event",
G_CALLBACK(pounce_double_click_cb), dialog);
-
gtk_container_add(GTK_CONTAINER(sw), treeview);
gtk_widget_show(treeview);
@@ -1458,27 +1457,27 @@ pounce_cb(PurplePounce *pounce, PurplePounceEvent events, void *data)
*/
tmp = g_strdup_printf(
(events & PURPLE_POUNCE_TYPING) ?
- _("%s has started typing to you (%s)") :
+ _("Started typing") :
(events & PURPLE_POUNCE_TYPED) ?
- _("%s has paused while typing to you (%s)") :
+ _("Paused while typing") :
(events & PURPLE_POUNCE_SIGNON) ?
- _("%s has signed on (%s)") :
+ _("Signed on") :
(events & PURPLE_POUNCE_IDLE_RETURN) ?
- _("%s has returned from being idle (%s)") :
+ _("Returned from being idle") :
(events & PURPLE_POUNCE_AWAY_RETURN) ?
- _("%s has returned from being away (%s)") :
+ _("Returned from being away") :
(events & PURPLE_POUNCE_TYPING_STOPPED) ?
- _("%s has stopped typing to you (%s)") :
+ _("Stopped typing") :
(events & PURPLE_POUNCE_SIGNOFF) ?
- _("%s has signed off (%s)") :
+ _("Signed off") :
(events & PURPLE_POUNCE_IDLE) ?
- _("%s has become idle (%s)") :
+ _("Became idle") :
(events & PURPLE_POUNCE_AWAY) ?
- _("%s has gone away. (%s)") :
+ _("Went away") :
(events & PURPLE_POUNCE_MESSAGE_RECEIVED) ?
- _("%s has sent you a message. (%s)") :
- _("Unknown pounce event. Please report this!"),
- alias, purple_account_get_protocol_name(account));
+ _("Sent a message") :
+ _("Unknown.... Please report this!")
+ );
/*
* Ok here is where I change the second argument, title, from
@@ -1488,16 +1487,9 @@ pounce_cb(PurplePounce *pounce, PurplePounceEvent events, void *data)
if ((name_shown = purple_account_get_alias(account)) == NULL)
name_shown = purple_account_get_username(account);
- if (reason == NULL)
- {
- purple_notify_info(NULL, name_shown, tmp, purple_date_format_full(NULL));
- }
- else
- {
- char *tmp2 = g_strdup_printf("%s\n\n%s", reason, purple_date_format_full(NULL));
- purple_notify_info(NULL, name_shown, tmp, tmp2);
- g_free(tmp2);
- }
+ pidgin_notify_pounce_add(account, pounce, alias, tmp, reason,
+ purple_date_format_full(NULL));
+
g_free(tmp);
}
diff --git a/pidgin/gtkprefs.c b/pidgin/gtkprefs.c
index 44f05ea794..9ca650993d 100644
--- a/pidgin/gtkprefs.c
+++ b/pidgin/gtkprefs.c
@@ -2385,14 +2385,12 @@ away_page(void)
/* 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 @@ away_page(void)
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 --git a/pidgin/gtkroomlist.c b/pidgin/gtkroomlist.c
index 5302481e87..82bac84809 100644
--- a/pidgin/gtkroomlist.c
+++ b/pidgin/gtkroomlist.c
@@ -64,7 +64,6 @@ typedef struct _PidginRoomlist {
gint num_rooms, total_rooms;
GtkWidget *tipwindow;
GdkRectangle tip_rect;
- guint timeout;
PangoLayout *tip_layout;
PangoLayout *tip_name_layout;
int tip_height;
diff --git a/pidgin/gtkutils.c b/pidgin/gtkutils.c
index 77ff10fa18..bc4030882a 100644
--- a/pidgin/gtkutils.c
+++ b/pidgin/gtkutils.c
@@ -2451,11 +2451,6 @@ GtkWidget *pidgin_buddy_icon_chooser_new(GtkWindow *parent, void(*callback)(cons
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 */
@@ -3583,7 +3578,9 @@ register_gnome_url_handlers(void)
if (tmp == NULL)
return FALSE;
+ g_free(tmp);
tmp = NULL;
+
if (!g_spawn_command_line_sync("gconftool-2 --all-dirs /desktop/gnome/url-handlers",
&tmp, &err, NULL, NULL))
{
diff --git a/pidgin/plugins/gevolution/gevo-util.c b/pidgin/plugins/gevolution/gevo-util.c
index 54f54abf53..d5cac965da 100644
--- a/pidgin/plugins/gevolution/gevo-util.c
+++ b/pidgin/plugins/gevolution/gevo-util.c
@@ -41,8 +41,12 @@ gevo_add_buddy(PurpleAccount *account, const char *group_name,
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 --git a/pidgin/plugins/gevolution/gevolution.h b/pidgin/plugins/gevolution/gevolution.h
index 7046070277..1b92b2b940 100644
--- a/pidgin/plugins/gevolution/gevolution.h
+++ b/pidgin/plugins/gevolution/gevolution.h
@@ -75,7 +75,7 @@ typedef struct
GtkWidget *win;
GtkWidget *accounts_menu;
- GtkWidget *screenname;
+ GtkWidget *username;
GtkWidget *firstname;
GtkWidget *lastname;
GtkWidget *email;
diff --git a/pidgin/win32/untar.c b/pidgin/win32/untar.c
index 0ec2e09ccc..7121513485 100644
--- a/pidgin/win32/untar.c
+++ b/pidgin/win32/untar.c
@@ -212,9 +212,11 @@ static void linkorcopy(src, dst, sym)
* 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 --git a/po/POTFILES.in b/po/POTFILES.in
index b221f12ced..0457332517 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -62,6 +62,7 @@ libpurple/plugins/log_reader.c
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/silc.c
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 --git a/po/de.po b/po/de.po
index 993315bf86..11abb7c79a 100644
--- a/po/de.po
+++ b/po/de.po
@@ -11,8 +11,8 @@ msgid ""
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 <jochenkemnade@web.de>\n"
"Language-Team: German <de@li.org>\n"
"MIME-Version: 1.0\n"
@@ -2630,6 +2630,31 @@ msgstr "Sichere Offline-Nachricht als Alarm"
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 @@ msgid "Unable to ping user %s"
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."
+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 user %s might be offline."
-msgstr "Kann nicht anklopfen, da der Benutzer %s vielleicht offline ist."
+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 "Unable to buzz, because the user %s does not support it."
-msgstr "Kann nicht anklopfen, da der Benutzer %s dies nicht unterstützt."
+msgid "Buzzing %s..."
+msgstr "%s anklopfen..."
#. Yahoo only supports one attention command: the 'buzz'.
#. This is index number YAHOO_BUZZ.
@@ -4460,10 +4493,6 @@ msgstr "Anklopfen"
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 @@ msgstr "Fehler beim Betreten des Chats %s"
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 @@ msgstr ""
"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 @@ msgstr "Ihr Benutzerkonto ist momentan gesperrt."
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[0] ""
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 @@ msgstr "Aktualisieren"
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 @@ msgstr ""
"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 @@ msgstr "Organisation"
msgid "Unit"
msgstr "Abteilung"
-msgid "Note"
-msgstr "Bemerkung"
-
msgid "Join Chat"
msgstr "Chat betreten"
@@ -9309,188 +9377,13 @@ msgid "Auth Domain"
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 @@ msgstr "Nicht stören"
msgid "Extended away"
msgstr "Abwesend (erweitert)"
-msgid "Mobile"
-msgstr "Mobil"
-
msgid "Listening to music"
msgstr "Musik hören"
@@ -10143,18 +10033,6 @@ msgstr "+++ %s wurde tätig"
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 @@ msgid "Unable to connect to %s: %s"
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 @@ msgstr "Verbindung abgelehnt."
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 @@ msgstr "Benachrichtigung über neue _Mails"
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 @@ msgstr "Wenn Sie genau hinschauen"
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 @@ msgstr "_Einfach"
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 @@ msgstr "/Werkzeuge/Buddy-_Alarm"
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 @@ msgstr "/Werkzeuge/_Einstellungen"
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 @@ msgstr "Manuell"
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 @@ msgstr "Wiederverbinden"
msgid "Re-enable"
msgstr "Reaktivieren"
+msgid "SSL FAQs"
+msgstr "SSL-FAQs"
+
msgid "Welcome back!"
msgstr "Willkommen zurück!"
@@ -10824,6 +10720,9 @@ msgstr ""
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 @@ msgstr "Georgisch"
msgid "Ubuntu Georgian Translators"
msgstr "Ubuntu-Georgisch-Übersetzer"
+msgid "Khmer"
+msgstr "Khmer"
+
msgid "Kannada"
msgstr "Kannada"
@@ -11825,15 +11727,6 @@ msgstr ""
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 ""
"<span size='larger' weight='bold'>Unrecognized file type</span>\n"
"\n"
@@ -12086,6 +11979,7 @@ msgid ""
"\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 @@ msgstr ""
"\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 @@ msgid ""
"\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 @@ msgstr ""
"\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 @@ msgstr "Pidgin"
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 "<span weight=\"bold\" size=\"larger\">You have mail!</span>"
-msgstr "<span weight=\"bold\" size=\"larger\">Sie haben Post!</span>"
-
#, c-format
msgid "%s has %d new message."
msgid_plural "%s has %d new messages."
@@ -12210,6 +12101,24 @@ msgid ""
msgstr ""
"Das benutzerdefinierte Browserkommando wurde ausgewählt, aber nicht gesetzt."
+msgid "Open All Messages"
+msgstr "Alle Nachrichten öffnen"
+
+msgid "<span weight=\"bold\" size=\"larger\">You have mail!</span>"
+msgstr "<span weight=\"bold\" size=\"larger\">Sie haben Post!</span>"
+
+msgid "New Pounces"
+msgstr "Neuer Alarm"
+
+msgid "Dismiss"
+msgstr "Verwerfen"
+
+msgid "<span weight=\"bold\" size=\"larger\">You have pounced!</span>"
+msgstr "<span weight=\"bold\" size=\"larger\">Sie haben geklopft!</span>"
+
+msgid "No message"
+msgstr "Keine Nachricht"
+
msgid "The following plugins will be unloaded."
msgstr "Die folgenden Plugins werden entladen."
@@ -12258,6 +12167,9 @@ msgstr "<b>Plugin-Details</b>"
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 @@ msgstr "_Wiederkehrend"
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 @@ msgstr "Tastaturkürzel"
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 @@ msgstr "Wenn abwesend und untätig"
msgid "Auto-away"
msgstr "Automatisch abwesend"
-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 when _idle"
+msgstr "Ändere Status, wenn _inaktiv"
+
msgid "Change _status to:"
msgstr "Ändere _Status zu:"
@@ -12833,6 +12793,12 @@ msgstr "S_peichern & Übernehmen"
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,15 +12808,15 @@ msgstr "Weitere Daten benötigt"
msgid "Please provide a shortcut to associate with the smiley."
msgstr "Bitte geben Sie eine Tastenkombination für den Smiley an."
-msgid "Duplicate Shortcut"
-msgstr "Doppelte Tastenkombination"
-
+#, c-format
msgid ""
-"A custom smiley for the selected shortcut already exists. Please specify a "
-"different shortcut."
+"A custom smiley for '%s' already exists. Please use a different shortcut."
msgstr ""
-"Für diese Tastenkombination existiert bereits ein benutzerdefinierter "
-"Smiley. Bitten wählen Sie eine andere Tastenkombination."
+"Für '%s' existiert bereits ein benutzerdefinierter Smiley. Bitten wählen Sie "
+"eine andere Tastenkombination."
+
+msgid "Duplicate Shortcut"
+msgstr "Doppelte Tastenkombination"
msgid "Please select an image for the smiley."
msgstr "Bitte wählen Sie ein Bild für den Smiley."
@@ -12861,16 +12827,21 @@ msgstr "Smiley bearbeiten"
msgid "Add Smiley"
msgstr "Smiley hinzufügen"
-msgid "Smiley _Image"
-msgstr "Smiley-_Bild"
+msgid "_Image:"
+msgstr "_Bild:"
-#. Smiley shortcut
-msgid "Smiley S_hortcut"
-msgstr "_Tastenkombination"
+#. 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 @@ msgstr ""
"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 @@ msgstr "Sendet und empfängt RAW-XMPP-Blöcke."
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"