pidgin: 9a5e5496: No functionality change--just cleanup.
markdoliner at pidgin.im
markdoliner at pidgin.im
Mon Dec 15 22:40:35 EST 2008
-----------------------------------------------------------------
Revision: 9a5e549612efd8ca6f60fc57b51a4eee7e32c861
Ancestor: 448583a763dcf343f1a4392bdcdcc4c4f01f3aed
Author: markdoliner at pidgin.im
Date: 2008-12-16T03:35:22
Branch: im.pidgin.pidgin
URL: http://d.pidgin.im/viewmtn/revision/info/9a5e549612efd8ca6f60fc57b51a4eee7e32c861
Modified files:
libpurple/protocols/myspace/myspace.c
libpurple/protocols/myspace/myspace.h
libpurple/protocols/myspace/persist.h
libpurple/protocols/myspace/session.c
libpurple/protocols/myspace/session.h
libpurple/protocols/myspace/user.c
libpurple/protocols/myspace/user.h
libpurple/protocols/myspace/zap.c
ChangeLog:
No functionality change--just cleanup.
* Remove stray whitespace
* Make functions static that don't need to be public
* Shuffling functions around so there is a general bottom-to-top
logic flow
* Remove foward declarations for functions that don't need them
-------------- next part --------------
============================================================
--- libpurple/protocols/myspace/myspace.c 6ad9d696de3bd60e5668bf40d2600cf25c00a528
+++ libpurple/protocols/myspace/myspace.c 33267a1c02c8d09f72652f34621a63cf700d03d1
@@ -1,4 +1,5 @@
-/* MySpaceIM Protocol Plugin
+/**
+ * MySpaceIM Protocol Plugin
*
* \author Jeff Connelly
*
@@ -35,351 +36,488 @@
#include "myspace.h"
-/* Internal functions */
+static void msim_set_status(PurpleAccount *account, PurpleStatus *status);
+static void msim_set_idle(PurpleConnection *gc, int time);
-#ifdef MSIM_DEBUG_MSG
-static void print_hash_item(gpointer key, gpointer value, gpointer user_data);
-#endif
+/**
+ * Perform actual postprocessing on a message, adding userid as specified.
+ *
+ * @param msg The message to postprocess.
+ * @param uid_before Name of field where to insert new field before, or NULL for end.
+ * @param uid_field_name Name of field to add uid to.
+ * @param uid The userid to insert.
+ *
+ * If the field named by uid_field_name already exists, then its string contents will
+ * be used for the field, except "<uid>" will be replaced by the userid.
+ *
+ * If the field named by uid_field_name does not exist, it will be added before the
+ * field named by uid_before, as an integer, with the userid.
+ *
+ * Does not handle sending, or scheduling userid lookup. For that, see msim_postprocess_outgoing().
+ */
+static MsimMessage *
+msim_do_postprocessing(MsimMessage *msg, const gchar *uid_before,
+ const gchar *uid_field_name, guint uid)
+{
+ MsimMessageElement *elem;
+ msim_msg_dump("msim_do_postprocessing msg: %s\n", msg);
-static int msim_send_really_raw(PurpleConnection *gc, const char *buf, int total_bytes);
-static gboolean msim_login_challenge(MsimSession *session, MsimMessage *msg);
-static gchar *msim_compute_login_response(const gchar nonce[2 * NONCE_SIZE], const gchar *email, const gchar *password, guint *response_len);
+ /* First, check - if the field already exists, replace <uid> within it */
+ if ((elem = msim_msg_get(msg, uid_field_name)) != NULL) {
+ gchar *fmt_string;
+ gchar *uid_str, *new_str;
-static gboolean msim_incoming_bm_record_cv(MsimSession *session, MsimMessage *msg);
-static gboolean msim_incoming_bm(MsimSession *session, MsimMessage *msg);
-static gboolean msim_incoming_status(MsimSession *session, MsimMessage *msg);
-static gboolean msim_incoming_im(MsimSession *session, MsimMessage *msg);
-/* static gboolean msim_incoming_zap(MsimSession *session, MsimMessage *msg); - in zap.c */
-static gboolean msim_incoming_action(MsimSession *session, MsimMessage *msg);
-static gboolean msim_incoming_media(MsimSession *session, MsimMessage *msg);
-static gboolean msim_incoming_unofficial_client(MsimSession *session,
- MsimMessage *msg);
+ /* Get the packed element, flattening it. This allows <uid> to be
+ * replaced within nested data structures, since the replacement is done
+ * on the linear, packed data, not on a complicated data structure.
+ *
+ * For example, if the field was originally a dictionary or a list, you
+ * would have to iterate over all the items in it to see what needs to
+ * be replaced. But by packing it first, the <uid> marker is easily replaced
+ * just by a string replacement.
+ */
+ fmt_string = msim_msg_pack_element_data(elem);
-#ifdef MSIM_SEND_CLIENT_VERSION
-static gboolean msim_send_unofficial_client(MsimSession *session, gchar *username);
-#endif
+ uid_str = g_strdup_printf("%d", uid);
+ new_str = purple_strreplace(fmt_string, "<uid>", uid_str);
+ g_free(uid_str);
+ g_free(fmt_string);
-static void msim_get_info_cb(MsimSession *session, MsimMessage *userinfo, gpointer data);
+ /* Free the old element data */
+ msim_msg_free_element_data(elem->data);
-static void msim_set_status_code(MsimSession *session, guint code, gchar *statstring);
+ /* Replace it with our new data */
+ elem->data = new_str;
+ elem->type = MSIM_TYPE_RAW;
-static gboolean msim_process_server_info(MsimSession *session, MsimMessage *msg);
-static gboolean msim_web_challenge(MsimSession *session, MsimMessage *msg);
-static gboolean msim_process_reply(MsimSession *session, MsimMessage *msg);
+ } else {
+ /* Otherwise, insert new field into outgoing message. */
+ msg = msim_msg_insert_before(msg, uid_before, uid_field_name, MSIM_TYPE_INTEGER, GUINT_TO_POINTER(uid));
+ }
-static gboolean msim_preprocess_incoming(MsimSession *session, MsimMessage *msg);
+ msim_msg_dump("msim_postprocess_outgoing_cb: postprocessed msg=%s\n", msg);
-#ifdef MSIM_USE_KEEPALIVE
-static gboolean msim_check_alive(gpointer data);
-#endif
+ return msg;
+}
-static gboolean msim_is_username_set(MsimSession *session, MsimMessage *msg);
+/**
+ * Callback for msim_postprocess_outgoing() to add a userid to a message, and send it (once receiving userid).
+ *
+ * @param session
+ * @param userinfo The user information reply message, containing the user ID
+ * @param data The message to postprocess and send.
+ *
+ * The data message should contain these fields:
+ *
+ * _uid_field_name: string, name of field to add with userid from userinfo message
+ * _uid_before: string, name of field before field to insert, or NULL for end
+ */
+static void
+msim_postprocess_outgoing_cb(MsimSession *session, MsimMessage *userinfo,
+ gpointer data)
+{
+ gchar *uid_field_name, *uid_before, *username;
+ guint uid;
+ MsimMessage *msg, *body;
-static gboolean msim_process(MsimSession *session, MsimMessage *msg);
+ msg = (MsimMessage *)data;
-static MsimMessage *msim_do_postprocessing(MsimMessage *msg, const gchar *uid_field_name, const gchar *uid_before, guint uid);
-static void msim_postprocess_outgoing_cb(MsimSession *session, MsimMessage *userinfo, gpointer data);
-static gboolean msim_postprocess_outgoing(MsimSession *session, MsimMessage *msg, const gchar *username, const gchar *uid_field_name, const gchar *uid_before);
+ msim_msg_dump("msim_postprocess_outgoing_cb() got msg=%s\n", msg);
-static gboolean msim_error(MsimSession *session, MsimMessage *msg);
+ /* Obtain userid from userinfo message. */
+ body = msim_msg_get_dictionary(userinfo, "body");
+ g_return_if_fail(body != NULL);
-static void msim_check_inbox_cb(MsimSession *session, MsimMessage *userinfo, gpointer data);
-static gboolean msim_check_inbox(gpointer data);
+ uid = msim_msg_get_integer(body, "UserID");
+ msim_msg_free(body);
-static void msim_input_cb(gpointer gc_uncasted, gint source, PurpleInputCondition cond);
+ username = msim_msg_get_string(msg, "_username");
+ if (!uid) {
+ gchar *msg;
-static void msim_connect_cb(gpointer data, gint source, const gchar *error_message);
+ msg = g_strdup_printf(_("No such user: %s"), username);
+ if (!purple_conv_present_error(username, session->account, msg)) {
+ purple_notify_error(NULL, NULL, _("User lookup"), msg);
+ }
-static void msim_import_friends(PurplePluginAction *action);
-static void msim_import_friends_cb(MsimSession *session, MsimMessage *reply, gpointer user_data);
-static gboolean msim_get_contact_list(MsimSession *session, int what_to_do_after);
+ g_free(msg);
+ g_free(username);
+ /* TODO: free
+ * msim_msg_free(msg);
+ */
+ return;
+ }
-static gboolean msim_uri_handler(const gchar *proto, const gchar *cmd, GHashTable *params);
-static void msim_uri_handler_addContact_cb(MsimSession *session, MsimMessage *userinfo, gpointer data);
-static void msim_uri_handler_sendIM_cb(MsimSession *session, MsimMessage *userinfo, gpointer data);
+ uid_field_name = msim_msg_get_string(msg, "_uid_field_name");
+ uid_before = msim_msg_get_string(msg, "_uid_before");
-/**
- * Load the plugin.
- */
-gboolean
-msim_load(PurplePlugin *plugin)
-{
- /* If compiled to use RC4 from libpurple, check if it is really there. */
- if (!purple_ciphers_find_cipher("rc4")) {
- purple_debug_error("msim", "rc4 not in libpurple, but it is required - not loading MySpaceIM plugin!\n");
- purple_notify_error(plugin, _("Missing Cipher"),
- _("The RC4 cipher could not be found"),
- _("Upgrade "
- "to a libpurple with RC4 support (>= 2.0.1). MySpaceIM "
- "plugin will not be loaded."));
- return FALSE;
+ msg = msim_do_postprocessing(msg, uid_before, uid_field_name, uid);
+
+ /* Send */
+ if (!msim_msg_send(session, msg)) {
+ msim_msg_dump("msim_postprocess_outgoing_cb: sending failed for message: %s\n", msg);
}
- return TRUE;
+
+
+ /* Free field names AFTER sending message, because MsimMessage does NOT copy
+ * field names - instead, treats them as static strings (which they usually are).
+ */
+ g_free(uid_field_name);
+ g_free(uid_before);
+ g_free(username);
+ /* TODO: free
+ * msim_msg_free(msg);
+ */
}
/**
- * Get possible user status types. Based on mockprpl.
+ * Postprocess and send a message.
*
- * @return GList of status types.
+ * @param session
+ * @param msg Message to postprocess. Will NOT be freed.
+ * @param username Username to resolve. Assumed to be a static string (will not be freed or copied).
+ * @param uid_field_name Name of new field to add, containing uid of username. Static string.
+ * @param uid_before Name of existing field to insert username field before. Static string.
+ *
+ * @return TRUE if successful.
*/
-GList *
-msim_status_types(PurpleAccount *acct)
+static gboolean
+msim_postprocess_outgoing(MsimSession *session, MsimMessage *msg,
+ const gchar *username, const gchar *uid_field_name,
+ const gchar *uid_before)
{
- GList *types;
- PurpleStatusType *status;
+ PurpleBuddy *buddy;
+ guint uid;
+ gboolean rc;
- purple_debug_info("myspace", "returning status types\n");
+ g_return_val_if_fail(msg != NULL, FALSE);
- types = NULL;
+ /* Store information for msim_postprocess_outgoing_cb(). */
+ msim_msg_dump("msim_postprocess_outgoing: msg before=%s\n", msg);
+ msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, g_strdup(username));
+ msg = msim_msg_append(msg, "_uid_field_name", MSIM_TYPE_STRING, g_strdup(uid_field_name));
+ msg = msim_msg_append(msg, "_uid_before", MSIM_TYPE_STRING, g_strdup(uid_before));
- /* Statuses are almost all the same. Define a macro to reduce code repetition. */
-#define _MSIM_ADD_NEW_STATUS(prim) status = \
- purple_status_type_new_with_attrs( \
- prim, /* PurpleStatusPrimitive */ \
- NULL, /* id - use default */ \
- NULL, /* name - use default */ \
- TRUE, /* saveable */ \
- TRUE, /* user_settable */ \
- FALSE, /* not independent */ \
- \
- /* Attributes - each status can have a message. */ \
- "message", \
- _("Message"), \
- purple_value_new(PURPLE_TYPE_STRING), \
- NULL); \
- \
- \
- types = g_list_append(types, status)
+ /* First, try the most obvious. If numeric userid is given, use that directly. */
+ if (msim_is_userid(username)) {
+ uid = atol(username);
+ } else {
+ /* Next, see if on buddy list and know uid. */
+ buddy = purple_find_buddy(session->account, username);
+ if (buddy) {
+ uid = purple_blist_node_get_int(&buddy->node, "UserID");
+ } else {
+ uid = 0;
+ }
+ if (!buddy || !uid) {
+ /* Don't have uid offhand - need to ask for it, and wait until hear back before sending. */
+ purple_debug_info("msim", ">>> msim_postprocess_outgoing: couldn't find username %s in blist\n",
+ username ? username : "(NULL)");
+ msim_msg_dump("msim_postprocess_outgoing - scheduling lookup, msg=%s\n", msg);
+ /* TODO: where is cloned message freed? Should be in _cb. */
+ msim_lookup_user(session, username, msim_postprocess_outgoing_cb, msim_msg_clone(msg));
+ return TRUE; /* not sure of status yet - haven't sent! */
+ }
+ }
- _MSIM_ADD_NEW_STATUS(PURPLE_STATUS_AVAILABLE);
- _MSIM_ADD_NEW_STATUS(PURPLE_STATUS_AWAY);
- _MSIM_ADD_NEW_STATUS(PURPLE_STATUS_OFFLINE);
- _MSIM_ADD_NEW_STATUS(PURPLE_STATUS_INVISIBLE);
+ /* Already have uid, postprocess and send msg immediately. */
+ purple_debug_info("msim", "msim_postprocess_outgoing: found username %s has uid %d\n",
+ username ? username : "(NULL)", uid);
- /* Except tune status is different... */
- status = purple_status_type_new_with_attrs(
- PURPLE_STATUS_TUNE, /* primitive */
- "tune", /* ID */
- NULL, /* name - use default */
- FALSE, /* saveable */
- TRUE, /* should be user_settable some day */
- TRUE, /* independent */
+ msg = msim_do_postprocessing(msg, uid_before, uid_field_name, uid);
- PURPLE_TUNE_ARTIST, _("Artist"), purple_value_new(PURPLE_TYPE_STRING),
- PURPLE_TUNE_TITLE, _("Title"), purple_value_new(PURPLE_TYPE_STRING),
- NULL);
+ msim_msg_dump("msim_postprocess_outgoing: msg after (uid immediate)=%s\n", msg);
- types = g_list_append(types, status);
+ rc = msim_msg_send(session, msg);
- return types;
+ /* TODO: free
+ * msim_msg_free(msg);
+ */
+
+ return rc;
}
/**
- * Return the icon name for a buddy and account.
+ * Send a buddy message of a given type.
*
- * @param acct The account to find the icon for, or NULL for protocol icon.
- * @param buddy The buddy to find the icon for, or NULL for the account icon.
+ * @param session
+ * @param who Username to send message to.
+ * @param text Message text to send. Not freed; will be copied.
+ * @param type A MSIM_BM_* constant.
*
- * @return The base icon name string.
+ * @return TRUE if success, FALSE if fail.
+ *
+ * Buddy messages ('bm') include instant messages, action messages, status messages, etc.
*/
-const gchar *
-msim_list_icon(PurpleAccount *acct, PurpleBuddy *buddy)
+gboolean
+msim_send_bm(MsimSession *session, const gchar *who, const gchar *text,
+ int type)
{
- /* Use a MySpace icon submitted by hbons at
- * http://developer.pidgin.im/wiki/MySpaceIM. */
- return "myspace";
-}
+ gboolean rc;
+ MsimMessage *msg;
+ const gchar *from_username;
-#ifdef MSIM_DEBUG_MSG
-static void
-print_hash_item(gpointer key, gpointer value, gpointer user_data)
-{
- purple_debug_info("msim", "%s=%s\n",
- key ? (gchar *)key : "(NULL)",
- value ? (gchar *)value : "(NULL)");
+ g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+ g_return_val_if_fail(who != NULL, FALSE);
+ g_return_val_if_fail(text != NULL, FALSE);
+
+ from_username = session->account->username;
+
+ g_return_val_if_fail(from_username != NULL, FALSE);
+
+ purple_debug_info("msim", "sending %d message from %s to %s: %s\n",
+ type, from_username, who, text);
+
+ msg = msim_msg_new(
+ "bm", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(type),
+ "sesskey", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(session->sesskey),
+ /* 't' will be inserted here */
+ "cv", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(MSIM_CLIENT_VERSION),
+ "msg", MSIM_TYPE_STRING, g_strdup(text),
+ NULL);
+
+ rc = msim_postprocess_outgoing(session, msg, who, "t", "cv");
+
+ msim_msg_free(msg);
+
+ return rc;
}
-#endif
-/**
- * Send raw data (given as a NUL-terminated string) to the server.
+/**
+ * Lookup a username by userid, from buddy list.
*
- * @param session
- * @param msg The raw data to send, in a NUL-terminated string.
+ * @param wanted_uid
*
- * @return TRUE if succeeded, FALSE if not.
+ * @return Username of wanted_uid, if on blist, or NULL.
+ * This is a static string, so don't free it. Copy it if needed.
*
*/
-gboolean
-msim_send_raw(MsimSession *session, const gchar *msg)
+static const gchar *
+msim_uid2username_from_blist(PurpleAccount *account, guint wanted_uid)
{
- g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
- g_return_val_if_fail(msg != NULL, FALSE);
-
- purple_debug_info("msim", "msim_send_raw: writing <%s>\n", msg);
+ GSList *buddies, *cur;
+ const gchar *ret;
- return msim_send_really_raw(session->gc, msg, strlen(msg)) ==
- strlen(msg);
+ buddies = purple_find_buddies(account, NULL);
+
+ if (!buddies)
+ {
+ purple_debug_info("msim", "msim_uid2username_from_blist: no buddies?\n");
+ return NULL;
+ }
+
+ ret = NULL;
+
+ for (cur = buddies; cur != NULL; cur = g_slist_next(cur))
+ {
+ PurpleBuddy *buddy;
+ guint uid;
+ const gchar *name;
+
+ /* See finch/gnthistory.c */
+ buddy = cur->data;
+
+ uid = purple_blist_node_get_int(&buddy->node, "UserID");
+ name = purple_buddy_get_name(buddy);
+
+ if (uid == wanted_uid)
+ {
+ ret = name;
+ break;
+ }
+ }
+
+ g_slist_free(buddies);
+ return ret;
}
-/** Send raw data to the server, possibly with embedded NULs.
+/**
+ * Setup a callback, to be called when a reply is received with the returned rid.
*
- * Used in prpl_info struct, so that plugins can have the most possible
- * control of what is sent over the connection. Inside this prpl,
- * msim_send_raw() is used, since it sends NUL-terminated strings (easier).
+ * @param cb The callback, an MSIM_USER_LOOKUP_CB.
+ * @param data Arbitrary user data to be passed to callback (probably an MsimMessage *).
*
- * @param gc PurpleConnection
- * @param buf Buffer to send
- * @param total_bytes Size of buffer to send
+ * @return The request/reply ID, used to link replies with requests, or -1.
+ * Put the rid in your request, 'rid' field.
*
- * @return Bytes successfully sent, or -1 on error.
+ * TODO: Make more generic and more specific:
+ * 1) MSIM_USER_LOOKUP_CB - make it for PERSIST_REPLY, not just user lookup
+ * 2) data - make it an MsimMessage?
*/
-static int
-msim_send_really_raw(PurpleConnection *gc, const char *buf, int total_bytes)
+guint
+msim_new_reply_callback(MsimSession *session, MSIM_USER_LOOKUP_CB cb,
+ gpointer data)
{
- int total_bytes_sent;
- MsimSession *session;
+ guint rid;
- g_return_val_if_fail(gc != NULL, -1);
- g_return_val_if_fail(buf != NULL, -1);
- g_return_val_if_fail(total_bytes >= 0, -1);
-
- session = (MsimSession *)gc->proto_data;
-
g_return_val_if_fail(MSIM_SESSION_VALID(session), -1);
-
- /* Loop until all data is sent, or a failure occurs. */
- total_bytes_sent = 0;
- do {
- int bytes_sent;
- bytes_sent = send(session->fd, buf + total_bytes_sent,
- total_bytes - total_bytes_sent, 0);
+ rid = session->next_rid++;
- if (bytes_sent < 0) {
- purple_debug_info("msim", "msim_send_raw(%s): send() failed: %s\n",
- buf, g_strerror(errno));
- return total_bytes_sent;
- }
- total_bytes_sent += bytes_sent;
+ g_hash_table_insert(session->user_lookup_cb, GUINT_TO_POINTER(rid), cb);
+ g_hash_table_insert(session->user_lookup_cb_data, GUINT_TO_POINTER(rid), data);
- } while(total_bytes_sent < total_bytes);
+ return rid;
+}
- return total_bytes_sent;
+/**
+ * Return the icon name for a buddy and account.
+ *
+ * @param acct The account to find the icon for, or NULL for protocol icon.
+ * @param buddy The buddy to find the icon for, or NULL for the account icon.
+ *
+ * @return The base icon name string.
+ */
+static const gchar *
+msim_list_icon(PurpleAccount *acct, PurpleBuddy *buddy)
+{
+ /* Use a MySpace icon submitted by hbons at
+ * http://developer.pidgin.im/wiki/MySpaceIM. */
+ return "myspace";
}
-
-/**
- * Start logging in to the MSIM servers.
- *
- * @param acct Account information to use to login.
+/**
+ * Obtain the status text for a buddy.
+ *
+ * @param buddy The buddy to obtain status text for.
+ *
+ * @return Status text, or NULL if error. Caller g_free()'s.
*/
-void
-msim_login(PurpleAccount *acct)
+static char *
+msim_status_text(PurpleBuddy *buddy)
{
- PurpleConnection *gc;
- const gchar *host;
- int port;
+ MsimSession *session;
+ MsimUser *user;
+ const gchar *display_name, *headline;
- g_return_if_fail(acct != NULL);
- g_return_if_fail(acct->username != NULL);
+ g_return_val_if_fail(buddy != NULL, NULL);
- purple_debug_info("msim", "logging in %s\n", acct->username);
+ user = msim_get_user_from_buddy(buddy);
- gc = purple_account_get_connection(acct);
- gc->proto_data = msim_session_new(acct);
- gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_URLDESC;
+ session = (MsimSession *)buddy->account->gc->proto_data;
+ g_return_val_if_fail(MSIM_SESSION_VALID(session), NULL);
- /* 1. connect to server */
- purple_connection_update_progress(gc, _("Connecting"),
- 0, /* which connection step this is */
- 4); /* total number of steps */
+ display_name = headline = NULL;
- host = purple_account_get_string(acct, "server", MSIM_SERVER);
- port = purple_account_get_int(acct, "port", MSIM_PORT);
+ /* Retrieve display name and/or headline, depending on user preference. */
+ if (purple_account_get_bool(session->account, "show_headline", TRUE)) {
+ headline = user->headline;
+ }
- /* From purple.sf.net/api:
- * """Note that this function name can be misleading--although it is called
- * "proxy connect," it is used for establishing any outgoing TCP connection,
- * whether through a proxy or not.""" */
+ if (purple_account_get_bool(session->account, "show_display_name", FALSE)) {
+ display_name = user->display_name;
+ }
- /* Calls msim_connect_cb when connected. */
- if (!purple_proxy_connect(gc, acct, host, port, msim_connect_cb, gc)) {
- /* TODO: try other ports if in auto mode, then save
- * working port and try that first next time. */
- purple_connection_error_reason (gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Couldn't create socket"));
- return;
+ /* Return appropriate combination of display name and/or headline, or neither. */
+
+ if (display_name && headline) {
+ return g_strconcat(display_name, " ", headline, NULL);
+ } else if (display_name) {
+ return g_strdup(display_name);
+ } else if (headline) {
+ return g_strdup(headline);
}
+
+ return NULL;
}
/**
- * Process a login challenge, sending a response.
+ * Obtain the tooltip text for a buddy.
*
- * @param session
- * @param msg Login challenge message.
- *
- * @return TRUE if successful, FALSE if not
+ * @param buddy Buddy to obtain tooltip text on.
+ * @param user_info Variable modified to have the tooltip text.
+ * @param full TRUE if should obtain full tooltip text.
*/
-static gboolean
-msim_login_challenge(MsimSession *session, MsimMessage *msg)
+static void
+msim_tooltip_text(PurpleBuddy *buddy, PurpleNotifyUserInfo *user_info,
+ gboolean full)
{
- PurpleAccount *account;
- gchar *response;
- guint response_len;
- gchar *nc;
- gsize nc_len;
- gboolean ret;
+ MsimUser *user;
- g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
- g_return_val_if_fail(msg != NULL, FALSE);
+ g_return_if_fail(buddy != NULL);
+ g_return_if_fail(user_info != NULL);
- g_return_val_if_fail(msim_msg_get_binary(msg, "nc", &nc, &nc_len), FALSE);
+ user = msim_get_user_from_buddy(buddy);
- account = session->account;
+ if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
+ MsimSession *session;
- g_return_val_if_fail(account != NULL, FALSE);
+ session = (MsimSession *)buddy->account->gc->proto_data;
- purple_connection_update_progress(session->gc, _("Reading challenge"), 1, 4);
+ g_return_if_fail(MSIM_SESSION_VALID(session));
- purple_debug_info("msim", "nc is %" G_GSIZE_FORMAT
- " bytes, decoded\n", nc_len);
+ /* TODO: if (full), do something different? */
- if (nc_len != MSIM_AUTH_CHALLENGE_LENGTH) {
- purple_debug_info("msim", "bad nc length: %" G_GSIZE_MODIFIER
- "x != 0x%x\n", nc_len, MSIM_AUTH_CHALLENGE_LENGTH);
- purple_connection_error_reason (session->gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Unexpected challenge length from server"));
- return FALSE;
+ /* TODO: request information? have to figure out how to do
+ * the asynchronous lookup like oscar does (tooltip shows
+ * 'retrieving...' if not yet available, then changes when it is).
+ *
+ * Right now, only show what we have on hand.
+ */
+
+ /* Show abbreviated user info. */
+ msim_append_user_info(session, user_info, user, FALSE);
}
+}
- purple_connection_update_progress(session->gc, _("Logging in"), 2, 4);
+/**
+ * Get possible user status types. Based on mockprpl.
+ *
+ * @return GList of status types.
+ */
+static GList *
+msim_status_types(PurpleAccount *acct)
+{
+ GList *types;
+ PurpleStatusType *status;
- response_len = 0;
- response = msim_compute_login_response(nc, account->username, account->password, &response_len);
+ purple_debug_info("myspace", "returning status types\n");
- g_free(nc);
+ types = NULL;
- ret = msim_send(session,
- "login2", MSIM_TYPE_INTEGER, MSIM_AUTH_ALGORITHM,
- /* This is actually user's email address. */
- "username", MSIM_TYPE_STRING, g_strdup(account->username),
- /* GString will be freed in msim_msg_free() in msim_send(). */
- "response", MSIM_TYPE_BINARY, g_string_new_len(response, response_len),
- "clientver", MSIM_TYPE_INTEGER, MSIM_CLIENT_VERSION,
- "langid", MSIM_TYPE_INTEGER, MSIM_LANGUAGE_ID_ENGLISH,
- "imlang", MSIM_TYPE_STRING, g_strdup(MSIM_LANGUAGE_NAME_ENGLISH),
- "reconn", MSIM_TYPE_INTEGER, 0,
- "status", MSIM_TYPE_INTEGER, 100,
- "id", MSIM_TYPE_INTEGER, 1,
+ /* Statuses are almost all the same. Define a macro to reduce code repetition. */
+#define _MSIM_ADD_NEW_STATUS(prim) status = \
+ purple_status_type_new_with_attrs( \
+ prim, /* PurpleStatusPrimitive */ \
+ NULL, /* id - use default */ \
+ NULL, /* name - use default */ \
+ TRUE, /* saveable */ \
+ TRUE, /* user_settable */ \
+ FALSE, /* not independent */ \
+ \
+ /* Attributes - each status can have a message. */ \
+ "message", \
+ _("Message"), \
+ purple_value_new(PURPLE_TYPE_STRING), \
+ NULL); \
+ \
+ \
+ types = g_list_append(types, status)
+
+
+ _MSIM_ADD_NEW_STATUS(PURPLE_STATUS_AVAILABLE);
+ _MSIM_ADD_NEW_STATUS(PURPLE_STATUS_AWAY);
+ _MSIM_ADD_NEW_STATUS(PURPLE_STATUS_OFFLINE);
+ _MSIM_ADD_NEW_STATUS(PURPLE_STATUS_INVISIBLE);
+
+ /* Except tune status is different... */
+ status = purple_status_type_new_with_attrs(
+ PURPLE_STATUS_TUNE, /* primitive */
+ "tune", /* ID */
+ NULL, /* name - use default */
+ FALSE, /* saveable */
+ TRUE, /* should be user_settable some day */
+ TRUE, /* independent */
+
+ PURPLE_TUNE_ARTIST, _("Artist"), purple_value_new(PURPLE_TYPE_STRING),
+ PURPLE_TUNE_TITLE, _("Title"), purple_value_new(PURPLE_TYPE_STRING),
NULL);
- g_free(response);
+ types = g_list_append(types, status);
- return ret;
+ return types;
}
/**
@@ -390,11 +528,11 @@ msim_login_challenge(MsimSession *sessio
* @param password User's cleartext password.
* @param response_len Will be written with response length.
*
- * @return Binary login challenge response, ready to send to the server.
+ * @return Binary login challenge response, ready to send to the server.
* Must be g_free()'d when finished. NULL if error.
*/
static gchar *
-msim_compute_login_response(const gchar nonce[2 * NONCE_SIZE],
+msim_compute_login_response(const gchar nonce[2 * NONCE_SIZE],
const gchar *email, const gchar *password, guint *response_len)
{
PurpleCipherContext *key_context;
@@ -426,22 +564,22 @@ msim_compute_login_response(const gchar
/* Convert ASCII password to UTF16 little endian */
purple_debug_info("msim", "converting password to UTF-16LE\n");
conv_error = NULL;
- password_utf16le = g_convert(password_utf8_lc, -1, "UTF-16LE", "UTF-8",
+ password_utf16le = g_convert(password_utf8_lc, -1, "UTF-16LE", "UTF-8",
&conv_bytes_read, &conv_bytes_written, &conv_error);
g_free(password_utf8_lc);
g_return_val_if_fail(conv_bytes_read == strlen(password), NULL);
if (conv_error != NULL) {
- purple_debug_error("msim",
+ purple_debug_error("msim",
"g_convert password UTF8->UTF16LE failed: %s",
conv_error->message);
g_error_free(conv_error);
return NULL;
}
- /* Compute password hash */
- purple_cipher_digest_region("sha1", (guchar *)password_utf16le,
+ /* Compute password hash */
+ purple_cipher_digest_region("sha1", (guchar *)password_utf16le,
conv_bytes_written, sizeof(hash_pw), hash_pw, NULL);
g_free(password_utf16le);
@@ -470,7 +608,7 @@ msim_compute_login_response(const gchar
rc4 = purple_cipher_context_new_by_name("rc4", NULL);
- /* Note: 'key' variable is 0x14 bytes (from SHA-1 hash),
+ /* Note: 'key' variable is 0x14 bytes (from SHA-1 hash),
* but only first 0x10 used for the RC4 key. */
purple_cipher_context_set_option(rc4, "key_len", (gpointer)0x10);
purple_cipher_context_set_key(rc4, key);
@@ -488,7 +626,7 @@ msim_compute_login_response(const gchar
data_out = g_new0(guchar, data_len);
- purple_cipher_context_encrypt(rc4, (const guchar *)data,
+ purple_cipher_context_encrypt(rc4, (const guchar *)data,
data_len, data_out, &data_out_len);
purple_cipher_context_destroy(rc4);
g_free(data);
@@ -509,224 +647,70 @@ msim_compute_login_response(const gchar
}
/**
- * Schedule an IM to be sent once the user ID is looked up.
+ * Process a login challenge, sending a response.
*
- * @param gc Connection.
- * @param who A user id, email, or username to send the message to.
- * @param message Instant message text to send.
- * @param flags Flags.
- *
- * @return 1 if successful or postponed, -1 if failed
- *
- * Allows sending to a user by username, email address, or userid. If
- * a username or email address is given, the userid must be looked up.
- * This function does that by calling msim_postprocess_outgoing().
- */
-int
-msim_send_im(PurpleConnection *gc, const gchar *who, const gchar *message,
- PurpleMessageFlags flags)
-{
- MsimSession *session;
- gchar *message_msim;
- int rc;
-
- g_return_val_if_fail(gc != NULL, -1);
- g_return_val_if_fail(who != NULL, -1);
- g_return_val_if_fail(message != NULL, -1);
-
- /* 'flags' has many options, not used here. */
-
- session = (MsimSession *)gc->proto_data;
-
- g_return_val_if_fail(MSIM_SESSION_VALID(session), -1);
-
- message_msim = html_to_msim_markup(session, message);
-
- if (msim_send_bm(session, who, message_msim, MSIM_BM_INSTANT)) {
- /* Return 1 to have Purple show this IM as being sent, 0 to not. I always
- * return 1 even if the message could not be sent, since I don't know if
- * it has failed yet--because the IM is only sent after the userid is
- * retrieved from the server (which happens after this function returns).
- * If an error does occur, it should be logged to the IM window.
- */
- rc = 1;
- } else {
- rc = -1;
- }
-
- g_free(message_msim);
-
- return rc;
-}
-
-/** Send a buddy message of a given type.
- *
* @param session
- * @param who Username to send message to.
- * @param text Message text to send. Not freed; will be copied.
- * @param type A MSIM_BM_* constant.
+ * @param msg Login challenge message.
*
- * @return TRUE if success, FALSE if fail.
- *
- * Buddy messages ('bm') include instant messages, action messages, status messages, etc.
- *
+ * @return TRUE if successful, FALSE if not
*/
-gboolean
-msim_send_bm(MsimSession *session, const gchar *who, const gchar *text,
- int type)
-{
- gboolean rc;
- MsimMessage *msg;
- const gchar *from_username;
-
- g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
- g_return_val_if_fail(who != NULL, FALSE);
- g_return_val_if_fail(text != NULL, FALSE);
-
- from_username = session->account->username;
-
- g_return_val_if_fail(from_username != NULL, FALSE);
-
- purple_debug_info("msim", "sending %d message from %s to %s: %s\n",
- type, from_username, who, text);
-
- msg = msim_msg_new(
- "bm", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(type),
- "sesskey", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(session->sesskey),
- /* 't' will be inserted here */
- "cv", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(MSIM_CLIENT_VERSION),
- "msg", MSIM_TYPE_STRING, g_strdup(text),
- NULL);
-
- rc = msim_postprocess_outgoing(session, msg, who, "t", "cv");
-
- msim_msg_free(msg);
-
- return rc;
-}
-
-
-/** Record the client version in the buddy list, from an incoming message. */
static gboolean
-msim_incoming_bm_record_cv(MsimSession *session, MsimMessage *msg)
+msim_login_challenge(MsimSession *session, MsimMessage *msg)
{
- gchar *username, *cv;
+ PurpleAccount *account;
+ gchar *response;
+ guint response_len;
+ gchar *nc;
+ gsize nc_len;
gboolean ret;
- MsimUser *user;
- username = msim_msg_get_string(msg, "_username");
- cv = msim_msg_get_string(msg, "cv");
+ g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+ g_return_val_if_fail(msg != NULL, FALSE);
- g_return_val_if_fail(username != NULL, FALSE);
- if (!cv) {
- /* No client version to record, don't worry about it. */
- g_free(username);
- return FALSE;
- }
+ g_return_val_if_fail(msim_msg_get_binary(msg, "nc", &nc, &nc_len), FALSE);
- user = msim_find_user(session, username);
+ account = session->account;
- if (user) {
- user->client_cv = atol(cv);
- ret = TRUE;
- } else {
- ret = FALSE;
- }
+ g_return_val_if_fail(account != NULL, FALSE);
- g_free(username);
- g_free(cv);
+ purple_connection_update_progress(session->gc, _("Reading challenge"), 1, 4);
- return ret;
-}
+ purple_debug_info("msim", "nc is %" G_GSIZE_FORMAT
+ " bytes, decoded\n", nc_len);
-/** Handle an incoming buddy message. */
-static gboolean
-msim_incoming_bm(MsimSession *session, MsimMessage *msg)
-{
- guint bm;
-
- bm = msim_msg_get_integer(msg, "bm");
-
- msim_incoming_bm_record_cv(session, msg);
-
- switch (bm) {
- case MSIM_BM_STATUS:
- return msim_incoming_status(session, msg);
- case MSIM_BM_INSTANT:
- return msim_incoming_im(session, msg);
- case MSIM_BM_ACTION:
- return msim_incoming_action(session, msg);
- case MSIM_BM_MEDIA:
- return msim_incoming_media(session, msg);
- case MSIM_BM_UNOFFICIAL_CLIENT:
- return msim_incoming_unofficial_client(session, msg);
- default:
- /* Not really an IM, but show it for informational
- * purposes during development. */
- return msim_incoming_im(session, msg);
- }
-}
-
-/**
- * Handle an incoming instant message.
- *
- * @param session The session
- * @param msg Message from the server, containing 'f' (userid from) and 'msg'.
- * Should also contain username in _username from preprocessing.
- *
- * @return TRUE if successful.
- */
-static gboolean
-msim_incoming_im(MsimSession *session, MsimMessage *msg)
-{
- gchar *username, *msg_msim_markup, *msg_purple_markup;
- gchar *userid;
- time_t time_received;
- PurpleConversation *conv;
-
- g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
- g_return_val_if_fail(msg != NULL, FALSE);
-
- username = msim_msg_get_string(msg, "_username");
- /* I know this isn't really a string... but we need it to be one for
- * purple_find_conversation_with_account(). */
- userid = msim_msg_get_string(msg, "f");
- g_return_val_if_fail(username != NULL, FALSE);
-
- purple_debug_info("msim_incoming_im", "UserID is %s", userid);
-
- if (msim_is_userid(username)) {
- purple_debug_info("msim", "Ignoring message from spambot (%s) on account %s\n",
- username, purple_account_get_username(session->account));
- g_free(username);
+ if (nc_len != MSIM_AUTH_CHALLENGE_LENGTH) {
+ purple_debug_info("msim", "bad nc length: %" G_GSIZE_MODIFIER
+ "x != 0x%x\n", nc_len, MSIM_AUTH_CHALLENGE_LENGTH);
+ purple_connection_error_reason (session->gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Unexpected challenge length from server"));
return FALSE;
}
-
- /* See if a conversation with their UID already exists...*/
- conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, userid, session->account);
- if (conv) {
- /* Since the conversation exists... We need to normalize it */
- purple_conversation_set_name(conv, username);
- }
- msg_msim_markup = msim_msg_get_string(msg, "msg");
- g_return_val_if_fail(msg_msim_markup != NULL, FALSE);
+ purple_connection_update_progress(session->gc, _("Logging in"), 2, 4);
- msg_purple_markup = msim_markup_to_html(session, msg_msim_markup);
- g_free(msg_msim_markup);
+ response_len = 0;
+ response = msim_compute_login_response(nc, account->username, account->password, &response_len);
- time_received = msim_msg_get_integer(msg, "date");
- if (!time_received) {
- purple_debug_info("msim_incoming_im", "date in message not set.\n");
- time_received = time(NULL);
- }
+ g_free(nc);
- serv_got_im(session->gc, username, msg_purple_markup, PURPLE_MESSAGE_RECV, time_received);
+ ret = msim_send(session,
+ "login2", MSIM_TYPE_INTEGER, MSIM_AUTH_ALGORITHM,
+ /* This is actually user's email address. */
+ "username", MSIM_TYPE_STRING, g_strdup(account->username),
+ /* GString will be freed in msim_msg_free() in msim_send(). */
+ "response", MSIM_TYPE_BINARY, g_string_new_len(response, response_len),
+ "clientver", MSIM_TYPE_INTEGER, MSIM_CLIENT_VERSION,
+ "langid", MSIM_TYPE_INTEGER, MSIM_LANGUAGE_ID_ENGLISH,
+ "imlang", MSIM_TYPE_STRING, g_strdup(MSIM_LANGUAGE_NAME_ENGLISH),
+ "reconn", MSIM_TYPE_INTEGER, 0,
+ "status", MSIM_TYPE_INTEGER, 100,
+ "id", MSIM_TYPE_INTEGER, 1,
+ NULL);
- g_free(username);
- g_free(msg_purple_markup);
+ g_free(response);
- return TRUE;
+ return ret;
}
/**
@@ -736,10 +720,10 @@ msim_incoming_im(MsimSession *session, M
* @param msg An MsimMessage that was unrecognized, or NULL.
* @param note Information on what was unrecognized, or NULL.
*/
-void
+void
msim_unrecognized(MsimSession *session, MsimMessage *msg, gchar *note)
{
- /* TODO: Some more context, outwardly equivalent to a backtrace,
+ /* TODO: Some more context, outwardly equivalent to a backtrace,
* for helping figure out what this msg is for. What was going on?
* But not too much information so that a user
* posting this dump reveals confidential information.
@@ -747,13 +731,13 @@ msim_unrecognized(MsimSession *session,
/* TODO: dump unknown msgs to file, so user can send them to me
* if they wish, to help add support for new messages (inspired
- * by Alexandr Shutko, who maintains OSCAR protocol documentation).
+ * by Alexandr Shutko, who maintains OSCAR protocol documentation).
*
* Filed enhancement ticket for libpurple as #4688.
*/
- purple_debug_info("msim", "Unrecognized data on account for %s\n",
- (session && session->account && session->account->username) ?
+ purple_debug_info("msim", "Unrecognized data on account for %s\n",
+ (session && session->account && session->account->username) ?
session->account->username : "(NULL)");
if (note) {
purple_debug_info("msim", "(Note: %s)\n", note);
@@ -764,562 +748,62 @@ msim_unrecognized(MsimSession *session,
}
}
-/**
- * Handle an incoming action message.
- *
- * @param session
- * @param msg
- *
- * @return TRUE if successful.
- *
- */
-static gboolean
-msim_incoming_action(MsimSession *session, MsimMessage *msg)
+/** Called when the session key arrives to check whether the user
+ * has a username, and set one if desired. */
+static gboolean
+msim_is_username_set(MsimSession *session, MsimMessage *msg)
{
- gchar *msg_text, *username;
- gboolean rc;
-
g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
g_return_val_if_fail(msg != NULL, FALSE);
+ g_return_val_if_fail(session->gc != NULL, FALSE);
- msg_text = msim_msg_get_string(msg, "msg");
- g_return_val_if_fail(msg_text != NULL, FALSE);
+ session->sesskey = msim_msg_get_integer(msg, "sesskey");
+ purple_debug_info("msim", "SESSKEY=<%d>\n", session->sesskey);
- username = msim_msg_get_string(msg, "_username");
- g_return_val_if_fail(username != NULL, FALSE);
+ /* What is proof? Used to be uid, but now is 52 base64'd bytes... */
- purple_debug_info("msim", "msim_incoming_action: action <%s> from <%s>\n",
- msg_text, username);
+ /* Comes with: proof,profileid,userid,uniquenick -- all same values
+ * some of the time, but can vary. This is our own user ID. */
+ session->userid = msim_msg_get_integer(msg, "userid");
- if (g_str_equal(msg_text, "%typing%")) {
- serv_got_typing(session->gc, username, 0, PURPLE_TYPING);
- rc = TRUE;
- } else if (g_str_equal(msg_text, "%stoptyping%")) {
- serv_got_typing_stopped(session->gc, username);
- rc = TRUE;
- } else if (strstr(msg_text, "!!!ZAP_SEND!!!=RTE_BTN_ZAPS_")) {
- rc = msim_incoming_zap(session, msg);
- } else if (strstr(msg_text, "!!!GroupCount=")) {
- /* TODO: support group chats. I think the number in msg_text has
- * something to do with the 'gid' field. */
- purple_debug_info("msim", "msim_incoming_action: TODO: implement #4691, group chats: %s\n", msg_text);
+ /* Save uid to account so this account can be looked up by uid. */
+ purple_account_set_int(session->account, "uid", session->userid);
- rc = TRUE;
- } else if (strstr(msg_text, "!!!Offline=")) {
- /* TODO: support group chats. This one might mean a user
- * went offline or exited the chat. */
- purple_debug_info("msim", "msim_incoming_action: TODO: implement #4691, group chats: %s\n", msg_text);
-
- rc = TRUE;
- } else if (msim_msg_get_integer(msg, "aid") != 0) {
- purple_debug_info("msim", "TODO: implement #4691, group chat from %d on %d: %s\n",
- msim_msg_get_integer(msg, "aid"),
- msim_msg_get_integer(msg, "f"),
- msg_text);
-
- rc = TRUE;
- } else {
- msim_unrecognized(session, msg,
- "got to msim_incoming_action but unrecognized value for 'msg'");
- rc = FALSE;
+ /* Not sure what profileid is used for. */
+ if (msim_msg_get_integer(msg, "profileid") != session->userid) {
+ msim_unrecognized(session, msg,
+ "Profile ID didn't match user ID, don't know why");
}
- g_free(msg_text);
- g_free(username);
+ /* We now know are our own username, only after we're logged in..
+ * which is weird, but happens because you login with your email
+ * address and not username. Will be freed in msim_session_destroy(). */
+ session->username = msim_msg_get_string(msg, "uniquenick");
- return rc;
-}
-
-/* Process an incoming media (message background?) message. */
-static gboolean
-msim_incoming_media(MsimSession *session, MsimMessage *msg)
-{
- gchar *username, *text;
-
- username = msim_msg_get_string(msg, "_username");
- text = msim_msg_get_string(msg, "msg");
-
- g_return_val_if_fail(username != NULL, FALSE);
- g_return_val_if_fail(text != NULL, FALSE);
-
- purple_debug_info("msim", "msim_incoming_media: from %s, got msg=%s\n", username, text);
-
- /* Media messages are sent when the user opens a window to someone.
- * Tell libpurple they started typing and stopped typing, to inform the Psychic
- * Mode plugin so it too can open a window to the user. */
- serv_got_typing(session->gc, username, 0, PURPLE_TYPING);
- serv_got_typing_stopped(session->gc, username);
-
- g_free(username);
-
- return TRUE;
-}
-
-/* Process an incoming "unofficial client" message. The plugin for
- * Miranda IM sends this message with the plugin information. */
-static gboolean
-msim_incoming_unofficial_client(MsimSession *session, MsimMessage *msg)
-{
- MsimUser *user;
- gchar *username, *client_info;
-
- username = msim_msg_get_string(msg, "_username");
- client_info = msim_msg_get_string(msg, "msg");
-
- g_return_val_if_fail(username != NULL, FALSE);
- g_return_val_if_fail(client_info != NULL, FALSE);
-
- purple_debug_info("msim", "msim_incoming_unofficial_client: %s is using client %s\n",
- username, client_info);
-
- user = msim_find_user(session, username);
-
- g_return_val_if_fail(user != NULL, FALSE);
-
- if (user->client_info) {
- g_free(user->client_info);
+ /* If user lacks a username, help them get one. */
+ if (msim_msg_get_integer(msg, "uniquenick") == session->userid) {
+ purple_debug_info("msim_is_username_set", "no username is set\n");
+ purple_request_yes_no(session->gc,
+ _("MySpaceIM - No Username Set"),
+ _("You appear to have no MySpace username."),
+ _("Would you like to set one now? (Note: THIS CANNOT BE CHANGED!)"),
+ 0,
+ session->account,
+ NULL,
+ NULL,
+ session->gc,
+ G_CALLBACK(msim_set_username_cb),
+ G_CALLBACK(msim_do_not_set_username_cb));
+ purple_debug_info("msim_is_username_set","'username not set' alert prompted\n");
+ return FALSE;
}
- user->client_info = client_info;
-
- g_free(username);
- /* Do not free client_info - the MsimUser now owns it. */
-
return TRUE;
}
-
-#ifdef MSIM_SEND_CLIENT_VERSION
-/** Send our client version to another unofficial client that understands it. */
-static gboolean
-msim_send_unofficial_client(MsimSession *session, gchar *username)
-{
- gchar *our_info;
- gboolean ret;
-
- our_info = g_strdup_printf("Libpurple %d.%d.%d - msimprpl %s",
- PURPLE_MAJOR_VERSION,
- PURPLE_MINOR_VERSION,
- PURPLE_MICRO_VERSION,
- MSIM_PRPL_VERSION_STRING);
-
- ret = msim_send_bm(session, username, our_info, MSIM_BM_UNOFFICIAL_CLIENT);
-
- return ret;
-}
-#endif
-
-/**
- * Handle when our user starts or stops typing to another user.
- *
- * @param gc
- * @param name The buddy name to which our user is typing to
- * @param state PURPLE_TYPING, PURPLE_TYPED, PURPLE_NOT_TYPING
- *
- * @return 0
+#ifdef MSIM_USE_KEEPALIVE
+/**
+ * Check if the connection is still alive, based on last communication.
*/
-unsigned int
-msim_send_typing(PurpleConnection *gc, const gchar *name,
- PurpleTypingState state)
-{
- const gchar *typing_str;
- MsimSession *session;
-
- g_return_val_if_fail(gc != NULL, 0);
- g_return_val_if_fail(name != NULL, 0);
-
- session = (MsimSession *)gc->proto_data;
-
- g_return_val_if_fail(MSIM_SESSION_VALID(session), 0);
-
- switch (state) {
- case PURPLE_TYPING:
- typing_str = "%typing%";
- break;
-
- case PURPLE_TYPED:
- case PURPLE_NOT_TYPING:
- default:
- typing_str = "%stoptyping%";
- break;
- }
-
- purple_debug_info("msim", "msim_send_typing(%s): %d (%s)\n", name, state, typing_str);
- msim_send_bm(session, name, typing_str, MSIM_BM_ACTION);
- return 0;
-}
-
-
-
-/** Callback for msim_get_info(), for when user info is received. */
-static void
-msim_get_info_cb(MsimSession *session, MsimMessage *user_info_msg,
- gpointer data)
-{
- MsimMessage *msg;
- gchar *username;
- PurpleNotifyUserInfo *user_info;
- MsimUser *user;
-
- g_return_if_fail(MSIM_SESSION_VALID(session));
-
- /* Get user{name,id} from msim_get_info, passed as an MsimMessage for
- orthogonality. */
- msg = (MsimMessage *)data;
- g_return_if_fail(msg != NULL);
-
- username = msim_msg_get_string(msg, "user");
- if (!username) {
- purple_debug_info("msim", "msim_get_info_cb: no 'user' in msg\n");
- return;
- }
-
- msim_msg_free(msg);
- purple_debug_info("msim", "msim_get_info_cb: got for user: %s\n", username);
-
- user = msim_find_user(session, username);
-
- if (!user) {
- /* User isn't on blist, create a temporary user to store info. */
- user = g_new0(MsimUser, 1);
- user->temporary_user = TRUE;
- }
-
- /* Update user structure with new information */
- msim_store_user_info(session, user_info_msg, user);
-
- user_info = purple_notify_user_info_new();
-
- /* Append data from MsimUser to PurpleNotifyUserInfo for display, full */
- msim_append_user_info(session, user_info, user, TRUE);
-
- purple_notify_userinfo(session->gc, username, user_info, NULL, NULL);
- purple_debug_info("msim", "msim_get_info_cb: username=%s\n", username);
-
- purple_notify_user_info_destroy(user_info);
-
- if (user->temporary_user) {
- g_free(user->client_info);
- g_free(user->gender);
- g_free(user->location);
- g_free(user->headline);
- g_free(user->display_name);
- g_free(user->username);
- g_free(user->image_url);
- g_free(user);
- }
- g_free(username);
-}
-
-/** Retrieve a user's profile.
- * @param username Username, user ID, or email address to lookup.
- */
-void
-msim_get_info(PurpleConnection *gc, const gchar *username)
-{
- MsimSession *session;
- MsimUser *user;
- gchar *user_to_lookup;
- MsimMessage *user_msg;
-
- g_return_if_fail(gc != NULL);
- g_return_if_fail(username != NULL);
-
- session = (MsimSession *)gc->proto_data;
-
- g_return_if_fail(MSIM_SESSION_VALID(session));
-
- /* Obtain uid of buddy. */
- user = msim_find_user(session, username);
-
- /* If is on buddy list, lookup by uid since it is faster. */
- if (user && user->id) {
- user_to_lookup = g_strdup_printf("%d", user->id);
- } else {
- /* Looking up buddy not on blist. Lookup by whatever user entered. */
- user_to_lookup = g_strdup(username);
- }
-
- /* Pass the username to msim_get_info_cb(), because since we lookup
- * by userid, the userinfo message will only contain the uid (not
- * the username) but it would be useful to display the username too.
- */
- user_msg = msim_msg_new(
- "user", MSIM_TYPE_STRING, g_strdup(username),
- NULL);
- purple_debug_info("msim", "msim_get_info, setting up lookup, user=%s\n", username);
-
- msim_lookup_user(session, user_to_lookup, msim_get_info_cb, user_msg);
-
- g_free(user_to_lookup);
-}
-
-/** Set your status - callback for when user manually sets it. */
-void
-msim_set_status(PurpleAccount *account, PurpleStatus *status)
-{
- PurpleStatusType *type;
- PurplePresence *pres;
- MsimSession *session;
- guint status_code;
- const gchar *message;
- gchar *stripped;
- gchar *unrecognized_msg;
-
- session = (MsimSession *)account->gc->proto_data;
-
- g_return_if_fail(MSIM_SESSION_VALID(session));
-
- type = purple_status_get_type(status);
- pres = purple_status_get_presence(status);
-
- switch (purple_status_type_get_primitive(type)) {
- case PURPLE_STATUS_AVAILABLE:
- purple_debug_info("msim", "msim_set_status: available (%d->%d)\n", PURPLE_STATUS_AVAILABLE,
- MSIM_STATUS_CODE_ONLINE);
- status_code = MSIM_STATUS_CODE_ONLINE;
- break;
-
- case PURPLE_STATUS_INVISIBLE:
- purple_debug_info("msim", "msim_set_status: invisible (%d->%d)\n", PURPLE_STATUS_INVISIBLE,
- MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN);
- status_code = MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN;
- break;
-
- case PURPLE_STATUS_AWAY:
- purple_debug_info("msim", "msim_set_status: away (%d->%d)\n", PURPLE_STATUS_AWAY,
- MSIM_STATUS_CODE_AWAY);
- status_code = MSIM_STATUS_CODE_AWAY;
- break;
-
- default:
- purple_debug_info("msim", "msim_set_status: unknown "
- "status interpreting as online");
- status_code = MSIM_STATUS_CODE_ONLINE;
-
- unrecognized_msg = g_strdup_printf("msim_set_status, unrecognized status type: %d\n",
- purple_status_type_get_primitive(type));
- msim_unrecognized(session, NULL, unrecognized_msg);
- g_free(unrecognized_msg);
-
- break;
- }
-
- message = purple_status_get_attr_string(status, "message");
-
- /* Status strings are plain text. */
- if (message != NULL)
- stripped = purple_markup_strip_html(message);
- else
- stripped = g_strdup("");
-
- msim_set_status_code(session, status_code, stripped);
-
- /* If we should be idle, set that status. Time is irrelevant here. */
- if (purple_presence_is_idle(pres) && status_code != MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN)
- msim_set_idle(account->gc, 1);
-
-}
-
-/** Go idle. */
-void
-msim_set_idle(PurpleConnection *gc, int time)
-{
- MsimSession *session;
- PurpleStatus *status;
-
- g_return_if_fail(gc != NULL);
-
- session = (MsimSession *)gc->proto_data;
-
- g_return_if_fail(MSIM_SESSION_VALID(session));
-
- status = purple_account_get_active_status(session->account);
-
- if (time == 0) {
- /* Going back from idle. In msim, idle is mutually exclusive
- * from the other states (you can only be away or idle, but not
- * both, for example), so by going non-idle I go back to what
- * libpurple says I should be.
- */
- msim_set_status(session->account, status);
- } else {
- const gchar *message;
- gchar *stripped;
-
- /* Set the idle message to the status message from the real
- * current status.
- */
- message = purple_status_get_attr_string(status, "message");
- if (message != NULL)
- stripped = purple_markup_strip_html(message);
- else
- stripped = g_strdup("");
-
- /* msim doesn't support idle time, so just go idle */
- msim_set_status_code(session, MSIM_STATUS_CODE_IDLE, stripped);
- }
-}
-
-/** Set status using an MSIM_STATUS_CODE_* value.
- * @param status_code An MSIM_STATUS_CODE_* value.
- * @param statstring Status string, must be a dynamic string (will be freed by msim_send).
- */
-static void
-msim_set_status_code(MsimSession *session, guint status_code, gchar *statstring)
-{
- g_return_if_fail(MSIM_SESSION_VALID(session));
- g_return_if_fail(statstring != NULL);
-
- purple_debug_info("msim", "msim_set_status_code: going to set status to code=%d,str=%s\n",
- status_code, statstring);
-
- if (!msim_send(session,
- "status", MSIM_TYPE_INTEGER, status_code,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "statstring", MSIM_TYPE_STRING, statstring,
- "locstring", MSIM_TYPE_STRING, g_strdup(""),
- NULL))
- {
- purple_debug_info("msim", "msim_set_status: failed to set status\n");
- }
-
-}
-
-/** After a uid is resolved to username, tag it with the username and submit for processing.
- *
- * @param session
- * @param userinfo Response messsage to resolving request.
- * @param data MsimMessage *, the message to attach information to.
- */
-static void
-msim_incoming_resolved(MsimSession *session, MsimMessage *userinfo,
- gpointer data)
-{
- gchar *username;
- MsimMessage *msg, *body;
-
- g_return_if_fail(MSIM_SESSION_VALID(session));
- g_return_if_fail(userinfo != NULL);
-
- body = msim_msg_get_dictionary(userinfo, "body");
- g_return_if_fail(body != NULL);
-
- username = msim_msg_get_string(body, "UserName");
- g_return_if_fail(username != NULL);
- /* Note: username will be owned by 'msg' below. */
-
- msg = (MsimMessage *)data;
- g_return_if_fail(msg != NULL);
-
- /* TODO: more elegant solution than below. attach whole message? */
- /* Special elements name beginning with '_', we'll use internally within the
- * program (did not come directly from the wire). */
- msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, username); /* This makes 'msg' the owner of 'username' */
-
- /* TODO: attach more useful information, like ImageURL */
-
- msim_process(session, msg);
-
- /* TODO: Free copy cloned from msim_preprocess_incoming(). */
- /* msim_msg_free(msg); */
- msim_msg_free(body);
-}
-
-/* Lookup a username by userid, from buddy list.
- *
- * @param wanted_uid
- *
- * @return Username of wanted_uid, if on blist, or NULL.
- * This is a static string, so don't free it. Copy it if needed.
- *
- */
-static const gchar *
-msim_uid2username_from_blist(PurpleAccount *account, guint wanted_uid)
-{
- GSList *buddies, *cur;
- const gchar *ret;
-
- buddies = purple_find_buddies(account, NULL);
-
- if (!buddies)
- {
- purple_debug_info("msim", "msim_uid2username_from_blist: no buddies?\n");
- return NULL;
- }
-
- ret = NULL;
-
- for (cur = buddies; cur != NULL; cur = g_slist_next(cur))
- {
- PurpleBuddy *buddy;
- guint uid;
- const gchar *name;
-
- /* See finch/gnthistory.c */
- buddy = cur->data;
-
- uid = purple_blist_node_get_int(&buddy->node, "UserID");
- name = purple_buddy_get_name(buddy);
-
- if (uid == wanted_uid)
- {
- ret = name;
- break;
- }
- }
-
- g_slist_free(buddies);
- return ret;
-}
-
-/** Preprocess incoming messages, resolving as needed, calling msim_process() when ready to process.
- *
- * @param session
- * @param msg MsimMessage *, freed by caller.
- */
-static gboolean
-msim_preprocess_incoming(MsimSession *session, MsimMessage *msg)
-{
- g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
- g_return_val_if_fail(msg != NULL, FALSE);
-
- if (msim_msg_get(msg, "bm") && msim_msg_get(msg, "f")) {
- guint uid;
- const gchar *username;
-
- /* 'f' = userid message is from, in buddy messages */
- uid = msim_msg_get_integer(msg, "f");
-
- username = msim_uid2username_from_blist(session->account, uid);
-
- if (username) {
- /* Know username already, use it. */
- purple_debug_info("msim", "msim_preprocess_incoming: tagging with _username=%s\n",
- username);
- msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, g_strdup(username));
- return msim_process(session, msg);
-
- } else {
- gchar *from;
-
- /* Send lookup request. */
- /* XXX: where is msim_msg_get_string() freed? make _strdup and _nonstrdup. */
- purple_debug_info("msim", "msim_incoming: sending lookup, setting up callback\n");
- from = msim_msg_get_string(msg, "f");
- msim_lookup_user(session, from, msim_incoming_resolved, msim_msg_clone(msg));
- g_free(from);
-
- /* indeterminate */
- return TRUE;
- }
- } else {
- /* Nothing to resolve - send directly to processing. */
- return msim_process(session, msg);
- }
-}
-
-#ifdef MSIM_USE_KEEPALIVE
-/** Check if the connection is still alive, based on last communication. */
static gboolean
msim_check_alive(gpointer data)
{
@@ -1348,7 +832,9 @@ msim_check_alive(gpointer data)
}
#endif
-/** Handle mail reply checks. */
+/**
+ * Handle mail reply checks.
+ */
static void
msim_check_inbox_cb(MsimSession *session, MsimMessage *reply, gpointer data)
{
@@ -1358,7 +844,7 @@ msim_check_inbox_cb(MsimSession *session
const gchar *froms[5], *tos[5], *urls[5], *subjects[5];
/* Information for each new inbox message type. */
- static struct
+ static struct
{
const gchar *key;
guint bit;
@@ -1395,7 +881,7 @@ msim_check_inbox_cb(MsimSession *session
for (i = 0; i < sizeof(message_types) / sizeof(message_types[0]); ++i) {
const gchar *key;
guint bit;
-
+
key = message_types[i].key;
bit = message_types[i].bit;
@@ -1433,7 +919,7 @@ msim_check_inbox_cb(MsimSession *session
purple_notify_emails(session->gc, /* handle */
n, /* count */
TRUE, /* detailed */
- subjects, froms, tos, urls,
+ subjects, froms, tos, urls,
NULL, /* PurpleNotifyCloseCallback cb */
NULL); /* gpointer user_data */
@@ -1442,7 +928,9 @@ msim_check_inbox_cb(MsimSession *session
msim_msg_free(body);
}
-/* Send request to check if there is new mail. */
+/**
+ * Send request to check if there is new mail.
+ */
static gboolean
msim_check_inbox(gpointer data)
{
@@ -1456,14 +944,14 @@ msim_check_inbox(gpointer data)
}
purple_debug_info("msim", "msim_check_inbox: checking mail\n");
- g_return_val_if_fail(msim_send(session,
+ g_return_val_if_fail(msim_send(session,
"persist", MSIM_TYPE_INTEGER, 1,
"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
"cmd", MSIM_TYPE_INTEGER, MSIM_CMD_GET,
"dsn", MSIM_TYPE_INTEGER, MG_CHECK_MAIL_DSN,
"lid", MSIM_TYPE_INTEGER, MG_CHECK_MAIL_LID,
"uid", MSIM_TYPE_INTEGER, session->userid,
- "rid", MSIM_TYPE_INTEGER,
+ "rid", MSIM_TYPE_INTEGER,
msim_new_reply_callback(session, msim_check_inbox_cb, NULL),
"body", MSIM_TYPE_STRING, g_strdup(""),
NULL), TRUE);
@@ -1472,145 +960,198 @@ msim_check_inbox(gpointer data)
return TRUE;
}
-#ifdef MSIM_CHECK_NEWER_VERSION
-/** Callback for when a currentversion.txt has been downloaded. */
+/**
+ * Add contact from server to buddy list, after looking up username.
+ * Callback from msim_add_contact_from_server().
+ *
+ * @param data An MsimMessage * of the contact information. Will be freed.
+ */
static void
-msim_check_newer_version_cb(PurpleUtilFetchUrlData *url_data,
- gpointer user_data,
- const gchar *url_text,
- gsize len,
- const gchar *error_message)
+msim_add_contact_from_server_cb(MsimSession *session, MsimMessage *user_lookup_info, gpointer data)
{
- GKeyFile *keyfile;
- GError *error;
- GString *data;
- gchar *newest_filever;
+ MsimMessage *contact_info, *user_lookup_info_body;
+ PurpleGroup *group;
+ PurpleBuddy *buddy;
+ MsimUser *user;
+ gchar *username, *group_name;
+ guint uid;
- if (!url_text) {
- purple_debug_info("msim_check_newer_version_cb",
- "got error: %s\n", error_message);
- return;
+ contact_info = (MsimMessage *)data;
+ purple_debug_info("msim_add_contact_from_server_cb", "contact_info addr=%p\n", contact_info);
+ uid = msim_msg_get_integer(contact_info, "ContactID");
+
+ if (!user_lookup_info) {
+ username = g_strdup(msim_uid2username_from_blist(session->account, uid));
+ g_return_if_fail(username != NULL);
+ } else {
+ user_lookup_info_body = msim_msg_get_dictionary(user_lookup_info, "body");
+ username = msim_msg_get_string(user_lookup_info_body, "UserName");
+ msim_msg_free(user_lookup_info_body);
+ g_return_if_fail(username != NULL);
}
- purple_debug_info("msim_check_newer_version_cb",
- "url_text=%s\n", url_text ? url_text : "(NULL)");
+ purple_debug_info("msim_add_contact_from_server_cb",
+ "*** about to add/update username=%s\n", username);
- /* Prepend [group] so that GKeyFile can parse it (requires a group). */
- data = g_string_new(url_text);
- purple_debug_info("msim", "data=%s\n", data->str
- ? data->str : "(NULL)");
- data = g_string_prepend(data, "[group]\n");
+ /* 1. Creates a new group, or gets existing group if it exists (or so
+ * the documentation claims). */
+ group_name = msim_msg_get_string(contact_info, "GroupName");
+ if (!group_name || (*group_name == '\0')) {
+ g_free(group_name);
+ group_name = g_strdup(_("IM Friends"));
+ purple_debug_info("myspace", "No GroupName specified, defaulting to '%s'.\n", group_name);
+ }
+ group = purple_find_group(group_name);
+ if (!group) {
+ group = purple_group_new(group_name);
+ /* Add group to beginning. See #2752. */
+ purple_blist_add_group(group, NULL);
+ }
+ g_free(group_name);
- purple_debug_info("msim", "data=%s\n", data->str
- ? data->str : "(NULL)");
+ /* 2. Get or create buddy */
+ buddy = purple_find_buddy(session->account, username);
+ if (!buddy) {
+ purple_debug_info("msim_add_contact_from_server_cb",
+ "creating new buddy: %s\n", username);
+ buddy = purple_buddy_new(session->account, username, NULL);
+ }
- /* url_text is variable=data\n...+*/
+ /* TODO: use 'Position' in contact_info to take into account where buddy is */
+ purple_blist_add_buddy(buddy, NULL, group, NULL /* insertion point */);
- /* Check FILEVER, 1.0.716.0. 716 is build, MSIM_CLIENT_VERSION */
- /* New (english) version can be downloaded from SETUPURL+SETUPFILE */
+ /* 3. Update buddy information */
+ user = msim_get_user_from_buddy(buddy);
- error = NULL;
- keyfile = g_key_file_new();
+ user->id = uid;
+ /* Keep track of the user ID across sessions */
+ purple_blist_node_set_int(&buddy->node, "UserID", uid);
- /* Default list seperator is ;, but currentversion.txt doesn't have
- * these, so set to an unused character to avoid parsing problems. */
- g_key_file_set_list_separator(keyfile, '\0');
+ /* Stores a few fields in the MsimUser, relevant to the buddy itself.
+ * AvatarURL, Headline, ContactID. */
+ msim_store_user_info(session, contact_info, NULL);
- g_key_file_load_from_data(keyfile, data->str, data->len,
- G_KEY_FILE_NONE, &error);
- g_string_free(data, TRUE);
+ /* TODO: other fields, store in 'user' */
+ msim_msg_free(contact_info);
- if (error != NULL) {
- purple_debug_info("msim_check_newer_version_cb",
- "couldn't parse, error: %d %d %s\n",
- error->domain, error->code, error->message);
- g_error_free(error);
- return;
- }
+ g_free(username);
+}
- gchar **ks;
- guint n;
- ks = g_key_file_get_keys(keyfile, "group", &n, NULL);
- purple_debug_info("msim", "n=%d\n", n);
- guint i;
- for (i = 0; ks[i] != NULL; ++i)
- {
- purple_debug_info("msim", "%d=%s\n", i, ks[i]);
- }
+/**
+ * Add first ContactID in contact_info to buddy's list. Used to add
+ * server-side buddies to client-side list.
+ *
+ * @return TRUE if added.
+ */
+static gboolean
+msim_add_contact_from_server(MsimSession *session, MsimMessage *contact_info)
+{
+ guint uid;
+ const gchar *username;
- newest_filever = g_key_file_get_string(keyfile, "group",
- "FILEVER", &error);
+ uid = msim_msg_get_integer(contact_info, "ContactID");
+ g_return_val_if_fail(uid != 0, FALSE);
- purple_debug_info("msim_check_newer_version_cb",
- "newest filever: %s\n", newest_filever ?
- newest_filever : "(NULL)");
- if (error != NULL) {
- purple_debug_info("msim_check_newer_version_cb",
- "error: %d %d %s\n",
- error->domain, error->code, error->message);
- g_error_free(error);
+ /* Lookup the username, since NickName and IMName is unreliable */
+ username = msim_uid2username_from_blist(session->account, uid);
+ if (!username) {
+ gchar *uid_str;
+
+ uid_str = g_strdup_printf("%d", uid);
+ purple_debug_info("msim_add_contact_from_server",
+ "contact_info addr=%p\n", contact_info);
+ msim_lookup_user(session, uid_str, msim_add_contact_from_server_cb, (gpointer)msim_msg_clone(contact_info));
+ g_free(uid_str);
+ } else {
+ msim_add_contact_from_server_cb(session, NULL, (gpointer)msim_msg_clone(contact_info));
}
- g_key_file_free(keyfile);
-
- exit(0);
+ /* Say that the contact was added, even if we're still looking up
+ * their username. */
+ return TRUE;
}
-#endif
-/** Called when the session key arrives to check whether the user
- * has a username, and set one if desired. */
-static gboolean
-msim_is_username_set(MsimSession *session, MsimMessage *msg)
+/**
+ * Called when contact list is received from server.
+ */
+static void
+msim_got_contact_list(MsimSession *session, MsimMessage *reply, gpointer user_data)
{
- g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
- g_return_val_if_fail(msg != NULL, FALSE);
- g_return_val_if_fail(session->gc != NULL, FALSE);
+ MsimMessage *body, *body_node;
+ gchar *msg;
+ guint buddy_count;
- session->sesskey = msim_msg_get_integer(msg, "sesskey");
- purple_debug_info("msim", "SESSKEY=<%d>\n", session->sesskey);
+ msim_msg_dump("msim_got_contact_list: reply=%s", reply);
- /* What is proof? Used to be uid, but now is 52 base64'd bytes... */
+ body = msim_msg_get_dictionary(reply, "body");
+ if (!body) {
+ /* No friends. Not an error. */
+ return;
+ }
- /* Comes with: proof,profileid,userid,uniquenick -- all same values
- * some of the time, but can vary. This is our own user ID. */
- session->userid = msim_msg_get_integer(msg, "userid");
+ buddy_count = 0;
- /* Save uid to account so this account can be looked up by uid. */
- purple_account_set_int(session->account, "uid", session->userid);
+ for (body_node = body;
+ body_node != NULL;
+ body_node = msim_msg_get_next_element_node(body_node))
+ {
+ MsimMessageElement *elem;
- /* Not sure what profileid is used for. */
- if (msim_msg_get_integer(msg, "profileid") != session->userid) {
- msim_unrecognized(session, msg,
- "Profile ID didn't match user ID, don't know why");
+ elem = (MsimMessageElement *)body_node->data;
+
+ if (g_str_equal(elem->name, "ContactID"))
+ {
+ /* Will look for first contact in body_node */
+ if (msim_add_contact_from_server(session, body_node)) {
+ ++buddy_count;
+ }
+ }
}
- /* We now know are our own username, only after we're logged in..
- * which is weird, but happens because you login with your email
- * address and not username. Will be freed in msim_session_destroy(). */
- session->username = msim_msg_get_string(msg, "uniquenick");
+ switch (GPOINTER_TO_UINT(user_data)) {
+ case MSIM_CONTACT_LIST_IMPORT_ALL_FRIENDS:
+ msg = g_strdup_printf(ngettext("%d buddy was added or updated from the server (including buddies already on the server-side list)",
+ "%d buddies were added or updated from the server (including buddies already on the server-side list)",
+ buddy_count),
+ buddy_count);
+ purple_notify_info(session->account, _("Add contacts from server"), msg, NULL);
+ g_free(msg);
+ break;
- /* If user lacks a username, help them get one. */
- if (msim_msg_get_integer(msg, "uniquenick") == session->userid) {
- purple_debug_info("msim_is_username_set", "no username is set\n");
- purple_request_yes_no(session->gc,
- _("MySpaceIM - No Username Set"),
- _("You appear to have no MySpace username."),
- _("Would you like to set one now? (Note: THIS CANNOT BE CHANGED!)"),
- 0,
- session->account,
- NULL,
- NULL,
- session->gc,
- G_CALLBACK(msim_set_username_cb),
- G_CALLBACK(msim_do_not_set_username_cb));
- purple_debug_info("msim_is_username_set","'username not set' alert prompted\n");
- return FALSE;
+ case MSIM_CONTACT_LIST_IMPORT_TOP_FRIENDS:
+ /* TODO */
+ break;
+
+ case MSIM_CONTACT_LIST_INITIAL_FRIENDS:
+ /* Nothing */
+ break;
}
- return TRUE;
+
+ msim_msg_free(body);
}
+/**
+ * Get contact list, calling msim_got_contact_list() with
+ * what_to_do_after as user_data gpointer.
+ */
+static gboolean
+msim_get_contact_list(MsimSession *session, int what_to_do_after)
+{
+ return msim_send(session,
+ "persist", MSIM_TYPE_INTEGER, 1,
+ "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+ "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_GET,
+ "dsn", MSIM_TYPE_INTEGER, MG_LIST_ALL_CONTACTS_DSN,
+ "lid", MSIM_TYPE_INTEGER, MG_LIST_ALL_CONTACTS_LID,
+ "uid", MSIM_TYPE_INTEGER, session->userid,
+ "rid", MSIM_TYPE_INTEGER,
+ msim_new_reply_callback(session, msim_got_contact_list, GUINT_TO_POINTER(what_to_do_after)),
+ "body", MSIM_TYPE_STRING, g_strdup(""),
+ NULL);
+}
+
/** Called after username is set, if necessary and we're open for business. */
-gboolean msim_we_are_logged_on(MsimSession *session)
+gboolean msim_we_are_logged_on(MsimSession *session)
{
MsimMessage *body;
@@ -1673,13 +1214,13 @@ gboolean msim_we_are_logged_on(MsimSessi
/* Disable due to problems with timeouts. TODO: fix. */
#ifdef MSIM_USE_KEEPALIVE
- purple_timeout_add(MSIM_KEEPALIVE_INTERVAL_CHECK,
+ purple_timeout_add(MSIM_KEEPALIVE_INTERVAL_CHECK,
(GSourceFunc)msim_check_alive, session);
#endif
/* Check mail if they want to. */
if (purple_account_get_check_mail(session->account)) {
- session->inbox_handle = purple_timeout_add(MSIM_MAIL_INTERVAL_CHECK,
+ session->inbox_handle = purple_timeout_add(MSIM_MAIL_INTERVAL_CHECK,
(GSourceFunc)msim_check_inbox, session);
msim_check_inbox(session);
}
@@ -1690,222 +1231,61 @@ gboolean msim_we_are_logged_on(MsimSessi
}
/**
- * Process a message.
- *
- * @param session
- * @param msg A message from the server, ready for processing (possibly with resolved username information attached). Caller frees.
- *
- * @return TRUE if successful. FALSE if processing failed.
+ * Record the client version in the buddy list, from an incoming message.
*/
-static gboolean
-msim_process(MsimSession *session, MsimMessage *msg)
+static gboolean
+msim_incoming_bm_record_cv(MsimSession *session, MsimMessage *msg)
{
- g_return_val_if_fail(session != NULL, FALSE);
- g_return_val_if_fail(msg != NULL, FALSE);
+ gchar *username, *cv;
+ gboolean ret;
+ MsimUser *user;
-#ifdef MSIM_DEBUG_MSG
- msim_msg_dump("ready to process: %s\n", msg);
-#endif
+ username = msim_msg_get_string(msg, "_username");
+ cv = msim_msg_get_string(msg, "cv");
- if (msim_msg_get_integer(msg, "lc") == 1) {
- return msim_login_challenge(session, msg);
- } else if (msim_msg_get_integer(msg, "lc") == 2) {
- /* return msim_we_are_logged_on(session, msg); */
- if (msim_is_username_set(session, msg)) {
- return msim_we_are_logged_on(session);
- } else {
- /* No username is set... We'll wait for the callbacks to do their work */
- /* When they're all done, the last one will call msim_we_are_logged_on() and pick up where we left off */
- return FALSE;
- }
- } else if (msim_msg_get(msg, "bm")) {
- return msim_incoming_bm(session, msg);
- } else if (msim_msg_get(msg, "rid")) {
- return msim_process_reply(session, msg);
- } else if (msim_msg_get(msg, "error")) {
- return msim_error(session, msg);
- } else if (msim_msg_get(msg, "ka")) {
- return TRUE;
- } else {
- msim_unrecognized(session, msg, "in msim_process");
+ g_return_val_if_fail(username != NULL, FALSE);
+ if (!cv) {
+ /* No client version to record, don't worry about it. */
+ g_free(username);
return FALSE;
}
-}
-/** Process the initial server information from the server. */
-static gboolean
-msim_process_server_info(MsimSession *session, MsimMessage *msg)
-{
- MsimMessage *body;
+ user = msim_find_user(session, username);
- body = msim_msg_get_dictionary(msg, "body");
- g_return_val_if_fail(body != NULL, FALSE);
-
- /* Example body:
-AdUnitRefreshInterval=10.
-AlertPollInterval=360.
-AllowChatRoomEmoticonSharing=False.
-ChatRoomUserIDs=78744676;163733130;1300326231;123521495;142663391.
-CurClientVersion=673.
-EnableIMBrowse=True.
-EnableIMStuffAvatars=False.
-EnableIMStuffZaps=False.
-MaxAddAllFriends=100.
-MaxContacts=1000.
-MinClientVersion=594.
-MySpaceIM_ENGLISH=78744676.
-MySpaceNowTimer=720.
-PersistenceDataTimeout=900.
-UseWebChallenge=1.
-WebTicketGoHome=False
-
- Anything useful? TODO: use what is useful, and use it.
-*/
- purple_debug_info("msim_process_server_info",
- "maximum contacts: %d\n",
- msim_msg_get_integer(body, "MaxContacts"));
-
- session->server_info = body;
- /* session->server_info freed in msim_session_destroy */
-
- return TRUE;
-}
-
-/** Process a web challenge, used to login to the web site. */
-static gboolean
-msim_web_challenge(MsimSession *session, MsimMessage *msg)
-{
- /* TODO: web challenge, store token. #2659. */
- return FALSE;
-}
-
-/**
- * Process a persistance message reply from the server.
- *
- * @param session
- * @param msg Message reply from server.
- *
- * @return TRUE if successful.
- *
- * msim_lookup_user sets callback for here
- */
-static gboolean
-msim_process_reply(MsimSession *session, MsimMessage *msg)
-{
- MSIM_USER_LOOKUP_CB cb;
- gpointer data;
- guint rid, cmd, dsn, lid;
-
- g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
- g_return_val_if_fail(msg != NULL, FALSE);
-
- msim_store_user_info(session, msg, NULL);
-
- rid = msim_msg_get_integer(msg, "rid");
- cmd = msim_msg_get_integer(msg, "cmd");
- dsn = msim_msg_get_integer(msg, "dsn");
- lid = msim_msg_get_integer(msg, "lid");
-
- /* Unsolicited messages */
- if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_GET)) {
- if (dsn == MG_SERVER_INFO_DSN && lid == MG_SERVER_INFO_LID) {
- return msim_process_server_info(session, msg);
- } else if (dsn == MG_WEB_CHALLENGE_DSN && lid == MG_WEB_CHALLENGE_LID) {
- return msim_web_challenge(session, msg);
- }
+ if (user) {
+ user->client_cv = atol(cv);
+ ret = TRUE;
+ } else {
+ ret = FALSE;
}
- /* If a callback is registered for this userid lookup, call it. */
- cb = g_hash_table_lookup(session->user_lookup_cb, GUINT_TO_POINTER(rid));
- data = g_hash_table_lookup(session->user_lookup_cb_data, GUINT_TO_POINTER(rid));
+ g_free(username);
+ g_free(cv);
- if (cb) {
- purple_debug_info("msim", "msim_process_reply: calling callback now\n");
- msim_msg_dump("for msg=%s\n", msg);
- /* Clone message, so that the callback 'cb' can use it (needs to free it also). */
- cb(session, msim_msg_clone(msg), data);
- g_hash_table_remove(session->user_lookup_cb, GUINT_TO_POINTER(rid));
- g_hash_table_remove(session->user_lookup_cb_data, GUINT_TO_POINTER(rid));
- } else {
- purple_debug_info("msim",
- "msim_process_reply: no callback for rid %d\n", rid);
- }
-
- return TRUE;
+ return ret;
}
+#ifdef MSIM_SEND_CLIENT_VERSION
/**
- * Handle an error from the server.
- *
- * @param session
- * @param msg The message.
- *
- * @return TRUE if successfully reported error.
+ * Send our client version to another unofficial client that understands it.
*/
-static gboolean
-msim_error(MsimSession *session, MsimMessage *msg)
+static gboolean
+msim_send_unofficial_client(MsimSession *session, gchar *username)
{
- gchar *errmsg, *full_errmsg;
- guint err;
+ gchar *our_info;
+ gboolean ret;
- g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
- g_return_val_if_fail(msg != NULL, FALSE);
+ our_info = g_strdup_printf("Libpurple %d.%d.%d - msimprpl %s",
+ PURPLE_MAJOR_VERSION,
+ PURPLE_MINOR_VERSION,
+ PURPLE_MICRO_VERSION,
+ MSIM_PRPL_VERSION_STRING);
- err = msim_msg_get_integer(msg, "err");
- errmsg = msim_msg_get_string(msg, "errmsg");
+ ret = msim_send_bm(session, username, our_info, MSIM_BM_UNOFFICIAL_CLIENT);
- full_errmsg = g_strdup_printf(_("Protocol error, code %d: %s"), err,
- errmsg ? errmsg : "no 'errmsg' given");
-
- g_free(errmsg);
-
- purple_debug_info("msim", "msim_error (sesskey=%d): %s\n",
- session->sesskey, full_errmsg);
-
- /* Destroy session if fatal. */
- if (msim_msg_get(msg, "fatal")) {
- PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
- purple_debug_info("msim", "fatal error, closing\n");
-
- switch (err) {
- case MSIM_ERROR_INCORRECT_PASSWORD: /* Incorrect password */
- reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
- if (!purple_account_get_remember_password(session->account))
- purple_account_set_password(session->account, NULL);
-#ifdef MSIM_MAX_PASSWORD_LENGTH
- if (session->account->password && (strlen(session->account->password) > MSIM_MAX_PASSWORD_LENGTH)) {
- gchar *suggestion;
-
- suggestion = g_strdup_printf(_("%s Your password is "
- "%d characters, greater than the "
- "expected maximum length of %d for "
- "MySpaceIM. Please shorten your "
- "password at http://profileedit.myspace.com/index.cfm?fuseaction=accountSettings.changePassword and try again."),
- full_errmsg, (int)
- strlen(session->account->password),
- MSIM_MAX_PASSWORD_LENGTH);
-
- /* Replace full_errmsg. */
- g_free(full_errmsg);
- full_errmsg = suggestion;
- }
-#endif
- break;
- case MSIM_ERROR_LOGGED_IN_ELSEWHERE: /* Logged in elsewhere */
- reason = PURPLE_CONNECTION_ERROR_NAME_IN_USE;
- if (!purple_account_get_remember_password(session->account))
- purple_account_set_password(session->account, NULL);
- break;
- }
- purple_connection_error_reason (session->gc, reason, full_errmsg);
- } else {
- purple_notify_error(session->account, _("MySpaceIM Error"), full_errmsg, NULL);
- }
-
- g_free(full_errmsg);
-
- return TRUE;
+ return ret;
}
+#endif
/**
* Process incoming status messages.
@@ -1915,7 +1295,7 @@ msim_error(MsimSession *session, MsimMes
*
* @return TRUE if successful.
*/
-static gboolean
+static gboolean
msim_incoming_status(MsimSession *session, MsimMessage *msg)
{
PurpleBuddyList *blist;
@@ -1939,15 +1319,15 @@ msim_incoming_status(MsimSession *sessio
gchar *ss;
ss = msim_msg_get_string(msg, "msg");
- purple_debug_info("msim",
+ purple_debug_info("msim",
"msim_status: updating status for <%s> to <%s>\n",
username, ss ? ss : "(NULL)");
g_free(ss);
}
- /* Example fields:
- * |s|0|ss|Offline
- * |s|1|ss|:-)|ls||ip|0|p|0
+ /* Example fields:
+ * |s|0|ss|Offline
+ * |s|1|ss|:-)|ls||ip|0|p|0
*/
list = msim_msg_get_list(msg, "msg");
@@ -1963,7 +1343,7 @@ msim_incoming_status(MsimSession *sessio
if (!user) {
PurpleBuddy *buddy;
- purple_debug_info("msim",
+ purple_debug_info("msim",
"msim_status: making new buddy for %s\n", username);
buddy = purple_buddy_new(session->account, username, NULL);
purple_blist_add_buddy(buddy, NULL, NULL, NULL);
@@ -1989,7 +1369,7 @@ msim_incoming_status(MsimSession *sessio
g_free(status_headline);
- if (user->headline)
+ if (user->headline)
g_free(user->headline);
/* don't copy; let the MsimUser own the headline, memory-wise */
@@ -1997,11 +1377,11 @@ msim_incoming_status(MsimSession *sessio
/* Set user status */
switch (status_code) {
- case MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN:
+ case MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN:
purple_status_code = PURPLE_STATUS_OFFLINE;
break;
- case MSIM_STATUS_CODE_ONLINE:
+ case MSIM_STATUS_CODE_ONLINE:
purple_status_code = PURPLE_STATUS_AVAILABLE;
break;
@@ -2019,7 +1399,7 @@ msim_incoming_status(MsimSession *sessio
username, status_code);
purple_status_code = PURPLE_STATUS_AVAILABLE;
- unrecognized_msg = g_strdup_printf("msim_incoming_status, unrecognized status code: %d\n",
+ unrecognized_msg = g_strdup_printf("msim_incoming_status, unrecognized status code: %d\n",
status_code);
msim_unrecognized(session, NULL, unrecognized_msg);
g_free(unrecognized_msg);
@@ -2057,422 +1437,533 @@ msim_incoming_status(MsimSession *sessio
return TRUE;
}
-/** Add a buddy to user's buddy list. */
-void
-msim_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
+/**
+ * Handle an incoming instant message.
+ *
+ * @param session The session
+ * @param msg Message from the server, containing 'f' (userid from) and 'msg'.
+ * Should also contain username in _username from preprocessing.
+ *
+ * @return TRUE if successful.
+ */
+static gboolean
+msim_incoming_im(MsimSession *session, MsimMessage *msg)
{
- MsimSession *session;
- MsimMessage *msg;
- MsimMessage *msg_persist;
- MsimMessage *body;
+ gchar *username, *msg_msim_markup, *msg_purple_markup;
+ gchar *userid;
+ time_t time_received;
+ PurpleConversation *conv;
- session = (MsimSession *)gc->proto_data;
- purple_debug_info("msim", "msim_add_buddy: want to add %s to %s\n",
- buddy->name, (group && group->name) ? group->name : "(no group)");
+ g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+ g_return_val_if_fail(msg != NULL, FALSE);
- msg = msim_msg_new(
- "addbuddy", MSIM_TYPE_BOOLEAN, TRUE,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- /* "newprofileid" will be inserted here with uid. */
- "reason", MSIM_TYPE_STRING, g_strdup(""),
- NULL);
+ username = msim_msg_get_string(msg, "_username");
+ /* I know this isn't really a string... but we need it to be one for
+ * purple_find_conversation_with_account(). */
+ userid = msim_msg_get_string(msg, "f");
+ g_return_val_if_fail(username != NULL, FALSE);
- if (!msim_postprocess_outgoing(session, msg, buddy->name, "newprofileid", "reason")) {
- purple_notify_error(NULL, NULL, _("Failed to add buddy"), _("'addbuddy' command failed."));
- msim_msg_free(msg);
- return;
+ purple_debug_info("msim_incoming_im", "UserID is %s", userid);
+
+ if (msim_is_userid(username)) {
+ purple_debug_info("msim", "Ignoring message from spambot (%s) on account %s\n",
+ username, purple_account_get_username(session->account));
+ g_free(username);
+ return FALSE;
}
- msim_msg_free(msg);
-
- /* TODO: if addbuddy fails ('error' message is returned), delete added buddy from
- * buddy list since Purple adds it locally. */
- body = msim_msg_new(
- "ContactID", MSIM_TYPE_STRING, g_strdup("<uid>"),
- "GroupName", MSIM_TYPE_STRING, g_strdup(group->name),
- "Position", MSIM_TYPE_INTEGER, 1000,
- "Visibility", MSIM_TYPE_INTEGER, 1,
- "NickName", MSIM_TYPE_STRING, g_strdup(""),
- "NameSelect", MSIM_TYPE_INTEGER, 0,
- NULL);
+ /* See if a conversation with their UID already exists...*/
+ conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, userid, session->account);
+ if (conv) {
+ /* Since the conversation exists... We need to normalize it */
+ purple_conversation_set_name(conv, username);
+ }
- /* TODO: Update blocklist. */
+ msg_msim_markup = msim_msg_get_string(msg, "msg");
+ g_return_val_if_fail(msg_msim_markup != NULL, FALSE);
- msg_persist = msim_msg_new(
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_BIT_ACTION | MSIM_CMD_PUT,
- "dsn", MSIM_TYPE_INTEGER, MC_CONTACT_INFO_DSN,
- "uid", MSIM_TYPE_INTEGER, session->userid,
- "lid", MSIM_TYPE_INTEGER, MC_CONTACT_INFO_LID,
- /* TODO: Use msim_new_reply_callback to get rid. */
- "rid", MSIM_TYPE_INTEGER, session->next_rid++,
- "body", MSIM_TYPE_DICTIONARY, body,
- NULL);
+ msg_purple_markup = msim_markup_to_html(session, msg_msim_markup);
+ g_free(msg_msim_markup);
- if (!msim_postprocess_outgoing(session, msg_persist, buddy->name, "body", NULL))
- {
- purple_notify_error(NULL, NULL, _("Failed to add buddy"), _("persist command failed"));
- msim_msg_free(msg_persist);
- return;
+ time_received = msim_msg_get_integer(msg, "date");
+ if (!time_received) {
+ purple_debug_info("msim_incoming_im", "date in message not set.\n");
+ time_received = time(NULL);
}
- msim_msg_free(msg_persist);
+ serv_got_im(session->gc, username, msg_purple_markup, PURPLE_MESSAGE_RECV, time_received);
+
+ g_free(username);
+ g_free(msg_purple_markup);
+
+ return TRUE;
}
-/** Perform actual postprocessing on a message, adding userid as specified.
+/**
+ * Handle an incoming action message.
*
- * @param msg The message to postprocess.
- * @param uid_before Name of field where to insert new field before, or NULL for end.
- * @param uid_field_name Name of field to add uid to.
- * @param uid The userid to insert.
+ * @param session
+ * @param msg
*
- * If the field named by uid_field_name already exists, then its string contents will
- * be used for the field, except "<uid>" will be replaced by the userid.
- *
- * If the field named by uid_field_name does not exist, it will be added before the
- * field named by uid_before, as an integer, with the userid.
- *
- * Does not handle sending, or scheduling userid lookup. For that, see msim_postprocess_outgoing().
- */
-static MsimMessage *
-msim_do_postprocessing(MsimMessage *msg, const gchar *uid_before,
- const gchar *uid_field_name, guint uid)
+ * @return TRUE if successful.
+ */
+static gboolean
+msim_incoming_action(MsimSession *session, MsimMessage *msg)
{
- MsimMessageElement *elem;
- msim_msg_dump("msim_do_postprocessing msg: %s\n", msg);
+ gchar *msg_text, *username;
+ gboolean rc;
- /* First, check - if the field already exists, replace <uid> within it */
- if ((elem = msim_msg_get(msg, uid_field_name)) != NULL) {
- gchar *fmt_string;
- gchar *uid_str, *new_str;
+ g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+ g_return_val_if_fail(msg != NULL, FALSE);
- /* Get the packed element, flattening it. This allows <uid> to be
- * replaced within nested data structures, since the replacement is done
- * on the linear, packed data, not on a complicated data structure.
- *
- * For example, if the field was originally a dictionary or a list, you
- * would have to iterate over all the items in it to see what needs to
- * be replaced. But by packing it first, the <uid> marker is easily replaced
- * just by a string replacement.
- */
- fmt_string = msim_msg_pack_element_data(elem);
+ msg_text = msim_msg_get_string(msg, "msg");
+ g_return_val_if_fail(msg_text != NULL, FALSE);
- uid_str = g_strdup_printf("%d", uid);
- new_str = purple_strreplace(fmt_string, "<uid>", uid_str);
- g_free(uid_str);
- g_free(fmt_string);
+ username = msim_msg_get_string(msg, "_username");
+ g_return_val_if_fail(username != NULL, FALSE);
- /* Free the old element data */
- msim_msg_free_element_data(elem->data);
+ purple_debug_info("msim", "msim_incoming_action: action <%s> from <%s>\n",
+ msg_text, username);
- /* Replace it with our new data */
- elem->data = new_str;
- elem->type = MSIM_TYPE_RAW;
+ if (g_str_equal(msg_text, "%typing%")) {
+ serv_got_typing(session->gc, username, 0, PURPLE_TYPING);
+ rc = TRUE;
+ } else if (g_str_equal(msg_text, "%stoptyping%")) {
+ serv_got_typing_stopped(session->gc, username);
+ rc = TRUE;
+ } else if (strstr(msg_text, "!!!ZAP_SEND!!!=RTE_BTN_ZAPS_")) {
+ rc = msim_incoming_zap(session, msg);
+ } else if (strstr(msg_text, "!!!GroupCount=")) {
+ /* TODO: support group chats. I think the number in msg_text has
+ * something to do with the 'gid' field. */
+ purple_debug_info("msim", "msim_incoming_action: TODO: implement #4691, group chats: %s\n", msg_text);
+ rc = TRUE;
+ } else if (strstr(msg_text, "!!!Offline=")) {
+ /* TODO: support group chats. This one might mean a user
+ * went offline or exited the chat. */
+ purple_debug_info("msim", "msim_incoming_action: TODO: implement #4691, group chats: %s\n", msg_text);
+
+ rc = TRUE;
+ } else if (msim_msg_get_integer(msg, "aid") != 0) {
+ purple_debug_info("msim", "TODO: implement #4691, group chat from %d on %d: %s\n",
+ msim_msg_get_integer(msg, "aid"),
+ msim_msg_get_integer(msg, "f"),
+ msg_text);
+
+ rc = TRUE;
} else {
- /* Otherwise, insert new field into outgoing message. */
- msg = msim_msg_insert_before(msg, uid_before, uid_field_name, MSIM_TYPE_INTEGER, GUINT_TO_POINTER(uid));
+ msim_unrecognized(session, msg,
+ "got to msim_incoming_action but unrecognized value for 'msg'");
+ rc = FALSE;
}
- msim_msg_dump("msim_postprocess_outgoing_cb: postprocessed msg=%s\n", msg);
+ g_free(msg_text);
+ g_free(username);
- return msg;
+ return rc;
}
-/** Callback for msim_postprocess_outgoing() to add a userid to a message, and send it (once receiving userid).
- *
- * @param session
- * @param userinfo The user information reply message, containing the user ID
- * @param data The message to postprocess and send.
- *
- * The data message should contain these fields:
- *
- * _uid_field_name: string, name of field to add with userid from userinfo message
- * _uid_before: string, name of field before field to insert, or NULL for end
- *
- *
-*/
-static void
-msim_postprocess_outgoing_cb(MsimSession *session, MsimMessage *userinfo,
- gpointer data)
+/**
+ * Process an incoming media (message background?) message.
+ */
+static gboolean
+msim_incoming_media(MsimSession *session, MsimMessage *msg)
{
- gchar *uid_field_name, *uid_before, *username;
- guint uid;
- MsimMessage *msg, *body;
+ gchar *username, *text;
- msg = (MsimMessage *)data;
+ username = msim_msg_get_string(msg, "_username");
+ text = msim_msg_get_string(msg, "msg");
- msim_msg_dump("msim_postprocess_outgoing_cb() got msg=%s\n", msg);
+ g_return_val_if_fail(username != NULL, FALSE);
+ g_return_val_if_fail(text != NULL, FALSE);
- /* Obtain userid from userinfo message. */
- body = msim_msg_get_dictionary(userinfo, "body");
- g_return_if_fail(body != NULL);
+ purple_debug_info("msim", "msim_incoming_media: from %s, got msg=%s\n", username, text);
- uid = msim_msg_get_integer(body, "UserID");
- msim_msg_free(body);
+ /* Media messages are sent when the user opens a window to someone.
+ * Tell libpurple they started typing and stopped typing, to inform the Psychic
+ * Mode plugin so it too can open a window to the user. */
+ serv_got_typing(session->gc, username, 0, PURPLE_TYPING);
+ serv_got_typing_stopped(session->gc, username);
+ g_free(username);
+
+ return TRUE;
+}
+
+/**
+ * Process an incoming "unofficial client" message. The plugin for
+ * Miranda IM sends this message with the plugin information.
+ */
+static gboolean
+msim_incoming_unofficial_client(MsimSession *session, MsimMessage *msg)
+{
+ MsimUser *user;
+ gchar *username, *client_info;
+
username = msim_msg_get_string(msg, "_username");
+ client_info = msim_msg_get_string(msg, "msg");
- if (!uid) {
- gchar *msg;
+ g_return_val_if_fail(username != NULL, FALSE);
+ g_return_val_if_fail(client_info != NULL, FALSE);
- msg = g_strdup_printf(_("No such user: %s"), username);
- if (!purple_conv_present_error(username, session->account, msg)) {
- purple_notify_error(NULL, NULL, _("User lookup"), msg);
- }
+ purple_debug_info("msim", "msim_incoming_unofficial_client: %s is using client %s\n",
+ username, client_info);
- g_free(msg);
- g_free(username);
- /* TODO: free
- * msim_msg_free(msg);
- */
- return;
+ user = msim_find_user(session, username);
+
+ g_return_val_if_fail(user != NULL, FALSE);
+
+ if (user->client_info) {
+ g_free(user->client_info);
}
+ user->client_info = client_info;
- uid_field_name = msim_msg_get_string(msg, "_uid_field_name");
- uid_before = msim_msg_get_string(msg, "_uid_before");
+ g_free(username);
+ /* Do not free client_info - the MsimUser now owns it. */
- msg = msim_do_postprocessing(msg, uid_before, uid_field_name, uid);
+ return TRUE;
+}
- /* Send */
- if (!msim_msg_send(session, msg)) {
- msim_msg_dump("msim_postprocess_outgoing_cb: sending failed for message: %s\n", msg);
+/**
+ * Handle an incoming buddy message.
+ */
+static gboolean
+msim_incoming_bm(MsimSession *session, MsimMessage *msg)
+{
+ guint bm;
+
+ bm = msim_msg_get_integer(msg, "bm");
+
+ msim_incoming_bm_record_cv(session, msg);
+
+ switch (bm) {
+ case MSIM_BM_STATUS:
+ return msim_incoming_status(session, msg);
+ case MSIM_BM_INSTANT:
+ return msim_incoming_im(session, msg);
+ case MSIM_BM_ACTION:
+ return msim_incoming_action(session, msg);
+ case MSIM_BM_MEDIA:
+ return msim_incoming_media(session, msg);
+ case MSIM_BM_UNOFFICIAL_CLIENT:
+ return msim_incoming_unofficial_client(session, msg);
+ default:
+ /* Not really an IM, but show it for informational
+ * purposes during development. */
+ return msim_incoming_im(session, msg);
}
+}
+/**
+ * Process the initial server information from the server.
+ */
+static gboolean
+msim_process_server_info(MsimSession *session, MsimMessage *msg)
+{
+ MsimMessage *body;
- /* Free field names AFTER sending message, because MsimMessage does NOT copy
- * field names - instead, treats them as static strings (which they usually are).
- */
- g_free(uid_field_name);
- g_free(uid_before);
- g_free(username);
- /* TODO: free
- * msim_msg_free(msg);
- */
+ body = msim_msg_get_dictionary(msg, "body");
+ g_return_val_if_fail(body != NULL, FALSE);
+
+ /* Example body:
+AdUnitRefreshInterval=10.
+AlertPollInterval=360.
+AllowChatRoomEmoticonSharing=False.
+ChatRoomUserIDs=78744676;163733130;1300326231;123521495;142663391.
+CurClientVersion=673.
+EnableIMBrowse=True.
+EnableIMStuffAvatars=False.
+EnableIMStuffZaps=False.
+MaxAddAllFriends=100.
+MaxContacts=1000.
+MinClientVersion=594.
+MySpaceIM_ENGLISH=78744676.
+MySpaceNowTimer=720.
+PersistenceDataTimeout=900.
+UseWebChallenge=1.
+WebTicketGoHome=False
+
+ Anything useful? TODO: use what is useful, and use it.
+*/
+ purple_debug_info("msim_process_server_info",
+ "maximum contacts: %d\n",
+ msim_msg_get_integer(body, "MaxContacts"));
+
+ session->server_info = body;
+ /* session->server_info freed in msim_session_destroy */
+
+ return TRUE;
}
-/** Postprocess and send a message.
+/**
+ * Process a web challenge, used to login to the web site.
+ */
+static gboolean
+msim_web_challenge(MsimSession *session, MsimMessage *msg)
+{
+ /* TODO: web challenge, store token. #2659. */
+ return FALSE;
+}
+
+/**
+ * Process a persistance message reply from the server.
*
* @param session
- * @param msg Message to postprocess. Will NOT be freed.
- * @param username Username to resolve. Assumed to be a static string (will not be freed or copied).
- * @param uid_field_name Name of new field to add, containing uid of username. Static string.
- * @param uid_before Name of existing field to insert username field before. Static string.
+ * @param msg Message reply from server.
*
* @return TRUE if successful.
+ *
+ * msim_lookup_user sets callback for here
*/
-gboolean
-msim_postprocess_outgoing(MsimSession *session, MsimMessage *msg,
- const gchar *username, const gchar *uid_field_name,
- const gchar *uid_before)
+static gboolean
+msim_process_reply(MsimSession *session, MsimMessage *msg)
{
- PurpleBuddy *buddy;
- guint uid;
- gboolean rc;
+ MSIM_USER_LOOKUP_CB cb;
+ gpointer data;
+ guint rid, cmd, dsn, lid;
+ g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
g_return_val_if_fail(msg != NULL, FALSE);
- /* Store information for msim_postprocess_outgoing_cb(). */
- msim_msg_dump("msim_postprocess_outgoing: msg before=%s\n", msg);
- msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, g_strdup(username));
- msg = msim_msg_append(msg, "_uid_field_name", MSIM_TYPE_STRING, g_strdup(uid_field_name));
- msg = msim_msg_append(msg, "_uid_before", MSIM_TYPE_STRING, g_strdup(uid_before));
+ msim_store_user_info(session, msg, NULL);
- /* First, try the most obvious. If numeric userid is given, use that directly. */
- if (msim_is_userid(username)) {
- uid = atol(username);
- } else {
- /* Next, see if on buddy list and know uid. */
- buddy = purple_find_buddy(session->account, username);
- if (buddy) {
- uid = purple_blist_node_get_int(&buddy->node, "UserID");
- } else {
- uid = 0;
- }
+ rid = msim_msg_get_integer(msg, "rid");
+ cmd = msim_msg_get_integer(msg, "cmd");
+ dsn = msim_msg_get_integer(msg, "dsn");
+ lid = msim_msg_get_integer(msg, "lid");
- if (!buddy || !uid) {
- /* Don't have uid offhand - need to ask for it, and wait until hear back before sending. */
- purple_debug_info("msim", ">>> msim_postprocess_outgoing: couldn't find username %s in blist\n",
- username ? username : "(NULL)");
- msim_msg_dump("msim_postprocess_outgoing - scheduling lookup, msg=%s\n", msg);
- /* TODO: where is cloned message freed? Should be in _cb. */
- msim_lookup_user(session, username, msim_postprocess_outgoing_cb, msim_msg_clone(msg));
- return TRUE; /* not sure of status yet - haven't sent! */
+ /* Unsolicited messages */
+ if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_GET)) {
+ if (dsn == MG_SERVER_INFO_DSN && lid == MG_SERVER_INFO_LID) {
+ return msim_process_server_info(session, msg);
+ } else if (dsn == MG_WEB_CHALLENGE_DSN && lid == MG_WEB_CHALLENGE_LID) {
+ return msim_web_challenge(session, msg);
}
}
-
- /* Already have uid, postprocess and send msg immediately. */
- purple_debug_info("msim", "msim_postprocess_outgoing: found username %s has uid %d\n",
- username ? username : "(NULL)", uid);
- msg = msim_do_postprocessing(msg, uid_before, uid_field_name, uid);
+ /* If a callback is registered for this userid lookup, call it. */
+ cb = g_hash_table_lookup(session->user_lookup_cb, GUINT_TO_POINTER(rid));
+ data = g_hash_table_lookup(session->user_lookup_cb_data, GUINT_TO_POINTER(rid));
- msim_msg_dump("msim_postprocess_outgoing: msg after (uid immediate)=%s\n", msg);
-
- rc = msim_msg_send(session, msg);
+ if (cb) {
+ purple_debug_info("msim", "msim_process_reply: calling callback now\n");
+ msim_msg_dump("for msg=%s\n", msg);
+ /* Clone message, so that the callback 'cb' can use it (needs to free it also). */
+ cb(session, msim_msg_clone(msg), data);
+ g_hash_table_remove(session->user_lookup_cb, GUINT_TO_POINTER(rid));
+ g_hash_table_remove(session->user_lookup_cb_data, GUINT_TO_POINTER(rid));
+ } else {
+ purple_debug_info("msim",
+ "msim_process_reply: no callback for rid %d\n", rid);
+ }
- /* TODO: free
- * msim_msg_free(msg);
- */
-
- return rc;
+ return TRUE;
}
-/** Remove a buddy from the user's buddy list. */
-void
-msim_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
+/**
+ * Handle an error from the server.
+ *
+ * @param session
+ * @param msg The message.
+ *
+ * @return TRUE if successfully reported error.
+ */
+static gboolean
+msim_error(MsimSession *session, MsimMessage *msg)
{
- MsimSession *session;
- MsimMessage *delbuddy_msg;
- MsimMessage *persist_msg;
- MsimMessage *blocklist_msg;
- GList *blocklist_updates;
+ gchar *errmsg, *full_errmsg;
+ guint err;
- session = (MsimSession *)gc->proto_data;
+ g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+ g_return_val_if_fail(msg != NULL, FALSE);
- delbuddy_msg = msim_msg_new(
- "delbuddy", MSIM_TYPE_BOOLEAN, TRUE,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- /* 'delprofileid' with uid will be inserted here. */
- NULL);
+ err = msim_msg_get_integer(msg, "err");
+ errmsg = msim_msg_get_string(msg, "errmsg");
- if (!msim_postprocess_outgoing(session, delbuddy_msg, buddy->name, "delprofileid", NULL)) {
- purple_notify_error(NULL, NULL, _("Failed to remove buddy"), _("'delbuddy' command failed"));
- msim_msg_free(delbuddy_msg);
- return;
- }
- msim_msg_free(delbuddy_msg);
+ full_errmsg = g_strdup_printf(_("Protocol error, code %d: %s"), err,
+ errmsg ? errmsg : "no 'errmsg' given");
- persist_msg = msim_msg_new(
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_BIT_ACTION | MSIM_CMD_DELETE,
- "dsn", MSIM_TYPE_INTEGER, MD_DELETE_BUDDY_DSN,
- "lid", MSIM_TYPE_INTEGER, MD_DELETE_BUDDY_LID,
- "uid", MSIM_TYPE_INTEGER, session->userid,
- "rid", MSIM_TYPE_INTEGER, session->next_rid++,
- /* <uid> will be replaced by postprocessing */
- "body", MSIM_TYPE_STRING, g_strdup("ContactID=<uid>"),
- NULL);
+ g_free(errmsg);
- if (!msim_postprocess_outgoing(session, persist_msg, buddy->name, "body", NULL)) {
- purple_notify_error(NULL, NULL, _("Failed to remove buddy"), _("persist command failed"));
- msim_msg_free(persist_msg);
- return;
- }
- msim_msg_free(persist_msg);
+ purple_debug_info("msim", "msim_error (sesskey=%d): %s\n",
+ session->sesskey, full_errmsg);
- blocklist_updates = NULL;
- blocklist_updates = g_list_prepend(blocklist_updates, "a-");
- blocklist_updates = g_list_prepend(blocklist_updates, "<uid>");
- blocklist_updates = g_list_prepend(blocklist_updates, "b-");
- blocklist_updates = g_list_prepend(blocklist_updates, "<uid>");
- blocklist_updates = g_list_reverse(blocklist_updates);
+ /* Destroy session if fatal. */
+ if (msim_msg_get(msg, "fatal")) {
+ PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
+ purple_debug_info("msim", "fatal error, closing\n");
- blocklist_msg = msim_msg_new(
- "blocklist", MSIM_TYPE_BOOLEAN, TRUE,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- /* TODO: MsimMessage lists. Currently <uid> isn't replaced in lists. */
- /* "idlist", MSIM_TYPE_STRING, g_strdup("a-|<uid>|b-|<uid>"), */
- "idlist", MSIM_TYPE_LIST, blocklist_updates,
- NULL);
+ switch (err) {
+ case MSIM_ERROR_INCORRECT_PASSWORD: /* Incorrect password */
+ reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+ if (!purple_account_get_remember_password(session->account))
+ purple_account_set_password(session->account, NULL);
+#ifdef MSIM_MAX_PASSWORD_LENGTH
+ if (session->account->password && (strlen(session->account->password) > MSIM_MAX_PASSWORD_LENGTH)) {
+ gchar *suggestion;
- if (!msim_postprocess_outgoing(session, blocklist_msg, buddy->name, "idlist", NULL)) {
- purple_notify_error(NULL, NULL, _("Failed to remove buddy"), _("blocklist command failed"));
- msim_msg_free(blocklist_msg);
- return;
+ suggestion = g_strdup_printf(_("%s Your password is "
+ "%d characters, greater than the "
+ "expected maximum length of %d for "
+ "MySpaceIM. Please shorten your "
+ "password at http://profileedit.myspace.com/index.cfm?fuseaction=accountSettings.changePassword and try again."),
+ full_errmsg, (int)
+ strlen(session->account->password),
+ MSIM_MAX_PASSWORD_LENGTH);
+
+ /* Replace full_errmsg. */
+ g_free(full_errmsg);
+ full_errmsg = suggestion;
+ }
+#endif
+ break;
+ case MSIM_ERROR_LOGGED_IN_ELSEWHERE: /* Logged in elsewhere */
+ reason = PURPLE_CONNECTION_ERROR_NAME_IN_USE;
+ if (!purple_account_get_remember_password(session->account))
+ purple_account_set_password(session->account, NULL);
+ break;
+ }
+ purple_connection_error_reason (session->gc, reason, full_errmsg);
+ } else {
+ purple_notify_error(session->account, _("MySpaceIM Error"), full_errmsg, NULL);
}
- msim_msg_free(blocklist_msg);
+
+ g_free(full_errmsg);
+
+ return TRUE;
}
/**
- * Returns a string of a username in canonical form. Basically removes all the
- * spaces, lowercases the string, and looks up user IDs to usernames.
- * Normalizing tom, TOM, Tom, and 6221 wil all return 'tom'.
+ * Process a message.
*
- * Borrowed this code from oscar_normalize. Added checking for
- * "if userid, get name before normalizing"
+ * @param session
+ * @param msg A message from the server, ready for processing (possibly with resolved username information attached). Caller frees.
+ *
+ * @return TRUE if successful. FALSE if processing failed.
*/
-const char *msim_normalize(const PurpleAccount *account, const char *str) {
- static char normalized[BUF_LEN];
- char *tmp1, *tmp2;
- int i, j;
- guint id;
+static gboolean
+msim_process(MsimSession *session, MsimMessage *msg)
+{
+ g_return_val_if_fail(session != NULL, FALSE);
+ g_return_val_if_fail(msg != NULL, FALSE);
- g_return_val_if_fail(str != NULL, NULL);
+#ifdef MSIM_DEBUG_MSG
+ msim_msg_dump("ready to process: %s\n", msg);
+#endif
- if (msim_is_userid(str)) {
- /* Have user ID, we need to get their username first :) */
- const char *username;
-
- /* If the account does not exist, we can't look up the user. */
- if (!account || !account->gc)
- return str;
-
- id = atol(str);
- username = msim_uid2username_from_blist((PurpleAccount *)account, id);
- if (!username) {
- /* Not in buddy list... scheisse... TODO: Manual Lookup! Bug #4631 */
- /* Note: manual lookup using msim_lookup_user() is a problem inside
- * msim_normalize(), because msim_lookup_user() calls a callback function
- * when the user information has been looked up, but msim_normalize() expects
- * the result immediately. */
- strncpy(normalized, str, BUF_LEN);
+ if (msim_msg_get_integer(msg, "lc") == 1) {
+ return msim_login_challenge(session, msg);
+ } else if (msim_msg_get_integer(msg, "lc") == 2) {
+ /* return msim_we_are_logged_on(session, msg); */
+ if (msim_is_username_set(session, msg)) {
+ return msim_we_are_logged_on(session);
} else {
- strncpy(normalized, username, BUF_LEN);
+ /* No username is set... We'll wait for the callbacks to do their work */
+ /* When they're all done, the last one will call msim_we_are_logged_on() and pick up where we left off */
+ return FALSE;
}
+ } else if (msim_msg_get(msg, "bm")) {
+ return msim_incoming_bm(session, msg);
+ } else if (msim_msg_get(msg, "rid")) {
+ return msim_process_reply(session, msg);
+ } else if (msim_msg_get(msg, "error")) {
+ return msim_error(session, msg);
+ } else if (msim_msg_get(msg, "ka")) {
+ return TRUE;
} else {
- /* Have username. */
- strncpy(normalized, str, BUF_LEN);
+ msim_unrecognized(session, msg, "in msim_process");
+ return FALSE;
}
+}
- /* Strip spaces. */
- for (i=0, j=0; normalized[j]; i++, j++) {
- while (normalized[j] == ' ')
- j++;
- normalized[i] = normalized[j];
- }
- normalized[i] = '\0';
+/**
+ * After a uid is resolved to username, tag it with the username and submit for processing.
+ *
+ * @param session
+ * @param userinfo Response messsage to resolving request.
+ * @param data MsimMessage *, the message to attach information to.
+ */
+static void
+msim_incoming_resolved(MsimSession *session, MsimMessage *userinfo,
+ gpointer data)
+{
+ gchar *username;
+ MsimMessage *msg, *body;
- /* Lowercase and perform UTF-8 normalization. */
- tmp1 = g_utf8_strdown(normalized, -1);
- tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_DEFAULT);
- g_snprintf(normalized, sizeof(normalized), "%s", tmp2);
- g_free(tmp2);
- g_free(tmp1);
+ g_return_if_fail(MSIM_SESSION_VALID(session));
+ g_return_if_fail(userinfo != NULL);
- /* TODO: re-add caps and spacing back to what the user wanted.
- * User can format their own names, for example 'msimprpl' is shown
- * as 'MsIm PrPl' in the official client.
- *
- * TODO: file a ticket to add this enhancement.
- */
+ body = msim_msg_get_dictionary(userinfo, "body");
+ g_return_if_fail(body != NULL);
- return normalized;
-}
+ username = msim_msg_get_string(body, "UserName");
+ g_return_if_fail(username != NULL);
+ /* Note: username will be owned by 'msg' below. */
-static GHashTable *
-msim_get_account_text_table(PurpleAccount *unused)
-{
- GHashTable *table;
+ msg = (MsimMessage *)data;
+ g_return_if_fail(msg != NULL);
- table = g_hash_table_new(g_str_hash, g_str_equal);
+ /* TODO: more elegant solution than below. attach whole message? */
+ /* Special elements name beginning with '_', we'll use internally within the
+ * program (did not come directly from the wire). */
+ msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, username); /* This makes 'msg' the owner of 'username' */
- g_hash_table_insert(table, "login_label", (gpointer)_("Email Address..."));
+ /* TODO: attach more useful information, like ImageURL */
- return table;
+ msim_process(session, msg);
+
+ /* TODO: Free copy cloned from msim_preprocess_incoming(). */
+ /* msim_msg_free(msg); */
+ msim_msg_free(body);
}
-/** Return whether the buddy can be messaged while offline.
+/**
+ * Preprocess incoming messages, resolving as needed, calling
+ * msim_process() when ready to process.
*
- * The protocol supports offline messages in just the same way as online
- * messages.
+ * @param session
+ * @param msg MsimMessage *, freed by caller.
*/
-gboolean
-msim_offline_message(const PurpleBuddy *buddy)
+static gboolean
+msim_preprocess_incoming(MsimSession *session, MsimMessage *msg)
{
- return TRUE;
+ g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+ g_return_val_if_fail(msg != NULL, FALSE);
+
+ if (msim_msg_get(msg, "bm") && msim_msg_get(msg, "f")) {
+ guint uid;
+ const gchar *username;
+
+ /* 'f' = userid message is from, in buddy messages */
+ uid = msim_msg_get_integer(msg, "f");
+
+ username = msim_uid2username_from_blist(session->account, uid);
+
+ if (username) {
+ /* Know username already, use it. */
+ purple_debug_info("msim", "msim_preprocess_incoming: tagging with _username=%s\n",
+ username);
+ msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, g_strdup(username));
+ return msim_process(session, msg);
+
+ } else {
+ gchar *from;
+
+ /* Send lookup request. */
+ /* XXX: where is msim_msg_get_string() freed? make _strdup and _nonstrdup. */
+ purple_debug_info("msim", "msim_incoming: sending lookup, setting up callback\n");
+ from = msim_msg_get_string(msg, "f");
+ msim_lookup_user(session, from, msim_incoming_resolved, msim_msg_clone(msg));
+ g_free(from);
+
+ /* indeterminate */
+ return TRUE;
+ }
+ } else {
+ /* Nothing to resolve - send directly to processing. */
+ return msim_process(session, msg);
+ }
}
/**
@@ -2484,7 +1975,7 @@ msim_offline_message(const PurpleBuddy *
*
* Reads the input, and calls msim_preprocess_incoming() to handle it.
*/
-static void
+static void
msim_input_cb(gpointer gc_uncasted, gint source, PurpleInputCondition cond)
{
PurpleConnection *gc;
@@ -2517,12 +2008,12 @@ msim_input_cb(gpointer gc_uncasted, gint
/* If approaching end of buffer, reallocate some more memory. */
if (session->rxsize < session->rxoff + MSIM_READ_BUF_SIZE) {
- purple_debug_info("msim",
+ purple_debug_info("msim",
"msim_input_cb: %d-byte read buffer full, rxoff=%d, " "growing by %d bytes\n",
session->rxsize, session->rxoff, MSIM_READ_BUF_SIZE);
session->rxsize += MSIM_READ_BUF_SIZE;
session->rxbuf = g_realloc(session->rxbuf, session->rxsize);
-
+
return;
}
@@ -2533,17 +2024,17 @@ msim_input_cb(gpointer gc_uncasted, gint
/* Read into buffer. On Win32, need recv() not read(). session->fd also holds
* the file descriptor, but it sometimes differs from the 'source' parameter.
*/
- n = recv(session->fd,
- session->rxbuf + session->rxoff,
+ n = recv(session->fd,
+ session->rxbuf + session->rxoff,
session->rxsize - session->rxoff - 1, 0);
if (n < 0 && errno == EAGAIN) {
return;
} else if (n < 0) {
purple_debug_error("msim", "msim_input_cb: read error, ret=%d, "
- "error=%s, source=%d, fd=%d (%X))\n",
+ "error=%s, source=%d, fd=%d (%X))\n",
n, g_strerror(errno), source, session->fd, session->fd);
- purple_connection_error_reason (gc,
+ purple_connection_error_reason (gc,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
_("Read error"));
return;
@@ -2574,7 +2065,7 @@ msim_input_cb(gpointer gc_uncasted, gint
if (strlen(session->rxbuf + session->rxoff) != n) {
/* Occurs after login, but it is not a null byte. */
purple_debug_info("msim", "msim_input_cb: strlen=%d, but read %d bytes"
- "--null byte encountered?\n",
+ "--null byte encountered?\n",
strlen(session->rxbuf + session->rxoff), n);
/*purple_connection_error_reason (gc,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
@@ -2616,43 +2107,15 @@ msim_input_cb(gpointer gc_uncasted, gint
/* Move remaining part of buffer to beginning. */
session->rxoff -= strlen(session->rxbuf) + strlen(MSIM_FINAL_STRING);
- memmove(session->rxbuf, end + strlen(MSIM_FINAL_STRING),
+ memmove(session->rxbuf, end + strlen(MSIM_FINAL_STRING),
session->rxsize - (end + strlen(MSIM_FINAL_STRING) - session->rxbuf));
- /* Clear end of buffer
+ /* Clear end of buffer
* memset(end, 0, MSIM_READ_BUF_SIZE - (end - session->rxbuf));
*/
}
}
-/* Setup a callback, to be called when a reply is received with the returned rid.
- *
- * @param cb The callback, an MSIM_USER_LOOKUP_CB.
- * @param data Arbitrary user data to be passed to callback (probably an MsimMessage *).
- *
- * @return The request/reply ID, used to link replies with requests, or -1.
- * Put the rid in your request, 'rid' field.
- *
- * TODO: Make more generic and more specific:
- * 1) MSIM_USER_LOOKUP_CB - make it for PERSIST_REPLY, not just user lookup
- * 2) data - make it an MsimMessage?
- */
-guint
-msim_new_reply_callback(MsimSession *session, MSIM_USER_LOOKUP_CB cb,
- gpointer data)
-{
- guint rid;
-
- g_return_val_if_fail(MSIM_SESSION_VALID(session), -1);
-
- rid = session->next_rid++;
-
- g_hash_table_insert(session->user_lookup_cb, GUINT_TO_POINTER(rid), cb);
- g_hash_table_insert(session->user_lookup_cb_data, GUINT_TO_POINTER(rid), data);
-
- return rid;
-}
-
/**
* Callback when connected. Sets up input handlers.
*
@@ -2660,7 +2123,7 @@ msim_new_reply_callback(MsimSession *ses
* @param source File descriptor.
* @param error_message
*/
-static void
+static void
msim_connect_cb(gpointer data, gint source, const gchar *error_message)
{
PurpleConnection *gc;
@@ -2674,24 +2137,68 @@ msim_connect_cb(gpointer data, gint sour
if (source < 0) {
purple_connection_error_reason (gc,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- g_strdup_printf(_("Couldn't connect to host: %s (%d)"),
- error_message ? error_message : "no message given",
+ g_strdup_printf(_("Couldn't connect to host: %s (%d)"),
+ error_message ? error_message : "no message given",
source));
return;
}
- session->fd = source;
+ session->fd = source;
gc->inpa = purple_input_add(source, PURPLE_INPUT_READ, msim_input_cb, gc);
}
-
-/**
+/**
+ * Start logging in to the MSIM servers.
+ *
+ * @param acct Account information to use to login.
+ */
+static void
+msim_login(PurpleAccount *acct)
+{
+ PurpleConnection *gc;
+ const gchar *host;
+ int port;
+
+ g_return_if_fail(acct != NULL);
+ g_return_if_fail(acct->username != NULL);
+
+ purple_debug_info("msim", "logging in %s\n", acct->username);
+
+ gc = purple_account_get_connection(acct);
+ gc->proto_data = msim_session_new(acct);
+ gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_URLDESC;
+
+ /* 1. connect to server */
+ purple_connection_update_progress(gc, _("Connecting"),
+ 0, /* which connection step this is */
+ 4); /* total number of steps */
+
+ host = purple_account_get_string(acct, "server", MSIM_SERVER);
+ port = purple_account_get_int(acct, "port", MSIM_PORT);
+
+ /* From purple.sf.net/api:
+ * """Note that this function name can be misleading--although it is called
+ * "proxy connect," it is used for establishing any outgoing TCP connection,
+ * whether through a proxy or not.""" */
+
+ /* Calls msim_connect_cb when connected. */
+ if (!purple_proxy_connect(gc, acct, host, port, msim_connect_cb, gc)) {
+ /* TODO: try other ports if in auto mode, then save
+ * working port and try that first next time. */
+ purple_connection_error_reason (gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Couldn't create socket"));
+ return;
+ }
+}
+
+/**
* Close the connection.
- *
+ *
* @param gc The connection.
*/
-void
+static void
msim_close(PurpleConnection *gc)
{
MsimSession *session;
@@ -2717,372 +2224,640 @@ msim_close(PurpleConnection *gc)
msim_session_destroy(session);
}
-
/**
- * Obtain the status text for a buddy.
+ * Schedule an IM to be sent once the user ID is looked up.
*
- * @param buddy The buddy to obtain status text for.
+ * @param gc Connection.
+ * @param who A user id, email, or username to send the message to.
+ * @param message Instant message text to send.
+ * @param flags Flags.
*
- * @return Status text, or NULL if error. Caller g_free()'s.
+ * @return 1 if successful or postponed, -1 if failed
*
+ * Allows sending to a user by username, email address, or userid. If
+ * a username or email address is given, the userid must be looked up.
+ * This function does that by calling msim_postprocess_outgoing().
*/
-char *
-msim_status_text(PurpleBuddy *buddy)
+static int
+msim_send_im(PurpleConnection *gc, const gchar *who, const gchar *message,
+ PurpleMessageFlags flags)
{
MsimSession *session;
- MsimUser *user;
- const gchar *display_name, *headline;
+ gchar *message_msim;
+ int rc;
- g_return_val_if_fail(buddy != NULL, NULL);
+ g_return_val_if_fail(gc != NULL, -1);
+ g_return_val_if_fail(who != NULL, -1);
+ g_return_val_if_fail(message != NULL, -1);
- user = msim_get_user_from_buddy(buddy);
+ /* 'flags' has many options, not used here. */
- session = (MsimSession *)buddy->account->gc->proto_data;
- g_return_val_if_fail(MSIM_SESSION_VALID(session), NULL);
+ session = (MsimSession *)gc->proto_data;
- display_name = headline = NULL;
+ g_return_val_if_fail(MSIM_SESSION_VALID(session), -1);
- /* Retrieve display name and/or headline, depending on user preference. */
- if (purple_account_get_bool(session->account, "show_headline", TRUE)) {
- headline = user->headline;
- }
+ message_msim = html_to_msim_markup(session, message);
- if (purple_account_get_bool(session->account, "show_display_name", FALSE)) {
- display_name = user->display_name;
- }
-
- /* Return appropriate combination of display name and/or headline, or neither. */
-
- if (display_name && headline) {
- return g_strconcat(display_name, " ", headline, NULL);
- } else if (display_name) {
- return g_strdup(display_name);
- } else if (headline) {
- return g_strdup(headline);
+ if (msim_send_bm(session, who, message_msim, MSIM_BM_INSTANT)) {
+ /* Return 1 to have Purple show this IM as being sent, 0 to not. I always
+ * return 1 even if the message could not be sent, since I don't know if
+ * it has failed yet--because the IM is only sent after the userid is
+ * retrieved from the server (which happens after this function returns).
+ * If an error does occur, it should be logged to the IM window.
+ */
+ rc = 1;
+ } else {
+ rc = -1;
}
- return NULL;
+ g_free(message_msim);
+
+ return rc;
}
/**
- * Obtain the tooltip text for a buddy.
+ * Handle when our user starts or stops typing to another user.
*
- * @param buddy Buddy to obtain tooltip text on.
- * @param user_info Variable modified to have the tooltip text.
- * @param full TRUE if should obtain full tooltip text.
+ * @param gc
+ * @param name The buddy name to which our user is typing to
+ * @param state PURPLE_TYPING, PURPLE_TYPED, PURPLE_NOT_TYPING
*
+ * @return 0
*/
-void
-msim_tooltip_text(PurpleBuddy *buddy, PurpleNotifyUserInfo *user_info,
- gboolean full)
+static unsigned int
+msim_send_typing(PurpleConnection *gc, const gchar *name,
+ PurpleTypingState state)
{
- MsimUser *user;
+ const gchar *typing_str;
+ MsimSession *session;
- g_return_if_fail(buddy != NULL);
- g_return_if_fail(user_info != NULL);
+ g_return_val_if_fail(gc != NULL, 0);
+ g_return_val_if_fail(name != NULL, 0);
- user = msim_get_user_from_buddy(buddy);
+ session = (MsimSession *)gc->proto_data;
- if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
- MsimSession *session;
+ g_return_val_if_fail(MSIM_SESSION_VALID(session), 0);
- session = (MsimSession *)buddy->account->gc->proto_data;
+ switch (state) {
+ case PURPLE_TYPING:
+ typing_str = "%typing%";
+ break;
- g_return_if_fail(MSIM_SESSION_VALID(session));
-
- /* TODO: if (full), do something different? */
-
- /* TODO: request information? have to figure out how to do
- * the asynchronous lookup like oscar does (tooltip shows
- * 'retrieving...' if not yet available, then changes when it is).
- *
- * Right now, only show what we have on hand.
- */
-
- /* Show abbreviated user info. */
- msim_append_user_info(session, user_info, user, FALSE);
+ case PURPLE_TYPED:
+ case PURPLE_NOT_TYPING:
+ default:
+ typing_str = "%stoptyping%";
+ break;
}
+
+ purple_debug_info("msim", "msim_send_typing(%s): %d (%s)\n", name, state, typing_str);
+ msim_send_bm(session, name, typing_str, MSIM_BM_ACTION);
+ return 0;
}
-/** Add contact from server to buddy list, after looking up username.
- * Callback from msim_add_contact_from_server().
- *
- * @param data An MsimMessage * of the contact information. Will be freed.
+/**
+ * Callback for msim_get_info(), for when user info is received.
*/
static void
-msim_add_contact_from_server_cb(MsimSession *session, MsimMessage *user_lookup_info, gpointer data)
+msim_get_info_cb(MsimSession *session, MsimMessage *user_info_msg,
+ gpointer data)
{
- MsimMessage *contact_info, *user_lookup_info_body;
- PurpleGroup *group;
- PurpleBuddy *buddy;
+ MsimMessage *msg;
+ gchar *username;
+ PurpleNotifyUserInfo *user_info;
MsimUser *user;
- gchar *username, *group_name;
- guint uid;
- contact_info = (MsimMessage *)data;
- purple_debug_info("msim_add_contact_from_server_cb", "contact_info addr=%p\n", contact_info);
- uid = msim_msg_get_integer(contact_info, "ContactID");
+ g_return_if_fail(MSIM_SESSION_VALID(session));
- if (!user_lookup_info) {
- username = g_strdup(msim_uid2username_from_blist(session->account, uid));
- g_return_if_fail(username != NULL);
- } else {
- user_lookup_info_body = msim_msg_get_dictionary(user_lookup_info, "body");
- username = msim_msg_get_string(user_lookup_info_body, "UserName");
- msim_msg_free(user_lookup_info_body);
- g_return_if_fail(username != NULL);
+ /* Get user{name,id} from msim_get_info, passed as an MsimMessage for
+ orthogonality. */
+ msg = (MsimMessage *)data;
+ g_return_if_fail(msg != NULL);
+
+ username = msim_msg_get_string(msg, "user");
+ if (!username) {
+ purple_debug_info("msim", "msim_get_info_cb: no 'user' in msg\n");
+ return;
}
- purple_debug_info("msim_add_contact_from_server_cb",
- "*** about to add/update username=%s\n", username);
+ msim_msg_free(msg);
+ purple_debug_info("msim", "msim_get_info_cb: got for user: %s\n", username);
- /* 1. Creates a new group, or gets existing group if it exists (or so
- * the documentation claims). */
- group_name = msim_msg_get_string(contact_info, "GroupName");
- if (!group_name || (*group_name == '\0')) {
- g_free(group_name);
- group_name = g_strdup(_("IM Friends"));
- purple_debug_info("myspace", "No GroupName specified, defaulting to '%s'.\n", group_name);
- }
- group = purple_find_group(group_name);
- if (!group) {
- group = purple_group_new(group_name);
- /* Add group to beginning. See #2752. */
- purple_blist_add_group(group, NULL);
- }
- g_free(group_name);
+ user = msim_find_user(session, username);
- /* 2. Get or create buddy */
- buddy = purple_find_buddy(session->account, username);
- if (!buddy) {
- purple_debug_info("msim_add_contact_from_server_cb",
- "creating new buddy: %s\n", username);
- buddy = purple_buddy_new(session->account, username, NULL);
+ if (!user) {
+ /* User isn't on blist, create a temporary user to store info. */
+ user = g_new0(MsimUser, 1);
+ user->temporary_user = TRUE;
}
- /* TODO: use 'Position' in contact_info to take into account where buddy is */
- purple_blist_add_buddy(buddy, NULL, group, NULL /* insertion point */);
+ /* Update user structure with new information */
+ msim_store_user_info(session, user_info_msg, user);
- /* 3. Update buddy information */
- user = msim_get_user_from_buddy(buddy);
+ user_info = purple_notify_user_info_new();
- user->id = uid;
- /* Keep track of the user ID across sessions */
- purple_blist_node_set_int(&buddy->node, "UserID", uid);
+ /* Append data from MsimUser to PurpleNotifyUserInfo for display, full */
+ msim_append_user_info(session, user_info, user, TRUE);
- /* Stores a few fields in the MsimUser, relevant to the buddy itself.
- * AvatarURL, Headline, ContactID. */
- msim_store_user_info(session, contact_info, NULL);
+ purple_notify_userinfo(session->gc, username, user_info, NULL, NULL);
+ purple_debug_info("msim", "msim_get_info_cb: username=%s\n", username);
- /* TODO: other fields, store in 'user' */
- msim_msg_free(contact_info);
+ purple_notify_user_info_destroy(user_info);
+ if (user->temporary_user) {
+ g_free(user->client_info);
+ g_free(user->gender);
+ g_free(user->location);
+ g_free(user->headline);
+ g_free(user->display_name);
+ g_free(user->username);
+ g_free(user->image_url);
+ g_free(user);
+ }
g_free(username);
}
-/** Add first ContactID in contact_info to buddy's list. Used to add
- * server-side buddies to client-side list.
- *
- * @return TRUE if added.
- * */
-static gboolean
-msim_add_contact_from_server(MsimSession *session, MsimMessage *contact_info)
+/**
+ * Retrieve a user's profile.
+ * @param username Username, user ID, or email address to lookup.
+ */
+static void
+msim_get_info(PurpleConnection *gc, const gchar *username)
{
- guint uid;
- const gchar *username;
+ MsimSession *session;
+ MsimUser *user;
+ gchar *user_to_lookup;
+ MsimMessage *user_msg;
- uid = msim_msg_get_integer(contact_info, "ContactID");
- g_return_val_if_fail(uid != 0, FALSE);
+ g_return_if_fail(gc != NULL);
+ g_return_if_fail(username != NULL);
- /* Lookup the username, since NickName and IMName is unreliable */
- username = msim_uid2username_from_blist(session->account, uid);
- if (!username) {
- gchar *uid_str;
+ session = (MsimSession *)gc->proto_data;
- uid_str = g_strdup_printf("%d", uid);
- purple_debug_info("msim_add_contact_from_server",
- "contact_info addr=%p\n", contact_info);
- msim_lookup_user(session, uid_str, msim_add_contact_from_server_cb, (gpointer)msim_msg_clone(contact_info));
- g_free(uid_str);
+ g_return_if_fail(MSIM_SESSION_VALID(session));
+
+ /* Obtain uid of buddy. */
+ user = msim_find_user(session, username);
+
+ /* If is on buddy list, lookup by uid since it is faster. */
+ if (user && user->id) {
+ user_to_lookup = g_strdup_printf("%d", user->id);
} else {
- msim_add_contact_from_server_cb(session, NULL, (gpointer)msim_msg_clone(contact_info));
+ /* Looking up buddy not on blist. Lookup by whatever user entered. */
+ user_to_lookup = g_strdup(username);
}
- /* Say that the contact was added, even if we're still looking up
- * their username. */
- return TRUE;
+ /* Pass the username to msim_get_info_cb(), because since we lookup
+ * by userid, the userinfo message will only contain the uid (not
+ * the username) but it would be useful to display the username too.
+ */
+ user_msg = msim_msg_new(
+ "user", MSIM_TYPE_STRING, g_strdup(username),
+ NULL);
+ purple_debug_info("msim", "msim_get_info, setting up lookup, user=%s\n", username);
+
+ msim_lookup_user(session, user_to_lookup, msim_get_info_cb, user_msg);
+
+ g_free(user_to_lookup);
}
-/** Called when contact list is received from server. */
+/**
+ * Set status using an MSIM_STATUS_CODE_* value.
+ * @param status_code An MSIM_STATUS_CODE_* value.
+ * @param statstring Status string, must be a dynamic string (will be freed by msim_send).
+ */
static void
-msim_got_contact_list(MsimSession *session, MsimMessage *reply, gpointer user_data)
+msim_set_status_code(MsimSession *session, guint status_code, gchar *statstring)
{
- MsimMessage *body, *body_node;
- gchar *msg;
- guint buddy_count;
+ g_return_if_fail(MSIM_SESSION_VALID(session));
+ g_return_if_fail(statstring != NULL);
- msim_msg_dump("msim_got_contact_list: reply=%s", reply);
+ purple_debug_info("msim", "msim_set_status_code: going to set status to code=%d,str=%s\n",
+ status_code, statstring);
- body = msim_msg_get_dictionary(reply, "body");
- if (!body) {
- /* No friends. Not an error. */
- return;
+ if (!msim_send(session,
+ "status", MSIM_TYPE_INTEGER, status_code,
+ "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+ "statstring", MSIM_TYPE_STRING, statstring,
+ "locstring", MSIM_TYPE_STRING, g_strdup(""),
+ NULL))
+ {
+ purple_debug_info("msim", "msim_set_status: failed to set status\n");
}
+}
- buddy_count = 0;
+/**
+ * Set your status - callback for when user manually sets it.
+ */
+static void
+msim_set_status(PurpleAccount *account, PurpleStatus *status)
+{
+ PurpleStatusType *type;
+ PurplePresence *pres;
+ MsimSession *session;
+ guint status_code;
+ const gchar *message;
+ gchar *stripped;
+ gchar *unrecognized_msg;
- for (body_node = body;
- body_node != NULL;
- body_node = msim_msg_get_next_element_node(body_node))
- {
- MsimMessageElement *elem;
+ session = (MsimSession *)account->gc->proto_data;
- elem = (MsimMessageElement *)body_node->data;
+ g_return_if_fail(MSIM_SESSION_VALID(session));
- if (g_str_equal(elem->name, "ContactID"))
- {
- /* Will look for first contact in body_node */
- if (msim_add_contact_from_server(session, body_node)) {
- ++buddy_count;
- }
- }
- }
+ type = purple_status_get_type(status);
+ pres = purple_status_get_presence(status);
- switch (GPOINTER_TO_UINT(user_data)) {
- case MSIM_CONTACT_LIST_IMPORT_ALL_FRIENDS:
- msg = g_strdup_printf(ngettext("%d buddy was added or updated from the server (including buddies already on the server-side list)",
- "%d buddies were added or updated from the server (including buddies already on the server-side list)",
- buddy_count),
- buddy_count);
- purple_notify_info(session->account, _("Add contacts from server"), msg, NULL);
- g_free(msg);
+ switch (purple_status_type_get_primitive(type)) {
+ case PURPLE_STATUS_AVAILABLE:
+ purple_debug_info("msim", "msim_set_status: available (%d->%d)\n", PURPLE_STATUS_AVAILABLE,
+ MSIM_STATUS_CODE_ONLINE);
+ status_code = MSIM_STATUS_CODE_ONLINE;
break;
- case MSIM_CONTACT_LIST_IMPORT_TOP_FRIENDS:
- /* TODO */
+ case PURPLE_STATUS_INVISIBLE:
+ purple_debug_info("msim", "msim_set_status: invisible (%d->%d)\n", PURPLE_STATUS_INVISIBLE,
+ MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN);
+ status_code = MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN;
break;
-
- case MSIM_CONTACT_LIST_INITIAL_FRIENDS:
- /* Nothing */
+
+ case PURPLE_STATUS_AWAY:
+ purple_debug_info("msim", "msim_set_status: away (%d->%d)\n", PURPLE_STATUS_AWAY,
+ MSIM_STATUS_CODE_AWAY);
+ status_code = MSIM_STATUS_CODE_AWAY;
break;
+
+ default:
+ purple_debug_info("msim", "msim_set_status: unknown "
+ "status interpreting as online");
+ status_code = MSIM_STATUS_CODE_ONLINE;
+
+ unrecognized_msg = g_strdup_printf("msim_set_status, unrecognized status type: %d\n",
+ purple_status_type_get_primitive(type));
+ msim_unrecognized(session, NULL, unrecognized_msg);
+ g_free(unrecognized_msg);
+
+ break;
}
- msim_msg_free(body);
+ message = purple_status_get_attr_string(status, "message");
+
+ /* Status strings are plain text. */
+ if (message != NULL)
+ stripped = purple_markup_strip_html(message);
+ else
+ stripped = g_strdup("");
+
+ msim_set_status_code(session, status_code, stripped);
+
+ /* If we should be idle, set that status. Time is irrelevant here. */
+ if (purple_presence_is_idle(pres) && status_code != MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN)
+ msim_set_idle(account->gc, 1);
}
-/* Get contact list, calling msim_got_contact_list() with what_to_do_after as user_data gpointer. */
-static gboolean
-msim_get_contact_list(MsimSession *session, int what_to_do_after)
+/**
+ * Go idle.
+ */
+static void
+msim_set_idle(PurpleConnection *gc, int time)
{
- return msim_send(session,
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_GET,
- "dsn", MSIM_TYPE_INTEGER, MG_LIST_ALL_CONTACTS_DSN,
- "lid", MSIM_TYPE_INTEGER, MG_LIST_ALL_CONTACTS_LID,
- "uid", MSIM_TYPE_INTEGER, session->userid,
- "rid", MSIM_TYPE_INTEGER,
- msim_new_reply_callback(session, msim_got_contact_list, GUINT_TO_POINTER(what_to_do_after)),
- "body", MSIM_TYPE_STRING, g_strdup(""),
- NULL);
+ MsimSession *session;
+ PurpleStatus *status;
+
+ g_return_if_fail(gc != NULL);
+
+ session = (MsimSession *)gc->proto_data;
+
+ g_return_if_fail(MSIM_SESSION_VALID(session));
+
+ status = purple_account_get_active_status(session->account);
+
+ if (time == 0) {
+ /* Going back from idle. In msim, idle is mutually exclusive
+ * from the other states (you can only be away or idle, but not
+ * both, for example), so by going non-idle I go back to what
+ * libpurple says I should be.
+ */
+ msim_set_status(session->account, status);
+ } else {
+ const gchar *message;
+ gchar *stripped;
+
+ /* Set the idle message to the status message from the real
+ * current status.
+ */
+ message = purple_status_get_attr_string(status, "message");
+ if (message != NULL)
+ stripped = purple_markup_strip_html(message);
+ else
+ stripped = g_strdup("");
+
+ /* msim doesn't support idle time, so just go idle */
+ msim_set_status_code(session, MSIM_STATUS_CODE_IDLE, stripped);
+ }
}
-
-/** Called when friends have been imported to buddy list on server. */
-static void
-msim_import_friends_cb(MsimSession *session, MsimMessage *reply, gpointer user_data)
+/**
+ * Add a buddy to user's buddy list.
+ */
+static void
+msim_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
{
+ MsimSession *session;
+ MsimMessage *msg;
+ MsimMessage *msg_persist;
MsimMessage *body;
- gchar *completed;
- msim_msg_dump("msim_import_friends_cb=%s", reply);
- /* Check if the friends were imported successfully. */
- body = msim_msg_get_dictionary(reply, "body");
- g_return_if_fail(body != NULL);
- completed = msim_msg_get_string(body, "Completed");
- g_return_if_fail(body != NULL);
- msim_msg_free(body);
- if (!g_str_equal(completed, "True"))
- {
- purple_debug_info("msim_import_friends_cb",
- "failed to import friends: %s", completed);
- purple_notify_error(session->account, _("Add friends from MySpace.com"),
- _("Importing friends failed"), NULL);
- g_free(completed);
+ session = (MsimSession *)gc->proto_data;
+ purple_debug_info("msim", "msim_add_buddy: want to add %s to %s\n",
+ buddy->name, (group && group->name) ? group->name : "(no group)");
+
+ msg = msim_msg_new(
+ "addbuddy", MSIM_TYPE_BOOLEAN, TRUE,
+ "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+ /* "newprofileid" will be inserted here with uid. */
+ "reason", MSIM_TYPE_STRING, g_strdup(""),
+ NULL);
+
+ if (!msim_postprocess_outgoing(session, msg, buddy->name, "newprofileid", "reason")) {
+ purple_notify_error(NULL, NULL, _("Failed to add buddy"), _("'addbuddy' command failed."));
+ msim_msg_free(msg);
return;
}
- g_free(completed);
+ msim_msg_free(msg);
- purple_debug_info("msim_import_friends_cb",
- "added friends to server-side buddy list, requesting new contacts from server");
+ /* TODO: if addbuddy fails ('error' message is returned), delete added buddy from
+ * buddy list since Purple adds it locally. */
- msim_get_contact_list(session, MSIM_CONTACT_LIST_IMPORT_ALL_FRIENDS);
+ body = msim_msg_new(
+ "ContactID", MSIM_TYPE_STRING, g_strdup("<uid>"),
+ "GroupName", MSIM_TYPE_STRING, g_strdup(group->name),
+ "Position", MSIM_TYPE_INTEGER, 1000,
+ "Visibility", MSIM_TYPE_INTEGER, 1,
+ "NickName", MSIM_TYPE_STRING, g_strdup(""),
+ "NameSelect", MSIM_TYPE_INTEGER, 0,
+ NULL);
- /* TODO: show, X friends have been added */
+ /* TODO: Update blocklist. */
+
+ msg_persist = msim_msg_new(
+ "persist", MSIM_TYPE_INTEGER, 1,
+ "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+ "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_BIT_ACTION | MSIM_CMD_PUT,
+ "dsn", MSIM_TYPE_INTEGER, MC_CONTACT_INFO_DSN,
+ "uid", MSIM_TYPE_INTEGER, session->userid,
+ "lid", MSIM_TYPE_INTEGER, MC_CONTACT_INFO_LID,
+ /* TODO: Use msim_new_reply_callback to get rid. */
+ "rid", MSIM_TYPE_INTEGER, session->next_rid++,
+ "body", MSIM_TYPE_DICTIONARY, body,
+ NULL);
+
+ if (!msim_postprocess_outgoing(session, msg_persist, buddy->name, "body", NULL))
+ {
+ purple_notify_error(NULL, NULL, _("Failed to add buddy"), _("persist command failed"));
+ msim_msg_free(msg_persist);
+ return;
+ }
+ msim_msg_free(msg_persist);
}
-/** Import friends from myspace.com. */
-static void msim_import_friends(PurplePluginAction *action)
+/**
+ * Remove a buddy from the user's buddy list.
+ */
+static void
+msim_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
{
- PurpleConnection *gc;
MsimSession *session;
- gchar *group_name;
+ MsimMessage *delbuddy_msg;
+ MsimMessage *persist_msg;
+ MsimMessage *blocklist_msg;
+ GList *blocklist_updates;
- gc = (PurpleConnection *)action->context;
session = (MsimSession *)gc->proto_data;
- group_name = "MySpace Friends";
+ delbuddy_msg = msim_msg_new(
+ "delbuddy", MSIM_TYPE_BOOLEAN, TRUE,
+ "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+ /* 'delprofileid' with uid will be inserted here. */
+ NULL);
- g_return_if_fail(msim_send(session,
+ if (!msim_postprocess_outgoing(session, delbuddy_msg, buddy->name, "delprofileid", NULL)) {
+ purple_notify_error(NULL, NULL, _("Failed to remove buddy"), _("'delbuddy' command failed"));
+ msim_msg_free(delbuddy_msg);
+ return;
+ }
+ msim_msg_free(delbuddy_msg);
+
+ persist_msg = msim_msg_new(
"persist", MSIM_TYPE_INTEGER, 1,
"sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_PUT,
- "dsn", MSIM_TYPE_INTEGER, MC_IMPORT_ALL_FRIENDS_DSN,
- "lid", MSIM_TYPE_INTEGER, MC_IMPORT_ALL_FRIENDS_LID,
+ "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_BIT_ACTION | MSIM_CMD_DELETE,
+ "dsn", MSIM_TYPE_INTEGER, MD_DELETE_BUDDY_DSN,
+ "lid", MSIM_TYPE_INTEGER, MD_DELETE_BUDDY_LID,
"uid", MSIM_TYPE_INTEGER, session->userid,
- "rid", MSIM_TYPE_INTEGER,
- msim_new_reply_callback(session, msim_import_friends_cb, NULL),
- "body", MSIM_TYPE_STRING,
- g_strdup_printf("GroupName=%s", group_name),
- NULL));
+ "rid", MSIM_TYPE_INTEGER, session->next_rid++,
+ /* <uid> will be replaced by postprocessing */
+ "body", MSIM_TYPE_STRING, g_strdup("ContactID=<uid>"),
+ NULL);
+ if (!msim_postprocess_outgoing(session, persist_msg, buddy->name, "body", NULL)) {
+ purple_notify_error(NULL, NULL, _("Failed to remove buddy"), _("persist command failed"));
+ msim_msg_free(persist_msg);
+ return;
+ }
+ msim_msg_free(persist_msg);
+ blocklist_updates = NULL;
+ blocklist_updates = g_list_prepend(blocklist_updates, "a-");
+ blocklist_updates = g_list_prepend(blocklist_updates, "<uid>");
+ blocklist_updates = g_list_prepend(blocklist_updates, "b-");
+ blocklist_updates = g_list_prepend(blocklist_updates, "<uid>");
+ blocklist_updates = g_list_reverse(blocklist_updates);
+
+ blocklist_msg = msim_msg_new(
+ "blocklist", MSIM_TYPE_BOOLEAN, TRUE,
+ "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+ /* TODO: MsimMessage lists. Currently <uid> isn't replaced in lists. */
+ /* "idlist", MSIM_TYPE_STRING, g_strdup("a-|<uid>|b-|<uid>"), */
+ "idlist", MSIM_TYPE_LIST, blocklist_updates,
+ NULL);
+
+ if (!msim_postprocess_outgoing(session, blocklist_msg, buddy->name, "idlist", NULL)) {
+ purple_notify_error(NULL, NULL, _("Failed to remove buddy"), _("blocklist command failed"));
+ msim_msg_free(blocklist_msg);
+ return;
+ }
+ msim_msg_free(blocklist_msg);
}
-/** Actions menu for account. */
-GList *
-msim_actions(PurplePlugin *plugin, gpointer context)
+/**
+ * Returns a string of a username in canonical form. Basically removes all the
+ * spaces, lowercases the string, and looks up user IDs to usernames.
+ * Normalizing tom, TOM, Tom, and 6221 wil all return 'tom'.
+ *
+ * Borrowed this code from oscar_normalize. Added checking for
+ * "if userid, get name before normalizing"
+ */
+static const char *msim_normalize(const PurpleAccount *account, const char *str) {
+ static char normalized[BUF_LEN];
+ char *tmp1, *tmp2;
+ int i, j;
+ guint id;
+
+ g_return_val_if_fail(str != NULL, NULL);
+
+ if (msim_is_userid(str)) {
+ /* Have user ID, we need to get their username first :) */
+ const char *username;
+
+ /* If the account does not exist, we can't look up the user. */
+ if (!account || !account->gc)
+ return str;
+
+ id = atol(str);
+ username = msim_uid2username_from_blist((PurpleAccount *)account, id);
+ if (!username) {
+ /* Not in buddy list... scheisse... TODO: Manual Lookup! Bug #4631 */
+ /* Note: manual lookup using msim_lookup_user() is a problem inside
+ * msim_normalize(), because msim_lookup_user() calls a callback function
+ * when the user information has been looked up, but msim_normalize() expects
+ * the result immediately. */
+ strncpy(normalized, str, BUF_LEN);
+ } else {
+ strncpy(normalized, username, BUF_LEN);
+ }
+ } else {
+ /* Have username. */
+ strncpy(normalized, str, BUF_LEN);
+ }
+
+ /* Strip spaces. */
+ for (i=0, j=0; normalized[j]; i++, j++) {
+ while (normalized[j] == ' ')
+ j++;
+ normalized[i] = normalized[j];
+ }
+ normalized[i] = '\0';
+
+ /* Lowercase and perform UTF-8 normalization. */
+ tmp1 = g_utf8_strdown(normalized, -1);
+ tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_DEFAULT);
+ g_snprintf(normalized, sizeof(normalized), "%s", tmp2);
+ g_free(tmp2);
+ g_free(tmp1);
+
+ /* TODO: re-add caps and spacing back to what the user wanted.
+ * User can format their own names, for example 'msimprpl' is shown
+ * as 'MsIm PrPl' in the official client.
+ *
+ * TODO: file a ticket to add this enhancement.
+ */
+
+ return normalized;
+}
+
+/**
+ * Return whether the buddy can be messaged while offline.
+ *
+ * The protocol supports offline messages in just the same way as online
+ * messages.
+ */
+static gboolean
+msim_offline_message(const PurpleBuddy *buddy)
{
- PurpleConnection *gc;
- GList *menu;
- PurplePluginAction *act;
+ return TRUE;
+}
- gc = (PurpleConnection *)context;
+/**
+ * Send raw data to the server, possibly with embedded NULs.
+ *
+ * Used in prpl_info struct, so that plugins can have the most possible
+ * control of what is sent over the connection. Inside this prpl,
+ * msim_send_raw() is used, since it sends NUL-terminated strings (easier).
+ *
+ * @param gc PurpleConnection
+ * @param buf Buffer to send
+ * @param total_bytes Size of buffer to send
+ *
+ * @return Bytes successfully sent, or -1 on error.
+ */
+static int
+msim_send_really_raw(PurpleConnection *gc, const char *buf, int total_bytes)
+{
+ int total_bytes_sent;
+ MsimSession *session;
- menu = NULL;
+ g_return_val_if_fail(gc != NULL, -1);
+ g_return_val_if_fail(buf != NULL, -1);
+ g_return_val_if_fail(total_bytes >= 0, -1);
-#if 0
- /* TODO: find out how */
- act = purple_plugin_action_new(_("Find people..."), msim_);
- menu = g_list_append(menu, act);
+ session = (MsimSession *)gc->proto_data;
- act = purple_plugin_action_new(_("Change IM name..."), NULL);
- menu = g_list_append(menu, act);
-#endif
+ g_return_val_if_fail(MSIM_SESSION_VALID(session), -1);
- act = purple_plugin_action_new(_("Add friends from MySpace.com"), msim_import_friends);
- menu = g_list_append(menu, act);
+ /* Loop until all data is sent, or a failure occurs. */
+ total_bytes_sent = 0;
+ do {
+ int bytes_sent;
- return menu;
+ bytes_sent = send(session->fd, buf + total_bytes_sent,
+ total_bytes - total_bytes_sent, 0);
+
+ if (bytes_sent < 0) {
+ purple_debug_info("msim", "msim_send_raw(%s): send() failed: %s\n",
+ buf, g_strerror(errno));
+ return total_bytes_sent;
+ }
+ total_bytes_sent += bytes_sent;
+
+ } while(total_bytes_sent < total_bytes);
+
+ return total_bytes_sent;
}
-/** Callbacks called by Purple, to access this plugin. */
+/**
+ * Send raw data (given as a NUL-terminated string) to the server.
+ *
+ * @param session
+ * @param msg The raw data to send, in a NUL-terminated string.
+ *
+ * @return TRUE if succeeded, FALSE if not.
+ *
+ */
+gboolean
+msim_send_raw(MsimSession *session, const gchar *msg)
+{
+ size_t len;
+
+ g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+ g_return_val_if_fail(msg != NULL, FALSE);
+
+ purple_debug_info("msim", "msim_send_raw: writing <%s>\n", msg);
+ len = strlen(msg);
+
+ return msim_send_really_raw(session->gc, msg, len) == len;
+}
+
+static GHashTable *
+msim_get_account_text_table(PurpleAccount *unused)
+{
+ GHashTable *table;
+
+ table = g_hash_table_new(g_str_hash, g_str_equal);
+
+ g_hash_table_insert(table, "login_label", (gpointer)_("Email Address..."));
+
+ return table;
+}
+
+/**
+ * Callbacks called by Purple, to access this plugin.
+ */
static PurplePluginProtocolInfo prpl_info = {
/* options */
OPT_PROTO_USE_POINTSIZE /* specify font size in sane point size */
| OPT_PROTO_MAIL_CHECK,
- /* | OPT_PROTO_IM_IMAGE - TODO: direct images. */
+ /* | OPT_PROTO_IM_IMAGE - TODO: direct images. */
NULL, /* user_splits */
NULL, /* protocol_options */
NO_BUDDY_ICONS, /* icon_spec - TODO: eventually should add this */
@@ -3152,9 +2927,120 @@ static PurplePluginProtocolInfo prpl_inf
msim_get_account_text_table, /* get_account_text_table */
};
+/**
+ * Load the plugin.
+ */
+static gboolean
+msim_load(PurplePlugin *plugin)
+{
+ /* If compiled to use RC4 from libpurple, check if it is really there. */
+ if (!purple_ciphers_find_cipher("rc4")) {
+ purple_debug_error("msim", "rc4 not in libpurple, but it is required - not loading MySpaceIM plugin!\n");
+ purple_notify_error(plugin, _("Missing Cipher"),
+ _("The RC4 cipher could not be found"),
+ _("Upgrade "
+ "to a libpurple with RC4 support (>= 2.0.1). MySpaceIM "
+ "plugin will not be loaded."));
+ return FALSE;
+ }
+ return TRUE;
+}
+/**
+ * Called when friends have been imported to buddy list on server.
+ */
+static void
+msim_import_friends_cb(MsimSession *session, MsimMessage *reply, gpointer user_data)
+{
+ MsimMessage *body;
+ gchar *completed;
+ msim_msg_dump("msim_import_friends_cb=%s", reply);
-/** Based on MSN's plugin info comments. */
+ /* Check if the friends were imported successfully. */
+ body = msim_msg_get_dictionary(reply, "body");
+ g_return_if_fail(body != NULL);
+ completed = msim_msg_get_string(body, "Completed");
+ g_return_if_fail(body != NULL);
+ msim_msg_free(body);
+ if (!g_str_equal(completed, "True"))
+ {
+ purple_debug_info("msim_import_friends_cb",
+ "failed to import friends: %s", completed);
+ purple_notify_error(session->account, _("Add friends from MySpace.com"),
+ _("Importing friends failed"), NULL);
+ g_free(completed);
+ return;
+ }
+ g_free(completed);
+
+ purple_debug_info("msim_import_friends_cb",
+ "added friends to server-side buddy list, requesting new contacts from server");
+
+ msim_get_contact_list(session, MSIM_CONTACT_LIST_IMPORT_ALL_FRIENDS);
+
+ /* TODO: show, X friends have been added */
+}
+
+/**
+ * Import friends from myspace.com.
+ */
+static void msim_import_friends(PurplePluginAction *action)
+{
+ PurpleConnection *gc;
+ MsimSession *session;
+ gchar *group_name;
+
+ gc = (PurpleConnection *)action->context;
+ session = (MsimSession *)gc->proto_data;
+
+ group_name = "MySpace Friends";
+
+ g_return_if_fail(msim_send(session,
+ "persist", MSIM_TYPE_INTEGER, 1,
+ "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+ "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_PUT,
+ "dsn", MSIM_TYPE_INTEGER, MC_IMPORT_ALL_FRIENDS_DSN,
+ "lid", MSIM_TYPE_INTEGER, MC_IMPORT_ALL_FRIENDS_LID,
+ "uid", MSIM_TYPE_INTEGER, session->userid,
+ "rid", MSIM_TYPE_INTEGER,
+ msim_new_reply_callback(session, msim_import_friends_cb, NULL),
+ "body", MSIM_TYPE_STRING,
+ g_strdup_printf("GroupName=%s", group_name),
+ NULL));
+}
+
+/**
+ * Actions menu for account.
+ */
+static GList *
+msim_actions(PurplePlugin *plugin, gpointer context)
+{
+ PurpleConnection *gc;
+ GList *menu;
+ PurplePluginAction *act;
+
+ gc = (PurpleConnection *)context;
+
+ menu = NULL;
+
+#if 0
+ /* TODO: find out how */
+ act = purple_plugin_action_new(_("Find people..."), msim_);
+ menu = g_list_append(menu, act);
+
+ act = purple_plugin_action_new(_("Change IM name..."), NULL);
+ menu = g_list_append(menu, act);
+#endif
+
+ act = purple_plugin_action_new(_("Add friends from MySpace.com"), msim_import_friends);
+ menu = g_list_append(menu, act);
+
+ return menu;
+}
+
+/**
+ * Based on MSN's plugin info comments.
+ */
static PurplePluginInfo info = {
PURPLE_PLUGIN_MAGIC,
PURPLE_MAJOR_VERSION,
@@ -3188,32 +3074,18 @@ static PurplePluginInfo info = {
NULL /**< reserved4 */
};
-
#ifdef MSIM_SELF_TEST
-/** Test functions.
+/*
+ * Test functions.
* Used to test or try out the internal workings of msimprpl. If you're reading
* this code for the first time, these functions can be instructive in learning
* how msimprpl is architected.
*/
-void
-msim_test_all(void) {
- guint failures;
-
- failures = 0;
- failures += msim_test_msg();
- failures += msim_test_escaping();
-
- if (failures) {
- purple_debug_info("msim", "msim_test_all HAD FAILURES: %d\n", failures);
- } else {
- purple_debug_info("msim", "msim_test_all - all tests passed!\n");
- }
- exit(0);
-}
-
-/** Test MsimMessage for basic functionality. */
-int
+/**
+ * Test MsimMessage for basic functionality.
+ */
+static int
msim_test_msg(void)
{
MsimMessage *msg, *msg_cloned, *msg2;
@@ -3290,8 +3162,10 @@ msim_test_msg(void)
return failures;
}
-/** Test protocol-level escaping/unescaping. */
-int
+/**
+ * Test protocol-level escaping/unescaping.
+ */
+static int
msim_test_escaping(void)
{
guint failures;
@@ -3322,8 +3196,179 @@ msim_test_escaping(void)
return failures;
}
+
+static void
+msim_test_all(void)
+{
+ guint failures;
+
+ failures = 0;
+ failures += msim_test_msg();
+ failures += msim_test_escaping();
+
+ if (failures) {
+ purple_debug_info("msim", "msim_test_all HAD FAILURES: %d\n", failures);
+ } else {
+ purple_debug_info("msim", "msim_test_all - all tests passed!\n");
+ }
+ exit(0);
+}
#endif
+#ifdef MSIM_CHECK_NEWER_VERSION
+/**
+ * Callback for when a currentversion.txt has been downloaded.
+ */
+static void
+msim_check_newer_version_cb(PurpleUtilFetchUrlData *url_data,
+ gpointer user_data,
+ const gchar *url_text,
+ gsize len,
+ const gchar *error_message)
+{
+ GKeyFile *keyfile;
+ GError *error;
+ GString *data;
+ gchar *newest_filever;
+
+ if (!url_text) {
+ purple_debug_info("msim_check_newer_version_cb",
+ "got error: %s\n", error_message);
+ return;
+ }
+
+ purple_debug_info("msim_check_newer_version_cb",
+ "url_text=%s\n", url_text ? url_text : "(NULL)");
+
+ /* Prepend [group] so that GKeyFile can parse it (requires a group). */
+ data = g_string_new(url_text);
+ purple_debug_info("msim", "data=%s\n", data->str
+ ? data->str : "(NULL)");
+ data = g_string_prepend(data, "[group]\n");
+
+ purple_debug_info("msim", "data=%s\n", data->str
+ ? data->str : "(NULL)");
+
+ /* url_text is variable=data\n...+*/
+
+ /* Check FILEVER, 1.0.716.0. 716 is build, MSIM_CLIENT_VERSION */
+ /* New (english) version can be downloaded from SETUPURL+SETUPFILE */
+
+ error = NULL;
+ keyfile = g_key_file_new();
+
+ /* Default list seperator is ;, but currentversion.txt doesn't have
+ * these, so set to an unused character to avoid parsing problems. */
+ g_key_file_set_list_separator(keyfile, '\0');
+
+ g_key_file_load_from_data(keyfile, data->str, data->len,
+ G_KEY_FILE_NONE, &error);
+ g_string_free(data, TRUE);
+
+ if (error != NULL) {
+ purple_debug_info("msim_check_newer_version_cb",
+ "couldn't parse, error: %d %d %s\n",
+ error->domain, error->code, error->message);
+ g_error_free(error);
+ return;
+ }
+
+ gchar **ks;
+ guint n;
+ ks = g_key_file_get_keys(keyfile, "group", &n, NULL);
+ purple_debug_info("msim", "n=%d\n", n);
+ guint i;
+ for (i = 0; ks[i] != NULL; ++i)
+ {
+ purple_debug_info("msim", "%d=%s\n", i, ks[i]);
+ }
+
+ newest_filever = g_key_file_get_string(keyfile, "group",
+ "FILEVER", &error);
+
+ purple_debug_info("msim_check_newer_version_cb",
+ "newest filever: %s\n", newest_filever ?
+ newest_filever : "(NULL)");
+ if (error != NULL) {
+ purple_debug_info("msim_check_newer_version_cb",
+ "error: %d %d %s\n",
+ error->domain, error->code, error->message);
+ g_error_free(error);
+ }
+
+ g_key_file_free(keyfile);
+
+ exit(0);
+}
+#endif
+
+/**
+ Handle a myim:addContact command, after username has been looked up.
+ */
+static void
+msim_uri_handler_addContact_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
+{
+ MsimMessage *body;
+ gchar *username;
+
+ body = msim_msg_get_dictionary(userinfo, "body");
+ username = msim_msg_get_string(body, "UserName");
+ msim_msg_free(body);
+
+ if (!username) {
+ guint uid;
+
+ uid = msim_msg_get_integer(userinfo, "UserID");
+ g_return_if_fail(uid != 0);
+
+ username = g_strdup_printf("%d", uid);
+ }
+
+ purple_blist_request_add_buddy(session->account, username, _("Buddies"), NULL);
+
+ g_free(username);
+}
+
+/* TODO: move uid->username resolving to IM sending and buddy adding functions,
+ * so that user can manually add or IM by userid and username automatically
+ * looked up if possible? */
+
+/**
+ * Handle a myim:sendIM URI command, after username has been looked up.
+ */
+static void
+msim_uri_handler_sendIM_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
+{
+ PurpleConversation *conv;
+ MsimMessage *body;
+ gchar *username;
+
+ body = msim_msg_get_dictionary(userinfo, "body");
+ username = msim_msg_get_string(body, "UserName");
+ msim_msg_free(body);
+
+ if (!username) {
+ guint uid;
+
+ uid = msim_msg_get_integer(userinfo, "UserID");
+ g_return_if_fail(uid != 0);
+
+ username = g_strdup_printf("%d", uid);
+ }
+
+
+ conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, username, session->account);
+ if (!conv) {
+ purple_debug_info("msim_uri_handler", "creating new conversation for %s\n", username);
+ conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, session->account, username);
+ }
+
+ /* Just open the window so the user can send an IM. */
+ purple_conversation_present(conv);
+
+ g_free(username);
+}
+
static gboolean
msim_uri_handler(const gchar *proto, const gchar *cmd, GHashTable *params)
{
@@ -3350,7 +3395,7 @@ msim_uri_handler(const gchar *proto, con
* http://collect.myspace.com/index.cfm?fuseaction=im.friendslist. Don't need a cid. */
/* Convert numeric contact ID back to a string. Needed for looking up. Don't just
- * directly use cid directly from parameters, because it might not be numeric.
+ * directly use cid directly from parameters, because it might not be numeric.
* It is trivial to change this to allow cID to be a username, but that's not how
* the official MySpaceIM client works, so don't provide that functionality. */
cid_str = g_strdup_printf("%d", cid);
@@ -3369,7 +3414,7 @@ msim_uri_handler(const gchar *proto, con
}
if (!account) {
- purple_notify_error(NULL, _("myim URL handler"),
+ purple_notify_error(NULL, _("myim URL handler"),
_("No suitable MySpaceIM account could be found to open this myim URL."),
_("Enable the proper MySpaceIM account and try again."));
g_free(cid_str);
@@ -3379,7 +3424,7 @@ msim_uri_handler(const gchar *proto, con
session = (MsimSession *)account->gc->proto_data;
g_return_val_if_fail(session != NULL, FALSE);
- /* Lookup userid to username. TODO: push this down, to IM sending/contact
+ /* Lookup userid to username. TODO: push this down, to IM sending/contact
* adding functions. */
/* myim:sendIM?uID=USERID&cID=CONTACTID */
@@ -3398,74 +3443,22 @@ msim_uri_handler(const gchar *proto, con
return FALSE;
}
-/* TODO: move uid->username resolving to IM sending and buddy adding functions,
- * so that user can manually add or IM by userid and username automatically
- * looked up if possible? */
-
-/** Handle a myim:sendIM URI command, after username has been looked up. */
+#ifdef MSIM_DEBUG_MSG
static void
-msim_uri_handler_sendIM_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
+print_hash_item(gpointer key, gpointer value, gpointer user_data)
{
- PurpleConversation *conv;
- MsimMessage *body;
- gchar *username;
-
- body = msim_msg_get_dictionary(userinfo, "body");
- username = msim_msg_get_string(body, "UserName");
- msim_msg_free(body);
-
- if (!username) {
- guint uid;
-
- uid = msim_msg_get_integer(userinfo, "UserID");
- g_return_if_fail(uid != 0);
-
- username = g_strdup_printf("%d", uid);
- }
-
-
- conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, username, session->account);
- if (!conv) {
- purple_debug_info("msim_uri_handler", "creating new conversation for %s\n", username);
- conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, session->account, username);
- }
-
- /* Just open the window so the user can send an IM. */
- purple_conversation_present(conv);
-
- g_free(username);
+ purple_debug_info("msim", "%s=%s\n",
+ key ? (gchar *)key : "(NULL)",
+ value ? (gchar *)value : "(NULL)");
}
+#endif
-/** Handle a myim:addContact command, after username has been looked up. */
+/**
+ * Initialize plugin.
+ */
static void
-msim_uri_handler_addContact_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
+init_plugin(PurplePlugin *plugin)
{
- MsimMessage *body;
- gchar *username;
-
- body = msim_msg_get_dictionary(userinfo, "body");
- username = msim_msg_get_string(body, "UserName");
- msim_msg_free(body);
-
- if (!username) {
- guint uid;
-
- uid = msim_msg_get_integer(userinfo, "UserID");
- g_return_if_fail(uid != 0);
-
- username = g_strdup_printf("%d", uid);
- }
-
-
- purple_blist_request_add_buddy(session->account, username, _("Buddies"), NULL);
-
- g_free(username);
-}
-
-/** Initialize plugin. */
-void
-init_plugin(PurplePlugin *plugin)
-{
#ifdef MSIM_SELF_TEST
msim_test_all();
exit(0);
@@ -3515,7 +3508,7 @@ init_plugin(PurplePlugin *plugin)
#endif
/* Code below only runs once. Based on oscar.c's oscar_init(). */
- if (initialized)
+ if (initialized)
return;
initialized = TRUE;
============================================================
--- libpurple/protocols/myspace/myspace.h 86d4edf3416ff5dd1ae529612b743df7b558b2e1
+++ libpurple/protocols/myspace/myspace.h 998a426c3c6d02381859ac03f8d608aa61f42a62
@@ -69,12 +69,12 @@
/*#define MSIM_DEBUG_LOGIN_CHALLENGE*/
/*#define MSIM_DEBUG_RXBUF */
-/* Encode unknown HTML tags from IM clients in messages as [tag], instead of
+/* Encode unknown HTML tags from IM clients in messages as [tag], instead of
* ignoring. Useful for debugging */
/*#define MSIM_MARKUP_SHOW_UNKNOWN_TAGS */
/* Define to cause init_plugin() to run some tests and print
- * the results to the Purple debug log, then exit. Useful to
+ * the results to the Purple debug log, then exit. Useful to
* run with 'pidgin -d' to see the output. Don't define if
* you want to actually use the plugin! */
/*#define MSIM_SELF_TEST */
@@ -119,9 +119,8 @@
#define MSIM_KEEPALIVE_INTERVAL_CHECK (30 * 1000)
/* Time to check for new mail (milliseconds) */
-#define MSIM_MAIL_INTERVAL_CHECK (60 * 1000)
+#define MSIM_MAIL_INTERVAL_CHECK (60 * 1000)
-
/* Constants */
#define HASH_SIZE 0x14 /**< Size of SHA-1 hash for login */
#define NONCE_SIZE 0x20 /**< Half of decoded 'nc' field */
@@ -143,7 +142,7 @@
#define MSIM_AUTH_CHALLENGE_LENGTH 0x40
/* TODO: obtain IPs of network interfaces from user's machine, instead of
- * hardcoding these values below (used in msim_compute_login_response).
+ * hardcoding these values below (used in msim_compute_login_response).
* This is not immediately
* important because you can still connect and perform basic
* functions of the protocol. There is also a high chance that the addreses
@@ -173,7 +172,6 @@
#define MSIM_STATUS_CODE_IDLE 2
#define MSIM_STATUS_CODE_AWAY 5
-
/* Inbox status bitfield values for MsimSession.inbox_status. */
#define MSIM_INBOX_MAIL (1 << 0)
#define MSIM_INBOX_BLOG_COMMENT (1 << 1)
@@ -191,49 +189,13 @@
#define MSIM_ERROR_LOGGED_IN_ELSEWHERE 6
/* Functions */
-gboolean msim_load(PurplePlugin *plugin);
-GList *msim_status_types(PurpleAccount *acct);
-
-const gchar *msim_list_icon(PurpleAccount *acct, PurpleBuddy *buddy);
gboolean msim_send_raw(MsimSession *session, const gchar *msg);
-void msim_login(PurpleAccount *acct);
-int msim_send_im(PurpleConnection *gc, const gchar *who, const gchar *message, PurpleMessageFlags flags);
-unsigned int msim_send_typing(PurpleConnection *gc, const gchar *name, PurpleTypingState state);
-
-void msim_get_info(PurpleConnection *gc, const gchar *name);
-
-void msim_set_status(PurpleAccount *account, PurpleStatus *status);
-void msim_set_idle(PurpleConnection *gc, int time);
-
-void msim_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
-void msim_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
-
-const char *msim_normalize(const PurpleAccount *account, const char *str);
-
-gboolean msim_offline_message(const PurpleBuddy *buddy);
-
-void msim_close(PurpleConnection *gc);
-
-char *msim_status_text(PurpleBuddy *buddy);
-void msim_tooltip_text(PurpleBuddy *buddy, PurpleNotifyUserInfo *user_info, gboolean full);
-GList *msim_actions(PurplePlugin *plugin, gpointer context);
-
-#ifdef MSIM_SELF_TEST
-void msim_test_all(void) __attribute__((__noreturn__));
-int msim_test_msg(void);
-int msim_test_escaping(void);
-#endif
-
gboolean msim_send_bm(MsimSession *session, const gchar *who, const gchar *text, int type);
gboolean msim_we_are_logged_on(MsimSession *session);
-
void msim_unrecognized(MsimSession *session, MsimMessage *msg, gchar *note);
guint msim_new_reply_callback(MsimSession *session, MSIM_USER_LOOKUP_CB cb, gpointer data);
-
-void init_plugin(PurplePlugin *plugin);
-
#endif /* !_MYSPACE_MYSPACE_H */
============================================================
--- libpurple/protocols/myspace/persist.h c1bb5a816d5914dc5cce181414368b638dbb4bb7
+++ libpurple/protocols/myspace/persist.h e003eb1f675f2be1eae1bae6fa9411c22b2d8d55
@@ -43,7 +43,7 @@
/** Define a set of _DSN and _LID constants for a persistance request. */
#define MSIM_PERSIST_DSN_LID(name,dsn,lid) \
static const int name##_DSN = dsn; \
- static const int name##_LID = lid;
+ static const int name##_LID = lid;
/* Can't do this, errors:
* persist.h:51:3: error: '#' is not followed by a macro parameter
============================================================
--- libpurple/protocols/myspace/session.c b04c86f6f2cce01380766179288ea45db239ff24
+++ libpurple/protocols/myspace/session.c e83604658f8e5ad67c316f667383e05f616df90d
@@ -17,7 +17,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
-
#include "myspace.h"
/* Session methods */
@@ -47,9 +46,9 @@ msim_session_new(PurpleAccount *acct)
session->fd = -1;
/* TODO: Remove. */
- session->user_lookup_cb = g_hash_table_new_full(g_direct_hash,
+ session->user_lookup_cb = g_hash_table_new_full(g_direct_hash,
g_direct_equal, NULL, NULL); /* do NOT free function pointers! (values) */
- session->user_lookup_cb_data = g_hash_table_new_full(g_direct_hash,
+ session->user_lookup_cb_data = g_hash_table_new_full(g_direct_hash,
g_direct_equal, NULL, NULL);/* TODO: we don't know what the values are,
they could be integers inside gpointers
or strings, so I don't freed them.
@@ -65,7 +64,7 @@ msim_session_new(PurpleAccount *acct)
session->last_comm = time(NULL);
session->inbox_status = 0;
session->inbox_handle = 0;
-
+
return session;
}
@@ -74,11 +73,11 @@ msim_session_new(PurpleAccount *acct)
*
* @param session The session to destroy.
*/
-void
+void
msim_session_destroy(MsimSession *session)
{
g_return_if_fail(MSIM_SESSION_VALID(session));
-
+
session->magic = -1;
g_free(session->rxbuf);
@@ -91,7 +90,7 @@ msim_session_destroy(MsimSession *sessio
if (session->server_info) {
msim_msg_free(session->server_info);
}
-
+
/* Stop checking the inbox at the end of the session. */
if (session->inbox_handle) {
purple_timeout_remove(session->inbox_handle);
@@ -99,4 +98,3 @@ msim_session_destroy(MsimSession *sessio
g_free(session);
}
-
============================================================
--- libpurple/protocols/myspace/session.h f071b915842225dfb079e46e01ceff29f85af941
+++ libpurple/protocols/myspace/session.h 90f5aa2a3960e80a42bb33540bb6e23ad465288e
@@ -54,7 +54,6 @@ typedef struct _MsimSession
/* Check if an MsimSession is valid */
#define MSIM_SESSION_VALID(s) (session != NULL && session->magic == MSIM_SESSION_STRUCT_MAGIC)
-
MsimSession *msim_session_new(PurpleAccount *acct);
void msim_session_destroy(MsimSession *session);
============================================================
--- libpurple/protocols/myspace/user.c caca336ec7b6020932ab271dd986313a423ffb18
+++ libpurple/protocols/myspace/user.c 34c2cc19e2337d613fba25a116611f74ea0bbca9
@@ -19,21 +19,13 @@
#include "myspace.h"
-static void msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user);
-static gchar *msim_format_now_playing(const gchar *band, const gchar *song);
-static void msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text,
- gsize len, const gchar *error_message);
+static void msim_check_username_availability_cb(PurpleConnection *gc, const char *username_to_check);
-/* Callbacks for setting the username bit */
-static void msim_check_username_availability_cb(PurpleConnection *gc, const char *value);
-static void msim_username_is_available_cb(MsimSession *session, MsimMessage *userinfo, gpointer data);
-static void msim_set_username_confirmed_cb(PurpleConnection *gc);
-static void msim_username_is_set_cb(MsimSession *session, MsimMessage *userinfo, gpointer data);
-static void msim_set_username(MsimSession *session, const gchar *username,
- MSIM_USER_LOOKUP_CB cb, gpointer data);
static char *msim_username_to_set;
-/** Format the "now playing" indicator, showing the artist and song.
+/**
+ * Format the "now playing" indicator, showing the artist and song.
+ *
* @return Return a new string (must be g_free()'d), or NULL.
*/
static gchar *
@@ -47,7 +39,10 @@ msim_format_now_playing(const gchar *ban
return NULL;
}
}
-/** Get the MsimUser from a PurpleBuddy, creating it if needed. */
+
+/**
+ * Get the MsimUser from a PurpleBuddy, creating it if needed.
+ */
MsimUser *
msim_get_user_from_buddy(PurpleBuddy *buddy)
{
@@ -65,14 +60,16 @@ msim_get_user_from_buddy(PurpleBuddy *bu
user->buddy = buddy;
user->id = purple_blist_node_get_int(&buddy->node, "UserID");
buddy->proto_data = (gpointer)user;
- }
+ }
user = (MsimUser *)(buddy->proto_data);
return user;
}
-/** Find and return an MsimUser * representing a user on the buddy list, or NULL. */
+/**
+ * Find and return an MsimUser * representing a user on the buddy list, or NULL.
+ */
MsimUser *
msim_find_user(MsimSession *session, const gchar *username)
{
@@ -89,7 +86,8 @@ msim_find_user(MsimSession *session, con
return user;
}
-/** Append user information to a PurpleNotifyUserInfo, given an MsimUser.
+/**
+ * Append user information to a PurpleNotifyUserInfo, given an MsimUser.
* Used by msim_tooltip_text() and msim_get_info_cb() to show a user's profile.
*/
void
@@ -99,7 +97,7 @@ msim_append_user_info(MsimSession *sessi
gchar *str;
guint cv;
- /* Useful to identify the account the tooltip refers to.
+ /* Useful to identify the account the tooltip refers to.
* Other prpls show this. */
if (user->username) {
purple_notify_user_info_add_pair(user_info, _("User"), user->username);
@@ -185,7 +183,39 @@ msim_append_user_info(MsimSession *sessi
}
}
-/** Set the currently playing song artist and or title.
+/**
+ * Callback for when a buddy icon finished being downloaded.
+ */
+static void
+msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data,
+ gpointer user_data,
+ const gchar *url_text,
+ gsize len,
+ const gchar *error_message)
+{
+ MsimUser *user;
+
+ user = (MsimUser *)user_data;
+
+ purple_debug_info("msim_downloaded_buddy_icon",
+ "Downloaded %" G_GSIZE_FORMAT " bytes\n", len);
+
+ if (!url_text) {
+ purple_debug_info("msim_downloaded_buddy_icon",
+ "failed to download icon for %s",
+ user->buddy->name);
+ return;
+ }
+
+ purple_buddy_icons_set_for_user(user->buddy->account,
+ user->buddy->name,
+ g_memdup((gchar *)url_text, len), len,
+ /* Use URL itself as buddy icon "checksum" (TODO: ETag) */
+ user->image_url); /* checksum */
+}
+
+/**
+ * Set the currently playing song artist and or title.
*
* @param user User associated with the now playing information.
*
@@ -224,15 +254,15 @@ static void msim_set_artist_or_title(Msi
if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
PurpleStatus *status;
-
+
status = purple_presence_get_status(presence, "tune");
prev_title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE);
prev_artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
- }
+ }
if (!new_artist)
new_artist = prev_artist;
-
+
if (!new_title)
new_title = prev_title;
@@ -242,14 +272,15 @@ static void msim_set_artist_or_title(Msi
NULL);
}
-/** Store a field of information about a buddy.
+/**
+ * Store a field of information about a buddy.
*
* @param key_str Key to store.
* @param value_str Value string, either user takes ownership of this string
* or it is freed if MsimUser doesn't store the string.
* @param user User to store data in. Existing data will be replaced.
- * */
-void
+ */
+static void
msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user)
{
if (g_str_equal(key_str, "UserID") || g_str_equal(key_str, "ContactID")) {
@@ -286,7 +317,7 @@ msim_store_user_info_each(const gchar *k
const gchar *previous_url;
if (user->temporary_user) {
- /* This user will be destroyed soon; don't try to look up its image or avatar,
+ /* This user will be destroyed soon; don't try to look up its image or avatar,
* since that won't return immediately and we will end up accessing freed data.
*/
g_free(value_str);
@@ -294,7 +325,7 @@ msim_store_user_info_each(const gchar *k
}
if (user->temporary_user) {
- /* This user will be destroyed soon; don't try to look up its image or avatar,
+ /* This user will be destroyed soon; don't try to look up its image or avatar,
* since that won't return immediately and we will end up accessing freed data.
*/
g_free(value_str);
@@ -342,7 +373,8 @@ msim_store_user_info_each(const gchar *k
}
}
-/** Save buddy information to the buddy list from a user info reply message.
+/**
+ * Save buddy information to the buddy list from a user info reply message.
*
* @param session
* @param msg The user information reply, with any amount of information.
@@ -354,9 +386,8 @@ msim_store_user_info_each(const gchar *k
*
* If the function has no buddy information, this function
* is a no-op (and returns FALSE).
- *
*/
-gboolean
+gboolean
msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user)
{
gchar *username;
@@ -373,13 +404,13 @@ msim_store_user_info(MsimSession *sessio
username = msim_msg_get_string(body, "UserName");
if (!username) {
- purple_debug_info("msim",
+ purple_debug_info("msim",
"msim_process_reply: not caching body, no UserName\n");
msim_msg_free(body);
g_free(username);
return FALSE;
}
-
+
/* Null user = find and store in PurpleBuddy's proto_data */
if (!user) {
user = msim_find_user(session, username);
@@ -391,8 +422,8 @@ msim_store_user_info(MsimSession *sessio
}
/* TODO: make looping over MsimMessage's easier. */
- for (body_node = body;
- body_node != NULL;
+ for (body_node = body;
+ body_node != NULL;
body_node = msim_msg_get_next_element_node(body_node))
{
const gchar *key_str;
@@ -410,7 +441,7 @@ msim_store_user_info(MsimSession *sessio
msim_msg_get_integer(msg, "lid") == MG_OWN_IM_INFO_LID) {
/* TODO: do something with our own IM info, if we need it for some
* specific purpose. Otherwise it is available on the buddy list,
- * if the user has themselves as their own buddy.
+ * if the user has themselves as their own buddy.
*
* However, much of the info is already available in MsimSession,
* stored in msim_we_are_logged_on(). */
@@ -425,7 +456,59 @@ msim_store_user_info(MsimSession *sessio
return TRUE;
}
+#if 0
/**
+ * Return whether a given username is syntactically valid.
+ * Note: does not actually check that the user exists.
+ */
+static gboolean
+msim_is_valid_username(const gchar *user)
+{
+ return !msim_is_userid(user) && /* Not all numeric */
+ strlen(user) <= MSIM_MAX_USERNAME_LENGTH
+ && strspn(user, "0123456789"
+ "abcdefghijklmnopqrstuvwxyz"
+ "_"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ") == strlen(user);
+}
+#endif
+
+/**
+ * Check if a string is a userid (all numeric).
+ *
+ * @param user The user id, email, or name.
+ *
+ * @return TRUE if is userid, FALSE if not.
+ */
+gboolean
+msim_is_userid(const gchar *user)
+{
+ g_return_val_if_fail(user != NULL, FALSE);
+
+ return strspn(user, "0123456789") == strlen(user);
+}
+
+/**
+ * Check if a string is an email address (contains an @).
+ *
+ * @param user The user id, email, or name.
+ *
+ * @return TRUE if is an email, FALSE if not.
+ *
+ * This function is not intended to be used as a generic
+ * means of validating email addresses, but to distinguish
+ * between a user represented by an email address from
+ * other forms of identification.
+ */
+static gboolean
+msim_is_email(const gchar *user)
+{
+ g_return_val_if_fail(user != NULL, FALSE);
+
+ return strchr(user, '@') != NULL;
+}
+
+/**
* Asynchronously lookup user information, calling callback when receive result.
*
* @param session
@@ -434,7 +517,7 @@ msim_store_user_info(MsimSession *sessio
* @param data An arbitray data pointer passed to the callback.
*/
/* TODO: change to not use callbacks */
-void
+void
msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data)
{
MsimMessage *body;
@@ -460,8 +543,8 @@ msim_lookup_user(MsimSession *session, c
if (msim_is_userid(user)) {
field_name = "UserID";
- dsn = MG_MYSPACE_INFO_BY_ID_DSN;
- lid = MG_MYSPACE_INFO_BY_ID_LID;
+ dsn = MG_MYSPACE_INFO_BY_ID_DSN;
+ lid = MG_MYSPACE_INFO_BY_ID_LID;
} else if (msim_is_email(user)) {
field_name = "Email";
dsn = MG_MYSPACE_INFO_BY_STRING_DSN;
@@ -486,117 +569,146 @@ msim_lookup_user(MsimSession *session, c
"rid", MSIM_TYPE_INTEGER, rid,
"body", MSIM_TYPE_DICTIONARY, body,
NULL));
-}
+}
-
/**
- * Check if a string is a userid (all numeric).
- *
- * @param user The user id, email, or name.
- *
- * @return TRUE if is userid, FALSE if not.
+ * Called after username is set.
*/
-gboolean
-msim_is_userid(const gchar *user)
+static void msim_username_is_set_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
{
- g_return_val_if_fail(user != NULL, FALSE);
+ gchar *username, *errmsg;
+ MsimMessage *body;
- return strspn(user, "0123456789") == strlen(user);
-}
+ guint rid;
+ gint cmd,dsn,uid,lid,code;
+ /* \persistr\\cmd\258\dsn\9\uid\204084363\lid\14\rid\369\body\UserName=TheAlbinoRhino1.Code=0\final\ */
-/** Return whether a given username is syntactically valid.
- * Note: does not actually check that the user exists. */
-gboolean
-msim_is_valid_username(const gchar *user)
-{
- return !msim_is_userid(user) && /* Not all numeric */
- strlen(user) <= MSIM_MAX_USERNAME_LENGTH
- && strspn(user, "0123456789"
- "abcdefghijklmnopqrstuvwxyz"
- "_"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ") == strlen(user);
-}
+ purple_debug_info("msim","username_is_set made\n");
-/**
- * Check if a string is an email address (contains an @).
- *
- * @param user The user id, email, or name.
- *
- * @return TRUE if is an email, FALSE if not.
- *
- * This function is not intended to be used as a generic
- * means of validating email addresses, but to distinguish
- * between a user represented by an email address from
- * other forms of identification.
- */
-gboolean
-msim_is_email(const gchar *user)
-{
- g_return_val_if_fail(user != NULL, FALSE);
+ g_return_if_fail(MSIM_SESSION_VALID(session));
- return strchr(user, '@') != NULL;
+ msim_msg_dump("username_is_set message is: %s\n", userinfo);
+ cmd = msim_msg_get_integer(userinfo, "cmd");
+ dsn = msim_msg_get_integer(userinfo, "dsn");
+ uid = msim_msg_get_integer(userinfo, "uid");
+ lid = msim_msg_get_integer(userinfo, "lid");
+ body = msim_msg_get_dictionary(userinfo, "body");
+ errmsg = g_strdup("An error occurred while trying to set the username.\n"
+ "Please try again, or visit http://editprofile.myspace.com/index.cfm?"
+ "fuseaction=profile.username to set your username.");
+
+ if (!body) {
+ purple_debug_info("msim_username_is_set_cb", "No body");
+ /* Error: No body! */
+ purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
+ }
+ username = msim_msg_get_string(body, "UserName");
+ code = msim_msg_get_integer(body,"Code");
+
+ msim_msg_free(body);
+
+ purple_debug_info("msim_username_is_set_cb",
+ "cmd = %d, dsn = %d, lid = %d, code = %d, username = %s\n",
+ cmd, dsn, lid, code, username);
+
+ if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_PUT)
+ && dsn == MC_SET_USERNAME_DSN
+ && lid == MC_SET_USERNAME_LID)
+ {
+ purple_debug_info("msim_username_is_set_cb", "Proper cmd,dsn,lid for username_is_set!\n");
+ purple_debug_info("msim_username_is_set_cb", "Username Set with return code %d\n",code);
+ if (code == 0) {
+ /* Good! */
+ session->username = username;
+ msim_we_are_logged_on(session);
+ } else {
+ purple_debug_info("msim_username_is_set", "code is %d",code);
+ /* TODO: what to do here? */
+ }
+ } else if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_GET)
+ && dsn == MG_MYSPACE_INFO_BY_STRING_DSN
+ && lid == MG_MYSPACE_INFO_BY_STRING_LID) {
+ /* Not quite done... ONE MORE STEP :) */
+ rid = msim_new_reply_callback(session, msim_username_is_set_cb, data);
+ body = msim_msg_new("UserName", MSIM_TYPE_STRING, g_strdup(username), NULL);
+ if (!msim_send(session, "persist", MSIM_TYPE_INTEGER, 1,
+ "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+ "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_PUT,
+ "dsn", MSIM_TYPE_INTEGER, MC_SET_USERNAME_DSN,
+ "uid", MSIM_TYPE_INTEGER, session->userid,
+ "lid", MSIM_TYPE_INTEGER, MC_SET_USERNAME_LID,
+ "rid", MSIM_TYPE_INTEGER, rid,
+ "body", MSIM_TYPE_DICTIONARY, body,
+ NULL)) {
+ /* Error! */
+ /* Can't set... Disconnect */
+ purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
+ }
+
+ } else {
+ /* Error! */
+ purple_debug_info("msim","username_is_set Error: Invalid cmd/dsn/lid combination");
+ purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
+ }
+ g_free(errmsg);
}
-
-/** Callback for when a buddy icon finished being downloaded. */
+/**
+ * Asynchronously set new username, calling callback when receive result.
+ *
+ * @param session
+ * @param username The username we're setting for ourselves. Not freed.
+ * @param cb Callback, called with user information when available.
+ * @param data An arbitray data pointer passed to the callback.
+ */
static void
-msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data,
- gpointer user_data,
- const gchar *url_text,
- gsize len,
- const gchar *error_message)
+msim_set_username(MsimSession *session, const gchar *username,
+ MSIM_USER_LOOKUP_CB cb, gpointer data)
{
- MsimUser *user;
+ MsimMessage *body;
+ guint rid;
- user = (MsimUser *)user_data;
+ g_return_if_fail(MSIM_SESSION_VALID(session));
+ g_return_if_fail(username != NULL);
+ g_return_if_fail(cb != NULL);
- purple_debug_info("msim_downloaded_buddy_icon",
- "Downloaded %" G_GSIZE_FORMAT " bytes\n", len);
+ purple_debug_info("msim", "msim_set_username: "
+ "Setting username %s\n", username);
- if (!url_text) {
- purple_debug_info("msim_downloaded_buddy_icon",
- "failed to download icon for %s",
- user->buddy->name);
- return;
- }
+ msim_msg_dump("msim_set_username: data=%s\n", (MsimMessage *)data);
- purple_buddy_icons_set_for_user(user->buddy->account,
- user->buddy->name,
- g_memdup((gchar *)url_text, len), len,
- /* Use URL itself as buddy icon "checksum" (TODO: ETag) */
- user->image_url); /* checksum */
-}
+ /* Setup callback. Response will be associated with request using 'rid'. */
+ rid = msim_new_reply_callback(session, cb, data);
-/***
- * If they hit cancel or no at any point in the Setting Username process, we come here. *
- * Currently.. We're safe letting them get by without setting it.. Unless we hear otherwise.. *
- * So for now, give them a menu.. If this becomes an issue with the Official client.. boot them here */
-void msim_do_not_set_username_cb(PurpleConnection *gc) {
- purple_debug_info("msim", "Don't set username");
+ /* TODO: I dont know if the ContactType is -/ALWAYS/- 1 */
- /* Protocol won't log in now without a username set.. Disconnect */
- purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("No username set"));
+ body = msim_msg_new("UserName", MSIM_TYPE_STRING, g_strdup(username),NULL);
+/* \setinfo\\sesskey\469958979\info\Age=21.AvatarUrl=.BandName=.ContactType=1.DisplayName=Msim.Gender=M.ImageURL=http:/1/1x.myspace.com/1images/1no_pic.gif.LastLogin=128335268400000000.Location=US.ShowAvatar=False.SongName=.TotalFriends=1.UserName=msimprpl2\final\
+*/
+
+ /* Send request */
+ g_return_if_fail(msim_send(session,
+ "setinfo", MSIM_TYPE_BOOLEAN, TRUE,
+ "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+ "info", MSIM_TYPE_DICTIONARY, body,
+ NULL));
+ body = msim_msg_new("UserName", MSIM_TYPE_STRING, g_strdup(username),NULL);
+ g_return_if_fail(msim_send(session,
+ "persist", MSIM_TYPE_INTEGER, 1,
+ "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+ "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_GET,
+ "dsn", MSIM_TYPE_INTEGER, MG_MYSPACE_INFO_BY_STRING_DSN,
+ "uid", MSIM_TYPE_INTEGER, session->userid,
+ "lid", MSIM_TYPE_INTEGER, MG_MYSPACE_INFO_BY_STRING_LID,
+ "rid", MSIM_TYPE_INTEGER, rid,
+ "body", MSIM_TYPE_DICTIONARY, body,
+ NULL));
}
-
-/** They've decided to set a username! Yay! */
-void msim_set_username_cb(PurpleConnection *gc) {
- g_return_if_fail(gc != NULL);
- purple_debug_info("msim","Set username\n");
- purple_request_input(gc, _("MySpaceIM - Please Set a Username"),
- _("Please enter a username to check its availability:"),
- NULL,
- "", FALSE, FALSE, NULL,
- _("OK"), G_CALLBACK(msim_check_username_availability_cb),
- _("Cancel"), G_CALLBACK(msim_do_not_set_username_cb),
- purple_connection_get_account(gc),
- NULL,
- NULL,
- gc);
-}
-/** Once they've submitted their desired new username,
- * check if it is available here. */
-static void msim_check_username_availability_cb(PurpleConnection *gc, const char *username_to_check)
+/**
+ * They've confirmed that username that was available, Lets make the call to set it
+ */
+static void msim_set_username_confirmed_cb(PurpleConnection *gc)
{
MsimMessage *user_msg;
MsimSession *session;
@@ -607,24 +719,24 @@ static void msim_check_username_availabi
g_return_if_fail(MSIM_SESSION_VALID(session));
- purple_debug_info("msim_check_username_availability_cb", "Checking username: %s\n", username_to_check);
-
+
user_msg = msim_msg_new(
- "user", MSIM_TYPE_STRING, g_strdup(username_to_check),
+ "user", MSIM_TYPE_STRING, g_strdup(msim_username_to_set),
NULL);
- /* 25 characters: letters, numbers, underscores */
- /* TODO: VERIFY ABOVE */
+ purple_debug_info("msim_set_username_confirmed_cb", "Setting username to %s\n", msim_username_to_set);
- /* \persist\1\sesskey\288500516\cmd\1\dsn\5\uid\204084363\lid\7\rid\367\body\UserName=Jaywalker\final\ */
- /* Official client uses a standard lookup... So do we! */
- msim_lookup_user(session, username_to_check, msim_username_is_available_cb, user_msg);
+ /* Sets our username... keep your fingers crossed :) */
+ msim_set_username(session, msim_username_to_set, msim_username_is_set_cb, user_msg);
+ g_free(msim_username_to_set);
}
-/** This is where we do a bit more than merely prompt the user.
- * Now we have some real data to tell us the state of their requested username
- * \persistr\\cmd\257\dsn\5\uid\204084363\lid\7\rid\367\body\UserName=TheAlbinoRhino1\final\ */
-static void msim_username_is_available_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
+/**
+ * This is where we do a bit more than merely prompt the user.
+ * Now we have some real data to tell us the state of their requested username
+ * \persistr\\cmd\257\dsn\5\uid\204084363\lid\7\rid\367\body\UserName=TheAlbinoRhino1\final\
+ */
+static void msim_username_is_available_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
{
MsimMessage *msg;
gchar *username;
@@ -632,17 +744,17 @@ static void msim_username_is_available_c
gint userid;
purple_debug_info("msim_username_is_available_cb", "Look up username callback made\n");
-
+
msg = (MsimMessage *)data;
g_return_if_fail(MSIM_SESSION_VALID(session));
g_return_if_fail(msg != NULL);
-
+
username = msim_msg_get_string(msg, "user");
body = msim_msg_get_dictionary(userinfo, "body");
if (!body) {
purple_debug_info("msim_username_is_available_cb", "No body for %s?!\n", username);
- purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
+ purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
"An error occurred while trying to set the username.\n"
"Please try again, or visit http://editprofile.myspace.com/index.cfm?"
"fuseaction=profile.username to set your username.");
@@ -655,7 +767,7 @@ static void msim_username_is_available_c
msim_msg_free(body);
msim_msg_free(msg);
- /* The response for a free username will ONLY have the UserName in it..
+ /* The response for a free username will ONLY have the UserName in it..
* thus making UserID return 0 when we msg_get_integer it */
if (userid == 0) {
/* This username is currently unused */
@@ -670,8 +782,8 @@ static void msim_username_is_available_c
session->account,
NULL,
NULL,
- session->gc,
- G_CALLBACK(msim_set_username_confirmed_cb),
+ session->gc,
+ G_CALLBACK(msim_set_username_confirmed_cb),
G_CALLBACK(msim_do_not_set_username_cb));
} else {
/* Looks like its in use or we have an invalid response */
@@ -689,8 +801,11 @@ static void msim_username_is_available_c
}
}
-/* They've confirmed that username that was available, Lets make the call to set it */
-static void msim_set_username_confirmed_cb(PurpleConnection *gc)
+/**
+ * Once they've submitted their desired new username,
+ * check if it is available here.
+ */
+static void msim_check_username_availability_cb(PurpleConnection *gc, const char *username_to_check)
{
MsimMessage *user_msg;
MsimSession *session;
@@ -701,146 +816,49 @@ static void msim_set_username_confirmed_
g_return_if_fail(MSIM_SESSION_VALID(session));
+ purple_debug_info("msim_check_username_availability_cb", "Checking username: %s\n", username_to_check);
user_msg = msim_msg_new(
- "user", MSIM_TYPE_STRING, g_strdup(msim_username_to_set),
+ "user", MSIM_TYPE_STRING, g_strdup(username_to_check),
NULL);
- purple_debug_info("msim_set_username_confirmed_cb", "Setting username to %s\n", msim_username_to_set);
-
- /* Sets our username... keep your fingers crossed :) */
- msim_set_username(session, msim_username_to_set, msim_username_is_set_cb, user_msg);
- g_free(msim_username_to_set);
+ /* 25 characters: letters, numbers, underscores */
+ /* TODO: VERIFY ABOVE */
+
+ /* \persist\1\sesskey\288500516\cmd\1\dsn\5\uid\204084363\lid\7\rid\367\body\UserName=Jaywalker\final\ */
+ /* Official client uses a standard lookup... So do we! */
+ msim_lookup_user(session, username_to_check, msim_username_is_available_cb, user_msg);
}
-/**
- * Asynchronously set new username, calling callback when receive result.
- *
- * @param session
- * @param username The username we're setting for ourselves. Not freed.
- * @param cb Callback, called with user information when available.
- * @param data An arbitray data pointer passed to the callback.
+/***
+ * If they hit cancel or no at any point in the Setting Username process,
+ * we come here. Currently we're safe letting them get by without
+ * setting it, unless we hear otherwise. So for now give them a menu.
+ * If this becomes an issue with the official client then boot them here.
*/
-static void
-msim_set_username(MsimSession *session, const gchar *username,
- MSIM_USER_LOOKUP_CB cb, gpointer data)
+void msim_do_not_set_username_cb(PurpleConnection *gc)
{
- MsimMessage *body;
- guint rid;
+ purple_debug_info("msim", "Don't set username");
- g_return_if_fail(MSIM_SESSION_VALID(session));
- g_return_if_fail(username != NULL);
- g_return_if_fail(cb != NULL);
-
- purple_debug_info("msim", "msim_set_username: "
- "Setting username %s\n", username);
-
- msim_msg_dump("msim_set_username: data=%s\n", (MsimMessage *)data);
-
- /* Setup callback. Response will be associated with request using 'rid'. */
- rid = msim_new_reply_callback(session, cb, data);
-
- /* TODO: I dont know if the ContactType is -/ALWAYS/- 1 */
-
- body = msim_msg_new("UserName", MSIM_TYPE_STRING, g_strdup(username),NULL);
-/* \setinfo\\sesskey\469958979\info\Age=21.AvatarUrl=.BandName=.ContactType=1.DisplayName=Msim.Gender=M.ImageURL=http:/1/1x.myspace.com/1images/1no_pic.gif.LastLogin=128335268400000000.Location=US.ShowAvatar=False.SongName=.TotalFriends=1.UserName=msimprpl2\final\
-*/
-
- /* Send request */
- g_return_if_fail(msim_send(session,
- "setinfo", MSIM_TYPE_BOOLEAN, TRUE,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "info", MSIM_TYPE_DICTIONARY, body,
- NULL));
- body = msim_msg_new("UserName", MSIM_TYPE_STRING, g_strdup(username),NULL);
- g_return_if_fail(msim_send(session,
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_GET,
- "dsn", MSIM_TYPE_INTEGER, MG_MYSPACE_INFO_BY_STRING_DSN,
- "uid", MSIM_TYPE_INTEGER, session->userid,
- "lid", MSIM_TYPE_INTEGER, MG_MYSPACE_INFO_BY_STRING_LID,
- "rid", MSIM_TYPE_INTEGER, rid,
- "body", MSIM_TYPE_DICTIONARY, body,
- NULL));
+ /* Protocol won't log in now without a username set.. Disconnect */
+ purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("No username set"));
}
-/** Called after username is set. */
-static void msim_username_is_set_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
+/**
+ * They've decided to set a username! Yay!
+ */
+void msim_set_username_cb(PurpleConnection *gc)
{
- gchar *username, *errmsg;
- MsimMessage *body;
-
- guint rid;
- gint cmd,dsn,uid,lid,code;
- /* \persistr\\cmd\258\dsn\9\uid\204084363\lid\14\rid\369\body\UserName=TheAlbinoRhino1.Code=0\final\ */
-
- purple_debug_info("msim","username_is_set made\n");
-
- g_return_if_fail(MSIM_SESSION_VALID(session));
-
-
- msim_msg_dump("username_is_set message is: %s\n", userinfo);
- cmd = msim_msg_get_integer(userinfo, "cmd");
- dsn = msim_msg_get_integer(userinfo, "dsn");
- uid = msim_msg_get_integer(userinfo, "uid");
- lid = msim_msg_get_integer(userinfo, "lid");
- body = msim_msg_get_dictionary(userinfo, "body");
- errmsg = g_strdup("An error occurred while trying to set the username.\n"
- "Please try again, or visit http://editprofile.myspace.com/index.cfm?"
- "fuseaction=profile.username to set your username.");
-
- if (!body) {
- purple_debug_info("msim_username_is_set_cb", "No body");
- /* Error: No body! */
- purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
- }
- username = msim_msg_get_string(body, "UserName");
- code = msim_msg_get_integer(body,"Code");
-
- msim_msg_free(body);
-
- purple_debug_info("msim_username_is_set_cb",
- "cmd = %d, dsn = %d, lid = %d, code = %d, username = %s\n",
- cmd, dsn, lid, code, username);
-
- if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_PUT)
- && dsn == MC_SET_USERNAME_DSN
- && lid == MC_SET_USERNAME_LID) {
- purple_debug_info("msim_username_is_set_cb", "Proper cmd,dsn,lid for username_is_set!\n");
- purple_debug_info("msim_username_is_set_cb", "Username Set with return code %d\n",code);
- if (code == 0) {
- /* Good! */
- session->username = username;
- msim_we_are_logged_on(session);
- } else {
- purple_debug_info("msim_username_is_set", "code is %d",code);
- /* TODO: what to do here? */
- }
- } else if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_GET)
- && dsn == MG_MYSPACE_INFO_BY_STRING_DSN
- && lid == MG_MYSPACE_INFO_BY_STRING_LID) {
- /* Not quite done... ONE MORE STEP :) */
- rid = msim_new_reply_callback(session, msim_username_is_set_cb, data);
- body = msim_msg_new("UserName", MSIM_TYPE_STRING, g_strdup(username), NULL);
- if (!msim_send(session, "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_PUT,
- "dsn", MSIM_TYPE_INTEGER, MC_SET_USERNAME_DSN,
- "uid", MSIM_TYPE_INTEGER, session->userid,
- "lid", MSIM_TYPE_INTEGER, MC_SET_USERNAME_LID,
- "rid", MSIM_TYPE_INTEGER, rid,
- "body", MSIM_TYPE_DICTIONARY, body,
- NULL)) {
- /* Error! */
- /* Can't set... Disconnect */
- purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
- }
-
- } else {
- /* Error! */
- purple_debug_info("msim","username_is_set Error: Invalid cmd/dsn/lid combination");
- purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
- }
- g_free(errmsg);
+ g_return_if_fail(gc != NULL);
+ purple_debug_info("msim","Set username\n");
+ purple_request_input(gc, _("MySpaceIM - Please Set a Username"),
+ _("Please enter a username to check its availability:"),
+ NULL,
+ "", FALSE, FALSE, NULL,
+ _("OK"), G_CALLBACK(msim_check_username_availability_cb),
+ _("Cancel"), G_CALLBACK(msim_do_not_set_username_cb),
+ purple_connection_get_account(gc),
+ NULL,
+ NULL,
+ gc);
}
============================================================
--- libpurple/protocols/myspace/user.h c88a559f7db6d3058dce7e9670a3a2fab8fee45c
+++ libpurple/protocols/myspace/user.h 5c34155c9331a949698f63a0dfbc109940604de1
@@ -42,7 +42,7 @@ typedef struct _MsimUser
gboolean temporary_user;
} MsimUser;
-/* Callback function pointer type for when a user's information is received,
+/* Callback function pointer type for when a user's information is received,
* initiated from a user lookup. */
typedef void (*MSIM_USER_LOOKUP_CB)(MsimSession *session, MsimMessage *userinfo, gpointer data);
@@ -51,8 +51,6 @@ gboolean msim_is_userid(const gchar *use
void msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full);
gboolean msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user);
gboolean msim_is_userid(const gchar *user);
-gboolean msim_is_email(const gchar *user);
-gboolean msim_is_valid_username(const gchar *user);
void msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data);
void msim_set_username_cb(PurpleConnection *gc);
void msim_do_not_set_username_cb(PurpleConnection *gc);
============================================================
--- libpurple/protocols/myspace/zap.c 6053f3bd91bca7367cc461e72a8a51fb52a31572
+++ libpurple/protocols/myspace/zap.c 96acfd1e8e6c4a8e1cae6936b6b8e171e086f54a
@@ -20,10 +20,6 @@
#include "myspace.h"
#include "zap.h"
-static gboolean msim_send_zap(MsimSession *session, const gchar *username, guint code);
-static void msim_send_zap_from_menu(PurpleBlistNode *node, gpointer zap_num_ptr);
-
-
/** Get zap types. */
GList *
msim_attention_types(PurpleAccount *acct)
@@ -100,6 +96,33 @@ msim_attention_types(PurpleAccount *acct
return types;
}
+/** Send a zap to a user. */
+static gboolean
+msim_send_zap(MsimSession *session, const gchar *username, guint code)
+{
+ gchar *zap_string;
+ gboolean rc;
+
+ g_return_val_if_fail(session != NULL, FALSE);
+ g_return_val_if_fail(username != NULL, FALSE);
+
+ /* Construct and send the actual zap command. */
+ zap_string = g_strdup_printf("!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", code);
+
+ if (!msim_send_bm(session, username, zap_string, MSIM_BM_ACTION)) {
+ purple_debug_info("msim_send_zap",
+ "msim_send_bm failed: zapping %s with %s\n",
+ username, zap_string);
+ rc = FALSE;
+ } else {
+ rc = TRUE;
+ }
+
+ g_free(zap_string);
+
+ return rc;
+}
+
/** Send a zap */
gboolean
msim_send_attention(PurpleConnection *gc, const gchar *username, guint code)
@@ -130,33 +153,6 @@ msim_send_attention(PurpleConnection *gc
return TRUE;
}
-/** Send a zap to a user. */
-static gboolean
-msim_send_zap(MsimSession *session, const gchar *username, guint code)
-{
- gchar *zap_string;
- gboolean rc;
-
- g_return_val_if_fail(session != NULL, FALSE);
- g_return_val_if_fail(username != NULL, FALSE);
-
- /* Construct and send the actual zap command. */
- zap_string = g_strdup_printf("!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", code);
-
- if (!msim_send_bm(session, username, zap_string, MSIM_BM_ACTION)) {
- purple_debug_info("msim_send_zap_from_menu", "msim_send_bm failed: zapping %s with %s\n",
- username, zap_string);
- rc = FALSE;
- } else {
- rc = TRUE;
- }
-
- g_free(zap_string);
-
- return rc;
-
-}
-
/** Zap someone. Callback from msim_blist_node_menu zap menu. */
static void
msim_send_zap_from_menu(PurpleBlistNode *node, gpointer zap_num_ptr)
@@ -248,5 +244,3 @@ msim_incoming_zap(MsimSession *session,
return TRUE;
}
-
-
More information about the Commits
mailing list