# HG changeset patch # User Christian Hammond # Date 1086489548 0 # Node ID 502707ca18364ff78e990ce142badf6633a9377c # Parent 5655dcd94d0f03152b4ceee230067f8212873ae0 [gaim-migrate @ 9988] Patch by Felipe Contreras to add MSN file transfer and buddy icons. Please test and report any bugs! committer: Tailor Script diff -r 5655dcd94d0f -r 502707ca1836 ChangeLog --- a/ChangeLog Sun Jun 06 02:16:08 2004 +0000 +++ b/ChangeLog Sun Jun 06 02:39:08 2004 +0000 @@ -13,6 +13,8 @@ * Show timestamps now has a per-conversation option in addition to the global one, bringing it in line with the other conver- sation options (Stu Tomlinson). + * Added MSN buddy icons (Felipe Contreras) + * Added MSN file transfer (Felipe Contreras) Bug Fixes: * Non-looping animated icons no longer cause Gaim to freeze diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/Makefile.am --- a/src/protocols/msn/Makefile.am Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/Makefile.am Sun Jun 06 02:39:08 2004 +0000 @@ -8,6 +8,8 @@ cmdproc.h \ command.c \ command.h \ + directconn.c \ + directconn.h \ error.c \ error.h \ group.c \ @@ -20,30 +22,42 @@ msg.h \ msn.c \ msn.h \ - msnobject.c \ - msnobject.h \ - msnslp.c \ - msnslp.h \ + notification.c \ + notification.h \ nexus.c \ nexus.h \ - notification.c \ - notification.h \ + object.c \ + object.h \ page.c \ page.h \ servconn.c \ servconn.h \ session.c \ session.h \ + slp.c \ + slp.h \ + slpcall.c \ + slpcall.h \ + slplink.c \ + slplink.h \ + slpmsg.c \ + slpmsg.h \ + slpsession.c \ + slpsession.h \ state.c \ state.h \ switchboard.c \ switchboard.h \ + sync.c \ + sync.h \ + transaction.c \ + transaction.h \ table.c \ table.h \ - transaction.c \ - transaction.h \ user.c \ user.h \ + userlist.c \ + userlist.h \ utils.c \ utils.h diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/Makefile.mingw --- a/src/protocols/msn/Makefile.mingw Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/Makefile.mingw Sun Jun 06 02:39:08 2004 +0000 @@ -70,24 +70,30 @@ C_SRC = cmdproc.c \ command.c \ + dispatch.c \ error.c \ group.c \ history.c \ httpmethod.c \ msg.c \ msn.c \ - msnobject.c \ - msnslp.c \ + nexus.c \ notification.c \ - nexus.c \ + object.c \ page.c \ servconn.c \ session.c \ + slp.c \ + slpcall.c \ + slplink.c \ + slpmsg.c \ + slpsession.c \ state.c \ switchboard.c \ table.c \ transaction.c \ user.c \ + userlist.c \ utils.c diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/cmdproc.c --- a/src/protocols/msn/cmdproc.c Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/cmdproc.c Sun Jun 06 02:39:08 2004 +0000 @@ -22,13 +22,6 @@ #include "msn.h" #include "cmdproc.h" -typedef struct -{ - char *command; - MsnMessage *msg; - -} MsnQueueEntry; - MsnCmdProc * msn_cmdproc_new(MsnSession *session) { @@ -56,13 +49,6 @@ g_queue_free(cmdproc->txqueue); - while (cmdproc->msg_queue != NULL) - { - MsnQueueEntry *entry = cmdproc->msg_queue->data; - - msn_cmdproc_unqueue_message(cmdproc, entry->msg); - } - msn_history_destroy(cmdproc->history); } @@ -84,8 +70,6 @@ g_return_if_fail(cmdproc != NULL); g_return_if_fail(trans != NULL); - gaim_debug_info("msn", "Appending command to queue.\n"); - g_queue_push_tail(cmdproc->txqueue, trans); } @@ -120,7 +104,7 @@ { MsnServConn *servconn; char *data; - gsize len; + size_t len; g_return_if_fail(cmdproc != NULL); g_return_if_fail(trans != NULL); @@ -218,20 +202,23 @@ msn_cmdproc_process_payload(MsnCmdProc *cmdproc, char *payload, int payload_len) { - g_return_if_fail(cmdproc != NULL); - g_return_if_fail(cmdproc->payload_cb != NULL); + MsnCommand *last; + + g_return_if_fail(cmdproc != NULL); - cmdproc->payload_cb(cmdproc, payload, payload_len); + last = cmdproc->last_cmd; + last->payload = g_memdup(payload, payload_len); + last->payload_len = payload_len; + + if (last->payload_cb != NULL) + last->payload_cb(cmdproc, last, payload, payload_len); } void msn_cmdproc_process_msg(MsnCmdProc *cmdproc, MsnMessage *msg) { - MsnServConn *servconn; MsnMsgCb cb; - servconn = cmdproc->servconn; - cb = g_hash_table_lookup(cmdproc->cbs_table->msgs, msn_message_get_content_type(msg)); @@ -249,14 +236,8 @@ void msn_cmdproc_process_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - MsnSession *session; - MsnServConn *servconn; + MsnTransCb cb = NULL; MsnTransaction *trans = NULL; - MsnTransCb cb = NULL; - GSList *l, *l_next = NULL; - - session = cmdproc->session; - servconn = cmdproc->servconn; if (cmd->trId) trans = msn_history_find(cmdproc->history, cmd->trId); @@ -291,53 +272,37 @@ if (cmdproc->cbs_table->async != NULL) cb = g_hash_table_lookup(cmdproc->cbs_table->async, cmd->command); - if (cb == NULL && cmd->trId) + if (cb == NULL && trans != NULL) { - if (trans != NULL) - { - cmd->trans = trans; + cmd->trans = trans; - if (trans->callbacks) - cb = g_hash_table_lookup(trans->callbacks, cmd->command); - } + if (trans->callbacks != NULL) + cb = g_hash_table_lookup(trans->callbacks, cmd->command); } if (cb != NULL) + { cb(cmdproc, cmd); + } else { gaim_debug_warning("msn", "Unhandled command '%s'\n", cmd->command); - - return; } - if (g_list_find(session->servconns, servconn) == NULL) - return; - - /* Process all queued messages that are waiting on this command. */ - for (l = cmdproc->msg_queue; l != NULL; l = l_next) - { - MsnQueueEntry *entry = l->data; - MsnMessage *msg; - - l_next = l->next; +#if 1 + /* TODO this is really ugly */ + /* Since commands have not stored payload and we need it for pendent + * commands at the time we process again the same command we will try + * to read again the payload of payload_len size but we will actually + * read sometime else, and reading from server syncronization goes to + * hell. */ + /* Now we store the payload in the command when we queue them :D */ - if (entry->command == NULL || - !g_ascii_strcasecmp(entry->command, cmd->command)) - { - msg = entry->msg; - - msn_message_ref(msg); - - msn_cmdproc_process_msg(cmdproc, msg); - - msn_cmdproc_unqueue_message(cmdproc, entry->msg); - - msn_message_destroy(msg); - entry->msg = NULL; - } - } + if (trans != NULL && trans->pendent_cmd != NULL) + if (cmdproc->ready) + msn_transaction_unqueue_cmd(trans, cmdproc); +#endif } void @@ -354,50 +319,29 @@ } void -msn_cmdproc_queue_message(MsnCmdProc *cmdproc, const char *command, - MsnMessage *msg) +msn_cmdproc_show_error(MsnCmdProc *cmdproc, int error) { - MsnQueueEntry *entry; - - g_return_if_fail(cmdproc != NULL); - g_return_if_fail(msg != NULL); + GaimConnection *gc = + gaim_account_get_connection(cmdproc->session->account); - entry = g_new0(MsnQueueEntry, 1); - entry->msg = msg; - entry->command = (command == NULL ? NULL : g_strdup(command)); + char *tmp; - cmdproc->msg_queue = g_slist_append(cmdproc->msg_queue, entry); - - msn_message_ref(msg); -} + tmp = NULL; -void -msn_cmdproc_unqueue_message(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - MsnQueueEntry *entry = NULL; - GSList *l; - - g_return_if_fail(cmdproc != NULL); - g_return_if_fail(msg != NULL); - - for (l = cmdproc->msg_queue; l != NULL; l = l->next) + switch (error) { - entry = l->data; - - if (entry->msg == msg) + case MSN_ERROR_MISC: + tmp = _("Miscellaneous error"); break; + case MSN_ERROR_SIGNOTHER: + tmp = _("You have signed on from another location."); break; + case MSN_ERROR_SERVDOWN: + tmp = _("The MSN servers are going down temporarily."); break; + default: break; - - entry = NULL; } - g_return_if_fail(entry != NULL); - - msn_message_unref(msg); - - cmdproc->msg_queue = g_slist_remove(cmdproc->msg_queue, entry); - - if (entry->command != NULL) - g_free(entry->command); - - g_free(entry); + if (tmp != NULL) + { + gaim_connection_error(gc, tmp); + } } diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/cmdproc.h --- a/src/protocols/msn/cmdproc.h Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/cmdproc.h Sun Jun 06 02:39:08 2004 +0000 @@ -30,10 +30,11 @@ #include "command.h" #include "table.h" #include "history.h" -#include "msg.h" +#if 0 typedef void (*MsnPayloadCb)(MsnCmdProc *cmdproc, char *payload, size_t len); +#endif struct _MsnCmdProc { @@ -49,13 +50,9 @@ char *last_trans; MsnTable *cbs_table; - MsnPayloadCb payload_cb; + /* MsnPayloadCb payload_cb; */ MsnHistory *history; - - GSList *msg_queue; - - char *temp; }; MsnCmdProc *msn_cmdproc_new(MsnSession *session); @@ -70,15 +67,16 @@ const char *format, ...); void msn_cmdproc_send_quick(MsnCmdProc *cmdproc, const char *command, const char *format, ...); + void msn_cmdproc_process_msg(MsnCmdProc *cmdproc, MsnMessage *msg); +void msn_cmdproc_process_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd); void msn_cmdproc_process_cmd_text(MsnCmdProc *cmdproc, const char *command); void msn_cmdproc_process_payload(MsnCmdProc *cmdproc, char *payload, int payload_len); -void msn_cmdproc_queue_message(MsnCmdProc *cmdproc, const char *command, - MsnMessage *msg); +void msn_cmdproc_disconnect(MsnCmdProc *cmdproc); -void msn_cmdproc_unqueue_message(MsnCmdProc *cmdproc, MsnMessage *msg); +void msn_cmdproc_show_error(MsnCmdProc *cmdproc, int error); #endif /* _MSN_CMDPROC_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/command.c --- a/src/protocols/msn/command.c Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/command.c Sun Jun 06 02:39:08 2004 +0000 @@ -82,7 +82,10 @@ msn_command_unref(cmd); return; } - + + if (cmd->payload != NULL) + g_free(cmd->payload); + g_free(cmd->command); g_strfreev(cmd->params); g_free(cmd); diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/command.h --- a/src/protocols/msn/command.h Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/command.h Sun Jun 06 02:39:08 2004 +0000 @@ -27,8 +27,10 @@ #include "cmdproc.h" #include "transaction.h" -/* typedef void (*MsnPayloadCb)(MsnCmdProc *cmdproc, MsnCommand *cmd, char - * *payload, size_t len); */ +#if 1 +typedef void (*MsnPayloadCb)(MsnCmdProc *cmdproc, MsnCommand *cmd, + char *payload, size_t len); +#endif /** * A received command. @@ -44,7 +46,11 @@ int ref_count; MsnTransaction *trans; - /* MsnPayloadCb payload_cb; */ + + char *payload; + size_t payload_len; + + MsnPayloadCb payload_cb; }; MsnCommand *msn_command_from_string(const char *string); diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/directconn.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/directconn.c Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,465 @@ +#include "msn.h" +#include "directconn.h" + +#include "slp.h" +#include "slpmsg.h" + +/************************************************************************** + * Directconn Specific + **************************************************************************/ + +void +msn_directconn_send_handshake(MsnDirectConn *directconn) +{ + MsnSlpLink *slplink; + MsnSlpMessage *slpmsg; + + g_return_if_fail(directconn != NULL); + + slplink = directconn->slplink; + + slpmsg = msn_slpmsg_new(slplink); + slpmsg->flags = 0x100; + + if (directconn->nonce != NULL) + { + guint32 t1; + guint16 t2; + guint16 t3; + guint16 t4; + guint64 t5; + + sscanf (directconn->nonce, "%08X-%04hX-%04hX-%04hX-%012llX", &t1, &t2, &t3, &t4, &t5); + + t1 = GUINT32_TO_LE(t1); + t2 = GUINT16_TO_LE(t2); + t3 = GUINT16_TO_LE(t3); + t4 = GUINT16_TO_BE(t4); + t5 = GUINT64_TO_BE(t5); + + slpmsg->ack_id = t1; + slpmsg->ack_sub_id = t2 | (t3 << 16); + slpmsg->ack_size = t4 | t5; + } + + g_free(directconn->nonce); + + msn_slplink_send_slpmsg(slplink, slpmsg); + + directconn->acked =TRUE; +} + +/************************************************************************** + * Connection Functions + **************************************************************************/ + +static int +create_listener(int port) +{ + int fd; + const int on = 1; + +#if 0 + struct addrinfo hints; + struct addrinfo *c, *res; + char port_str[5]; + + snprintf(port_str, sizeof(port_str), "%d", port); + + memset(&hints, 0, sizeof(hints)); + + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if (getaddrinfo(NULL, port_str, &hints, &res) != 0) + { + gaim_debug_error("msn", "Could not get address info: %s.\n", + port_str); + return -1; + } + + for (c = res; c != NULL; c = c->ai_next) + { + fd = socket(c->ai_family, c->ai_socktype, c->ai_protocol); + + if (fd < 0) + continue; + + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + if (bind(fd, c->ai_addr, c->ai_addrlen) == 0) + break; + + close(fd); + } + + if (c == NULL) + { + gaim_debug_error("msn", "Could not find socket: %s.\n", port_str); + return -1; + } + + freeaddrinfo(res); +#else + struct sockaddr_in sockin; + + fd = socket(AF_INET, SOCK_STREAM, 0); + + if (fd < 0) + return -1; + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) + { + close(fd); + return -1; + } + + memset(&sockin, 0, sizeof(struct sockaddr_in)); + sockin.sin_family = AF_INET; + sockin.sin_port = htons(port); + + if (bind(fd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) + { + close(fd); + return -1; + } +#endif + + if (listen (fd, 4) != 0) + { + close (fd); + return -1; + } + + fcntl(fd, F_SETFL, O_NONBLOCK); + + return fd; +} + +size_t +msn_directconn_write(MsnDirectConn *directconn, + const char *data, size_t len) +{ + char *buffer, *tmp; + size_t buf_size; + size_t ret; + guint32 sent_len; + + g_return_val_if_fail(directconn != NULL, 0); + + buf_size = len + 4; + buffer = tmp = g_malloc(buf_size); + + sent_len = GUINT32_TO_LE(len); + + memcpy(tmp, &sent_len, 4); + tmp += 4; + memcpy(tmp, data, len); + tmp += len; + + ret = write(directconn->fd, buffer, buf_size); + +#ifdef DEBUG_DC + char *str; + str = g_strdup_printf("%s/msntest/w%.4d.bin", g_get_home_dir(), directconn->c); + + FILE *tf = fopen(str, "w"); + fwrite(buffer, 1, buf_size, tf); + fclose(tf); + + g_free(str); +#endif + + g_free(buffer); + +#if 0 + /* Let's write the length of the data. */ + ret = write(directconn->fd, &len, sizeof(len)); + + /* Let's write the data. */ + ret = write(directconn->fd, data, len); + + char *str; + str = g_strdup_printf("/home/revo/msntest/w%.4d.bin", directconn->c); + + FILE *tf = fopen(str, "w"); + fwrite(&len, 1, sizeof(len), tf); + fwrite(data, 1, len, tf); + fclose(tf); + + g_free(str); +#endif + + directconn->c++; + + return ret; +} + +#if 0 +void +msn_directconn_parse_nonce(MsnDirectConn *directconn, const char *nonce) +{ + guint32 t1; + guint16 t2; + guint16 t3; + guint16 t4; + guint64 t5; + + g_return_if_fail(directconn != NULL); + g_return_if_fail(nonce != NULL); + + sscanf (nonce, "%08X-%04hX-%04hX-%04hX-%012llX", &t1, &t2, &t3, &t4, &t5); + + t1 = GUINT32_TO_LE(t1); + t2 = GUINT16_TO_LE(t2); + t3 = GUINT16_TO_LE(t3); + t4 = GUINT16_TO_BE(t4); + t5 = GUINT64_TO_BE(t5); + + directconn->slpheader = g_new0(MsnSlpHeader, 1); + + directconn->slpheader->ack_id = t1; + directconn->slpheader->ack_sub_id = t2 | (t3 << 16); + directconn->slpheader->ack_size = t4 | t5; +} +#endif + +void +msn_directconn_send_msg(MsnDirectConn *directconn, MsnMessage *msg) +{ + char *body; + size_t body_len; + + body = msn_message_gen_slp_body(msg, &body_len); + + msn_directconn_write(directconn, body, body_len); +} + +void +msn_directconn_process_msg(MsnDirectConn *directconn, MsnMessage *msg) +{ + gaim_debug_info("msn", "directconn: process_msg\n"); + + msn_slplink_process_msg(directconn->slplink, msg); +} + +static void +read_cb(gpointer data, gint source, GaimInputCondition cond) +{ + MsnDirectConn* directconn; + char *body; + size_t len, body_len; + + gaim_debug_info("msn", "read_cb: %d, %d\n", source, cond); + + directconn = data; + + /* Let's read the length of the data. */ + len = read(directconn->fd, &body_len, sizeof(body_len)); + + if (len <= 0) + { + /* ERROR */ + gaim_debug_error("msn", "error reading\n"); + + if (directconn->inpa) + gaim_input_remove(directconn->inpa); + + close(directconn->fd); + + msn_directconn_destroy(directconn); + + return; + } + + body_len = GUINT32_FROM_LE(body_len); + + gaim_debug_info("msn", "body_len=%d\n", body_len); + + if (body_len <= 0) + { + /* ERROR */ + gaim_debug_error("msn", "error reading\n"); + + if (directconn->inpa) + gaim_input_remove(directconn->inpa); + + close(directconn->fd); + + msn_directconn_destroy(directconn); + + return; + } + + body = g_malloc(body_len); + + /* Let's read the data. */ + len = read(directconn->fd, body, body_len); + + gaim_debug_info("msn", "len=%d\n", len); + + if (len > 0) + { + MsnMessage *msg; + +#ifdef DEBUG_DC + str = g_strdup_printf("/home/revo/msntest/r%.4d.bin", directconn->c); + + FILE *tf = fopen(str, "w"); + fwrite(body, 1, len, tf); + fclose(tf); + + g_free(str); +#endif + + directconn->c++; + + msg = msn_message_new_msnslp(); + msn_message_parse_slp_body(msg, body, body_len); + + msn_directconn_process_msg(directconn, msg); + } + else + { + /* ERROR */ + gaim_debug_error("msn", "error reading\n"); + + if (directconn->inpa) + gaim_input_remove(directconn->inpa); + + close(directconn->fd); + + msn_directconn_destroy(directconn); + } +} + +static void +connect_cb(gpointer data, gint source, GaimInputCondition cond) +{ + MsnDirectConn* directconn; + int fd; + + gaim_debug_misc("msn", "directconn: connect_cb: %d, %d.\n", source, cond); + + directconn = data; + + if (TRUE) + { + fd = source; + } + else + { + struct sockaddr_in client_addr; + int client; + fd = accept (source, (struct sockaddr *)&client_addr, &client); + } + + directconn->fd = fd; + + if (fd > 0) + { + directconn->inpa = gaim_input_add(fd, GAIM_INPUT_READ, read_cb, + directconn); + + if (TRUE) + { + /* Send foo. */ + msn_directconn_write(directconn, "foo", strlen("foo") + 1); + + /* Send Handshake */ + msn_directconn_send_handshake(directconn); + } + else + { + } + } + else + { + /* ERROR */ + gaim_debug_error("msn", "could not add input\n"); + + if (directconn->inpa) + gaim_input_remove(directconn->inpa); + + close(directconn->fd); + } +} + +gboolean +msn_directconn_connect(MsnDirectConn *directconn, const char *host, int port) +{ + MsnSession *session; + int r; + + g_return_val_if_fail(directconn != NULL, FALSE); + g_return_val_if_fail(host != NULL, TRUE); + g_return_val_if_fail(port > 0, FALSE); + + session = directconn->slplink->session; + +#if 0 + if (session->http_method) + { + servconn->http_data->gateway_host = g_strdup(host); + } +#endif + + r = gaim_proxy_connect(session->account, host, port, connect_cb, + directconn); + + if (r == 0) + { + return TRUE; + } + else + return FALSE; +} + +void +msn_directconn_listen(MsnDirectConn *directconn) +{ + int port; + int fd; + + port = 7000; + + for (fd = -1; fd < 0;) + fd = create_listener(++port); + + directconn->fd = fd; + + directconn->inpa = gaim_input_add(fd, GAIM_INPUT_READ, + connect_cb, directconn); + + directconn->port = port; + directconn->c = 0; +} + +MsnDirectConn* +msn_directconn_new(MsnSlpLink *slplink) +{ + MsnDirectConn *directconn; + + directconn = g_new0(MsnDirectConn, 1); + + directconn->slplink = slplink; + + if (slplink->directconn != NULL) + gaim_debug_info("msn", "got_transresp: LEAK\n"); + + slplink->directconn = directconn; + + return directconn; +} + +void +msn_directconn_destroy(MsnDirectConn *directconn) +{ + if (directconn->nonce != NULL) + g_free(directconn->nonce); + + directconn->slplink->directconn = NULL; + + g_free(directconn); +} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/directconn.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/directconn.h Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,36 @@ +#ifndef _MSN_DIRECTCONN_H_ +#define _MSN_DIRECTCONN_H_ + +typedef struct _MsnDirectConn MsnDirectConn; + +#include "slplink.h" +#include "slp.h" +#include "msg.h" + +struct _MsnDirectConn +{ + MsnSlpLink *slplink; + MsnSlpCall *initial_call; + + gboolean acked; + + char *nonce; + + int fd; + + int port; + int inpa; + + int c; +}; + +MsnDirectConn *msn_directconn_new(MsnSlpLink *slplink); +gboolean msn_directconn_connect(MsnDirectConn *directconn, + const char *host, int port); +void msn_directconn_listen(MsnDirectConn *directconn); +void msn_directconn_send_msg(MsnDirectConn *directconn, MsnMessage *msg); +void msn_directconn_parse_nonce(MsnDirectConn *directconn, const char *nonce); +void msn_directconn_destroy(MsnDirectConn *directconn); +void msn_directconn_send_handshake(MsnDirectConn *directconn); + +#endif /* _MSN_DIRECTCONN_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/group.c --- a/src/protocols/msn/group.c Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/group.c Sun Jun 06 02:39:08 2004 +0000 @@ -23,26 +23,19 @@ #include "group.h" MsnGroup * -msn_group_new(MsnSession *session, int id, const char *name) +msn_group_new(MsnUserList *userlist, int id, const char *name) { MsnGroup *group; - g_return_val_if_fail(session != NULL, NULL); - g_return_val_if_fail(id >= 0, NULL); - g_return_val_if_fail(name != NULL, NULL); + g_return_val_if_fail(id >= 0, NULL); + g_return_val_if_fail(name != NULL, NULL); - group = msn_groups_find_with_id(session->groups, id); + group = g_new0(MsnGroup, 1); - if (group == NULL) { - group = g_new0(MsnGroup, 1); + msn_userlist_add_group(userlist, group); - group->session = session; - group->id = id; - group->name = g_strdup(name); - group->users = msn_users_new(); - } - - msn_group_ref(group); + group->id = id; + group->name = g_strdup(name); return group; } @@ -52,50 +45,10 @@ { g_return_if_fail(group != NULL); - if (group->ref_count > 0) { - msn_group_unref(group); - - return; - } - - if (group->session != NULL && group->session->groups != NULL) - msn_groups_remove(group->session->groups, group); - - msn_users_destroy(group->users); - g_free(group->name); g_free(group); } -MsnGroup * -msn_group_ref(MsnGroup *group) -{ - g_return_val_if_fail(group != NULL, NULL); - - group->ref_count++; - - return group; -} - -MsnGroup * -msn_group_unref(MsnGroup *group) -{ - g_return_val_if_fail(group != NULL, NULL); - - if (group->ref_count <= 0) - return NULL; - - group->ref_count--; - - if (group->ref_count == 0) { - msn_group_destroy(group); - - return NULL; - } - - return group; -} - void msn_group_set_id(MsnGroup *group, int id) { @@ -132,143 +85,3 @@ return group->name; } - -void -msn_group_add_user(MsnGroup *group, MsnUser *user) -{ - g_return_if_fail(group != NULL); - g_return_if_fail(user != NULL); - - msn_users_add(group->users, user); - - msn_user_ref(user); - - gaim_debug(GAIM_DEBUG_INFO, "msn", "Adding user %s to group %s (%d)\n", - msn_user_get_passport(user), msn_group_get_name(group), - msn_group_get_id(group)); -} - -void -msn_group_remove_user(MsnGroup *group, MsnUser *user) -{ - g_return_if_fail(group != NULL); - g_return_if_fail(user != NULL); - - msn_users_remove(group->users, user); - - msn_user_unref(user); -} - -MsnUsers * -msn_group_get_users(const MsnGroup *group) -{ - g_return_val_if_fail(group != NULL, NULL); - - return group->users; -} - - -MsnGroups * -msn_groups_new(void) -{ - return g_new0(MsnGroups, 1); -} - -void -msn_groups_destroy(MsnGroups *groups) -{ - g_return_if_fail(groups != NULL); - - while (groups->groups != NULL) - msn_group_destroy(groups->groups->data); - - /* See if we've leaked anybody. */ - while (groups->groups != NULL) { - gaim_debug(GAIM_DEBUG_WARNING, "msn", - "Leaking group %s (id %d)\n", - msn_group_get_name(groups->groups->data), - msn_group_get_id(groups->groups->data)); - } - - g_free(groups); -} - -void -msn_groups_add(MsnGroups *groups, MsnGroup *group) -{ - g_return_if_fail(groups != NULL); - g_return_if_fail(group != NULL); - - groups->groups = g_list_append(groups->groups, group); - - groups->count++; - - gaim_debug(GAIM_DEBUG_INFO, "msn", "Adding group %s (%d)\n", - msn_group_get_name(group), msn_group_get_id(group)); -} - -void -msn_groups_remove(MsnGroups *groups, MsnGroup *group) -{ - g_return_if_fail(groups != NULL); - g_return_if_fail(group != NULL); - - gaim_debug(GAIM_DEBUG_INFO, "msn", "Removing group %s (%d)\n", - msn_group_get_name(group), msn_group_get_id(group)); - - groups->groups = g_list_remove(groups->groups, group); - - groups->count--; -} - -size_t -msn_groups_get_count(const MsnGroups *groups) -{ - g_return_val_if_fail(groups != NULL, 0); - - return groups->count; -} - -GList * -msn_groups_get_list(const MsnGroups *groups) -{ - g_return_val_if_fail(groups != NULL, NULL); - - return groups->groups; -} - -MsnGroup * -msn_groups_find_with_id(MsnGroups *groups, int id) -{ - GList *l; - - g_return_val_if_fail(groups != NULL, NULL); - g_return_val_if_fail(id >= 0, NULL); - - for (l = groups->groups; l != NULL; l = l->next) { - MsnGroup *group = l->data; - - if (group->id == id) - return group; - } - - return NULL; -} - -MsnGroup * -msn_groups_find_with_name(MsnGroups *groups, const char *name) -{ - GList *l; - - g_return_val_if_fail(groups != NULL, NULL); - g_return_val_if_fail(name != NULL, NULL); - - for (l = groups->groups; l != NULL; l = l->next) { - MsnGroup *group = l->data; - - if (group->name != NULL && !g_ascii_strcasecmp(name, group->name)) - return group; - } - - return NULL; -} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/group.h --- a/src/protocols/msn/group.h Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/group.h Sun Jun 06 02:39:08 2004 +0000 @@ -23,36 +23,23 @@ #define _MSN_GROUP_H_ typedef struct _MsnGroup MsnGroup; -typedef struct _MsnGroups MsnGroups; #include #include "session.h" #include "user.h" +#include "userlist.h" + /** * A group. */ struct _MsnGroup { - size_t ref_count; /**< The reference count. */ - MsnSession *session; /**< The MSN session. */ int id; /**< The group ID. */ char *name; /**< The name of the group. */ - - MsnUsers *users; /**< The users in the group. */ -}; - -/** - * A list of groups. - */ -struct _MsnGroups -{ - size_t count; /**< The number of groups. */ - - GList *groups; /**< The list of groups. */ }; /**************************************************************************/ @@ -69,7 +56,7 @@ * * @return A new group structure. */ -MsnGroup *msn_group_new(MsnSession *session, int id, const char *name); +MsnGroup *msn_group_new(MsnUserList *userlist, int id, const char *name); /** * Destroys a group structure. @@ -79,26 +66,6 @@ void msn_group_destroy(MsnGroup *group); /** - * Increments the reference count on a group. - * - * @param group The group. - * - * @return @a group - */ -MsnGroup *msn_group_ref(MsnGroup *group); - -/** - * Decrements the reference count on a group. - * - * This will destroy the structure if the count hits 0. - * - * @param group The group. - * - * @return @a group, or @c NULL if the new count is 0. - */ -MsnGroup *msn_group_unref(MsnGroup *group); - -/** * Sets the ID for a group. * * @param group The group. @@ -131,105 +98,4 @@ * @return The name. */ const char *msn_group_get_name(const MsnGroup *group); - -/** - * Adds a user to the group. - * - * @param group The group. - * @param user The user. - */ -void msn_group_add_user(MsnGroup *group, MsnUser *user); - -/** - * Removes a user from the group. - * - * @param group The group. - * @param user The user. - */ -void msn_group_remove_user(MsnGroup *group, MsnUser *user); - -/** - * Returns the users in a group. - * - * @param group The group. - * - * @return The list of users. - */ -MsnUsers *msn_group_get_users(const MsnGroup *group); - -/*@}*/ - -/**************************************************************************/ -/** @name Group List API */ -/**************************************************************************/ -/*@{*/ - -/** - * Creates a new MsnGroups structure. - * - * @return A new MsnGroups structure. - */ -MsnGroups *msn_groups_new(void); - -/** - * Destroys a groups list. - * - * @param groups The groups list. - */ -void msn_groups_destroy(MsnGroups *groups); - -/** - * Adds a group to a groups list. - * - * @param groups The groups list. - * @param group The group. - */ -void msn_groups_add(MsnGroups *groups, MsnGroup *group); - -/** - * Removes a group from a groups list. - * - * @param groups The groups list. - * @param group The group. - */ -void msn_groups_remove(MsnGroups *groups, MsnGroup *group); - -/** - * Returns the number of groups in a groups list. - * - * @param groups The groups list. - * - * @return The number of groups. - */ -size_t msn_groups_get_count(const MsnGroups *groups); - -/** - * Finds a group with the specified ID. - * - * @param groups A list of groups. - * @param id The group ID. - * - * @return The group if found, or @c NULL otherwise. - */ -MsnGroup *msn_groups_find_with_id(MsnGroups *groups, int id); - -/** - * Returns a GList of all groups. - * - * @param groups The list of groups. - * - * @return A GList of all groups. - */ -GList *msn_groups_get_list(const MsnGroups *groups); - -/** - * Finds a group with the specified name. - * - * @param groups A list of groups. - * @param name The group name. - * - * @return The group if found, or @c NULL otherwise. - */ -MsnGroup *msn_groups_find_with_name(MsnGroups *groups, const char *name); - #endif /* _MSN_GROUP_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/httpmethod.c --- a/src/protocols/msn/httpmethod.c Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/httpmethod.c Sun Jun 06 02:39:08 2004 +0000 @@ -48,24 +48,32 @@ static gboolean http_poll(gpointer data) { - MsnSession *session = data; - MsnServConn *servconn; + MsnSession *session; GList *l; - for (l = session->servconns; l != NULL; l = l->next) + session = data; + + for (l = session->switches; l != NULL; l = l->next) { - servconn = (MsnServConn *)l->data; + MsnSwitchBoard *swboard; + + swboard = l->data; - if (servconn->http_data->dirty) + g_return_val_if_fail(swboard->servconn->http_data != NULL, FALSE); + + if (swboard->servconn->http_data->dirty) { #if 0 gaim_debug_info("msn", "Polling server %s.\n", servconn->http_data->gateway_host); #endif - msn_http_servconn_poll(servconn); + msn_http_servconn_poll(swboard->servconn); } } + if (session->notification->servconn->http_data->dirty) + msn_http_servconn_poll(session->notification->servconn); + return TRUE; } diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/msg.c --- a/src/protocols/msn/msg.c Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/msg.c Sun Jun 06 02:39:08 2004 +0000 @@ -22,38 +22,6 @@ #include "msn.h" #include "msg.h" -#define GET_NEXT(tmp) \ - while (*(tmp) && *(tmp) != ' ' && *(tmp) != '\r') \ - (tmp)++; \ - if (*(tmp) != '\0') *(tmp)++ = '\0'; \ - if (*(tmp) == '\n') (tmp)++; \ - while (*(tmp) && *(tmp) == ' ') \ - (tmp)++ - -#define GET_NEXT_LINE(tmp) \ - while (*(tmp) && *(tmp) != '\r') \ - (tmp)++; \ - if (*(tmp) != '\0') *(tmp)++ = '\0'; \ - if (*(tmp) == '\n') (tmp)++ - - -#define msn_put16(buf, data) ( \ - (*(buf) = (unsigned char)((data)>>8)&0xff), \ - (*((buf)+1) = (unsigned char)(data)&0xff), \ - 2) -#define msn_get16(buf) ((((*(buf))<<8)&0xff00) + ((*((buf)+1)) & 0xff)) -#define msn_put32(buf, data) ( \ - (*((buf)) = (unsigned char)((data)>>24)&0xff), \ - (*((buf)+1) = (unsigned char)((data)>>16)&0xff), \ - (*((buf)+2) = (unsigned char)((data)>>8)&0xff), \ - (*((buf)+3) = (unsigned char)(data)&0xff), \ - 4) -#define msn_get32(buf) ((((*(buf))<<24)&0xff000000) + \ - (((*((buf)+1))<<16)&0x00ff0000) + \ - (((*((buf)+2))<< 8)&0x0000ff00) + \ - (((*((buf)+3) )&0x000000ff))) - - MsnMessage * msn_message_new(void) { @@ -107,27 +75,36 @@ return msg; } -MsnMessage * -msn_message_new_msnslp_ack(MsnMessage *acked_msg) +void +msn_message_parse_slp_body(MsnMessage *msg, const char *body, size_t len) { - MsnMessage *msg; + MsnSlpHeader header; + const char *tmp; - g_return_val_if_fail(acked_msg != NULL, NULL); - g_return_val_if_fail(acked_msg->msnslp_message, NULL); + tmp = body; - msg = msn_message_new_msnslp(); + /* Import the header. */ + memcpy(&header, tmp, sizeof(header)); + tmp += sizeof(header); - msg->msnslp_ack_message = TRUE; - msg->acked_msg = msn_message_ref(acked_msg); + msg->msnslp_header.session_id = GUINT32_FROM_LE(header.session_id); + msg->msnslp_header.id = GUINT32_FROM_LE(header.id); + msg->msnslp_header.offset = GUINT64_FROM_LE(header.offset); + msg->msnslp_header.total_size = GUINT64_FROM_LE(header.total_size); + msg->msnslp_header.length = GUINT32_FROM_LE(header.length); + msg->msnslp_header.flags = GUINT32_FROM_LE(header.flags); + msg->msnslp_header.ack_id = GUINT32_FROM_LE(header.ack_id); + msg->msnslp_header.ack_sub_id = GUINT32_FROM_LE(header.ack_sub_id); + msg->msnslp_header.ack_size = GUINT64_FROM_LE(header.ack_size); + + /* Import the body. */ + /* msg->body_len = msg->msnslp_header.length; */ + msg->body_len = len - (tmp - body); + + if (msg->body_len > 0) + msg->body = g_memdup(tmp, msg->body_len); - msg->msnslp_header.session_id = acked_msg->msnslp_header.session_id; - msg->msnslp_header.total_size = acked_msg->msnslp_header.total_size; - msg->msnslp_header.flags = 0x02; - msg->msnslp_header.ack_id = acked_msg->msnslp_header.id; - msg->msnslp_header.ack_sub_id = acked_msg->msnslp_header.ack_id; - msg->msnslp_header.ack_size = acked_msg->msnslp_header.total_size; - - return msg; + tmp += msg->body_len; } void @@ -136,33 +113,36 @@ { char *tmp_base, *tmp; const char *content_type; + char *end; + char **elems, **cur, **tokens; g_return_if_fail(payload != NULL); - tmp_base = tmp = g_memdup(payload, payload_len); + tmp_base = tmp = g_memdup(payload, payload_len + 1); + tmp[payload_len] = '\0'; - /* Back to the parsination. */ - while (*tmp != '\r') - { - char *key, *value, *c; + /* Parse the attributes. */ + end = strstr(tmp, "\r\n\r\n"); + g_return_if_fail(end != NULL); + *end = '\0'; - key = tmp; + elems = g_strsplit(tmp, "\r\n", 0); - GET_NEXT(tmp); /* Key */ - - value = tmp; + for (cur = elems; *cur != NULL; cur++) + { + const char *key, *value; - GET_NEXT_LINE(tmp); /* Value */ + tokens = g_strsplit(*cur, ": ", 2); - if ((c = strchr(key, ':')) != NULL) - *c = '\0'; + key = tokens[0]; + value = tokens[1]; - if (!g_ascii_strcasecmp(key, "MIME-Version")) + if (!strcmp(key, "MIME-Version")) continue; - if (!g_ascii_strcasecmp(key, "Content-Type")) + if (!strcmp(key, "Content-Type")) { - char *charset; + char *charset, *c; if ((c = strchr(value, ';')) != NULL) { @@ -178,11 +158,16 @@ msn_message_set_content_type(msg, value); } else + { msn_message_set_attr(msg, key, value); + } + + g_strfreev(tokens); } - /* "\r\n" */ - tmp += 2; + g_strfreev(elems); + + tmp = end + 4; /* Now we *should* be at the body. */ content_type = msn_message_get_content_type(msg); @@ -200,9 +185,9 @@ tmp += sizeof(header); msg->msnslp_header.session_id = GUINT32_FROM_LE(header.session_id); - msg->msnslp_header.id = GUINT64_FROM_LE(header.id); + msg->msnslp_header.id = GUINT32_FROM_LE(header.id); msg->msnslp_header.offset = GUINT64_FROM_LE(header.offset); - msg->msnslp_header.total_size = GUINT32_FROM_LE(header.total_size); + msg->msnslp_header.total_size = GUINT64_FROM_LE(header.total_size); msg->msnslp_header.length = GUINT32_FROM_LE(header.length); msg->msnslp_header.flags = GUINT32_FROM_LE(header.flags); msg->msnslp_header.ack_id = GUINT32_FROM_LE(header.ack_id); @@ -230,8 +215,22 @@ } g_free(tmp_base); +} - /* Done! */ +MsnMessage * +msn_message_new_from_cmd(MsnSession *session, MsnCommand *cmd) +{ + MsnMessage *msg; + + g_return_val_if_fail(cmd != NULL, NULL); + + msg = msn_message_new(); + + msg->remote_user = g_strdup(cmd->params[0]); + /* msg->size = atoi(cmd->params[2]); */ + msg->cmd = cmd; + + return msg; } void @@ -246,6 +245,9 @@ return; } + if (msg->remote_user != NULL) + g_free(msg->remote_user); + if (msg->body != NULL) g_free(msg->body); @@ -258,9 +260,6 @@ g_hash_table_destroy(msg->attr_table); g_list_free(msg->attr_list); - if (msg->msnslp_ack_message) - msn_message_unref(msg->acked_msg); - g_free(msg); } @@ -284,7 +283,8 @@ msg->ref_count--; - if (msg->ref_count == 0) { + if (msg->ref_count == 0) + { msn_message_destroy(msg); return NULL; @@ -294,7 +294,49 @@ } char * -msn_message_gen_payload(const MsnMessage *msg, size_t *ret_size) +msn_message_gen_slp_body(MsnMessage *msg, size_t *ret_size) +{ + MsnSlpHeader header; + + char *tmp, *base; + const void *body; + size_t len, body_len; + + g_return_val_if_fail(msg != NULL, NULL); + + len = MSN_BUF_LEN; + + base = tmp = g_malloc(len + 1); + + body = msn_message_get_bin_data(msg, &body_len); + + header.session_id = GUINT32_TO_LE(msg->msnslp_header.session_id); + header.id = GUINT32_TO_LE(msg->msnslp_header.id); + header.offset = GUINT64_TO_LE(msg->msnslp_header.offset); + header.total_size = GUINT64_TO_LE(msg->msnslp_header.total_size); + header.length = GUINT32_TO_LE(msg->msnslp_header.length); + header.flags = GUINT32_TO_LE(msg->msnslp_header.flags); + header.ack_id = GUINT32_TO_LE(msg->msnslp_header.ack_id); + header.ack_sub_id = GUINT32_TO_LE(msg->msnslp_header.ack_sub_id); + header.ack_size = GUINT64_TO_LE(msg->msnslp_header.ack_size); + + memcpy(tmp, &header, 48); + tmp += 48; + + if (body != NULL) + { + memcpy(tmp, body, body_len); + tmp += body_len; + } + + if (ret_size != NULL) + *ret_size = tmp - base; + + return base; +} + +char * +msn_message_gen_payload(MsnMessage *msg, size_t *ret_size) { GList *l; char *n, *base, *end; @@ -349,9 +391,9 @@ MsnSlpFooter footer; header.session_id = GUINT32_TO_LE(msg->msnslp_header.session_id); - header.id = GUINT64_TO_LE(msg->msnslp_header.id); + header.id = GUINT32_TO_LE(msg->msnslp_header.id); header.offset = GUINT64_TO_LE(msg->msnslp_header.offset); - header.total_size = GUINT32_TO_LE(msg->msnslp_header.total_size); + header.total_size = GUINT64_TO_LE(msg->msnslp_header.total_size); header.length = GUINT32_TO_LE(msg->msnslp_header.length); header.flags = GUINT32_TO_LE(msg->msnslp_header.flags); header.ack_id = GUINT32_TO_LE(msg->msnslp_header.ack_id); @@ -364,6 +406,7 @@ if (body != NULL) { memcpy(n, body, body_len); + n += body_len; } @@ -383,10 +426,10 @@ if (ret_size != NULL) { - *ret_size = n - base; - if (*ret_size > 1664) *ret_size = 1664; + + *ret_size = n - base; } return base; @@ -452,10 +495,7 @@ if (msg->content_type != NULL) g_free(msg->content_type); - if (type != NULL) - msg->content_type = g_strdup(type); - else - msg->content_type = NULL; + msg->content_type = (type != NULL) ? g_strdup(type) : NULL; } const char * @@ -474,10 +514,7 @@ if (msg->charset != NULL) g_free(msg->charset); - if (charset != NULL) - msg->charset = g_strdup(charset); - else - msg->charset = NULL; + msg->charset = (charset != NULL) ? g_strdup(charset) : NULL; } const char * @@ -542,37 +579,135 @@ msn_message_get_hashtable_from_body(const MsnMessage *msg) { GHashTable *table; - char *body, *s, *c; + const char *body; + char **elems, **cur, **tokens; g_return_val_if_fail(msg != NULL, NULL); - s = body = g_strdup(msn_message_get_bin_data(msg, NULL)); - - g_return_val_if_fail(body != NULL, NULL); - table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - while (*s != '\r' && *s != '\0') + body = msn_message_get_bin_data(msg, NULL); + + g_return_val_if_fail(body != NULL, NULL); + + elems = g_strsplit(body, "\r\n", 0); + + for (cur = elems; *cur != NULL; cur++) { - char *key, *value; + if (**cur == '\0') + break; + + tokens = g_strsplit(*cur, ": ", 2); + + if (tokens[0] != NULL && tokens[1] != NULL) + g_hash_table_insert(table, tokens[0], tokens[1]); + + g_free(tokens); + } + + g_strfreev(elems); + + return table; +} - key = s; +void +msn_message_show_readable(MsnMessage *msg, const char *info, + gboolean text_body) +{ + GString *str; + size_t body_len; + const char *body; + GList *l; + + g_return_if_fail(msg != NULL); + + str = g_string_new(NULL); - GET_NEXT(s); + /* Standard header. */ + if (msg->charset == NULL) + { + g_string_append_printf(str, + "MIME-Version: 1.0\r\n" + "Content-Type: %s\r\n", + msg->content_type); + } + else + { + g_string_append_printf(str, + "MIME-Version: 1.0\r\n" + "Content-Type: %s; charset=%s\r\n", + msg->content_type, msg->charset); + } + + for (l = msg->attr_list; l; l = l->next) + { + char *key; + const char *value; - value = s; + key = l->data; + value = msn_message_get_attr(msg, key); + + g_string_append_printf(str, "%s: %s\r\n", key, value); + } + + g_string_append(str, "\r\n"); + + body = msn_message_get_bin_data(msg, &body_len); - GET_NEXT_LINE(s); + if (msg->msnslp_message) + { + g_string_append_printf(str, "%u ", msg->msnslp_header.session_id); + g_string_append_printf(str, "%u ", msg->msnslp_header.id); + g_string_append_printf(str, "%llu ", msg->msnslp_header.offset); + g_string_append(str, "\r\n"); + g_string_append_printf(str, "%llu ", + msg->msnslp_header.total_size); + g_string_append_printf(str, "%u ", msg->msnslp_header.length); + g_string_append_printf(str, "%u ", msg->msnslp_header.flags); + g_string_append(str, "\r\n"); + g_string_append_printf(str, "%u ", msg->msnslp_header.ack_id); + g_string_append_printf(str, "%u ", msg->msnslp_header.ack_sub_id); + g_string_append_printf(str, "%lld ", msg->msnslp_header.ack_size); + g_string_append(str, "\r\n"); - if ((c = strchr(key, ':')) != NULL) + if (body != NULL) { - *c = '\0'; - - g_hash_table_insert(table, g_strdup(key), g_strdup(value)); + if (text_body) + { + g_string_append_len(str, body, body_len); + if (body[body_len - 1] == '\0') + { + str->len--; + g_string_append(str, " 0x00"); + } + g_string_append(str, "\r\n"); + } + else + { + int i; + for (i = 0; i < msg->body_len; i++) + { + g_string_append_printf(str, "%.2hhX ", body[i]); + if ((i % 16) == 15) + g_string_append(str, "\r\n"); + } + g_string_append(str, "\r\n"); + } + } + + g_string_append_printf(str, "%u ", msg->msnslp_footer.value); + g_string_append(str, "\r\n"); + } + else + { + if (body != NULL) + { + g_string_append_len(str, body, body_len); + g_string_append(str, "\r\n"); } } - g_free(body); - - return table; + gaim_debug_info("msn", "Message %s:\n{%s}\n", info, str->str); + + g_string_free(str, TRUE); } diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/msg.h --- a/src/protocols/msn/msg.h Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/msg.h Sun Jun 06 02:39:08 2004 +0000 @@ -27,6 +27,17 @@ #include "session.h" #include "user.h" +#include "command.h" +#include "transaction.h" + +typedef enum +{ + MSN_MSG_NORMAL, + MSN_MSG_SLP_SB, + MSN_MSG_SLP_DC + +} MsnMsgType; + typedef struct { guint32 session_id; @@ -54,27 +65,30 @@ { size_t ref_count; /**< The reference count. */ + MsnMsgType type; + gboolean msnslp_message; - gboolean msnslp_ack_message; - char *passport; + char *remote_user; char flag; char *content_type; char *charset; char *body; - size_t body_len; + gsize body_len; MsnSlpHeader msnslp_header; MsnSlpFooter msnslp_footer; - MsnMessage *acked_msg; - GHashTable *attr_table; GList *attr_list; -}; + + MsnCommand *cmd; + MsnTransaction *trans; -#define MSN_MESSAGE(msg) ((MsnMessage *)(msg)) + MsnTransCb ack_cb; + void *ack_data; +}; /** * Creates a new, empty message. @@ -83,8 +97,6 @@ */ MsnMessage *msn_message_new(void); -MsnMessage *msn_message_new_plain(const char *message); - /** * Creates a new, empty MSNSLP message. * @@ -92,6 +104,8 @@ */ MsnMessage *msn_message_new_msnslp(void); +MsnMessage *msn_message_new_plain(const char *message); + /** * Creates a MSNSLP ack message. * @@ -102,7 +116,17 @@ MsnMessage *msn_message_new_msnslp_ack(MsnMessage *acked_msg); /** - * Parse the payload of a message. + * Creates a new message based off a command. + * + * @param session The MSN session. + * @param cmd The command. + * + * @return The new message. + */ +MsnMessage *msn_message_new_from_cmd(MsnSession *session, MsnCommand *cmd); + +/** + * Parses the payload of a message. * * @param msg The message. * @param payload The payload. @@ -146,7 +170,7 @@ * * @return The payload data of the message. */ -char *msn_message_gen_payload(const MsnMessage *msg, size_t *ret_size); +char *msn_message_gen_payload(MsnMessage *msg, size_t *ret_size); /** * Sets the flag for an outgoing message. @@ -165,6 +189,7 @@ */ char msn_message_get_flag(const MsnMessage *msg); +#if 0 /** * Sets the body of a message. * @@ -181,7 +206,7 @@ * @return The body of the message. */ const char *msn_message_get_body(const MsnMessage *msg); - +#endif /** * Sets the binary content of the message. * @@ -264,4 +289,13 @@ */ GHashTable *msn_message_get_hashtable_from_body(const MsnMessage *msg); +void msn_message_show_readable(MsnMessage *msg, const char *info, + gboolean text_body); + +void msn_message_parse_slp_body(MsnMessage *msg, const char *body, + size_t len); + +char *msn_message_gen_slp_body(MsnMessage *msg, size_t *ret_size); + + #endif /* _MSN_MSG_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/msn.c --- a/src/protocols/msn/msn.c Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/msn.c Sun Jun 06 02:39:08 2004 +0000 @@ -20,9 +20,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include -#include "internal.h" -#include "blist.h" #include "msn.h" #include "accountopt.h" #include "msg.h" @@ -32,10 +30,13 @@ #include "session.h" #include "state.h" #include "utils.h" +#include "multi.h" #include "util.h" +#include "switchboard.h" #include "notification.h" -#include "switchboard.h" +#include "sync.h" +#include "slplink.h" #define BUDDY_ALIAS_MAXLEN 387 @@ -82,7 +83,7 @@ const char *alias; session = gc->proto_data; - cmdproc = session->notification_conn->cmdproc; + cmdproc = session->notification->cmdproc; account = gaim_connection_get_account(gc); alias = (entry && *entry) ? entry : ""; @@ -91,7 +92,6 @@ { gaim_notify_error(gc, NULL, _("Your new MSN friendly name is too long."), NULL); - return; } @@ -107,7 +107,7 @@ MsnSession *session; session = gc->proto_data; - cmdproc = session->notification_conn->cmdproc; + cmdproc = session->notification->cmdproc; if (entry == NULL || *entry == '\0') { @@ -153,17 +153,15 @@ static void send_to_mobile(GaimConnection *gc, const char *who, const char *entry) { + MsnTransaction *trans; MsnSession *session; - MsnServConn *servconn; MsnCmdProc *cmdproc; - MsnTransaction *trans; MsnPage *page; char *payload; size_t payload_len; session = gc->proto_data; - servconn = session->notification_conn; - cmdproc = servconn->cmdproc; + cmdproc = session->notification->cmdproc; page = msn_page_new(); msn_page_set_body(page, entry); @@ -262,13 +260,13 @@ gc = (GaimConnection *) action->context; gaim_request_action(gc, NULL, _("Allow MSN Mobile pages?"), - _("Do you want to allow or disallow people on " - "your buddy list to send you MSN Mobile pages " - "to your cell phone or other mobile device?"), - -1, gc, 3, - _("Allow"), G_CALLBACK(enable_msn_pages_cb), - _("Disallow"), G_CALLBACK(disable_msn_pages_cb), - _("Cancel"), NULL); + _("Do you want to allow or disallow people on " + "your buddy list to send you MSN Mobile pages " + "to your cell phone or other mobile device?"), + -1, gc, 3, + _("Allow"), G_CALLBACK(enable_msn_pages_cb), + _("Disallow"), G_CALLBACK(disable_msn_pages_cb), + _("Cancel"), NULL); } static void @@ -286,17 +284,17 @@ gc = gaim_account_get_connection(buddy->account); session = gc->proto_data; - user = msn_users_find_with_passport(session->users, buddy->name); + user = msn_userlist_find_user(session->userlist, buddy->name); data = g_new0(MsnMobileData, 1); data->gc = gc; data->passport = buddy->name; gaim_request_input(gc, NULL, _("Send a mobile message."), NULL, - NULL, TRUE, FALSE, NULL, - _("Page"), G_CALLBACK(send_to_mobile_cb), - _("Close"), G_CALLBACK(close_mobile_page_cb), - data); + NULL, TRUE, FALSE, NULL, + _("Page"), G_CALLBACK(send_to_mobile_cb), + _("Close"), G_CALLBACK(close_mobile_page_cb), + data); } static void @@ -306,33 +304,59 @@ GaimConnection *gc; MsnSession *session; - MsnCmdProc *cmdproc; MsnSwitchBoard *swboard; - MsnUser *user; - + g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); buddy = (GaimBuddy *) node; gc = gaim_account_get_connection(buddy->account); session = gc->proto_data; - cmdproc = session->notification_conn->cmdproc; + + swboard = msn_switchboard_new(session); + msn_switchboard_request(swboard); + msn_switchboard_request_add_user(swboard, buddy->name); + + /* TODO: This might move somewhere else, after USR might be */ + swboard->chat_id = session->conv_seq++; + swboard->conv = serv_got_joined_chat(gc, swboard->chat_id, "MSN Chat"); +} - if ((swboard = msn_session_open_switchboard(session)) == NULL) - return; +static void +t_msn_xfer_init(GaimXfer *xfer) +{ + MsnSlpLink *slplink; - user = msn_user_new(session, buddy->name, NULL); + slplink = xfer->data; - msn_switchboard_set_user(swboard, user); + msn_slplink_request_ft(slplink, xfer); +} - swboard->total_users = 1; +static void +show_send_file_cb(GaimBlistNode *node, gpointer ignored) +{ + GaimBuddy *buddy; + GaimConnection *gc; + MsnSession *session; + MsnSlpLink *slplink; + GaimXfer *xfer; + + g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); + + buddy = (GaimBuddy *) node; - session->last_chat_id++; - swboard->chat_id = session->last_chat_id; - swboard->chat = serv_got_joined_chat(gc, swboard->chat_id, "MSN Chat"); + gc = gaim_account_get_connection(buddy->account); + session = gc->proto_data; + + xfer = gaim_xfer_new(buddy->account, GAIM_XFER_SEND, buddy->name); - gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->chat), - gaim_account_get_username(buddy->account), NULL); + slplink = msn_session_get_slplink(session, buddy->name); + + xfer->data = slplink; + + gaim_xfer_set_init_fnc(xfer, t_msn_xfer_init); + + gaim_xfer_request(xfer); } /************************************************************************** @@ -460,6 +484,8 @@ GList *m = NULL; GaimBlistNodeAction *act; + g_return_val_if_fail(buddy != NULL, NULL); + user = buddy->proto_data; if (user != NULL) @@ -470,6 +496,11 @@ show_send_to_mobile_cb, NULL); m = g_list_append(m, act); } + + act = gaim_blist_node_action_new(_("Send File"), + show_send_file_cb, NULL); + + m = g_list_append(m, act); } if (g_ascii_strcasecmp(buddy->name, @@ -522,7 +553,7 @@ { http_method = TRUE; - gaim_debug(GAIM_DEBUG_INFO, "msn", "using http method\n"); + gaim_debug_info("msn", "using http method\n"); host = "gateway.messenger.hotmail.com"; port = 80; @@ -533,15 +564,14 @@ port = gaim_account_get_int(account, "port", MSN_PORT); } - session = msn_session_new(account, host, port); - session->http_method = http_method; + session = msn_session_new(account, host, port, http_method); session->prpl = my_protocol; if (session->http_method) msn_http_session_init(session); gc->proto_data = session; - gc->flags |= GAIM_CONNECTION_HTML | GAIM_CONNECTION_FORMATTING_WBFO | GAIM_CONNECTION_NO_BGCOLOR | GAIM_CONNECTION_NO_FONTSIZE | GAIM_CONNECTION_NO_URLDESC; + gc->flags |= GAIM_CONNECTION_HTML | GAIM_CONNECTION_FORMATTING_WBFO | GAIM_CONNECTION_NO_BGCOLOR | GAIM_CONNECTION_NO_FONTSIZE | GAIM_CONNECTION_NO_URLDESC;; gaim_connection_update_progress(gc, _("Connecting"), 0, MSN_CONNECT_STEPS); @@ -551,26 +581,22 @@ if (strcmp(username, gaim_account_get_username(account))) gaim_account_set_username(account, username); - if (!msn_session_connect(session)) - { - gaim_connection_error(gc, _("Unable to connect.")); - - return; - } + msn_session_connect(session); } static void msn_close(GaimConnection *gc) { - MsnSession *session = gc->proto_data; + MsnSession *session; + + session = gc->proto_data; - if (session != NULL) - { - if (session->http_method) - msn_http_session_uninit(session); + g_return_if_fail(session != NULL); - msn_session_destroy(session); - } + if (session->http_method) + msn_http_session_uninit(session); + + msn_session_destroy(session); gc->proto_data = NULL; } @@ -588,40 +614,31 @@ MsnSession *session; MsnSwitchBoard *swboard; MsnMessage *msg; - MsnUser *user; char *msgformat; char *msgtext; session = gc->proto_data; - swboard = msn_session_find_switch_with_passport(session, who); - user = msn_user_new(session, who, NULL); + swboard = msn_session_get_swboard(session, who); msn_import_html(message, &msgformat, &msgtext); - msg = msn_message_new_plain(msgtext); msn_message_set_attr(msg, "X-MMS-IM-Format", msgformat); g_free(msgformat); g_free(msgtext); - if (swboard != NULL) + swboard = msn_session_get_swboard(session, who); + + if (!g_queue_is_empty(swboard->im_queue) || + !swboard->user_joined) { - msn_switchboard_send_msg(swboard, msg); + msn_switchboard_queue_msg(swboard, msg); } else { - if ((swboard = msn_session_open_switchboard(session)) == NULL) - { - msn_message_destroy(msg); - - return 1; - } - - msn_switchboard_set_user(swboard, user); msn_switchboard_send_msg(swboard, msg); } - msn_user_destroy(user); msn_message_destroy(msg); } else @@ -630,7 +647,7 @@ * In MSN, you can't send messages to yourself, so * we'll fake like we received it ;) */ - serv_got_typing_stopped(gc, (char *)who); + serv_got_typing_stopped(gc, who); serv_got_im(gc, who, message, flags, time(NULL)); } @@ -659,11 +676,14 @@ return MSN_TYPING_SEND_TIMEOUT; } - swboard = msn_session_find_switch_with_passport(session, who); + swboard = msn_session_find_swboard(session, who); if (swboard == NULL) return 0; + if (!swboard->user_joined) + return 0; + msg = msn_message_new(); msn_message_set_content_type(msg, "text/x-msmsgscontrol"); msn_message_set_flag(msg, 'U'); @@ -682,7 +702,7 @@ msn_set_away(GaimConnection *gc, const char *state, const char *msg) { MsnSession *session; - const char *status; + int status; session = gc->proto_data; @@ -695,37 +715,37 @@ if (msg != NULL) { gc->away = g_strdup(""); - status = "AWY"; + status = MSN_AWAY; } else if (state) { gc->away = g_strdup(""); if (!strcmp(state, _("Away From Computer"))) - status = "AWY"; + status = MSN_AWAY; else if (!strcmp(state, _("Be Right Back"))) - status = "BRB"; + status = MSN_BRB; else if (!strcmp(state, _("Busy"))) - status = "BSY"; + status = MSN_BUSY; else if (!strcmp(state, _("On The Phone"))) - status = "PHN"; + status = MSN_PHONE; else if (!strcmp(state, _("Out To Lunch"))) - status = "LUN"; + status = MSN_LUNCH; else if (!strcmp(state, _("Hidden"))) - status = "HDN"; + status = MSN_HIDDEN; else { g_free(gc->away); gc->away = NULL; - status = "NLN"; + status = MSN_ONLINE; } } else if (gc->is_idle) - status = "IDL"; + status = MSN_IDLE; else - status = "NLN"; + status = MSN_ONLINE; - msn_session_change_status(session, status); + msn_change_status(session, status); } static void @@ -738,228 +758,120 @@ if (gc->away != NULL) return; - msn_session_change_status(session, (idle ? "IDL" : "NLN")); + msn_change_status(session, (idle ? MSN_IDLE : MSN_ONLINE)); } static void msn_add_buddy(GaimConnection *gc, const char *name, GaimGroup *group) { MsnSession *session; - MsnCmdProc *cmdproc; - MsnGroup *msn_group = NULL; + MsnUserList *userlist; const char *who; - GSList *l; session = gc->proto_data; - cmdproc = session->notification_conn->cmdproc; + userlist = session->userlist; who = msn_normalize(gc->account, name); - if (strchr(who, ' ')) - { - /* This is a broken blist entry. */ - return; - } - if (group != NULL) - msn_group = msn_groups_find_with_name(session->groups, group->name); - - /* We should check if the user isn't alredy there. */ - for (l = session->lists.forward; l != NULL; l = l->next) - { - MsnUser *user = l->data; + gaim_debug_info("msn", "msn_add_buddy: %s, %s\n", who, group->name); + else + gaim_debug_info("msn", "msn_add_buddy: %s\n", who); - if (!gaim_utf8_strcasecmp(who, msn_user_get_passport(user))) - { - if (group == NULL) - break; - else if (msn_group != NULL) - { - /* Now we should check if it's in the group. */ - if (g_list_find(user->group_ids, - GINT_TO_POINTER(msn_group->id))) - break; - } - } +#if 0 + /* Which is the max? */ + if (session->fl_users_count >= 150) + { + gaim_debug_info("msn", "Too many buddies\n"); + /* Buddy list full */ + /* TODO: gaim should be notifyied of this */ + return; } - - if (l != NULL) - return; - - if (msn_group != NULL) - { - msn_cmdproc_send(cmdproc, "ADD", "FL %s %s %d", who, who, - msn_group_get_id(msn_group)); - } - else - { - msn_cmdproc_send(cmdproc, "ADD", "FL %s %s", who, who); - } +#endif + + msn_userlist_add_buddy(userlist, who, MSN_LIST_FL, + group ? group->name : NULL); } static void msn_rem_buddy(GaimConnection *gc, const char *who, const char *group_name) { MsnSession *session; - MsnCmdProc *cmdproc; - MsnGroup *group; - GSList *l; - + MsnUserList *userlist; + session = gc->proto_data; - cmdproc = session->notification_conn->cmdproc; - - if (strchr(who, ' ')) - { - /* This is a broken blist entry. */ - return; - } - - group = msn_groups_find_with_name(session->groups, group_name); - - /* We should check if the user is there. */ - for (l = session->lists.forward; l != NULL; l = l->next) - { - MsnUser *user = l->data; + userlist = session->userlist; - if (!gaim_utf8_strcasecmp(who, msn_user_get_passport(user))) - { - if (group_name == NULL) - break; - else if (group != NULL) - { - /* Now we should check if it's in the group. */ - if (g_list_find(user->group_ids, - GINT_TO_POINTER(group->id))) - break; - } - } - } - - if (l == NULL) - return; - - if (group == NULL) - { - msn_cmdproc_send(cmdproc, "REM", "FL %s", who); - } - else - { - msn_cmdproc_send(cmdproc, "REM", "FL %s %d", who, - msn_group_get_id(group)); - } + msn_userlist_rem_buddy(userlist, who, MSN_LIST_FL, group_name); } static void msn_add_permit(GaimConnection *gc, const char *who) { MsnSession *session; - MsnCmdProc *cmdproc; + MsnUserList *userlist; + MsnUser *user; session = gc->proto_data; - cmdproc = session->notification_conn->cmdproc; - - if (!strchr(who, '@')) - { - char buf[MSN_BUF_LEN]; - - g_snprintf(buf, sizeof(buf), - _("An MSN screen name must be in the form \"user@server.com\". " - "Perhaps you meant %s@hotmail.com. No changes were made " - "to your allow list."), who); - - gaim_notify_error(gc, NULL, _("Invalid MSN screen name"), buf); - gaim_privacy_permit_remove(gc->account, who, TRUE); + userlist = session->userlist; + user = msn_userlist_find_user(userlist, who); - return; - } - - if (g_slist_find_custom(gc->account->deny, who, (GCompareFunc)strcasecmp)) - { - gaim_debug_info("msn", "Moving %s from BL to AL\n", who); - gaim_privacy_deny_remove(gc->account, who, TRUE); - - msn_cmdproc_send(cmdproc, "REM", "BL %s", who); - - if (cmdproc->error) - return; - } - - msn_cmdproc_send(cmdproc, "ADD", "AL %s %s", who, who); + if (user->list_op & MSN_LIST_BL_OP) + msn_userlist_rem_buddy(userlist, who, MSN_LIST_BL, NULL); + + msn_userlist_add_buddy(userlist, who, MSN_LIST_AL, NULL); } static void msn_add_deny(GaimConnection *gc, const char *who) { - MsnCmdProc *cmdproc; MsnSession *session; - + MsnUserList *userlist; + MsnUser *user; + session = gc->proto_data; - cmdproc = session->notification_conn->cmdproc; - - if (!strchr(who, '@')) - { - char buf[MSN_BUF_LEN]; - g_snprintf(buf, sizeof(buf), - _("An MSN screen name must be in the form \"user@server.com\". " - "Perhaps you meant %s@hotmail.com. No changes were made " - "to your block list."), who); - - gaim_notify_error(gc, NULL, _("Invalid MSN screen name"), buf); + userlist = session->userlist; + user = msn_userlist_find_user(userlist, who); - gaim_privacy_deny_remove(gc->account, who, TRUE); - - return; - } + if (user->list_op & MSN_LIST_AL_OP) + msn_userlist_rem_buddy(userlist, who, MSN_LIST_AL, NULL); - if (g_slist_find_custom(gc->account->permit, who, (GCompareFunc)strcmp)) - { - gaim_debug(GAIM_DEBUG_INFO, "msn", "Moving %s from AL to BL\n", who); - gaim_privacy_permit_remove(gc->account, who, TRUE); - - msn_cmdproc_send(cmdproc, "REM", "AL %s", who); - - if (cmdproc->error) - return; - } - - msn_cmdproc_send(cmdproc, "ADD", "BL %s %s", who, who); + msn_userlist_add_buddy(userlist, who, MSN_LIST_BL, NULL); } static void msn_rem_permit(GaimConnection *gc, const char *who) { MsnSession *session; - MsnCmdProc *cmdproc; - + MsnUserList *userlist; + MsnUser *user; + session = gc->proto_data; - cmdproc = session->notification_conn->cmdproc; - - msn_cmdproc_send(cmdproc, "REM", "AL %s", who); + userlist = session->userlist; - if (cmdproc->error) - return; + user = msn_userlist_find_user(userlist, who); + + msn_userlist_rem_buddy(userlist, who, MSN_LIST_AL, NULL); - gaim_privacy_deny_add(gc->account, who, TRUE); - - msn_cmdproc_send(cmdproc, "ADD", "BL %s %s", who, who); + if (user->list_op & MSN_LIST_RL_OP) + msn_userlist_add_buddy(userlist, who, MSN_LIST_BL, NULL); } -static void +void msn_rem_deny(GaimConnection *gc, const char *who) { MsnSession *session; - MsnCmdProc *cmdproc; - + MsnUserList *userlist; + MsnUser *user; + session = gc->proto_data; - cmdproc = session->notification_conn->cmdproc; - - msn_cmdproc_send(cmdproc, "REM", "BL %s", who); + userlist = session->userlist; - if (cmdproc->error) - return; + user = msn_userlist_find_user(userlist, who); - gaim_privacy_permit_add(gc->account, who, TRUE); + msn_userlist_rem_buddy(userlist, who, MSN_LIST_BL, NULL); - msn_cmdproc_send(cmdproc, "ADD", "AL %s %s", who, who); + if (user->list_op & MSN_LIST_RL_OP) + msn_userlist_add_buddy(userlist, who, MSN_LIST_AL, NULL); } static void @@ -968,11 +880,10 @@ GaimAccount *account; MsnSession *session; MsnCmdProc *cmdproc; - GSList *s, *t = NULL; account = gaim_connection_get_account(gc); session = gc->proto_data; - cmdproc = session->notification_conn->cmdproc; + cmdproc = session->notification->cmdproc; if (account->perm_deny == GAIM_PRIVACY_ALLOW_ALL || account->perm_deny == GAIM_PRIVACY_DENY_USERS) @@ -983,107 +894,6 @@ { msn_cmdproc_send(cmdproc, "BLP", "%s", "BL"); } - - if (cmdproc->error) - return; - - /* - * This is safe because we'll always come here after we've gotten - * the list off the server, and data is never removed. So if the - * lengths are equal we don't know about anyone locally and so - * there's no sense in going through them all. - */ - if (g_slist_length(gc->account->permit) == - g_slist_length(session->lists.allow)) - { - g_slist_free(session->lists.allow); - session->lists.allow = NULL; - } - - if (g_slist_length(gc->account->deny) == - g_slist_length(session->lists.block)) - { - g_slist_free(session->lists.block); - session->lists.block = NULL; - } - - if (session->lists.allow == NULL && session->lists.block == NULL) - return; - - if (session->lists.allow != NULL) - { - for (s = g_slist_nth(gc->account->permit, - g_slist_length(session->lists.allow)); - s != NULL; - s = s->next) - { - char *who = s->data; - - if (!strchr(who, '@')) - { - t = g_slist_append(t, who); - continue; - } - - if (g_slist_find(session->lists.block, who)) - { - t = g_slist_append(t, who); - continue; - } - - msn_cmdproc_send(cmdproc, "ADD", "AL %s %s", who, who); - - if (cmdproc->error) - return; - } - - for (; t != NULL; t = t->next) - gaim_privacy_permit_remove(gc->account, t->data, TRUE); - - if (t != NULL) - g_slist_free(t); - - t = NULL; - g_slist_free(session->lists.allow); - session->lists.allow = NULL; - } - - if (session->lists.block) - { - for (s = g_slist_nth(gc->account->deny, - g_slist_length(session->lists.block)); - s != NULL; - s = s->next) - { - char *who = s->data; - - if (!strchr(who, '@')) - { - t = g_slist_append(t, who); - continue; - } - - if (g_slist_find(session->lists.block, who)) - { - t = g_slist_append(t, who); - continue; - } - - msn_cmdproc_send(cmdproc, "ADD", "BL %s %s", who, who); - - if (cmdproc->error) - return; - } - - for (; t != NULL; t = t->next) - gaim_privacy_deny_remove(gc->account, t->data, TRUE); - - if (t != NULL) - g_slist_free(t); - - g_slist_free(session->lists.block); - session->lists.block = NULL; - } } static void @@ -1099,7 +909,7 @@ swboard = msn_session_find_switch_with_id(session, id); g_return_if_fail(swboard != NULL); - cmdproc = swboard->cmdproc; + cmdproc = swboard->servconn->cmdproc; msn_cmdproc_send(cmdproc, "CAL", "%s", who); } @@ -1112,6 +922,7 @@ MsnCmdProc *cmdproc; session = gc->proto_data; + swboard = msn_session_find_switch_with_id(session, id); g_return_if_fail(swboard != NULL); @@ -1140,20 +951,21 @@ if (swboard == NULL) return -EINVAL; - msn_import_html(message, &msgformat, &msgtext); - - msg = msn_message_new_plain(msgtext); - msn_message_set_attr(msg, "X-MMS-IM-Format", msgformat); + if (swboard->ready) + { + msn_import_html(message, &msgformat, &msgtext); - g_free(msgformat); - g_free(msgtext); - - msn_switchboard_send_msg(swboard, msg); + msg = msn_message_new_plain(msgtext); + msn_message_set_attr(msg, "X-MMS-IM-Format", msgformat); + msn_switchboard_send_msg(swboard, msg); + msn_message_destroy(msg); - msn_message_destroy(msg); + g_free(msgformat); + g_free(msgtext); - serv_got_chat_in(gc, id, gaim_account_get_username(account), 0, - message, time(NULL)); + serv_got_chat_in(gc, id, gaim_account_get_username(account), 0, + message, time(NULL)); + } return 0; } @@ -1165,7 +977,7 @@ MsnCmdProc *cmdproc; session = gc->proto_data; - cmdproc = session->notification_conn->cmdproc; + cmdproc = session->notification->cmdproc; if (!session->http_method) msn_cmdproc_send_quick(cmdproc, "PNG", NULL, NULL); @@ -1176,68 +988,12 @@ const char *old_group_name, const char *new_group_name) { MsnSession *session; - MsnCmdProc *cmdproc; - MsnGroup *old_group, *new_group; - MsnUser *user; - const char *friendly; - + MsnUserList *userlist; + session = gc->proto_data; - cmdproc = session->notification_conn->cmdproc; - old_group = msn_groups_find_with_name(session->groups, old_group_name); - new_group = msn_groups_find_with_name(session->groups, new_group_name); - - user = msn_users_find_with_passport(session->users, who); - - if ((friendly = msn_user_get_name(user)) == NULL) - friendly = msn_user_get_passport(user); - - if (old_group != NULL) - msn_user_remove_group_id(user, msn_group_get_id(old_group)); - - if (new_group == NULL) - { - msn_cmdproc_send(cmdproc, "ADG", "%s 0", - gaim_url_encode(new_group_name)); - - if (cmdproc->error) - return; - - /* I hate this. So much. */ - session->moving_buddy = TRUE; - session->dest_group_name = g_strdup(new_group_name); - session->old_group = old_group; + userlist = session->userlist; - session->moving_user = - msn_users_find_with_passport(session->users, who); - - msn_user_ref(session->moving_user); - } - else - { - msn_cmdproc_send(cmdproc, "ADD", "FL %s %s %d", - who, gaim_url_encode(friendly), - msn_group_get_id(new_group)); - - if (cmdproc->error) - return; - } - - if (old_group != NULL) - { - msn_cmdproc_send(cmdproc, "REM", "FL %s %d", who, - msn_group_get_id(old_group)); - - if (cmdproc->error) - return; - -#if 0 - if (msn_users_get_count(msn_group_get_users(old_group)) <= 0) - { - msn_cmdproc_send(cmdproc, "RMG", "%d", - msn_group_get_id(old_group)); - } -#endif - } + msn_userlist_move_buddy(userlist, who, old_group_name, new_group_name); } static void @@ -1246,23 +1002,19 @@ { MsnSession *session; MsnCmdProc *cmdproc; - MsnGroup *old_group; + int old_gid; const char *enc_new_group_name; session = gc->proto_data; - cmdproc = session->notification_conn->cmdproc; + cmdproc = session->notification->cmdproc; enc_new_group_name = gaim_url_encode(new_group_name); - if ((old_group = msn_groups_find_with_name(session->groups, - old_group_name)) != NULL) + old_gid = msn_userlist_find_group_id(session->userlist, old_group_name); + + if (old_gid >= 0) { - msn_cmdproc_send(cmdproc, "REG", "%d %s 0", - msn_group_get_id(old_group), enc_new_group_name); - - if (cmdproc->error) - return; - - msn_group_set_name(old_group, new_group_name); + msn_cmdproc_send(cmdproc, "REG", "%d %s 0", old_gid, + enc_new_group_name); } else { @@ -1271,16 +1023,6 @@ } static void -msn_buddy_free(GaimBuddy *b) -{ - if (b->proto_data != NULL) - { - msn_user_destroy(b->proto_data); - b->proto_data = NULL; - } -} - -static void msn_convo_closed(GaimConnection *gc, const char *who) { MsnSession *session; @@ -1289,13 +1031,21 @@ session = gc->proto_data; - swboard = msn_session_find_switch_with_passport(session, who); - g_return_if_fail(swboard != NULL); + swboard = msn_session_find_swboard(session, who); + + /* + * Don't perform an assertion here. It swboard is NULL, then the + * switchboard was either closed by the other party, or the person + * is talking to himself. + */ + if (swboard == NULL) + return; cmdproc = swboard->servconn->cmdproc; - if (swboard->chat == NULL) + if (swboard->current_users == 1) { + /* This must happen on both IM's and Chat's, right? */ GaimAccount *account; account = gaim_connection_get_account(gc); @@ -1318,7 +1068,7 @@ msn_user_set_buddy_icon(user, filename); - msn_session_change_status(session, session->away_state); + msn_change_status(session, session->state); } static void @@ -1326,14 +1076,14 @@ { MsnSession *session; MsnCmdProc *cmdproc; - MsnGroup *group; + int group_id; session = gc->proto_data; - cmdproc = session->notification_conn->cmdproc; + cmdproc = session->notification->cmdproc; - if ((group = msn_groups_find_with_name(session->groups, name)) != NULL) + if ((group_id = msn_userlist_find_group_id(session->userlist, name)) >= 0) { - msn_cmdproc_send(cmdproc, "RMG", "%d", msn_group_get_id(group)); + msn_cmdproc_send(cmdproc, "RMG", "%d", group_id); } } @@ -1355,9 +1105,9 @@ if (url_text == NULL || strcmp(url_text, "") == 0) { gaim_notify_formatted(info_data->gc, NULL, - _("Buddy Information"), NULL, - _("Error retrieving profile"), - NULL, NULL); + _("Buddy Information"), NULL, + _("Error retrieving profile"), + NULL, NULL); return; } @@ -1644,6 +1394,7 @@ { msn_notification_init(); msn_switchboard_init(); + msn_sync_init(); return TRUE; } @@ -1652,6 +1403,7 @@ { msn_notification_end(); msn_switchboard_end(); + msn_sync_end(); return TRUE; } @@ -1686,7 +1438,7 @@ static GaimPluginProtocolInfo prpl_info = { GAIM_PRPL_API_VERSION, - OPT_PROTO_MAIL_CHECK /* | OPT_PROTO_BUDDY_ICON */, + OPT_PROTO_MAIL_CHECK | OPT_PROTO_BUDDY_ICON, NULL, NULL, msn_list_icon, @@ -1728,7 +1480,7 @@ NULL, msn_group_buddy, msn_rename_group, - msn_buddy_free, + NULL, /* msn_buddy_free */ msn_convo_closed, msn_normalize, msn_set_buddy_icon, diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/msn.h --- a/src/protocols/msn/msn.h Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/msn.h Sun Jun 06 02:39:08 2004 +0000 @@ -36,11 +36,13 @@ #include "proxy.h" #include "prpl.h" #include "request.h" -#include "server.h" +#include "servconn.h" #include "sha.h" #include "sslconn.h" #include "util.h" +#include "ft.h" + /* XXX */ #include "gaim.h" @@ -111,4 +113,6 @@ (MSN_CLIENT_ID_RESERVED_2 << 8) | \ (MSN_CLIENT_ID_CAPABILITIES)) +void msn_request_buddy_icon(GaimConnection *gc, const char *who); + #endif /* _MSN_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/nexus.c --- a/src/protocols/msn/nexus.c Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/nexus.c Sun Jun 06 02:39:08 2004 +0000 @@ -65,7 +65,6 @@ { MsnNexus *nexus; MsnSession *session; - GaimConnection *gc; char *username, *password; char *request_str; char *buffer = NULL; @@ -77,9 +76,6 @@ session = nexus->session; g_return_if_fail(session != NULL); - gc = gaim_account_get_connection(session->account); - g_return_if_fail(gc != NULL); - username = g_strdup(gaim_url_encode(gaim_account_get_username(session->account))); @@ -118,7 +114,6 @@ if ((s = gaim_ssl_write(gsc, request_str, strlen(request_str))) <= 0) { g_free(request_str); - gaim_connection_error(gc, _("Unable to write to MSN Nexus server.")); return; } @@ -126,10 +121,7 @@ g_free(request_str); if ((s = msn_ssl_read(gsc, &buffer)) <= 0) - { - gaim_connection_error(gc, _("Unable to write to MSN Nexus server.")); return; - } gaim_ssl_close(gsc); @@ -143,14 +135,10 @@ location = strstr(buffer, "Location: "); if (location == NULL) { - gaim_connection_error(gc, - _("MSN Nexus server returned invalid redirect information.")); - g_free(buffer); return; } - location = strchr(location, ' ') + 1; if ((c = strchr(location, '\r')) != NULL) @@ -209,7 +197,6 @@ } else if (strstr(buffer, "HTTP/1.1 200 OK")) { - MsnCmdProc *cmdproc; char *base, *c; char *login_params; @@ -230,18 +217,9 @@ } #endif - cmdproc = session->notification_conn->cmdproc; base = strstr(buffer, "Authentication-Info: "); - if (base == NULL) - { - gaim_debug(GAIM_DEBUG_ERROR, "msn", - "Authentication information was not found. This did " - "not just happen, but if it did, you're screwed. " - "Report this.\n"); - - return; - } + g_return_if_fail(base != NULL); base = strstr(base, "from-PP='"); base += strlen("from-PP='"); @@ -249,7 +227,7 @@ login_params = g_strndup(base, c - base); - msn_cmdproc_send(cmdproc, "USR", "TWN S %s", login_params); + msn_got_login_params(session, login_params); g_free(login_params); diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/nexus.h --- a/src/protocols/msn/nexus.h Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/nexus.h Sun Jun 06 02:39:08 2004 +0000 @@ -3,7 +3,7 @@ typedef struct _MsnNexus MsnNexus; -#include "session.h" +#include "nexus.h" struct _MsnNexus { diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/notification.c --- a/src/protocols/msn/notification.c Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/notification.c Sun Jun 06 02:39:08 2004 +0000 @@ -24,174 +24,29 @@ #include "state.h" #include "error.h" #include "utils.h" - -typedef struct -{ - GaimConnection *gc; - MsnUser *user; - -} MsnPermitAdd; - -static MsnTable *cbs_table = NULL; - -/************************************************************************** - * Utility functions - **************************************************************************/ -static gboolean -add_buddy(MsnCmdProc *cmdproc, MsnUser *user) -{ - MsnSession *session; - GaimAccount *account; - GaimConnection *gc; - GaimBuddy *b; - MsnGroup *group = NULL; - GaimGroup *g = NULL; - GList *l, *l2; - GSList *sl; - GSList *buddies; - - session = cmdproc->session; - account = session->account; - gc = gaim_account_get_connection(account); - buddies = gaim_find_buddies(account, msn_user_get_passport(user)); - - for (l = msn_user_get_group_ids(user); l != NULL; l = l->next) - { - int group_id = GPOINTER_TO_INT(l->data); - - if (group_id > -1) - group = msn_groups_find_with_id(session->groups, group_id); - - if (group == NULL) - { - gaim_debug(GAIM_DEBUG_WARNING, "msn", - "Group ID %d for user %s was not defined.\n", - group_id, msn_user_get_passport(user)); - - /* Find a group that we can stick this guy into. Lamer. */ - l2 = msn_groups_get_list(session->groups); - - if (l2 != NULL) - { - group = l2->data; - - msn_user_add_group_id(user, msn_group_get_id(group)); - } - } - - if (group == NULL || - (g = gaim_find_group(msn_group_get_name(group))) == NULL) - { - gaim_debug(GAIM_DEBUG_ERROR, "msn", - "Group '%s' appears in server-side " - "buddy list, but not here!", - msn_group_get_name(group)); - } - - if (group != NULL) - msn_group_add_user(group, user); - - b = NULL; - - for (sl = buddies; sl != NULL; sl = sl->next) - { - b = (GaimBuddy *)sl->data; - - if (gaim_find_buddys_group(b) == g) - break; - - b = NULL; - } +#include "page.h" - if (b == NULL) - { - const char *passport, *friendly; - - passport = msn_user_get_passport(user); - - b = gaim_buddy_new(account, passport, NULL); - - b->proto_data = user; - - gaim_blist_add_buddy(b, NULL, g, NULL); - - if ((friendly = msn_user_get_name(user)) != NULL) - serv_got_alias(gc, passport, friendly); - } - else - b->proto_data = user; - } - - g_slist_free(buddies); - - serv_got_alias(gc, (char *)msn_user_get_passport(user), - (char *)msn_user_get_name(user)); - - return TRUE; -} - -/************************************************************************** - * Callbacks - **************************************************************************/ -static void -msn_accept_add_cb(MsnPermitAdd *pa) -{ - if (g_list_find(gaim_connections_get_all(), pa->gc) != NULL) - { - MsnSession *session; - MsnCmdProc *cmdproc; - - session = pa->gc->proto_data; - cmdproc = session->notification_conn->cmdproc; +#include "userlist.h" +#include "sync.h" - msn_cmdproc_send(cmdproc, "ADD", "AL %s %s", - msn_user_get_passport(pa->user), - gaim_url_encode(msn_user_get_name(pa->user))); - - if (cmdproc->error) - return; - - gaim_privacy_permit_add(pa->gc->account, - msn_user_get_passport(pa->user), TRUE); - gaim_account_notify_added(pa->gc->account, NULL, - msn_user_get_passport(pa->user), - msn_user_get_name(pa->user), NULL); - } - - msn_user_destroy(pa->user); - g_free(pa); -} +#define BUDDY_ALIAS_MAXLEN 388 -static void -msn_cancel_add_cb(MsnPermitAdd *pa) -{ - if (g_list_find(gaim_connections_get_all(), pa->gc) != NULL) - { - MsnSession *session; - MsnCmdProc *cmdproc; - - session = pa->gc->proto_data; - cmdproc = session->notification_conn->cmdproc; - - msn_cmdproc_send(cmdproc, "ADD", "BL %s %s", - msn_user_get_passport(pa->user), - gaim_url_encode(msn_user_get_name(pa->user))); - - if (cmdproc->error) - return; - - gaim_privacy_deny_add(pa->gc->account, - msn_user_get_passport(pa->user), TRUE); - } - - msn_user_destroy(pa->user); - g_free(pa); -} +static MsnTable *cbs_table; /************************************************************************** * Login **************************************************************************/ +void +msn_got_login_params(MsnSession *session, const char *login_params) +{ + MsnCmdProc *cmdproc; + + cmdproc = session->notification->cmdproc; + + msn_cmdproc_send(cmdproc, "USR", "TWN S %s", login_params); +} + static void cvr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { @@ -214,8 +69,7 @@ if (strcmp(cmd->params[1], "MD5")) { - gaim_connection_error(gc, _("Unable to login using MD5")); - + msn_cmdproc_show_error(cmdproc, MSN_ERROR_MISC); return; } @@ -254,8 +108,6 @@ gaim_connection_set_display_name(gc, friendly); - session->syncing_lists = TRUE; - msn_cmdproc_send(cmdproc, "SYN", "%s", "0"); if (cmdproc->error) @@ -272,6 +124,7 @@ session->nexus = msn_nexus_new(session); /* Parse the challenge data. */ + elems = g_strsplit(cmd->params[3], ",", 0); for (cur = elems; *cur != NULL; cur++) @@ -325,14 +178,12 @@ { MsnSession *session; GaimAccount *account; - GaimConnection *gc; gboolean protocol_supported = FALSE; char proto_str[8]; size_t i; session = cmdproc->session; account = session->account; - gc = gaim_account_get_connection(account); g_snprintf(proto_str, sizeof(proto_str), "MSNP%d", session->protocol_ver); @@ -347,21 +198,13 @@ if (!protocol_supported) { - gaim_connection_error(gc, _("Protocol not supported")); - + msn_cmdproc_show_error(cmdproc, MSN_ERROR_MISC); return; } - if (session->protocol_ver >= 8) - { - msn_cmdproc_send(cmdproc, "CVR", - "0x0409 winnt 5.1 i386 MSNMSGR 6.0.0602 MSMSGS %s", - gaim_account_get_username(account)); - } - else - { - msn_cmdproc_send(cmdproc, "INF", NULL, NULL); - } + msn_cmdproc_send(cmdproc, "CVR", + "0x0409 winnt 5.1 i386 MSNMSGR 6.0.0602 MSMSGS %s", + gaim_account_get_username(account)); } /************************************************************************** @@ -370,41 +213,28 @@ static void out_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - GaimConnection *gc; - - gc = cmdproc->session->account->gc; - if (!g_ascii_strcasecmp(cmd->params[0], "OTH")) - { - gc->wants_to_die = TRUE; - gaim_connection_error(gc, - _("You have been disconnected. You have " - "signed on from another location.")); - } + msn_cmdproc_show_error(cmdproc, MSN_ERROR_SIGNOTHER); else if (!g_ascii_strcasecmp(cmd->params[0], "SSD")) - { - gaim_connection_error(gc, - _("You have been disconnected. The MSN servers " - "are going down temporarily.")); - } + msn_cmdproc_show_error(cmdproc, MSN_ERROR_SERVDOWN); } /************************************************************************** * Messages **************************************************************************/ static void -msg_cmd_post(MsnCmdProc *cmdproc, char *payload, size_t len) +msg_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, + size_t len) { MsnMessage *msg; - msg = msn_message_new(); + msg = msn_message_new_from_cmd(cmdproc->session, cmd); msn_message_parse_payload(msg, payload, len); + /* msn_message_show_readable(msg, "Notification", TRUE); */ - msg->passport = cmdproc->temp; + msg->remote_user = g_strdup(cmd->params[0]); msn_cmdproc_process_msg(cmdproc, msg); - g_free(cmdproc->temp); - cmdproc->temp = NULL; msn_message_destroy(msg); } @@ -412,9 +242,20 @@ static void msg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - cmdproc->payload_cb = msg_cmd_post; - cmdproc->servconn->payload_len = atoi(cmd->params[2]); - cmdproc->temp = g_strdup(cmd->params[0]); + /* NOTE: cmd is not always cmdproc->last_cmd, sometimes cmd is a queued + * command and we are processing it */ + + if (cmd->payload == NULL) + { + cmdproc->last_cmd->payload_cb = msg_cmd_post; + cmdproc->servconn->payload_len = atoi(cmd->params[2]); + } + else + { + g_return_if_fail(cmd->payload_cb != NULL); + + cmd->payload_cb(cmdproc, cmd, cmd->payload, cmd->payload_len); + } } /************************************************************************** @@ -423,31 +264,18 @@ static void chl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - MsnSession *session; MsnTransaction *trans; char buf[33]; const char *challenge_resp; - const char *challenge_str; md5_state_t st; md5_byte_t di[16]; int i; - session = cmdproc->session; - md5_init(&st); md5_append(&st, (const md5_byte_t *)cmd->params[1], strlen(cmd->params[1])); - if (session->protocol_ver >= 8) - { - challenge_resp = "VT6PX?UQTM4WM%YR"; - challenge_str = "PROD0038W!61ZTF9"; - } - else - { - challenge_resp = "Q1P7W2E4J9R8U3S5"; - challenge_str = "msmsgs@msnmsgr.com"; - } + challenge_resp = "VT6PX?UQTM4WM%YR"; md5_append(&st, (const md5_byte_t *)challenge_resp, strlen(challenge_resp)); @@ -456,7 +284,7 @@ for (i = 0; i < 16; i++) g_snprintf(buf + (i*2), 3, "%02x", di[i]); - trans = msn_transaction_new("QRY", "%s 32", challenge_str); + trans = msn_transaction_new("QRY", "%s 32", "PROD0038W!61ZTF9"); msn_transaction_set_payload(trans, buf, 32); @@ -471,57 +299,34 @@ { MsnSession *session; MsnUser *user; - GaimAccount *account; - GaimConnection *gc; - MsnPermitAdd *pa; - GSList *sl; - const char *list, *passport, *group_id = NULL; - const char *friend; - char msg[MSN_BUF_LEN]; - - session = cmdproc->session; - account = session->account; - gc = gaim_account_get_connection(account); + const char *list; + const char *passport; + const char *friendly; + MsnListId list_id; + int group_id; list = cmd->params[1]; passport = cmd->params[3]; - friend = gaim_url_decode(cmd->params[4]); - - if (cmd->param_count >= 6) - group_id = cmd->params[5]; - - if (!g_ascii_strcasecmp(list, "FL")) - { - user = msn_user_new(session, passport, NULL); + friendly = gaim_url_decode(cmd->params[4]); - if (group_id != NULL) - msn_user_add_group_id(user, atoi(group_id)); - - add_buddy(cmdproc, user); + session = cmdproc->session; - return; - } - else if (g_ascii_strcasecmp(list, "RL")) - return; + user = msn_userlist_find_user(session->userlist, passport); - for (sl = gc->account->permit; sl != NULL; sl = sl->next) - if (!gaim_utf8_strcasecmp(sl->data, passport)) - return; - - user = msn_user_new(session, passport, friend); - msn_user_set_name(user, friend); + if (user == NULL) + { + user = msn_user_new(session->userlist, passport, friendly); + msn_userlist_add_user(session->userlist, user); + } - pa = g_new0(MsnPermitAdd, 1); - pa->user = user; - pa->gc = gc; + list_id = msn_get_list_id(list); + + if (cmd->param_count >= 6) + group_id = atoi(cmd->params[5]); + else + group_id = -1; - g_snprintf(msg, sizeof(msg), - _("The user %s (%s) wants to add %s to his or her buddy list."), - passport, friend, gaim_account_get_username(account)); - - gaim_request_action(gc, NULL, msg, NULL, 0, pa, 2, - _("Authorize"), G_CALLBACK(msn_accept_add_cb), - _("Deny"), G_CALLBACK(msn_cancel_add_cb)); + msn_got_add_user(session, user, list_id, group_id); } static void @@ -585,6 +390,7 @@ g_strfreev(params); } + static void adg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { @@ -599,98 +405,24 @@ group_name = gaim_url_decode(cmd->params[2]); - group = msn_group_new(session, group_id, group_name); - - msn_groups_add(session->groups, group); -} - -static void -blp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - GaimConnection *gc; - const char *list_name; - - gc = cmdproc->session->account->gc; - - if (cmdproc->session->protocol_ver >= 8) - list_name = cmd->params[0]; - else - list_name = cmd->params[2]; + group = msn_group_new(session->userlist, group_id, group_name); - if (!g_ascii_strcasecmp(list_name, "AL")) + /* There is a user that must me moved to this group */ + if (cmd->trans->data) { - /* - * If the current setting is AL, messages from users who - * are not in BL will be delivered. - * - * In other words, deny some. - */ - gc->account->perm_deny = GAIM_PRIVACY_DENY_USERS; - } - else - { - /* If the current setting is BL, only messages from people - * who are in the AL will be delivered. - * - * In other words, permit some. - */ - gc->account->perm_deny = GAIM_PRIVACY_ALLOW_USERS; - } -} + /* msn_userlist_move_buddy(); */ + MsnUserList *userlist = cmdproc->session->userlist; + MsnMoveBuddy *data = cmd->trans->data; -static void -bpr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSession *session; - GaimConnection *gc; - const char *passport, *type, *value; - GaimBuddy *b; - MsnUser *user; - - session = cmdproc->session; - gc = session->account->gc; - - if (cmd->param_count == 4) - { - passport = cmd->params[1]; - type = cmd->params[2]; - value = cmd->params[3]; - } - else if (cmd->param_count == 2) - { - passport = msn_user_get_passport(session->last_user_added); - type = cmd->params[0]; - value = cmd->params[1]; - } - else - return; + if (data->old_group_name != NULL) + { + msn_userlist_rem_buddy(userlist, data->who, MSN_LIST_FL, data->old_group_name); + g_free(data->old_group_name); + } + + msn_userlist_add_buddy(userlist, data->who, MSN_LIST_FL, group_name); + g_free(data->who); - user = msn_users_find_with_passport(session->users, passport); - - if (value != NULL) - { - if (!strcmp(type, "MOB")) - { - if (!strcmp(value, "Y") || !strcmp(value, "N")) - { - user->mobile = (!strcmp(value, "Y") ? TRUE : FALSE); - - if ((b = gaim_find_buddy(gc->account, passport)) != NULL) - { - if (GAIM_BUDDY_IS_ONLINE(b)) - { - serv_got_update(gc, (char *)passport, - 1, 0, 0, 0, b->uc); - } - } - } - } - else if (!strcmp(type, "PHH")) - msn_user_set_home_phone(user, gaim_url_decode(value)); - else if (!strcmp(type, "PHW")) - msn_user_set_work_phone(user, gaim_url_decode(value)); - else if (!strcmp(type, "PHM")) - msn_user_set_mobile_phone(user, gaim_url_decode(value)); } } @@ -712,7 +444,7 @@ MsnUser *user; MsnObject *msnobj; int status = 0; - const char *state, *passport, *friend; + const char *state, *passport, *friendly; GaimBuddy *b; session = cmdproc->session; @@ -720,13 +452,14 @@ state = cmd->params[1]; passport = cmd->params[2]; - friend = gaim_url_decode(cmd->params[3]); + friendly = gaim_url_decode(cmd->params[3]); - user = msn_users_find_with_passport(session->users, passport); + user = msn_userlist_find_user(session->userlist, passport); - serv_got_alias(gc, passport, friend); + /* serv_got_nick(gc, passport, friendly); */ + serv_got_alias(gc, passport, friendly); - msn_user_set_name(user, friend); + msn_user_set_friendly_name(user, friendly); if (session->protocol_ver >= 9 && cmd->param_count == 6) { @@ -750,373 +483,22 @@ else if (!g_ascii_strcasecmp(state, "LUN")) status |= UC_UNAVAILABLE | (MSN_LUNCH << 1); - serv_got_update(gc, (char *)passport, 1, 0, 0, 0, status); + serv_got_update(gc, passport, 1, 0, 0, 0, status); +} + +static void +ipg_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len) +{ +#if 0 + gaim_debug_misc("msn", "Incoming Page: {%s}\n", payload); +#endif } static void ipg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - cmdproc->payload_cb = NULL; cmdproc->servconn->payload_len = atoi(cmd->params[0]); -} - -static void -lsg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSession *session; - MsnGroup *group; - GaimGroup *g; - const char *name; - int num_groups, group_id; - - session = cmdproc->session; - - if (session->protocol_ver >= 8) - { - group_id = atoi(cmd->params[0]); - name = gaim_url_decode(cmd->params[1]); - } - else - { - num_groups = atoi(cmd->params[3]); - group_id = atoi(cmd->params[4]); - name = gaim_url_decode(cmd->params[5]); - - if (num_groups == 0) - return; - - if (!strcmp(name, "~")) - name = _("Buddies"); - } - - group = msn_group_new(session, group_id, name); - - msn_groups_add(session->groups, group); - - if ((g = gaim_find_group(name)) == NULL) - { - g = gaim_group_new(name); - gaim_blist_add_group(g, NULL); - } -} - -static void -lst_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSession *session; - GaimAccount *account; - GaimConnection *gc; - const char *passport = NULL; - const char *friend = NULL; - - session = cmdproc->session; - account = session->account; - gc = gaim_account_get_connection(account); - - if (session->protocol_ver >= 8) - { - const char *group_nums; - int list_op; - - passport = cmd->params[0]; - friend = gaim_url_decode(cmd->params[1]); - list_op = atoi(cmd->params[2]); - group_nums = cmd->params[3]; - - if (list_op & MSN_LIST_FL_OP) - { - MsnUser *user; - char **c; - char **tokens; - - user = msn_user_new(session, passport, friend); - - /* Ensure we have a friendly name set. */ - msn_user_set_name(user, friend); - - tokens = g_strsplit((group_nums ? group_nums : ""), ",", -1); - - gaim_debug_misc("msn", "Fetching group IDs from '%s'\n", - group_nums); - for (c = tokens; *c != NULL; c++) - { - gaim_debug_misc("msn", "Appending group ID %d\n", atoi(*c)); - msn_user_add_group_id(user, atoi(*c)); - } - - g_strfreev(tokens); - - session->lists.forward = - g_slist_append(session->lists.forward, user); - - session->last_user_added = user; - } - - if (list_op & MSN_LIST_AL_OP) - { - /* These are users who are allowed to see our status. */ - - if (g_slist_find_custom(account->deny, passport, - (GCompareFunc)strcmp)) - { - gaim_privacy_deny_remove(gc->account, passport, TRUE); - } - - gaim_privacy_permit_add(account, passport, TRUE); - } - - if (list_op & MSN_LIST_BL_OP) - { - /* These are users who are not allowed to see our status. */ - gaim_privacy_deny_add(account, passport, TRUE); - } - - if (list_op & MSN_LIST_RL_OP) - { - /* These are users who have us on their contact list. */ - - gboolean new_entry = TRUE; - - if (g_slist_find_custom(account->permit, passport, - (GCompareFunc)g_ascii_strcasecmp) || - g_slist_find_custom(account->deny, passport, - (GCompareFunc)g_ascii_strcasecmp)) - { - new_entry = FALSE; - } - - if (new_entry) - { - MsnPermitAdd *pa; - char msg[MSN_BUF_LEN]; - - pa = g_new0(MsnPermitAdd, 1); - pa->user = msn_user_new(session, passport, friend); - pa->gc = gc; - - /* Ensure we have a friendly name set. */ - msn_user_set_name(pa->user, friend); - - g_snprintf(msg, sizeof(msg), - _("The user %s (%s) wants to add you to their " - "buddy list."), - msn_user_get_passport(pa->user), - msn_user_get_name(pa->user)); - - gaim_request_action(gc, NULL, msg, NULL, 0, pa, 2, - _("Authorize"), - G_CALLBACK(msn_accept_add_cb), - _("Deny"), - G_CALLBACK(msn_cancel_add_cb)); - } - } - - session->num_users++; - - if (session->num_users == session->total_users) - { - msn_user_set_buddy_icon(session->user, - gaim_account_get_buddy_icon(session->account)); - - if (!msn_session_change_status(session, "NLN")) - return; - - gaim_connection_set_state(gc, GAIM_CONNECTED); - serv_finish_login(gc); - - if (session->lists.allow == NULL) - session->lists.allow = g_slist_copy(account->permit); - else - session->lists.allow = g_slist_concat(session->lists.allow, - account->permit); - - if (session->lists.block == NULL) - session->lists.block = g_slist_copy(account->permit); - else - session->lists.block = g_slist_concat(session->lists.block, - account->deny); - - while (session->lists.forward != NULL) - { - MsnUser *user = session->lists.forward->data; - GSList *buddies; - GSList *sl; - - session->lists.forward = - g_slist_remove(session->lists.forward, user); - - add_buddy(cmdproc, user); - - buddies = gaim_find_buddies(account, - msn_user_get_passport(user)); - - /* Find all occurrences of this buddy in the wrong place. */ - for (sl = buddies; sl != NULL; sl = sl->next) - { - GaimBuddy *b = sl->data; - - if (b->proto_data == NULL) - { - gaim_debug_warning("msn", - "Deleting misplaced user %s (%s) during sync " - "with server.\n", - b->name, gaim_find_buddys_group(b)->name); - - gaim_blist_remove_buddy(b); - } - } - - g_slist_free(buddies); - } - - session->syncing_lists = FALSE; - session->lists_synced = TRUE; - } - } - else - { - const char *list_name; - int user_num; - int num_users; - - list_name = cmd->params[1]; - user_num = atoi(cmd->params[3]); - num_users = atoi(cmd->params[4]); - - if (g_ascii_strcasecmp(list_name, "RL") && - user_num == 0 && num_users == 0) - { - return; /* There are no users on this list. */ - } - - if (num_users > 0) - { - passport = cmd->params[5]; - friend = gaim_url_decode(cmd->params[6]); - } - - if (session->syncing_lists && session->lists_synced) - return; - - if (!g_ascii_strcasecmp(list_name, "FL") && user_num != 0) - { - /* These are users on our contact list. */ - MsnUser *user; - - user = msn_user_new(session, passport, friend); - - if (cmd->param_count == 8) - msn_user_add_group_id(user, atoi(cmd->params[7])); - - session->lists.forward = - g_slist_append(session->lists.forward, user); - } - else if (!g_ascii_strcasecmp(list_name, "AL") && user_num != 0) - { - /* These are users who are allowed to see our status. */ - if (g_slist_find_custom(gc->account->deny, passport, - (GCompareFunc)strcmp)) - { - gaim_debug(GAIM_DEBUG_INFO, "msn", - "Moving user from deny list to permit: %s (%s)\n", - passport, friend); - - gaim_privacy_deny_remove(gc->account, passport, TRUE); - } - - gaim_privacy_permit_add(gc->account, passport, TRUE); - } - else if (!g_ascii_strcasecmp(list_name, "BL") && user_num != 0) - { - /* These are users who are not allowed to see our status. */ - gaim_privacy_deny_add(gc->account, passport, TRUE); - } - else if (!g_ascii_strcasecmp(list_name, "RL")) - { - /* These are users who have us on their contact list. */ - if (user_num > 0) - { - gboolean new_entry = TRUE; - - if (g_slist_find_custom(gc->account->permit, passport, - (GCompareFunc)g_ascii_strcasecmp)) - { - new_entry = FALSE; - } - - if (g_slist_find_custom(gc->account->deny, passport, - (GCompareFunc)g_ascii_strcasecmp)) - { - new_entry = FALSE; - } - - if (new_entry) - { - MsnPermitAdd *pa; - char msg[MSN_BUF_LEN]; - - gaim_debug(GAIM_DEBUG_WARNING, "msn", - "Unresolved MSN RL entry: %s\n", passport); - - pa = g_new0(MsnPermitAdd, 1); - pa->user = msn_user_new(session, passport, friend); - pa->gc = gc; - - msn_user_set_name(pa->user, friend); - - g_snprintf(msg, sizeof(msg), - _("The user %s (%s) wants to add you to their " - "buddy list."), - msn_user_get_passport(pa->user), - msn_user_get_name(pa->user)); - - gaim_request_action(gc, NULL, msg, NULL, 0, pa, 2, - _("Authorize"), - G_CALLBACK(msn_accept_add_cb), - _("Deny"), - G_CALLBACK(msn_cancel_add_cb)); - } - } - - if (user_num != num_users) - return; /* This isn't the last one in the RL. */ - - /* Now we're at the last one, so we can do final work. */ - if (!session->lists_synced) - { - if (!msn_session_change_status(session, "NLN")) - return; - - gaim_connection_set_state(gc, GAIM_CONNECTED); - serv_finish_login(gc); - } - - if (session->lists.allow == NULL) - session->lists.allow = g_slist_copy(gc->account->permit); - else - session->lists.allow = g_slist_concat(session->lists.allow, - gc->account->permit); - - if (session->lists.block == NULL) - session->lists.block = g_slist_copy(gc->account->deny); - else - session->lists.block = g_slist_concat(session->lists.block, - gc->account->deny); - - while (session->lists.forward != NULL) - { - MsnUser *user = session->lists.forward->data; - - session->lists.forward = - g_slist_remove(session->lists.forward, user); - - add_buddy(cmdproc, user); - } - - session->syncing_lists = FALSE; - session->lists_synced = TRUE; - } - } + cmdproc->last_cmd->payload_cb = ipg_cmd_post; } static void @@ -1128,7 +510,7 @@ MsnObject *msnobj; const char *state; const char *passport; - const char *friend; + const char *friendly; int status = 0; session = cmdproc->session; @@ -1136,13 +518,14 @@ state = cmd->params[0]; passport = cmd->params[1]; - friend = gaim_url_decode(cmd->params[2]); + friendly = gaim_url_decode(cmd->params[2]); - user = msn_users_find_with_passport(session->users, passport); + user = msn_userlist_find_user(session->userlist, passport); - serv_got_alias(gc, passport, friend); + /* serv_got_nick(gc, passport, friendly); */ + serv_got_alias(gc, passport, friendly); - msn_user_set_name(user, friend); + msn_user_set_friendly_name(user, friendly); if (session->protocol_ver >= 9 && cmd->param_count == 5) { @@ -1167,9 +550,37 @@ } static void -not_cmd_post(MsnCmdProc *cmdproc, char *payload, size_t len) +chg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + char *state = cmd->params[1]; + int state_id = 0; + + if (!strcmp(state, "NLN")) + state_id = MSN_ONLINE; + else if (!strcmp(state, "BSY")) + state_id = MSN_BUSY; + else if (!strcmp(state, "IDL")) + state_id = MSN_IDLE; + else if (!strcmp(state, "BRB")) + state_id = MSN_BRB; + else if (!strcmp(state, "AWY")) + state_id = MSN_AWAY; + else if (!strcmp(state, "PHN")) + state_id = MSN_PHONE; + else if (!strcmp(state, "LUN")) + state_id = MSN_LUNCH; + else if (!strcmp(state, "HDN")) + state_id = MSN_HIDDEN; + + cmdproc->session->state = state_id; +} + + +static void +not_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len) { #if 0 + MSN_SET_PARAMS("NOT %d\r\n%s", cmdproc->servconn->payload, payload); gaim_debug_misc("msn", "Notification: {%s}\n", payload); #endif } @@ -1178,153 +589,76 @@ not_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { cmdproc->servconn->payload_len = atoi(cmd->params[0]); - cmdproc->payload_cb = not_cmd_post; -} - -static void -prp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSession *session; - const char *type, *value; - - session = cmdproc->session; - - type = cmd->params[2]; - value = cmd->params[3]; - - if (cmd->param_count == 4) - { - if (!strcmp(type, "PHH")) - msn_user_set_home_phone(session->user, gaim_url_decode(value)); - else if (!strcmp(type, "PHW")) - msn_user_set_work_phone(session->user, gaim_url_decode(value)); - else if (!strcmp(type, "PHM")) - msn_user_set_mobile_phone(session->user, gaim_url_decode(value)); - } + cmdproc->last_cmd->payload_cb = not_cmd_post; } static void rea_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { + /* TODO: This might be with us too */ + MsnSession *session; GaimConnection *gc; - const char *friend; + const char *friendly; session = cmdproc->session; gc = session->account->gc; - friend = gaim_url_decode(cmd->params[3]); + friendly = gaim_url_decode(cmd->params[3]); - gaim_connection_set_display_name(gc, friend); + gaim_connection_set_display_name(gc, friendly); } static void reg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session; - MsnGroup *group; int group_id; const char *group_name; session = cmdproc->session; group_id = atoi(cmd->params[2]); - group_name = gaim_url_decode(cmd->params[3]); - group = msn_groups_find_with_id(session->groups, group_id); - - gaim_debug(GAIM_DEBUG_INFO, "msn", "Renamed group %s to %s\n", - msn_group_get_name(group), group_name); - - if (group != NULL) - msn_group_set_name(group, group_name); + msn_userlist_rename_group_id(session->userlist, group_id, group_name); } static void rem_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session; + MsnUser *user; + const char *list; const char *passport; + MsnListId list_id; + int group_id; session = cmdproc->session; + list = cmd->params[1]; passport = cmd->params[3]; + user = msn_userlist_find_user(session->userlist, passport); + + g_return_if_fail(user != NULL); + + list_id = msn_get_list_id(list); if (cmd->param_count == 5) - { - MsnUser *user; - int group_id = atoi(cmd->params[4]); - - user = msn_users_find_with_passport(session->users, passport); - - msn_user_remove_group_id(user, group_id); - } - - /* I hate this. */ - /* shx: it won't be here for long. */ - if (session->moving_buddy) - { - MsnGroup *group, *old_group; - const char *friendly; - - group = msn_groups_find_with_name(session->groups, - session->dest_group_name); - - old_group = session->old_group; - - session->moving_buddy = FALSE; - session->old_group = NULL; - - if (group == NULL) - { - gaim_debug_error("msn", - "Still don't have a group ID for %s while moving %s!\n", - session->dest_group_name, passport); + group_id = atoi(cmd->params[4]); + else + group_id = -1; - g_free(session->dest_group_name); - session->dest_group_name = NULL; - - return; - } - - g_free(session->dest_group_name); - session->dest_group_name = NULL; - - if ((friendly = msn_user_get_name(session->moving_user)) == NULL) - friendly = passport; - - msn_cmdproc_send(cmdproc, "ADD", "FL %s %s %d", - passport, gaim_url_encode(friendly), - msn_group_get_id(group)); - - if (cmdproc->error) - return; - - if (old_group != NULL) - msn_group_remove_user(old_group, session->moving_user); - - msn_user_unref(session->moving_user); - - session->moving_user = NULL; - - if (old_group != NULL && - msn_users_get_count(msn_group_get_users(old_group)) <= 0) - { - msn_cmdproc_send(cmdproc, "RMG", "%s", "%d", - msn_group_get_id(old_group)); - } - } + msn_got_rem_user(session, user, list_id, group_id); } static void rmg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session; - MsnGroup *group; + int group_id; session = cmdproc->session; - group = msn_groups_find_with_id(session->groups, atoi(cmd->params[2])); + group_id = atoi(cmd->params[2]); - if (group != NULL) - msn_groups_remove(session->groups, group); + msn_userlist_remove_group_id(session->userlist, group_id); } static void @@ -1332,44 +666,28 @@ { MsnSession *session; GaimConnection *gc; + int total_users; session = cmdproc->session; gc = gaim_account_get_connection(session->account); - - if (session->protocol_ver >= 8) - { - if (cmd->param_count == 2) - { - char *buf; - - /* - * This can happen if we sent a SYN with an up-to-date - * buddy list revision, but we send 0 to get a full list. - * So, error out. - */ - buf = g_strdup_printf( - _("Your MSN buddy list for %s is temporarily unavailable. " - "Please wait and try again."), - gaim_account_get_username(session->account)); + total_users = atoi(cmd->params[2]); - gaim_connection_error(gc, buf); - - g_free(buf); - - return; - } + if (total_users == 0) + { + gaim_connection_set_state(gc, GAIM_CONNECTED); + serv_finish_login(gc); + } + else + { + /* syn_table */ + MsnSync *sync; - session->total_users = atoi(cmd->params[2]); - session->total_groups = atoi(cmd->params[3]); + sync = msn_sync_new(session); + sync->total_users = total_users; + sync->old_cbs_table = cmdproc->cbs_table; - if (session->total_users == 0) - { - gaim_connection_set_state(gc, GAIM_CONNECTED); - serv_finish_login(gc); - - session->syncing_lists = FALSE; - session->lists_synced = TRUE; - } + session->sync = sync; + cmdproc->cbs_table = sync->cbs_table; } } @@ -1480,7 +798,9 @@ */ char *tmp; - if ((tmp = g_strdup_printf("%s.html", session->passport_info.file)) != NULL) + if ((tmp = + g_strdup_printf("%s.html", session->passport_info.file)) + != NULL) { if (rename(session->passport_info.file, tmp) == 0) { @@ -1501,46 +821,27 @@ { MsnSession *session; MsnSwitchBoard *swboard; - MsnUser *user; const char *session_id; - char *host, *c; + char *host; int port; session = cmdproc->session; session_id = cmd->params[0]; - host = g_strdup(cmd->params[1]); - - if ((c = strchr(host, ':')) != NULL) - { - *c = '\0'; - port = atoi(c + 1); - } - else - port = 1863; + msn_parse_socket(cmd->params[1], &host, &port); if (session->http_method) port = 80; swboard = msn_switchboard_new(session); - user = msn_user_new(session, cmd->params[4], NULL); - msn_switchboard_set_invited(swboard, TRUE); msn_switchboard_set_session_id(swboard, cmd->params[0]); msn_switchboard_set_auth_key(swboard, cmd->params[3]); - msn_switchboard_set_user(swboard, user); + swboard->im_user = g_strdup(cmd->params[4]); + /* msn_switchboard_add_user(swboard, cmd->params[4]); */ - if (!msn_switchboard_connect(swboard, host, port)) - { - gaim_debug_error("msn", - "Unable to connect to switchboard on %s, port %d\n", - host, port); - - g_free(host); - - return; - } + msn_switchboard_connect(swboard, host, port); g_free(host); } @@ -1548,73 +849,41 @@ static void xfr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - MsnSession *session; - MsnSwitchBoard *swboard; - GaimConnection *gc; char *host; - char *c; int port; - session = cmdproc->session; - gc = session->account->gc; - if (strcmp(cmd->params[1], "SB") && strcmp(cmd->params[1], "NS")) { - gaim_connection_error(gc, _("Got invalid XFR")); - + msn_cmdproc_show_error(cmdproc, MSN_ERROR_MISC); return; } - host = g_strdup(cmd->params[2]); - - if ((c = strchr(host, ':')) != NULL) - { - *c = '\0'; - port = atoi(c + 1); - } - else - port = 1863; + msn_parse_socket(cmd->params[2], &host, &port); if (!strcmp(cmd->params[1], "SB")) { - swboard = msn_session_find_unused_switch(session); - - if (swboard == NULL) - { - gaim_debug_error("msn", - "Received an XFR SB request when there's no unused " - "switchboards!\n"); - return; - } - - msn_switchboard_set_auth_key(swboard, cmd->params[4]); + gaim_debug_error("msn", "This shouldn't be handled here.\n"); +#if 0 + swboard = cmd->trans->data; - if (session->http_method) - port = 80; - - if (!msn_switchboard_connect(swboard, host, port)) + if (swboard != NULL) { - gaim_debug_error("msn", - "Unable to connect to switchboard on %s, port %d\n", - host, port); + msn_switchboard_set_auth_key(swboard, cmd->params[4]); - g_free(host); + if (session->http_method) + port = 80; - return; + msn_switchboard_connect(swboard, host, port); } +#endif } else if (!strcmp(cmd->params[1], "NS")) { - if (!msn_notification_connect(session->notification_conn, host, - port)) - { - gaim_connection_error(gc, _("Unable to transfer to " - "notification server")); + MsnSession *session; - g_free(host); + session = cmdproc->session; - return; - } + msn_notification_connect(session->notification, host, port); } g_free(host); @@ -1628,16 +897,12 @@ { MsnSession *session; const char *value; - const char *passport; session = cmdproc->session; - passport = msg->passport; - if (strcmp(passport, "Hotmail")) - { + if (strcmp(msg->remote_user, "Hotmail")) /* This isn't an official message. */ return; - } if ((value = msn_message_get_attr(msg, "kv")) != NULL) session->passport_info.kv = g_strdup(value); @@ -1662,26 +927,24 @@ GaimConnection *gc; GHashTable *table; const char *unread; - const char *passport; session = cmdproc->session; gc = session->account->gc; - passport = msg->passport; - if (strcmp(passport, "Hotmail")) - { + if (strcmp(msg->remote_user, "Hotmail")) /* This isn't an official message. */ return; - } if (!gaim_account_get_check_mail(session->account)) return; if (session->passport_info.file == NULL) { - msn_cmdproc_send(cmdproc, "URL", "%s", "INBOX"); + MsnTransaction *trans; + trans = msn_transaction_new("URL", "%s", "INBOX"); + msn_transaction_queue_cmd(trans, msg->cmd); - msn_cmdproc_queue_message(cmdproc, "URL", msg); + msn_cmdproc_send_trans(cmdproc, trans); return; } @@ -1694,20 +957,16 @@ { int count = atoi(unread); - if (count != 0) + if (count > 0) { const char *passport; - const char *file; - gchar *url; + const char *url; passport = msn_user_get_passport(session->user); - file = session->passport_info.file; - while (*file && *file == '/') - ++file; - url = g_strconcat ("file:///", file, 0); - gaim_notify_emails(gc, count, FALSE, NULL, NULL, - &passport, (const char **)&url, NULL, NULL); - g_free (url); + url = session->passport_info.file; + + gaim_notify_emails(gc, atoi(unread), FALSE, NULL, NULL, + &passport, &url, NULL, NULL); } } @@ -1721,34 +980,32 @@ GaimConnection *gc; GHashTable *table; char *from, *subject, *tmp; - const char *passport; session = cmdproc->session; gc = session->account->gc; - passport = msg->passport; - from = subject = NULL; - - if (strcmp(passport, "Hotmail")) - { + if (strcmp(msg->remote_user, "Hotmail")) /* This isn't an official message. */ return; - } if (!gaim_account_get_check_mail(session->account)) return; if (session->passport_info.file == NULL) { - msn_cmdproc_send(cmdproc, "URL", "%s", "INBOX"); + MsnTransaction *trans; + trans = msn_transaction_new("URL", "%s", "INBOX"); + msn_transaction_queue_cmd(trans, msg->cmd); - msn_cmdproc_queue_message(cmdproc, "URL", msg); + msn_cmdproc_send_trans(cmdproc, trans); return; } table = msn_message_get_hashtable_from_body(msg); + from = subject = NULL; + tmp = g_hash_table_lookup(table, "From"); if (tmp != NULL) from = gaim_mime_decode_field(tmp); @@ -1777,15 +1034,10 @@ { GHashTable *table; const char *type_s; - const char *passport; - passport = msg->passport; - - if (strcmp(passport, "Hotmail")) - { + if (strcmp(msg->remote_user, "Hotmail")) /* This isn't an official message. */ return; - } table = msn_message_get_hashtable_from_body(msg); @@ -1824,18 +1076,20 @@ g_hash_table_destroy(table); } -static gboolean +static void connect_cb(MsnServConn *servconn) { + MsnNotification *notification; MsnCmdProc *cmdproc; MsnSession *session; GaimAccount *account; GaimConnection *gc; char **a, **c, *vers; - size_t i; + int i; - g_return_val_if_fail(servconn != NULL, FALSE); + g_return_if_fail(servconn != NULL); + notification = servconn->data; cmdproc = servconn->cmdproc; session = servconn->session; account = session->account; @@ -1857,34 +1111,63 @@ g_free(vers); if (cmdproc->error) - return FALSE; + return; - session->user = msn_user_new(session, + session->user = msn_user_new(session->userlist, gaim_account_get_username(account), NULL); +#if 0 gaim_connection_update_progress(gc, _("Syncing with server"), 4, MSN_CONNECT_STEPS); +#endif +} - return TRUE; +void +msn_notification_add_buddy(MsnNotification *notification, const char *list, + const char *who, const char *store_name, + int group_id) +{ + MsnCmdProc *cmdproc; + cmdproc = notification->servconn->cmdproc; + + if (group_id >= 0) + { + msn_cmdproc_send(cmdproc, "ADD", "%s %s %s %d", list, who, + store_name, group_id); + } + else + { + msn_cmdproc_send(cmdproc, "ADD", "%s %s %s", list, who, + store_name); + } +} + +void +msn_notification_rem_buddy(MsnNotification *notification, const char *list, + const char *who, int group_id) +{ + MsnCmdProc *cmdproc; + cmdproc = notification->servconn->cmdproc; + + if (group_id >= 0) + { + msn_cmdproc_send(cmdproc, "REM", "%s %s %d", list, who, group_id); + } + else + { + msn_cmdproc_send(cmdproc, "REM", "%s %s", list, who); + } } void msn_notification_init(void) { + /* TODO: check prp, blp */ + cbs_table = msn_table_new(); - /* Register the command callbacks. */ - - /* Syncing */ - msn_table_add_cmd(cbs_table, NULL, "GTC", NULL); - msn_table_add_cmd(cbs_table, NULL, "BLP", blp_cmd); - msn_table_add_cmd(cbs_table, NULL, "PRP", prp_cmd); - msn_table_add_cmd(cbs_table, NULL, "LSG", lsg_cmd); - msn_table_add_cmd(cbs_table, NULL, "LST", lst_cmd); - msn_table_add_cmd(cbs_table, NULL, "BPR", bpr_cmd); - /* Syncronous */ - /* msn_table_add_cmd(cbs_table, "CHG", "CHG", chg_cmd); */ + msn_table_add_cmd(cbs_table, "CHG", "CHG", chg_cmd); msn_table_add_cmd(cbs_table, "CHG", "ILN", iln_cmd); msn_table_add_cmd(cbs_table, "ADD", "ADD", add_cmd); msn_table_add_cmd(cbs_table, "ADD", "ILN", iln_cmd); @@ -1921,10 +1204,12 @@ msn_table_add_cmd(cbs_table, NULL, "RNG", rng_cmd); msn_table_add_cmd(cbs_table, NULL, "URL", url_cmd); + + /* msn_table_add_cmd(cbs_table, NULL, "XFR", xfr_cmd); */ msn_table_add_error(cbs_table, "ADD", add_error); + /* msn_table_add_error(cbs_table, "REA", rea_error); */ - /* Register the message type callbacks. */ msn_table_add_msg_type(cbs_table, "text/x-msmsgsprofile", profile_msg); @@ -1945,29 +1230,56 @@ msn_table_destroy(cbs_table); } -MsnServConn * +MsnNotification * msn_notification_new(MsnSession *session) { - MsnServConn *notification; - MsnCmdProc *cmdproc; + MsnNotification *notification; + MsnServConn *servconn; + + g_return_val_if_fail(session != NULL, NULL); - notification = msn_servconn_new(session, MSN_SERVER_NS); - cmdproc = notification->cmdproc; + notification = g_new0(MsnNotification, 1); - msn_servconn_set_connect_cb(notification, connect_cb); + notification->session = session; + notification->servconn = servconn = msn_servconn_new(session, MSN_SERVER_NS); + notification->cmdproc = servconn->cmdproc; + msn_servconn_set_connect_cb(servconn, connect_cb); if (session->http_method) - notification->http_data->server_type = "NS"; + servconn->http_data->server_type = "NS"; - cmdproc->cbs_table = cbs_table; + servconn->cmdproc->cbs_table = cbs_table; return notification; } +void +msn_notification_destroy(MsnNotification *notification) +{ + msn_servconn_destroy(notification->servconn); + + g_free(notification); +} + gboolean -msn_notification_connect(MsnServConn *notification, const char *host, int port) +msn_notification_connect(MsnNotification *notification, const char *host, int port) { + MsnServConn *servconn; + g_return_val_if_fail(notification != NULL, FALSE); - return msn_servconn_connect(notification, host, port); + servconn = notification->servconn; + + return (notification->in_use = msn_servconn_connect(servconn, host, port)); } + +void +msn_notification_disconnect(MsnNotification *notification) +{ + g_return_if_fail(notification != NULL); + + notification->in_use = FALSE; + + if (notification->servconn->connected) + msn_servconn_disconnect(notification->servconn); +} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/notification.h --- a/src/protocols/msn/notification.h Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/notification.h Sun Jun 06 02:39:08 2004 +0000 @@ -22,22 +22,38 @@ #ifndef _MSN_NOTIFICATION_H_ #define _MSN_NOTIFICATION_H_ +typedef struct _MsnNotification MsnNotification; + #include "session.h" #include "servconn.h" +#include "cmdproc.h" -/** - * Initialize the variables for notifiaction server creation. - */ +struct _MsnNotification +{ + MsnSession *session; + MsnCmdProc *cmdproc; + MsnServConn *servconn; + + gboolean in_use; +}; + +#include "state.h" + +void msn_notification_end(void); void msn_notification_init(void); -/** - * Destroy the variables for notification server creation. - */ -void msn_notification_end(void); +void msn_notification_add_buddy(MsnNotification *notification, + const char *list, const char *who, + const char *store_name, int group_id); +void msn_notification_rem_buddy(MsnNotification *notification, + const char *list, const char *who, + int group_id); +MsnNotification *msn_notification_new(MsnSession *session); +void msn_notification_destroy(MsnNotification *notification); +gboolean msn_notification_connect(MsnNotification *notification, + const char *host, int port); +void msn_notification_disconnect(MsnNotification *notification); -MsnServConn *msn_notification_new(MsnSession *session); -gboolean msn_notification_connect(MsnServConn *notification, - const char *host, int port); -void msn_notification_disconnect(MsnServConn *notification); +void msn_got_login_params(MsnSession *session, const char *login_params); #endif /* _MSN_NOTIFICATION_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/object.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/object.c Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,310 @@ +/** + * @file object.c MSNObject API + * + * gaim + * + * Copyright (C) 2003 Christian Hammond + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "object.h" + +#define GET_STRING_TAG(field, id) \ + if ((tag = strstr(str, id "=\"")) != NULL) \ + { \ + tag += strlen(id "=\""); \ + c = strchr(tag, '"'); \ + obj->field = g_strndup(tag, c - tag); \ + } + +#define GET_INT_TAG(field, id) \ + if ((tag = strstr(str, id "=\"")) != NULL) \ + { \ + char buf[16]; \ + tag += strlen(id "=\""); \ + c = strchr(tag, '"'); \ + strncpy(buf, tag, c - tag); \ + buf[c - tag] = '\0'; \ + obj->field = atoi(buf); \ + } + +static GList *local_objs; + +MsnObject * +msn_object_new(void) +{ + MsnObject *obj; + + obj = g_new0(MsnObject, 1); + + msn_object_set_type(obj, MSN_OBJECT_UNKNOWN); + msn_object_set_friendly(obj, "AAA="); + + return obj; +} + +MsnObject * +msn_object_new_from_string(const char *str) +{ + MsnObject *obj; + char *tag, *c; + + g_return_val_if_fail(str != NULL, NULL); + g_return_val_if_fail(!strncmp(str, "creator != NULL) + g_free(obj->creator); + + if (obj->location != NULL) + g_free(obj->location); + + if (obj->friendly != NULL) + g_free(obj->friendly); + + if (obj->sha1d != NULL) + g_free(obj->sha1d); + + if (obj->sha1c != NULL) + g_free(obj->sha1c); + + if (obj->local) + local_objs = g_list_remove(local_objs, obj); + + g_free(obj); +} + +char * +msn_object_to_string(const MsnObject *obj) +{ + char *str; + + g_return_val_if_fail(obj != NULL, NULL); + + str = g_strdup_printf("", + msn_object_get_creator(obj), + msn_object_get_size(obj), + msn_object_get_type(obj), + msn_object_get_location(obj), + msn_object_get_friendly(obj), + msn_object_get_sha1d(obj), + msn_object_get_sha1c(obj)); + + return str; +} + +void +msn_object_set_creator(MsnObject *obj, const char *creator) +{ + g_return_if_fail(obj != NULL); + + if (obj->creator != NULL) + g_free(obj->creator); + + obj->creator = (creator == NULL ? NULL : g_strdup(creator)); +} + +void +msn_object_set_size(MsnObject *obj, int size) +{ + g_return_if_fail(obj != NULL); + + obj->size = size; +} + +void +msn_object_set_type(MsnObject *obj, MsnObjectType type) +{ + g_return_if_fail(obj != NULL); + + obj->type = type; +} + +void +msn_object_set_location(MsnObject *obj, const char *location) +{ + g_return_if_fail(obj != NULL); + + if (obj->location != NULL) + g_free(obj->location); + + obj->location = (location == NULL ? NULL : g_strdup(location)); +} + +void +msn_object_set_friendly(MsnObject *obj, const char *friendly) +{ + g_return_if_fail(obj != NULL); + + if (obj->friendly != NULL) + g_free(obj->friendly); + + obj->friendly = (friendly == NULL ? NULL : g_strdup(friendly)); +} + +void +msn_object_set_sha1d(MsnObject *obj, const char *sha1d) +{ + g_return_if_fail(obj != NULL); + + if (obj->sha1d != NULL) + g_free(obj->sha1d); + + obj->sha1d = (sha1d == NULL ? NULL : g_strdup(sha1d)); +} + +void +msn_object_set_sha1c(MsnObject *obj, const char *sha1c) +{ + g_return_if_fail(obj != NULL); + + if (obj->sha1c != NULL) + g_free(obj->sha1c); + + obj->sha1c = (sha1c == NULL ? NULL : g_strdup(sha1c)); +} + +const char * +msn_object_get_creator(const MsnObject *obj) +{ + g_return_val_if_fail(obj != NULL, NULL); + + return obj->creator; +} + +int +msn_object_get_size(const MsnObject *obj) +{ + g_return_val_if_fail(obj != NULL, 0); + + return obj->size; +} + +MsnObjectType +msn_object_get_type(const MsnObject *obj) +{ + g_return_val_if_fail(obj != NULL, MSN_OBJECT_UNKNOWN); + + return obj->type; +} + +const char * +msn_object_get_location(const MsnObject *obj) +{ + g_return_val_if_fail(obj != NULL, NULL); + + return obj->location; +} + +const char * +msn_object_get_friendly(const MsnObject *obj) +{ + g_return_val_if_fail(obj != NULL, NULL); + + return obj->friendly; +} + +const char * +msn_object_get_sha1d(const MsnObject *obj) +{ + g_return_val_if_fail(obj != NULL, NULL); + + return obj->sha1d; +} + +const char * +msn_object_get_sha1c(const MsnObject *obj) +{ + g_return_val_if_fail(obj != NULL, NULL); + + return obj->sha1c; +} + +MsnObject * +msn_object_find_local(const char *sha1c) +{ + GList *l; + + g_return_val_if_fail(sha1c != NULL, NULL); + + for (l = local_objs; l != NULL; l = l->next) + { + MsnObject *local_obj = l->data; + + if (!strcmp(msn_object_get_sha1c(local_obj), sha1c)) + return local_obj; + } + + return NULL; + +} + +void +msn_object_set_local(MsnObject *obj) +{ + g_return_if_fail(obj != NULL); + + obj->local = TRUE; + + local_objs = g_list_append(local_objs, obj); +} + +void +msn_object_set_real_location(MsnObject *obj, const char *real_location) +{ + g_return_if_fail(obj != NULL); + + /* obj->local = TRUE; */ + + if (obj->real_location != NULL) + g_free(obj->real_location); + + obj->real_location = + (real_location == NULL ? NULL : g_strdup(real_location)); +} + +const char * +msn_object_get_real_location(const MsnObject *obj) +{ + MsnObject *local_obj; + + g_return_val_if_fail(obj != NULL, NULL); + + local_obj = msn_object_find_local(msn_object_get_sha1c(obj)); + + if (local_obj != NULL) + return local_obj->real_location; + + return NULL; +} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/object.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/object.h Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,202 @@ +/** + * @file object.h MSNObject API + * + * gaim + * + * Copyright (C) 2003 Christian Hammond + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _MSN_OBJECT_H_ +#define _MSN_OBJECT_H_ + +#include "internal.h" + +typedef enum +{ + MSN_OBJECT_UNKNOWN = -1, /**< Unknown object */ + MSN_OBJECT_RESERVED1 = 1, /**< Reserved */ + MSN_OBJECT_EMOTICON = 2, /**< Custom Emoticon */ + MSN_OBJECT_USERTILE = 3, /**< UserTile (buddy icon) */ + MSN_OBJECT_RESERVED2 = 4, /**< Reserved */ + MSN_OBJECT_BACKGROUND = 5 /**< Background */ + +} MsnObjectType; + +typedef struct +{ + gboolean local; + + char *creator; + int size; + MsnObjectType type; + char *real_location; + char *location; + char *friendly; + char *sha1d; + char *sha1c; + +} MsnObject; + +/** + * Creates a MsnObject structure. + * + * @return A new MsnObject structure. + */ +MsnObject *msn_object_new(); + +/** + * Creates a MsnObject structure from a string. + * + * @param str The string. + * + * @return The new MsnObject structure. + */ +MsnObject *msn_object_new_from_string(const char *str); + +/** + * Destroys an MsnObject structure. + * + * @param obj The object structure. + */ +void msn_object_destroy(MsnObject *obj); + +/** + * Outputs a string representation of an MsnObject. + * + * @param obj The object. + * + * @return The string representation. This must be freed. + */ +char *msn_object_to_string(const MsnObject *obj); + +/** + * Sets the creator field in a MsnObject. + * + * @param creator The creator value. + */ +void msn_object_set_creator(MsnObject *obj, const char *creator); + +/** + * Sets the size field in a MsnObject. + * + * @param size The size value. + */ +void msn_object_set_size(MsnObject *obj, int size); + +/** + * Sets the type field in a MsnObject. + * + * @param type The type value. + */ +void msn_object_set_type(MsnObject *obj, MsnObjectType type); + +/** + * Sets the location field in a MsnObject. + * + * @param location The location value. + */ +void msn_object_set_location(MsnObject *obj, const char *location); + +/** + * Sets the friendly name field in a MsnObject. + * + * @param friendly The friendly name value. + */ +void msn_object_set_friendly(MsnObject *obj, const char *friendly); + +/** + * Sets the SHA1D field in a MsnObject. + * + * @param sha1d The sha1d value. + */ +void msn_object_set_sha1d(MsnObject *obj, const char *sha1d); + +/** + * Sets the SHA1C field in a MsnObject. + * + * @param sha1c The sha1c value. + */ +void msn_object_set_sha1c(MsnObject *obj, const char *sha1c); + +/** + * Returns a MsnObject's creator value. + * + * @param obj The object. + * + * @return The creator value. + */ +const char *msn_object_get_creator(const MsnObject *obj); + +/** + * Returns a MsnObject's size value. + * + * @param obj The object. + * + * @return The size value. + */ +int msn_object_get_size(const MsnObject *obj); + +/** + * Returns a MsnObject's type. + * + * @param obj The object. + * + * @return The object type. + */ +MsnObjectType msn_object_get_type(const MsnObject *obj); + +/** + * Returns a MsnObject's location value. + * + * @param obj The object. + * + * @return The location value. + */ +const char *msn_object_get_location(const MsnObject *obj); + +/** + * Returns a MsnObject's friendly name value. + * + * @param obj The object. + * + * @return The friendly name value. + */ +const char *msn_object_get_friendly(const MsnObject *obj); + +/** + * Returns a MsnObject's SHA1D value. + * + * @param obj The object. + * + * @return The SHA1D value. + */ +const char *msn_object_get_sha1d(const MsnObject *obj); + +/** + * Returns a MsnObject's SHA1C value. + * + * @param obj The object. + * + * @return The SHA1C value. + */ +const char *msn_object_get_sha1c(const MsnObject *obj); + +void msn_object_set_local(MsnObject *obj); +const char *msn_object_get_real_location(const MsnObject *obj); +void msn_object_set_real_location(MsnObject *obj, + const char *real_location); + +#endif /* _MSN_OBJECT_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/servconn.c --- a/src/protocols/msn/servconn.c Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/servconn.c Sun Jun 06 02:39:08 2004 +0000 @@ -34,7 +34,7 @@ const char *names[] = { "Notification", "Switchboard" }; const char *name; - + gc = gaim_account_get_connection(servconn->session->account); name = names[servconn->type]; @@ -58,12 +58,17 @@ } if (servconn->type != MSN_SERVER_SB) + { gaim_connection_error(gc, tmp); + } else { - GaimAccount *account = gaim_connection_get_account(gc); - char *primary = g_strdup_printf(_("MSN error for account %s"), - gaim_account_get_username(account)); + GaimAccount *account; + char *primary; + + account = gaim_connection_get_account(gc); + primary = g_strdup_printf(_("MSN error for account %s"), + gaim_account_get_username(account)); gaim_notify_error(gc, NULL, primary, tmp); @@ -116,7 +121,6 @@ } servconn->num = session->servconns_count++; - session->servconns = g_list_append(session->servconns, servconn); return servconn; } @@ -124,8 +128,6 @@ void msn_servconn_destroy(MsnServConn *servconn) { - MsnSession *session; - g_return_if_fail(servconn != NULL); if (servconn->processing) @@ -134,15 +136,18 @@ return; } - session = servconn->session; - - session->servconns = g_list_remove(session->servconns, servconn); - if (servconn->connected) msn_servconn_disconnect(servconn); + if (servconn->http_data != NULL) + g_free(servconn->http_data); + +#if 0 + if (servconn->rx_buf != NULL) + g_free(servconn->rx_buf); +#endif + msn_cmdproc_destroy(servconn->cmdproc); - g_free(servconn); } @@ -163,6 +168,9 @@ if (session->http_method) { + if (servconn->http_data->gateway_host != NULL) + g_free(servconn->http_data->gateway_host); + servconn->http_data->gateway_host = g_strdup(host); } @@ -170,21 +178,21 @@ servconn); if (r == 0) + { servconn->connected = TRUE; - - return servconn->connected; + servconn->cmdproc->ready = TRUE; + return TRUE; + } + else + return FALSE; } void msn_servconn_disconnect(MsnServConn *servconn) { - MsnSession *session; - g_return_if_fail(servconn != NULL); g_return_if_fail(servconn->connected); - session = servconn->session; - if (servconn->inpa > 0) { gaim_input_remove(servconn->inpa); @@ -206,33 +214,27 @@ if (servconn->http_data->timer) gaim_timeout_remove(servconn->http_data->timer); - - g_free(servconn->http_data); - servconn->http_data = NULL; } servconn->rx_len = 0; servconn->payload_len = 0; + servconn->connected = FALSE; + servconn->cmdproc->ready = FALSE; + if (servconn->disconnect_cb != NULL) servconn->disconnect_cb(servconn); - - servconn->connected = FALSE; } void -msn_servconn_set_connect_cb(MsnServConn *servconn, - gboolean (*connect_cb)(MsnServConn *servconn)) +msn_servconn_set_connect_cb(MsnServConn *servconn, void (*connect_cb)(MsnServConn *)) { g_return_if_fail(servconn != NULL); - servconn->connect_cb = connect_cb; } void -msn_servconn_set_disconnect_cb(MsnServConn *servconn, - void (*disconnect_cb)(MsnServConn - *servconn)) +msn_servconn_set_disconnect_cb(MsnServConn *servconn, void (*disconnect_cb)(MsnServConn *)) { g_return_if_fail(servconn != NULL); @@ -256,17 +258,30 @@ g_return_val_if_fail(servconn != NULL, 0); - if (servconn->session->http_method) + if (servconn->http_data == NULL) + { + switch (servconn->type) + { + case MSN_SERVER_NS: + case MSN_SERVER_SB: + ret = write(servconn->fd, buf, len); + break; + case MSN_SERVER_DC: + ret = write(servconn->fd, &buf, sizeof(len)); + ret = write(servconn->fd, buf, len); + break; + default: + ret = write(servconn->fd, buf, len); + break; + } + } + else { ret = msn_http_servconn_write(servconn, buf, len, servconn->http_data->server_type); } - else - { - ret = write(servconn->fd, buf, len); - } - if (ret < 0) + if (ret == -1) { servconn->cmdproc->error = MSN_ERROR_WRITE; failed_io(servconn); @@ -288,7 +303,6 @@ session = servconn->session; len = read(servconn->fd, buf, sizeof(buf) - 1); - buf[len] = '\0'; if (len <= 0) { @@ -299,8 +313,10 @@ return; } - servconn->rx_buf = g_realloc(servconn->rx_buf, len + servconn->rx_len); - memcpy(servconn->rx_buf + servconn->rx_len, buf, len); + buf[len] = '\0'; + + servconn->rx_buf = g_realloc(servconn->rx_buf, len + servconn->rx_len + 1); + memcpy(servconn->rx_buf + servconn->rx_len, buf, len + 1); servconn->rx_len += len; if (session->http_method) @@ -387,13 +403,13 @@ { end = strstr(cur, "\r\n"); - if (!end) + if (end == NULL) /* The command is still not complete. */ break; *end = '\0'; - cur_len = end - cur + 2; end += 2; + cur_len = end - cur; } servconn->rx_len -= cur_len; @@ -407,11 +423,11 @@ { msn_cmdproc_process_cmd_text(servconn->cmdproc, cur); } - } while (servconn->connected && servconn->rx_len); + } while (servconn->connected && servconn->rx_len > 0); if (servconn->connected) { - if (servconn->rx_len) + if (servconn->rx_len > 0) servconn->rx_buf = g_memdup(cur, servconn->rx_len); else servconn->rx_buf = NULL; @@ -424,3 +440,89 @@ g_free(old_rx_buf); } + +#if 0 +static int +create_listener(int port) +{ + int fd; + const int on = 1; + +#if 0 + struct addrinfo hints; + struct addrinfo *c, *res; + char port_str[5]; + + snprintf(port_str, sizeof(port_str), "%d", port); + + memset(&hints, 0, sizeof(hints)); + + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if (getaddrinfo(NULL, port_str, &hints, &res) != 0) + { + gaim_debug_error("msn", "Could not get address info: %s.\n", + port_str); + return -1; + } + + for (c = res; c != NULL; c = c->ai_next) + { + fd = socket(c->ai_family, c->ai_socktype, c->ai_protocol); + + if (fd < 0) + continue; + + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + if (bind(fd, c->ai_addr, c->ai_addrlen) == 0) + break; + + close(fd); + } + + if (c == NULL) + { + gaim_debug_error("msn", "Could not find socket: %s.\n", port_str); + return -1; + } + + freeaddrinfo(res); +#else + struct sockaddr_in sockin; + + fd = socket(AF_INET, SOCK_STREAM, 0); + + if (fd < 0) + return -1; + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) + { + close(fd); + return -1; + } + + memset(&sockin, 0, sizeof(struct sockaddr_in)); + sockin.sin_family = AF_INET; + sockin.sin_port = htons(port); + + if (bind(fd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) + { + close(fd); + return -1; + } +#endif + + if (listen (fd, 4) != 0) + { + close (fd); + return -1; + } + + fcntl(fd, F_SETFL, O_NONBLOCK); + + return fd; +} +#endif diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/servconn.h --- a/src/protocols/msn/servconn.h Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/servconn.h Sun Jun 06 02:39:08 2004 +0000 @@ -24,13 +24,16 @@ typedef struct _MsnServConn MsnServConn; +#include "session.h" #include "cmdproc.h" + #include "proxy.h" - -#include "msg.h" #include "httpmethod.h" -#include "session.h" +/* +#include "msg.h" +#include "history.h" +*/ typedef enum { @@ -62,29 +65,27 @@ char *rx_buf; int rx_len; - int payload_len; + size_t payload_len; - gboolean (*connect_cb)(MsnServConn *servconn); - void (*disconnect_cb)(MsnServConn *servconn); - + void (*connect_cb)(MsnServConn *); +/* void (*failed_io_cb)(MsnServConn *); */ + void (*disconnect_cb)(MsnServConn *); + void (*data_free_cb)(void *data); void *data; }; MsnServConn *msn_servconn_new(MsnSession *session, MsnServConnType type); - void msn_servconn_destroy(MsnServConn *servconn); -gboolean msn_servconn_connect(MsnServConn *servconn, const char *host, - int port); +gboolean msn_servconn_connect(MsnServConn *servconn, const char *host, int port); void msn_servconn_disconnect(MsnServConn *servconn); void msn_servconn_set_connect_cb(MsnServConn *servconn, - gboolean (*connect_cb)(MsnServConn *servconn)); - + void (*connect_cb)(MsnServConn *)); void msn_servconn_set_disconnect_cb(MsnServConn *servconn, - void (*disconnect_cb)(MsnServConn *servconn)); - -size_t msn_servconn_write(MsnServConn *servconn, const char *buf, - size_t size); + void (*disconnect_cb)(MsnServConn *)); +void msn_servconn_set_failed_io_cb(MsnServConn *servconn, + void (*failed_io_cb)(MsnServConn *)); +size_t msn_servconn_write(MsnServConn *servconn, const char *buf, size_t size); #endif /* _MSN_SERVCONN_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/session.c --- a/src/protocols/msn/session.c Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/session.c Sun Jun 06 02:39:08 2004 +0000 @@ -23,8 +23,11 @@ #include "session.h" #include "notification.h" +#include "slplink.h" + MsnSession * -msn_session_new(GaimAccount *account, const char *host, int port) +msn_session_new(GaimAccount *account, const char *host, int port, + gboolean http_method) { MsnSession *session; @@ -35,17 +38,12 @@ session->account = account; session->dispatch_host = g_strdup(host); session->dispatch_port = port; - - session->away_state = NULL; - - session->users = msn_users_new(); - session->groups = msn_groups_new(); + session->http_method = http_method; -#ifdef HAVE_SSL + session->notification = msn_notification_new(session); + session->userlist = msn_userlist_new(session); + session->protocol_ver = 9; -#else - session->protocol_ver = 7; -#endif return session; } @@ -61,26 +59,16 @@ if (session->dispatch_host != NULL) g_free(session->dispatch_host); + if (session->notification != NULL) + msn_notification_destroy(session->notification); + while (session->switches != NULL) msn_switchboard_destroy(session->switches->data); - while (session->lists.forward) - { - MsnUser *user = (MsnUser *)session->lists.forward->data; - - msn_user_destroy(user); - - session->lists.forward = g_slist_remove(session->lists.forward, user); - } + while (session->slplinks != NULL) + msn_slplink_destroy(session->slplinks->data); - if (session->lists.allow != NULL) - g_slist_free(session->lists.allow); - - if (session->lists.block != NULL) - g_slist_free(session->lists.block); - - msn_groups_destroy(session->groups); - msn_users_destroy(session->users); + msn_userlist_destroy(session->userlist); if (session->passport_info.kv != NULL) g_free(session->passport_info.kv); @@ -94,8 +82,8 @@ if (session->passport_info.file != NULL) g_free(session->passport_info.file); - if (session->away_state != NULL) - g_free(session->away_state); + if (session->sync != NULL) + msn_sync_destroy(session->sync); if (session->nexus != NULL) msn_nexus_destroy(session->nexus); @@ -111,9 +99,7 @@ session->connected = TRUE; - session->notification_conn = msn_notification_new(session); - - if (msn_notification_connect(session->notification_conn, + if (msn_notification_connect(session->notification, session->dispatch_host, session->dispatch_port)) { @@ -130,99 +116,31 @@ g_return_if_fail(session->connected); while (session->switches != NULL) - { - MsnSwitchBoard *board = (MsnSwitchBoard *)session->switches->data; - - msn_switchboard_destroy(board); - } - - if (session->notification_conn != NULL) - { - msn_servconn_destroy(session->notification_conn); - session->notification_conn = NULL; - } -} + msn_switchboard_destroy(session->switches->data); -MsnSwitchBoard * -msn_session_open_switchboard(MsnSession *session) -{ - MsnSwitchBoard *swboard; - MsnCmdProc *cmdproc; - - g_return_val_if_fail(session != NULL, NULL); - - cmdproc = session->notification_conn->cmdproc; - - msn_cmdproc_send(cmdproc, "XFR", "%s", "SB"); - - if (cmdproc->error) - return NULL; - - swboard = msn_switchboard_new(session); - - return swboard; + if (session->notification != NULL) + msn_notification_disconnect(session->notification); } -gboolean -msn_session_change_status(MsnSession *session, const char *state) -{ - MsnCmdProc *cmdproc; - MsnUser *user; - MsnObject *msnobj; - - g_return_val_if_fail(session != NULL, FALSE); - g_return_val_if_fail(state != NULL, FALSE); - - user = session->user; - msnobj = msn_user_get_object(user); - - if (state != session->away_state) - { - if (session->away_state != NULL) - g_free(session->away_state); - - session->away_state = g_strdup(state); - } - - cmdproc = session->notification_conn->cmdproc; - - if (msnobj == NULL) - { - msn_cmdproc_send(cmdproc, "CHG", "%s %d", state, MSN_CLIENT_ID); - } - else - { - char *msnobj_str = msn_object_to_string(msnobj); - - msn_cmdproc_send(cmdproc, "CHG", "%s %d %s", state, MSN_CLIENT_ID, - gaim_url_encode(msnobj_str)); - - g_free(msnobj_str); - } - - return TRUE; -} +/* TODO: This must go away when conversation is redesigned */ MsnSwitchBoard * -msn_session_find_switch_with_passport(const MsnSession *session, - const char *passport) +msn_session_find_swboard(MsnSession *session, const char *username) { GList *l; - MsnSwitchBoard *swboard; g_return_val_if_fail(session != NULL, NULL); - g_return_val_if_fail(passport != NULL, NULL); + g_return_val_if_fail(username != NULL, NULL); for (l = session->switches; l != NULL; l = l->next) { - swboard = (MsnSwitchBoard *)l->data; + MsnSwitchBoard *swboard; + + swboard = l->data; - if (!swboard->hidden && !swboard->chat_id && - !g_ascii_strcasecmp(passport, - msn_user_get_passport(swboard->user))) - { - return swboard; - } + if (swboard->im_user != NULL) + if (!strcmp(username, swboard->im_user)) + return swboard; } return NULL; @@ -232,14 +150,15 @@ msn_session_find_switch_with_id(const MsnSession *session, int chat_id) { GList *l; - MsnSwitchBoard *swboard; g_return_val_if_fail(session != NULL, NULL); - g_return_val_if_fail(chat_id > 0, NULL); + g_return_val_if_fail(chat_id >= 0, NULL); for (l = session->switches; l != NULL; l = l->next) { - swboard = (MsnSwitchBoard *)l->data; + MsnSwitchBoard *swboard; + + swboard = l->data; if (swboard->chat_id == chat_id) return swboard; @@ -249,20 +168,19 @@ } MsnSwitchBoard * -msn_session_find_unused_switch(const MsnSession *session) +msn_session_get_swboard(MsnSession *session, const char *username) { - GList *l; MsnSwitchBoard *swboard; - g_return_val_if_fail(session != NULL, NULL); + swboard = msn_session_find_swboard(session, username); - for (l = session->switches; l != NULL; l = l->next) + if (swboard == NULL) { - swboard = (MsnSwitchBoard *)l->data; - - if (!swboard->in_use) - return swboard; + swboard = msn_switchboard_new(session); + msn_switchboard_request(swboard); + msn_switchboard_request_add_user(swboard, username); + swboard->im_user = g_strdup(username); } - return NULL; + return swboard; } diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/session.h --- a/src/protocols/msn/session.h Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/session.h Sun Jun 06 02:39:08 2004 +0000 @@ -24,19 +24,24 @@ typedef struct _MsnSession MsnSession; -#include "group.h" -#include "nexus.h" -#include "servconn.h" #include "sslconn.h" + +#include "notification.h" #include "switchboard.h" #include "user.h" +#include "group.h" +#include "cmdproc.h" +#include "nexus.h" + +#include "userlist.h" +#include "sync.h" struct _MsnSession { GaimAccount *account; MsnUser *user; - char *away_state; + int state; guint protocol_ver; @@ -45,28 +50,19 @@ gboolean connected; - MsnServConn *notification_conn; - + MsnNotification *notification; MsnNexus *nexus; gboolean http_method; gint http_poll_timer; - MsnUsers *users; - MsnGroups *groups; + MsnUserList *userlist; int servconns_count; - GList *servconns; GList *switches; + GList *directconns; - struct - { - GSList *forward; - GSList *reverse; - GSList *allow; - GSList *block; - - } lists; + int conv_seq; struct { @@ -81,40 +77,27 @@ } passport_info; /* You have no idea how much I hate all that is below. */ + /* shx: What? ;) */ + GaimPlugin *prpl; - /* For MSNP8 and MSNP9. */ - int num_users; - int total_users; - int num_groups; - int total_groups; - MsnUser *last_user_added; + MsnSync *sync; - /* For MSNP7 and lower. */ - gboolean syncing_lists; - gboolean lists_synced; - - /* For moving buddies from one group to another. Ugh. */ - gboolean moving_buddy; - char *dest_group_name; - MsnUser *moving_user; - MsnGroup *old_group; - - /* The last chat ID. */ - int last_chat_id; + GList *slplinks; }; /** * Creates an MSN session. * * @param account The account. - * @param server The dispatch server host. + * @param host The dispatch server host. * @param port The dispatch server port. * * @return The new MSN session. */ MsnSession *msn_session_new(GaimAccount *account, - const char *host, int port); + const char *host, int port, + gboolean http_method); /** * Destroys an MSN session. @@ -140,34 +123,6 @@ void msn_session_disconnect(MsnSession *session); /** - * Opens a new switchboard connection. - * - * @param session The MSN session. - * - * @return The new switchboard connection. - */ -MsnSwitchBoard *msn_session_open_switchboard(MsnSession *session); - -/** - * Changes the status of the user. - * - * @param session The MSN session. - * @param state The new state. - */ -gboolean msn_session_change_status(MsnSession *session, const char *state); - -/** - * Finds a switch with the given passport. - * - * @param session The MSN session. - * @param passport The passport to search for. - * - * @return The switchboard, if found. - */ -MsnSwitchBoard *msn_session_find_switch_with_passport( - const MsnSession *session, const char *passport); - -/** * Finds a switchboard with the given chat ID. * * @param session The MSN session. @@ -178,13 +133,9 @@ MsnSwitchBoard *msn_session_find_switch_with_id(const MsnSession *session, int chat_id); -/** - * Finds the first unused switchboard. - * - * @param session The MSN session. - * - * @return The first unused, writable switchboard, if found. - */ -MsnSwitchBoard *msn_session_find_unused_switch(const MsnSession *session); +MsnSwitchBoard *msn_session_find_swboard(MsnSession *session, + const char *username); +MsnSwitchBoard *msn_session_get_swboard(MsnSession *session, + const char *username); #endif /* _MSN_SESSION_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/slp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/slp.c Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,822 @@ +/** + * @file msnslp.c MSNSLP support + * + * gaim + * + * Copyright (C) 2003 Christian Hammond + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "msn.h" +#include "slp.h" +#include "slpcall.h" +#include "slpmsg.h" +#include "slpsession.h" + +#include "object.h" +#include "user.h" +#include "switchboard.h" + +/* #include "slplink.h" */ +/* #include "directconn.h" */ + +static void send_ok(MsnSlpCall *slpcall, const char *branch, + const char *type, const char *content); + +static void send_decline(MsnSlpCall *slpcall, const char *branch, + const char *type, const char *content); + +/************************************************************************** + * Util + **************************************************************************/ + +char * +get_token(const char *str, const char *start, const char *end) +{ + const char *c, *c2; + + if ((c = strstr(str, start)) == NULL) + return NULL; + + c += strlen(start); + + if (end != NULL) + { + if ((c2 = strstr(c, end)) == NULL) + return NULL; + + return g_strndup(c, c2 - c); + } + else + { + /* This has to be changed */ + return g_strdup(c); + } + +} + +/************************************************************************** + * Xfer + **************************************************************************/ + +static void +msn_xfer_init(GaimXfer *xfer) +{ + MsnSlpCall *slpcall; + /* MsnSlpLink *slplink; */ + char *content; + + gaim_debug_info("msn", "xfer_init\n"); + + slpcall = xfer->data; + + /* Send Ok */ + content = g_strdup_printf("SessionID: %lu\r\n\r\n", + slpcall->session_id); + + send_ok(slpcall, slpcall->branch, "application/x-msnmsgr-sessionreqbody", + content); + + g_free(content); + gaim_xfer_add(xfer); + msn_slplink_unleash(slpcall->slplink); +} + +void +msn_xfer_cancel(GaimXfer *xfer) +{ + MsnSlpCall *slpcall; + char *content; + + slpcall = xfer->data; + + if (gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_CANCEL_LOCAL) + { + if (slpcall->started) + { + msn_slp_call_close(slpcall); + } + else + { + content = g_strdup_printf("SessionID: %lu\r\n\r\n", + slpcall->session_id); + + send_decline(slpcall, slpcall->branch, "application/x-msnmsgr-sessionreqbody", + content); + + g_free(content); + msn_slplink_unleash(slpcall->slplink); + } + } +} + +void +msn_xfer_progress_cb(MsnSlpCall *slpcall, gsize total_length, gsize len, gsize offset) +{ + GaimXfer *xfer; + + xfer = slpcall->xfer; + + xfer->bytes_sent = offset; + xfer->bytes_remaining = total_length - offset; + + gaim_xfer_update_progress(xfer); +} + +void +msn_xfer_finish_cb(MsnSlpCall *slpcall, + const char *body, long long size) +{ + if (size < 0) + gaim_xfer_cancel_remote(slpcall->xfer); + else + gaim_xfer_set_completed(slpcall->xfer, TRUE); +} + +/************************************************************************** + * SLP Control + **************************************************************************/ + +#if 0 +static void +got_transresp(MsnSlpCall *slpcall, const char *nonce, + const char *ips_str, int port) +{ + MsnDirectConn *directconn; + char **ip_addrs, **c; + + directconn = msn_directconn_new(slpcall->slplink); + + directconn->initial_call = slpcall; + + /* msn_directconn_parse_nonce(directconn, nonce); */ + directconn->nonce = g_strdup(nonce); + + ip_addrs = g_strsplit(ips_str, " ", -1); + + for (c = ip_addrs; *c != NULL; c++) + { + gaim_debug_info("msn", "ip_addr = %s\n", *c); + if (msn_directconn_connect(directconn, *c, port)) + break; + } + + g_strfreev(ip_addrs); +} +#endif + +static void +send_ok(MsnSlpCall *slpcall, const char *branch, + const char *type, const char *content) +{ + MsnSlpLink *slplink; + MsnSlpMessage *slpmsg; + + slplink = slpcall->slplink; + + /* 200 OK */ + slpmsg = msn_slpmsg_sip_new(slpcall, 1, + "MSNSLP/1.0 200 OK", + branch, type, content); + +#ifdef DEBUG_SLP + slpmsg->info = "SLP 200 OK"; + slpmsg->text_body = TRUE; +#endif + + msn_slplink_queue_slpmsg(slplink, slpmsg); + + msn_slp_call_session_init(slpcall); +} + +static void +send_decline(MsnSlpCall *slpcall, const char *branch, + const char *type, const char *content) +{ + MsnSlpLink *slplink; + MsnSlpMessage *slpmsg; + + slplink = slpcall->slplink; + + /* 603 Decline */ + slpmsg = msn_slpmsg_sip_new(slpcall, 1, + "MSNSLP/1.0 603 Decline", + branch, type, content); + +#ifdef DEBUG_SLP + slpmsg->info = "SLP 603 Decline"; + slpmsg->text_body = TRUE; +#endif + + msn_slplink_queue_slpmsg(slplink, slpmsg); +} + +static void +got_sessionreq(MsnSlpCall *slpcall, const char *branch, + const char *euf_guid, const char *context) +{ + if (!strcmp(euf_guid, "A4268EEC-FEC5-49E5-95C3-F126696BDBF6")) + { + /* Emoticon or UserDisplay */ + MsnSlpSession *slpsession; + MsnSlpLink *slplink; + MsnSlpMessage *slpmsg; + MsnObject *obj; + char *msnobj_data; + const char *sha1c; + const char *file_name; + char *content; + gsize len; + int type; + + /* Send Ok */ + content = g_strdup_printf("SessionID: %lu\r\n\r\n", + slpcall->session_id); + + send_ok(slpcall, branch, "application/x-msnmsgr-sessionreqbody", + content); + + g_free(content); + + slplink = slpcall->slplink; + + gaim_base64_decode(context, &msnobj_data, &len); + obj = msn_object_new_from_string(msnobj_data); + type = msn_object_get_type(obj); + sha1c = msn_object_get_sha1c(obj); + g_free(msnobj_data); + + if (!(type == MSN_OBJECT_USERTILE)) + { + gaim_debug_error("msn", "Wrong object?\n"); + msn_object_destroy(obj); + g_return_if_reached(); + } + + file_name = msn_object_get_real_location(obj); + + slpsession = msn_slplink_find_slp_session(slplink, + slpcall->session_id); + + /* DATA PREP */ + slpmsg = msn_slpmsg_new(slplink); + slpmsg->slpsession = slpsession; + slpmsg->session_id = slpsession->id; + msn_slpmsg_set_body(slpmsg, NULL, 4); +#ifdef DEBUG_SLP + slpmsg->info = "SLP DATA PREP"; +#endif + msn_slplink_queue_slpmsg(slplink, slpmsg); + + /* DATA */ + slpmsg = msn_slpmsg_new(slplink); + slpmsg->slpsession = slpsession; + slpmsg->flags = 0x20; +#ifdef DEBUG_SLP + slpmsg->info = "SLP DATA"; +#endif + msn_slpmsg_open_file(slpmsg, file_name); + msn_slplink_queue_slpmsg(slplink, slpmsg); + } + else if (!strcmp(euf_guid, "5D3E02AB-6190-11D3-BBBB-00C04F795683")) + { + /* File Transfer */ + GaimAccount *account; + GaimXfer *xfer; + char *bin; + gsize bin_len; + guint32 file_size; + char *file_name; + + account = slpcall->slplink->session->account; + + slpcall->cb = msn_xfer_finish_cb; + slpcall->progress_cb = msn_xfer_progress_cb; + slpcall->branch = g_strdup(branch); + + xfer = gaim_xfer_new(account, GAIM_XFER_RECEIVE, + slpcall->slplink->remote_user); + + gaim_base64_decode(context, &bin, &bin_len); + file_size = *((gsize *)bin + 2); + file_name = g_utf16_to_utf8((const gunichar2 *)(bin + 20), -1, + NULL, NULL, NULL); + + g_free(bin); + + gaim_xfer_set_filename(xfer, file_name); + gaim_xfer_set_size(xfer, file_size); + gaim_xfer_set_init_fnc(xfer, msn_xfer_init); + gaim_xfer_set_request_denied_fnc(xfer, msn_xfer_cancel); + gaim_xfer_set_cancel_recv_fnc(xfer, msn_xfer_cancel); + + slpcall->xfer = xfer; + xfer->data = slpcall; + + gaim_xfer_request(xfer); + } +} + +void +send_bye(MsnSlpCall *slpcall, const char *type) +{ + MsnSlpLink *slplink; + MsnSlpMessage *slpmsg; + char *header; + + slplink = slpcall->slplink; + + g_return_if_fail(slplink != NULL); + + header = g_strdup_printf("BYE MSNMSGR:%s MSNSLP/1.0", + slplink->local_user); + + slpmsg = msn_slpmsg_sip_new(slpcall, 0, header, + "A0D624A6-6C0C-4283-A9E0-BC97B4B46D32", + type, + "\r\n"); + g_free(header); + +#ifdef DEBUG_SLP + slpmsg->info = "SLP BYE"; + slpmsg->text_body = TRUE; +#endif + + msn_slplink_queue_slpmsg(slplink, slpmsg); +} + +static void +got_invite(MsnSlpCall *slpcall, + const char *branch, const char *type, const char *content) +{ + MsnSlpLink *slplink; + + slplink = slpcall->slplink; + + if (!strcmp(type, "application/x-msnmsgr-sessionreqbody")) + { + char *euf_guid, *context; + char *temp; + + euf_guid = get_token(content, "EUF-GUID: {", "}\r\n"); + + temp = get_token(content, "SessionID: ", "\r\n"); + if (temp != NULL) + slpcall->session_id = atoi(temp); + g_free(temp); + + temp = get_token(content, "AppID: ", "\r\n"); + if (temp != NULL) + slpcall->app_id = atoi(temp); + g_free(temp); + + context = get_token(content, "Context: ", "\r\n"); + + got_sessionreq(slpcall, branch, euf_guid, context); + + g_free(context); + g_free(euf_guid); + } + else if (!strcmp(type, "application/x-msnmsgr-transreqbody")) + { + /* A direct connection? */ + + char *listening, *nonce; + char *content; + + if (FALSE) + { +#if 0 + MsnDirectConn *directconn; + /* const char *ip_addr; */ + char *ip_port; + int port; + + /* ip_addr = gaim_prefs_get_string("/core/ft/public_ip"); */ + ip_port = "5190"; + listening = "true"; + nonce = rand_guid(); + + directconn = msn_directconn_new(slplink); + + /* msn_directconn_parse_nonce(directconn, nonce); */ + directconn->nonce = g_strdup(nonce); + + msn_directconn_listen(directconn); + + port = directconn->port; + + content = g_strdup_printf( + "Bridge: TCPv1\r\n" + "Listening: %s\r\n" + "Nonce: {%s}\r\n" + "Ipv4Internal-Addrs: 192.168.0.82\r\n" + "Ipv4Internal-Port: %d\r\n" + "\r\n", + listening, + nonce, + port); +#endif + } + else + { + listening = "false"; + nonce = g_strdup("00000000-0000-0000-0000-000000000000"); + + content = g_strdup_printf( + "Bridge: TCPv1\r\n" + "Listening: %s\r\n" + "Nonce: {%s}\r\n" + "\r\n", + listening, + nonce); + } + + send_ok(slpcall, branch, + "application/x-msnmsgr-transrespbody", content); + + g_free(content); + g_free(nonce); + } + else if (!strcmp(type, "application/x-msnmsgr-transrespbody")) + { +#if 0 + char *ip_addrs; + char *temp; + char *nonce; + int port; + + nonce = get_token(content, "Nonce: {", "}\r\n"); + ip_addrs = get_token(content, "IPv4Internal-Addrs: ", "\r\n"); + + temp = get_token(content, "IPv4Internal-Port: ", "\r\n"); + if (temp != NULL) + port = atoi(temp); + else + port = -1; + g_free(temp); + + if (ip_addrs == NULL) + return; + + if (port > 0) + got_transresp(slpcall, nonce, ip_addrs, port); + + g_free(nonce); + g_free(ip_addrs); +#endif + } +} + +static void +got_ok(MsnSlpCall *slpcall, + const char *type, const char *content) +{ + g_return_if_fail(slpcall != NULL); + g_return_if_fail(type != NULL); + + if (!strcmp(type, "application/x-msnmsgr-sessionreqbody")) + { +#if 0 + if (slpcall->type == MSN_SLPCALL_DC) + { + /* First let's try a DirectConnection. */ + + MsnSlpLink *slplink; + MsnSlpMessage *slpmsg; + char *header; + char *content; + char *branch; + + slplink = slpcall->slplink; + + branch = rand_guid(); + + content = g_strdup_printf( + "Bridges: TRUDPv1 TCPv1\r\n" + "NetID: 0\r\n" + "Conn-Type: Direct-Connect\r\n" + "UPnPNat: false\r\n" + "ICF: false\r\n" + ); + + header = g_strdup_printf("INVITE MSNMSGR:%s MSNSLP/1.0", + slplink->remote_user); + + slpmsg = msn_slp_sipmsg_new(slpcall, 0, header, branch, + "application/x-msnmsgr-transreqbody", + content); + +#ifdef DEBUG_SLP + slpmsg->info = "SLP INVITE"; + slpmsg->text_body = TRUE; +#endif + msn_slplink_send_slpmsg(slplink, slpmsg); + + g_free(header); + g_free(content); + + g_free(branch); + } + else + { + msn_slp_call_session_init(slpcall); + } +#else + msn_slp_call_session_init(slpcall); +#endif + } + else if (!strcmp(type, "application/x-msnmsgr-transreqbody")) + { + /* Do we get this? */ + gaim_debug_info("msn", "OK with transreqbody\n"); + } + else if (!strcmp(type, "application/x-msnmsgr-transrespbody")) + { +#if 0 + char *ip_addrs; + char *temp; + char *nonce; + int port; + + nonce = get_token(content, "Nonce: {", "}\r\n"); + ip_addrs = get_token(content, "IPv4Internal-Addrs: ", "\r\n"); + + temp = get_token(content, "IPv4Internal-Port: ", "\r\n"); + if (temp != NULL) + port = atoi(temp); + else + port = -1; + g_free(temp); + + if (ip_addrs == NULL) + return; + + if (port > 0) + got_transresp(slpcall, nonce, ip_addrs, port); + + g_free(nonce); + g_free(ip_addrs); +#endif + } +} + +MsnSlpCall * +msn_slp_sip_recv(MsnSlpLink *slplink, const char *body, gsize len) +{ + MsnSlpCall *slpcall; + + if (!strncmp(body, "INVITE", strlen("INVITE"))) + { + char *branch; + char *content; + char *content_type; + + slpcall = msn_slp_call_new(slplink); + + /* From: */ +#if 0 + slpcall->remote_user = get_token(body, "From: \r\n"); +#endif + + branch = get_token(body, ";branch={", "}"); + + slpcall->id = get_token(body, "Call-ID: {", "}"); + +#if 0 + long content_len = -1; + + temp = get_token(body, "Content-Length: ", "\r\n"); + if (temp != NULL) + content_len = atoi(temp); + g_free(temp); +#endif + content_type = get_token(body, "Content-Type: ", "\r\n"); + + content = get_token(body, "\r\n\r\n", NULL); + + got_invite(slpcall, branch, content_type, content); + + g_free(content_type); + g_free(content); + } + else if (!strncmp(body, "MSNSLP/1.0 ", strlen("MSNSLP/1.0 "))) + { + char *content; + char *content_type; + /* Make sure this is "OK" */ + const char *status = body + strlen("MSNSLP/1.0 "); + char *call_id; + + call_id = get_token(body, "Call-ID: {", "}"); + slpcall = msn_slplink_find_slp_call(slplink, call_id); + g_free(call_id); + + if (strncmp(status, "200 OK", 6)) + { + /* It's not valid. Kill this off. */ + char temp[32]; + const char *c; + + /* Eww */ + if ((c = strchr(status, '\r')) || (c = strchr(status, '\n')) || + (c = strchr(status, '\0'))) + { + strncpy(temp, status, c - status); + temp[c - status] = '\0'; + } + + gaim_debug_error("msn", "Received non-OK result: %s\n", temp); + + slpcall->wasted = TRUE; + + /* msn_slp_call_destroy(slpcall); */ + return slpcall; + } + + content_type = get_token(body, "Content-Type: ", "\r\n"); + + content = get_token(body, "\r\n\r\n", NULL); + + got_ok(slpcall, content_type, content); + + g_free(content_type); + g_free(content); + } + else if (!strncmp(body, "BYE", strlen("BYE"))) + { + char *call_id; + + call_id = get_token(body, "Call-ID: {", "}"); + slpcall = msn_slplink_find_slp_call(slplink, call_id); + g_free(call_id); + + if (slpcall != NULL) + slpcall->wasted = TRUE; + + /* msn_slp_call_destroy(slpcall); */ + } + else + slpcall = NULL; + + return slpcall; +} + +/************************************************************************** + * Msg Callbacks + **************************************************************************/ + +void +msn_p2p_msg(MsnCmdProc *cmdproc, MsnMessage *msg) +{ + MsnSession *session; + MsnSlpLink *slplink; + + session = cmdproc->servconn->session; + slplink = msn_session_get_slplink(session, msg->remote_user); + + msn_slplink_process_msg(slplink, msg); +} + +void +got_emoticon(MsnSlpCall *slpcall, + const char *data, long long size) +{ + gaim_debug_info("msn", "Got smiley: %s\n", slpcall->data_info); + +#if 0 + GaimConversation *conv; + GaimConnection *gc = slpsession->swboard->servconn->session->account->gc; + serv_got_smiley(gc, info, data, size); +#endif +} + +void +msn_emoticon_msg(MsnCmdProc *cmdproc, MsnMessage *msg) +{ + MsnSession *session; + MsnSlpLink *slplink; + MsnObject *obj; + char **tokens; + char *smile; + const char *who; + + session = cmdproc->servconn->session; + + tokens = g_strsplit(msg->body, "\t", 2); + + smile = tokens[0]; + obj = msn_object_new_from_string(gaim_url_decode(tokens[1])); + + who = msn_object_get_creator(obj); + + slplink = msn_session_get_slplink(session, who); + + msn_slplink_request_object(slplink, smile, got_emoticon, obj); + + g_strfreev(tokens); +} + +void +got_user_display(MsnSlpCall *slpcall, + const char *data, long long size) +{ + const char *info; + GaimAccount *account; + GSList *sl; + + info = slpcall->data_info; + gaim_debug_info("msn", "Got User Display: %s\n", info); + + account = slpcall->slplink->session->account; + + /* TODO: I think we need better buddy icon core functions. */ + gaim_buddy_icons_set_for_user(account, slpcall->slplink->remote_user, + (void *)data, size); + + sl = gaim_find_buddies(account, slpcall->slplink->remote_user); + + for (; sl != NULL; sl = sl->next) + { + GaimBuddy *buddy = (GaimBuddy *)sl->data; + gaim_blist_node_set_string((GaimBlistNode*)buddy, "icon_checksum", info); + gaim_blist_save(); + } +} + +static gboolean +buddy_icon_cached(GaimConnection *gc, MsnObject *obj) +{ + GaimAccount *account; + GaimBuddy *buddy; + GSList *sl; + const char *old; + const char *new; + + g_return_val_if_fail(obj != NULL, FALSE); + + account = gaim_connection_get_account(gc); + + sl = gaim_find_buddies(account, msn_object_get_creator(obj)); + + if (sl == NULL) + { + return FALSE; + } + + buddy = (GaimBuddy *)sl->data; + + old = gaim_blist_node_get_string((GaimBlistNode *)buddy, "icon_checksum"); + new = msn_object_get_sha1c(obj); + + if (new == NULL) + { + return FALSE; + } + + if (old != NULL && !strcmp(old, new)) + return TRUE; + + return FALSE; +} + +void +msn_request_buddy_icon(GaimConnection *gc, const char *passport) +{ + MsnSession *session; + MsnSlpLink *slplink; + MsnUser *user; + MsnObject *obj; + const char *info; + + session = gc->proto_data; + + g_return_if_fail(session->protocol_ver == 9); + + slplink = msn_session_get_slplink(session, passport); + + user = msn_userlist_find_user(session->userlist, passport); + + obj = msn_user_get_object(user); + + if (obj == NULL) + /* It seems the user has not set a msnobject */ + return; + + info = msn_object_get_sha1c(obj); + + if (!buddy_icon_cached(gc, obj)) + msn_slplink_request_object(slplink, info, got_user_display, obj); +} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/slp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/slp.h Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,43 @@ +/** + * @file slp.h MSNSLP support + * + * gaim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _MSN_SLP_H_ +#define _MSN_SLP_H_ + +#define DEBUG_SLP 1 +/* #define DEBUG_SLP_FILES 1 */ + +#include "slpcall.h" + +#include "ft.h" + +void msn_xfer_progress_cb(MsnSlpCall *slpcall, gsize total_length, gsize + len, gsize offset); + +MsnSlpCall * msn_slp_sip_recv(MsnSlpLink *slplink, + const char *body, gsize len); + +void send_bye(MsnSlpCall *slpcall, const char *type); + +void msn_xfer_finish_cb(MsnSlpCall *slpcall, + const char *body, long long size); + +void msn_xfer_cancel(GaimXfer *xfer); + +#endif /* _MSN_SLP_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/slpcall.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/slpcall.c Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,216 @@ +/** + * @file slpcall.c SLP Call Functions + * + * gaim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "msn.h" +#include "slpcall.h" +#include "slpsession.h" + +#include "slp.h" + +/************************************************************************** + * Util + **************************************************************************/ + +char * +rand_guid() +{ + return g_strdup_printf("%4X%4X-%4X-%4X-%4X-%4X%4X%4X", + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111); +} + +/************************************************************************** + * SLP Call + **************************************************************************/ + +MsnSlpCall * +msn_slp_call_new(MsnSlpLink *slplink) +{ + MsnSlpCall *slpcall; + + g_return_val_if_fail(slplink != NULL, NULL); + + slpcall = g_new0(MsnSlpCall, 1); + + slpcall->slplink = slplink; + slplink->slp_calls = + g_list_append(slplink->slp_calls, slpcall); + + return slpcall; +} + +void +msn_slp_call_init(MsnSlpCall *slpcall, MsnSlpCallType type) +{ + slpcall->session_id = rand() % 0xFFFFFF00 + 4; + slpcall->id = rand_guid(); + slpcall->type = type; +} + +void +msn_slp_call_session_init(MsnSlpCall *slpcall) +{ + MsnSlpSession *slpsession; + + slpsession = msn_slp_session_new(slpcall); + + if (slpcall->session_init_cb) + slpcall->session_init_cb(slpsession); + + slpcall->started = TRUE; +} + +void +msn_slp_call_destroy(MsnSlpCall *slpcall) +{ + GList *e; + + g_return_if_fail(slpcall != NULL); + + if (slpcall->id != NULL) + g_free(slpcall->id); + + if (slpcall->branch != NULL) + g_free(slpcall->branch); + + if (slpcall->data_info != NULL) + g_free(slpcall->data_info); + + slpcall->slplink->slp_calls = + g_list_remove(slpcall->slplink->slp_calls, slpcall); + + for (e = slpcall->slplink->slp_msgs; e != NULL; ) + { + MsnSlpMessage *slpmsg = e->data; + e = e->next; + + g_return_if_fail(slpmsg != NULL); + + if (slpmsg->slpcall == slpcall) + { +#if 1 + msn_slpmsg_destroy(slpmsg); +#else + slpmsg->wasted = TRUE; +#endif + } + } + + if (slpcall->cb != NULL) + slpcall->cb(slpcall, NULL, -1); + + g_free(slpcall); +} + +void +msn_slp_call_invite(MsnSlpCall *slpcall, const char *euf_guid, + int app_id, const char *context) +{ + MsnSlpLink *slplink; + MsnSlpMessage *slpmsg; + char *header; + char *content; + char *branch; + + g_return_if_fail(slpcall != NULL); + g_return_if_fail(context != NULL); + + slplink = slpcall->slplink; + + branch = rand_guid(); + + content = g_strdup_printf( + "EUF-GUID: {%s}\r\n" + "SessionID: %lu\r\n" + "AppID: %d\r\n" + "Context: %s\r\n\r\n", + euf_guid, + slpcall->session_id, + app_id, + context); + + header = g_strdup_printf("INVITE MSNMSGR:%s MSNSLP/1.0", + slplink->remote_user); + + slpmsg = msn_slpmsg_sip_new(slpcall, 0, header, branch, + "application/x-msnmsgr-sessionreqbody", content); +#ifdef DEBUG_SLP + slpmsg->info = "SLP INVITE"; + slpmsg->text_body = TRUE; +#endif + + msn_slplink_send_slpmsg(slplink, slpmsg); + + g_free(header); + g_free(content); + + g_free(branch); +} + +void +msn_slp_call_close(MsnSlpCall *slpcall) +{ + g_return_if_fail(slpcall != NULL); + g_return_if_fail(slpcall->slplink != NULL); + + send_bye(slpcall, "application/x-msnmsgr-sessionclosebody"); + msn_slplink_unleash(slpcall->slplink); + msn_slp_call_destroy(slpcall); +} + +MsnSlpCall * +msn_slp_process_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) +{ + MsnSlpCall *slpcall; + const char *body; + gsize body_len; + + slpcall = NULL; + body = slpmsg->buffer; + body_len = slpmsg->size; + + if (slpmsg->flags == 0x0) + { + slpcall = msn_slp_sip_recv(slplink, body, body_len); + } + else if (slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) + { + slpcall = msn_slplink_find_slp_call_with_session_id(slplink, slpmsg->session_id); + + if (slpcall != NULL) + slpcall->cb(slpcall, body, body_len); + } +#if 0 + else if (slpmsg->flags == 0x100) + { + slpcall = slplink->directconn->initial_call; + + if (slpcall != NULL) + msn_slp_call_session_init(slpcall); + } +#endif + + return slpcall; +} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/slpcall.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/slpcall.h Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,76 @@ +/** + * @file slpcall.h SLP Call functions + * + * gaim + * + * Copyright (C) 2003-2004 Christian Hammond + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _MSN_SLPCALL_H_ +#define _MSN_SLPCALL_H_ + +typedef struct _MsnSlpCall MsnSlpCall; + +typedef void (*MsnSlpCb)(MsnSlpCall *slpcall, + const char *data, long long size); + +#include "slplink.h" +#include "slpsession.h" + +typedef enum +{ + MSN_SLPCALL_ANY, + MSN_SLPCALL_DC, + +} MsnSlpCallType; + +struct _MsnSlpCall +{ + /* MsnSession *session; */ + MsnSlpLink *slplink; + + MsnSlpCallType type; + + /* Call-ID */ + char *id; + char *branch; + + long session_id; + long app_id; + + void (*progress_cb)(MsnSlpCall *slpcall, + gsize total_length, gsize len, gsize offset); + void (*session_init_cb)(MsnSlpSession *slpsession); + + /* Can be checksum, or smile */ + char *data_info; + + void *xfer; + + MsnSlpCb cb; + gboolean wasted; + gboolean started; +}; + +MsnSlpCall *msn_slp_call_new(MsnSlpLink *slplink); +void msn_slp_call_init(MsnSlpCall *slpcall, MsnSlpCallType type); +void msn_slp_call_session_init(MsnSlpCall *slpcall); +void msn_slp_call_destroy(MsnSlpCall *slpcall); +void msn_slp_call_invite(MsnSlpCall *slpcall, const char *euf_guid, + int app_id, const char *context); +void msn_slp_call_close(MsnSlpCall *slpcall); + +#endif /* _MSN_SLPCALL_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/slplink.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/slplink.c Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,656 @@ +#include "msn.h" +#include "slplink.h" + +#include "switchboard.h" +#include "slp.h" + +void msn_slplink_send_msgpart(MsnSlpLink *slplink, MsnSlpMessage *slpmsg); + +#ifdef DEBUG_SLP_FILES +static int m_sc = 0; +static int m_rc = 0; + +static void +debug_msg_to_file(MsnMessage *msg, gboolean send) +{ + char *tmp; + char *dir; + char *pload; + FILE *tf; + int c; + gsize pload_size; + + dir = send ? "send" : "recv"; + c = send ? m_sc++ : m_rc++; + tmp = g_strdup_printf("%s/msntest/%s/%03d", g_get_home_dir(), dir, c); + tf = fopen(tmp, "w"); + pload = msn_message_gen_payload(msg, &pload_size); + fwrite(pload, 1, pload_size, tf); + fclose(tf); + g_free(tmp); +} +#endif + +MsnSlpLink * +msn_slplink_new(MsnSession *session, const char *username) +{ + MsnSlpLink *slplink; + + slplink = g_new0(MsnSlpLink, 1); + + slplink->session = session; + slplink->slp_seq_id = rand() % 0xFFFFFF00 + 4; + + slplink->local_user = g_strdup(msn_user_get_passport(session->user)); + slplink->remote_user = g_strdup(username); + + slplink->slp_msg_queue = g_queue_new(); + + session->slplinks = + g_list_append(session->slplinks, slplink); + + return slplink; +} + +void +msn_slplink_destroy(MsnSlpLink *slplink) +{ + MsnSession *session; + + session = slplink->session; + + if (slplink->local_user != NULL) + g_free(slplink->local_user); + + if (slplink->remote_user != NULL) + g_free(slplink->remote_user); + + if (slplink->directconn != NULL) + msn_directconn_destroy(slplink->directconn); + + session->slplinks = + g_list_remove(session->slplinks, slplink); + + g_free(slplink); +} + +MsnSlpLink * +msn_session_find_slplink(MsnSession *session, const char *who) +{ + MsnSlpLink *slplink; + GList *l; + + for (l = session->slplinks; l != NULL; l = l->next) + { + slplink = l->data; + + if (!strcmp(slplink->remote_user, who)) + return slplink; + } + + return NULL; +} + +MsnSlpLink * +msn_session_get_slplink(MsnSession *session, const char *username) +{ + MsnSlpLink *slplink; + + slplink = msn_session_find_slplink(session, username); + + if (slplink == NULL) + slplink = msn_slplink_new(session, username); + + return slplink; +} + +MsnSlpSession * +msn_slplink_find_slp_session(MsnSlpLink *slplink, long session_id) +{ + GList *l; + MsnSlpSession *slpsession; + + for (l = slplink->slp_sessions; l != NULL; l = l->next) + { + slpsession = l->data; + + if (slpsession->id == session_id) + return slpsession; + } + + return NULL; +} + +MsnSlpCall * +msn_slplink_find_slp_call(MsnSlpLink *slplink, const char *id) +{ + GList *l; + MsnSlpCall *slpcall; + + for (l = slplink->slp_calls; l != NULL; l = l->next) + { + slpcall = l->data; + + if (!strcmp(slpcall->id, id)) + return slpcall; + } + + return NULL; +} + +MsnSlpCall * +msn_slplink_find_slp_call_with_session_id(MsnSlpLink *slplink, long id) +{ + GList *l; + MsnSlpCall *slpcall; + + for (l = slplink->slp_calls; l != NULL; l = l->next) + { + slpcall = l->data; + + if (slpcall->session_id == id) + return slpcall; + } + + return NULL; +} + +void +msn_slplink_send_msg(MsnSlpLink *slplink, MsnMessage *msg) +{ + if (slplink->directconn != NULL) + { + msn_directconn_send_msg(slplink->directconn, msg); + } + else + { + MsnSwitchBoard *swboard; + + swboard = msn_session_get_swboard(slplink->session, slplink->remote_user); + + if (swboard == NULL) + return; + + if (!g_queue_is_empty(swboard->im_queue) || + !swboard->user_joined) + { + msn_switchboard_queue_msg(swboard, msg); + } + else + { + msn_switchboard_send_msg(swboard, msg); + } + } +} + +void t_ack(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + MsnSlpMessage *slpmsg; + long long real_size; + + slpmsg = cmd->trans->data; + +#if 0 + if (slpmsg->wasted) + { + gaim_debug_info("msn", "slpmsg cancelled %p\n", slpmsg); + + if (slpmsg->slpcall != NULL) + { + if (slpmsg->slpcall->cb != NULL) + slpmsg->slpcall->cb(slpmsg->slpcall, NULL, -1); + + msn_slpcall_destroy(slpmsg->slpcall); + } + + msn_slpmsg_destroy(slpmsg); + } +#endif + + real_size = (slpmsg->flags == 0x2) ? 0 : slpmsg->size; + + if (slpmsg->offset < real_size) + { + msn_slplink_send_msgpart(slpmsg->slplink, slpmsg); + } + else + { + /* The whole message has been sent */ + + if ((slpmsg->slpcall != NULL) && + (slpmsg->slpcall->cb != NULL)) + { + slpmsg->slpcall->cb(slpmsg->slpcall, NULL, 0); + } + + msn_slpmsg_destroy(slpmsg); + } +} + +void +msn_slplink_send_msgpart(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) +{ + MsnMessage *msg; + long long real_size; + size_t len = 0; + + msg = slpmsg->msg; + + real_size = (slpmsg->flags == 0x2) ? 0 : slpmsg->size; + + if (slpmsg->offset < real_size) + { + if (slpmsg->fp) + { + char data[1202]; + len = fread(data, 1, sizeof(data), slpmsg->fp); + msn_message_set_bin_data(msg, data, len); + } + else + { + len = slpmsg->size - slpmsg->offset; + + if (len > 1202) + len = 1202; + + msn_message_set_bin_data(msg, slpmsg->buffer + slpmsg->offset, len); + } + + msg->msnslp_header.offset = slpmsg->offset; + msg->msnslp_header.length = len; + } + +#ifdef DEBUG_SLP + msn_message_show_readable(msg, slpmsg->info, slpmsg->text_body); +#endif + +#ifdef DEBUG_SLP_FILES + debug_msg_to_file(msg, TRUE); +#endif + + msn_slplink_send_msg(slplink, msg); + + if ((slpmsg->slpcall != NULL) && + (slpmsg->slpcall->progress_cb != NULL)) + { + slpmsg->slpcall->progress_cb(slpmsg->slpcall, slpmsg->size, len, + slpmsg->offset); + } + + slpmsg->offset += len; +} + +void +msn_slplink_release_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) +{ + MsnMessage *msg; + + slpmsg->msg = msg = msn_message_new_msnslp(); + + if (slpmsg->flags == 0x0) + { + msg->msnslp_header.session_id = slpmsg->session_id; + msg->msnslp_header.ack_id = rand() % 0xFFFFFF00; + } + else if (slpmsg->flags == 0x2) + { + msg->msnslp_header.session_id = slpmsg->session_id; + msg->msnslp_header.ack_id = slpmsg->ack_id; + msg->msnslp_header.ack_size = slpmsg->ack_size; + } + else if (slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) + { + MsnSlpSession *slpsession; + slpsession = slpmsg->slpsession; + + g_return_if_fail(slpsession != NULL); + msg->msnslp_header.session_id = slpsession->id; + msg->msnslp_footer.value = slpsession->app_id; + msg->msnslp_header.ack_id = rand() % 0xFFFFFF00; + } + else if (slpmsg->flags == 0x100) + { + msg->msnslp_header.ack_id = slpmsg->ack_id; + msg->msnslp_header.ack_sub_id = slpmsg->ack_sub_id; + msg->msnslp_header.ack_size = slpmsg->ack_size; + } + + msg->msnslp_header.id = slpmsg->id; + msg->msnslp_header.flags = slpmsg->flags; + + msg->msnslp_header.total_size = slpmsg->size; + + msn_message_set_attr(msg, "P2P-Dest", slplink->remote_user); + + msg->ack_cb = t_ack; + msg->ack_data = slpmsg; + + msn_slplink_send_msgpart(slplink, slpmsg); +} + +void +msn_slplink_queue_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) +{ + slpmsg->id = slplink->slp_seq_id++; + + g_queue_push_head(slplink->slp_msg_queue, slpmsg); +} + +void +msn_slplink_send_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) +{ + slpmsg->id = slplink->slp_seq_id++; + + msn_slplink_release_msg(slplink, slpmsg); +} + +void +msn_slplink_unleash(MsnSlpLink *slplink) +{ + MsnSlpMessage *slpmsg; + + /* Send the queued msgs in the order they came. */ + + while ((slpmsg = g_queue_pop_tail(slplink->slp_msg_queue)) != NULL) + msn_slplink_release_msg(slplink, slpmsg); +} + +void +msn_slplink_send_ack(MsnSlpLink *slplink, MsnMessage *msg) +{ + MsnSlpMessage *slpmsg; + + slpmsg = msn_slpmsg_new(slplink); + + slpmsg->session_id = msg->msnslp_header.session_id; + slpmsg->size = msg->msnslp_header.total_size; + slpmsg->flags = 0x02; + slpmsg->ack_id = msg->msnslp_header.id; + slpmsg->ack_sub_id = msg->msnslp_header.ack_id; + slpmsg->ack_size = msg->msnslp_header.total_size; + +#ifdef DEBUG_SLP + slpmsg->info = "SLP ACK"; +#endif + + msn_slplink_send_slpmsg(slplink, slpmsg); +} + +void +send_file(MsnSlpSession *slpsession) +{ + MsnSlpCall *slpcall; + MsnSlpMessage *slpmsg; + + slpcall = slpsession->slpcall; + slpmsg = msn_slpmsg_new(slpcall->slplink); + slpmsg->flags = 0x1000030; + slpmsg->slpsession = slpsession; +#ifdef DEBUG_SLP + slpmsg->info = "SLP FILE"; +#endif + slpmsg->slpcall = slpcall; + msn_slpmsg_open_file(slpmsg, gaim_xfer_get_local_filename(slpcall->xfer)); + + gaim_xfer_add(slpcall->xfer); + msn_slplink_send_slpmsg(slpcall->slplink, slpmsg); +} + +void +msn_slplink_process_msg(MsnSlpLink *slplink, MsnMessage *msg) +{ + MsnSlpMessage *slpmsg; + const char *data; + gsize offset; + gsize len; + +#ifdef DEBUG_SLP + msn_slpmsg_show(msg); +#endif + +#ifdef DEBUG_SLP_FILES + debug_msg_to_file(msg, FALSE); +#endif + + if (msg->msnslp_header.total_size < msg->msnslp_header.length) + { + gaim_debug_error("msn", "This can't be good\n"); + g_return_if_reached(); + } + + slpmsg = NULL; + data = msn_message_get_bin_data(msg, &len); + + /* + OVERHEAD! + if (msg->msnslp_header.length < msg->msnslp_header.total_size) + */ + + offset = msg->msnslp_header.offset; + + if (offset == 0) + { + slpmsg = msn_slpmsg_new(slplink); + slpmsg->id = msg->msnslp_header.id; + slpmsg->session_id = msg->msnslp_header.session_id; + slpmsg->size = msg->msnslp_header.total_size; + slpmsg->flags = msg->msnslp_header.flags; + slpmsg->buffer = g_malloc(slpmsg->size); + + if (slpmsg->session_id) + { + if (slpmsg->slpcall == NULL) + slpmsg->slpcall = msn_slplink_find_slp_call_with_session_id(slplink, slpmsg->session_id); + + if (slpmsg->slpcall != NULL) + { + GaimXfer *xfer; + + xfer = slpmsg->slpcall->xfer; + + if (xfer != NULL) + { + slpmsg->fp = + fopen(gaim_xfer_get_local_filename(slpmsg->slpcall->xfer), "w"); + } + } + } + } + else + { + slpmsg = msn_slplink_message_find(slplink, msg->msnslp_header.id); + } + + if (slpmsg != NULL) + { + if (slpmsg->fp) + { + /* fseek(slpmsg->fp, offset, SEEK_SET); */ + len = fwrite(data, 1, len, slpmsg->fp); + } + else + { + memcpy(slpmsg->buffer + offset, data, len); + } + } + else + { + gaim_debug_error("msn", "Couldn't find slpmsg\n"); + g_return_if_reached(); + } + + if ((slpmsg->slpcall != NULL) && + (slpmsg->slpcall->progress_cb != NULL)) + { + slpmsg->slpcall->progress_cb(slpmsg->slpcall, slpmsg->size, len, offset); + } + +#if 0 + if (slpmsg->buffer == NULL) + return; +#endif + + if (msg->msnslp_header.offset + msg->msnslp_header.length + >= msg->msnslp_header.total_size) + { + /* All the pieces of the slpmsg have been received */ + MsnSlpCall *slpcall; + + slpcall = msn_slp_process_msg(slplink, slpmsg); + + if (slpmsg->flags == 0x100) + { + MsnDirectConn *directconn; + + directconn = slplink->directconn; + + if (!directconn->acked) + msn_directconn_send_handshake(directconn); + } + else if (slpmsg->flags == 0x0 || slpmsg->flags == 0x20 || + slpmsg->flags == 0x1000030) + { + /* Release all the messages and send the ACK */ + + msn_slplink_send_ack(slplink, msg); + msn_slplink_unleash(slplink); + } + + msn_slpmsg_destroy(slpmsg); + + if (slpcall != NULL && slpcall->wasted) + msn_slp_call_destroy(slpcall); + } +} + +MsnSlpMessage * +msn_slplink_message_find(MsnSlpLink *slplink, long id) +{ + GList *e; + + for (e = slplink->slp_msgs; e != NULL; e = e->next) + { + MsnSlpMessage *slpmsg = e->data; + + if (slpmsg->id == id) + return slpmsg; + } + + return NULL; +} + +typedef struct +{ + guint32 length; + guint32 unk1; + guint32 file_size; + guint32 unk2; + guint32 unk3; +} MsnContextHeader; + +#define MAX_FILE_NAME_LEN 0x226 + +char * +gen_context(const char *file_name) +{ + struct stat st; + gsize size = 0; + MsnContextHeader header; + gchar *u8; + gchar *base, *n; + gunichar2 *uni; + glong uni_len; + gsize len; + + if (stat(file_name, &st) == 0) + size = st.st_size; + + u8 = g_locale_to_utf8(g_basename(file_name), -1, NULL, NULL, NULL); + uni = g_utf8_to_utf16(u8, -1, NULL, &uni_len, NULL); + g_free(u8); + + len = sizeof(MsnContextHeader) + MAX_FILE_NAME_LEN + 4; + + header.length = GUINT32_TO_LE(len); + header.unk1 = GUINT32_TO_LE(2); + header.file_size = GUINT32_TO_LE(size); + header.unk2 = GUINT32_TO_LE(0); + header.unk3 = GUINT32_TO_LE(0); + + base = n = g_malloc(len + 1); + + memcpy(n, &header, sizeof(MsnContextHeader)); + n += sizeof(MsnContextHeader); + + memset(n, 0x00, MAX_FILE_NAME_LEN); + memcpy(n, uni, uni_len * 2); + n += MAX_FILE_NAME_LEN; + + memset(n, 0xFF, 4); + n += 4; + + g_free(uni); + + return gaim_base64_encode(base, len); +} + +void +msn_slplink_request_ft(MsnSlpLink *slplink, GaimXfer *xfer) +{ + MsnSlpCall *slpcall; + char *context; + const char *fn; + + fn = gaim_xfer_get_local_filename(xfer); + + g_return_if_fail(slplink != NULL); + g_return_if_fail(fn != NULL); + + slpcall = msn_slp_call_new(slplink); + msn_slp_call_init(slpcall, MSN_SLPCALL_DC); + + slpcall->session_init_cb = send_file; + slpcall->progress_cb = msn_xfer_progress_cb; + slpcall->cb = msn_xfer_finish_cb; + slpcall->xfer = xfer; + + gaim_xfer_set_cancel_send_fnc(xfer, msn_xfer_cancel); + + xfer->data = slpcall; + + context = gen_context(fn); + + msn_slp_call_invite(slpcall, "5D3E02AB-6190-11D3-BBBB-00C04F795683", 2, + context); + + g_free(context); +} + +void +msn_slplink_request_object(MsnSlpLink *slplink, + const char *info, + MsnSlpCb cb, + const MsnObject *obj) +{ + MsnSlpCall *slpcall; + char *msnobj_data; + char *msnobj_base64; + + g_return_if_fail(slplink != NULL); + g_return_if_fail(obj != NULL); + + msnobj_data = msn_object_to_string(obj); + msnobj_base64 = gaim_base64_encode(msnobj_data, strlen(msnobj_data)); + g_free(msnobj_data); + + slpcall = msn_slp_call_new(slplink); + msn_slp_call_init(slpcall, MSN_SLPCALL_ANY); + + slpcall->data_info = g_strdup(info); + slpcall->cb = cb; + + msn_slp_call_invite(slpcall, "A4268EEC-FEC5-49E5-95C3-F126696BDBF6", 1, + msnobj_base64); + + g_free(msnobj_base64); +} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/slplink.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/slplink.h Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,63 @@ +#ifndef _MSN_SLPLINK_H_ +#define _MSN_SLPLINK_H_ + +typedef struct _MsnSlpLink MsnSlpLink; + +#include "session.h" +#include "directconn.h" +#include "slpcall.h" +#include "slpmsg.h" + +#include "ft.h" + +struct _MsnSlpLink +{ + MsnSession *session; + + char *local_user; + char *remote_user; + + int slp_seq_id; + + MsnDirectConn *directconn; + + GList *slp_calls; + GList *slp_sessions; + GList *slp_msgs; + + GQueue *slp_msg_queue; +}; + +MsnSlpLink *msn_slplink_new(MsnSession *session, const char *username); +void msn_slplink_destroy(MsnSlpLink *slplink); +MsnSlpLink *msn_session_find_slplink(MsnSession *session, + const char *who); +MsnSlpLink *msn_session_get_slplink(MsnSession *session, const char *username); +MsnSlpSession *msn_slplink_find_slp_session(MsnSlpLink *slplink, + long session_id); +MsnSlpCall *msn_slplink_find_slp_call(MsnSlpLink *slplink, + const char *id); +MsnSlpCall *msn_slplink_find_slp_call_with_session_id(MsnSlpLink *slplink, long id); +void msn_slplink_send_msg(MsnSlpLink *slplink, MsnMessage *msg); +void msn_slplink_release_msg(MsnSlpLink *slplink, + MsnSlpMessage *slpmsg); +void msn_slplink_queue_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg); +void msn_slplink_send_slpmsg(MsnSlpLink *slplink, + MsnSlpMessage *slpmsg); +void msn_slplink_unleash(MsnSlpLink *slplink); +void msn_slplink_send_ack(MsnSlpLink *slplink, MsnMessage *msg); +void msn_slplink_process_msg(MsnSlpLink *slplink, MsnMessage *msg); +MsnSlpMessage *msn_slplink_message_find(MsnSlpLink *slplink, long id); +void msn_slplink_append_slp_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg); +void msn_slplink_remove_slp_msg(MsnSlpLink *slplink, + MsnSlpMessage *slpmsg); +void msn_slplink_request_ft(MsnSlpLink *slplink, GaimXfer *xfer); + +void msn_slplink_request_object(MsnSlpLink *slplink, + const char *info, + MsnSlpCb cb, + const MsnObject *obj); + +MsnSlpCall *msn_slp_process_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg); + +#endif /* _MSN_SLPLINK_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/slpmsg.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/slpmsg.c Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,187 @@ +/** + * @file slpmsg.h SLP Message functions + * + * gaim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "msn.h" +#include "slpmsg.h" +#include "slplink.h" + +/************************************************************************** + * SLP Message + **************************************************************************/ + +MsnSlpMessage * +msn_slpmsg_new(MsnSlpLink *slplink) +{ + MsnSlpMessage *slpmsg; + slpmsg = g_new0(MsnSlpMessage, 1); + + slpmsg->slplink = slplink; + + slplink->slp_msgs = + g_list_append(slplink->slp_msgs, slpmsg); + + return slpmsg; +} + +void +msn_slpmsg_destroy(MsnSlpMessage *slpmsg) +{ + MsnSlpLink *slplink; + + slplink = slpmsg->slplink; + + if (slpmsg->fp != NULL) + fclose(slpmsg->fp); + + if (slpmsg->buffer != NULL) + g_free(slpmsg->buffer); + +#ifdef DEBUG_SLP + /* + if (slpmsg->info != NULL) + g_free(slpmsg->info); + */ +#endif + + if (slpmsg->msg != NULL) + { + if (slpmsg->msg->trans != NULL) + { + slpmsg->msg->trans->callbacks = NULL; + slpmsg->msg->trans->data = NULL; + } + } + + slplink->slp_msgs = + g_list_remove(slplink->slp_msgs, slpmsg); + + g_free(slpmsg); +} + +void +msn_slpmsg_set_body(MsnSlpMessage *slpmsg, const char *body, + long long size) +{ + if (body != NULL) + slpmsg->buffer = g_memdup(body, size); + else + slpmsg->buffer = g_new0(char, size); + + slpmsg->size = size; +} + +void +msn_slpmsg_open_file(MsnSlpMessage *slpmsg, const char *file_name) +{ + struct stat st; + + slpmsg->fp = fopen(file_name, "r"); + + if (stat(file_name, &st) == 0) + slpmsg->size = st.st_size; +} + +#ifdef DEBUG_SLP +const void +msn_slpmsg_show(MsnMessage *msg) +{ + const char *info; + gboolean text; + guint32 flags; + + text = FALSE; + + flags = GUINT32_TO_LE(msg->msnslp_header.flags);; + + switch (flags) + { + case 0x0: + info = "SLP CONTROL"; + text = TRUE; + break; + case 0x2: + info = "SLP ACK"; break; + case 0x20: + info = "SLP DATA"; break; + default: + info = "SLP UNKNOWN"; break; + } + + msn_message_show_readable(msg, info, text); +} +#endif + +MsnSlpMessage * +msn_slpmsg_sip_new(MsnSlpCall *slpcall, int cseq, + const char *header, const char *branch, + const char *content_type, const char *content) +{ + MsnSlpLink *slplink; + MsnSlpMessage *slpmsg; + char *body; + gsize body_len; + gsize content_len; + + g_return_val_if_fail(slpcall != NULL, NULL); + g_return_val_if_fail(header != NULL, NULL); + + slplink = slpcall->slplink; + + /* Let's remember that "content" should end with a 0x00 */ + + content_len = (content != NULL) ? strlen(content) + 1 : 0; + + body = g_strdup_printf( + "%s\r\n" + "To: \r\n" + "From: \r\n" + "Via: MSNSLP/1.0/TLP ;branch={%s}\r\n" + "CSeq: %d\r\n" + "Call-ID: {%s}\r\n" + "Max-Forwards: 0\r\n" + "Content-Type: %s\r\n" + "Content-Length: %d\r\n" + "\r\n", + header, + slplink->remote_user, + slplink->local_user, + branch, + cseq, + slpcall->id, + content_type, + content_len); + + body_len = strlen(body); + + if (content_len > 0) + { + body_len += content_len; + body = g_realloc(body, body_len); + g_strlcat(body, content, body_len); + } + + slpmsg = msn_slpmsg_new(slplink); + msn_slpmsg_set_body(slpmsg, body, body_len); + + slpmsg->sip = TRUE; + + g_free(body); + + return slpmsg; +} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/slpmsg.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/slpmsg.h Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,82 @@ +/** + * @file slpmsg.h SLP Message functions + * + * gaim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _MSN_SLPMSG_H_ +#define _MSN_SLPMSG_H_ + +typedef struct _MsnSlpMessage MsnSlpMessage; + +#include "slpsession.h" +#include "slpcall.h" +#include "slplink.h" +#include "session.h" +#include "msg.h" + +#include "slp.h" + +struct _MsnSlpMessage +{ + MsnSlpSession *slpsession; + MsnSlpCall *slpcall; + MsnSlpLink *slplink; + MsnSession *session; + + long session_id; + long id; + long ack_id; + long ack_sub_id; + long long ack_size; + long app_id; + + gboolean sip; +#if 0 + gboolean wasted; +#endif + long flags; + + FILE *fp; + char *buffer; + long long offset; + long long size; + + MsnMessage *msg; /* The temporary real message that will be sent */ + +#ifdef DEBUG_SLP + char *info; + gboolean text_body; +#endif +}; + +MsnSlpMessage *msn_slpmsg_new(MsnSlpLink *slplink); +void msn_slpmsg_destroy(MsnSlpMessage *slpmsg); +void msn_slpmsg_set_body(MsnSlpMessage *slpmsg, const char *body, + long long size); +void msn_slpmsg_open_file(MsnSlpMessage *slpmsg, + const char *file_name); +MsnSlpMessage * msn_slpmsg_sip_new(MsnSlpCall *slpcall, int cseq, + const char *header, + const char *branch, + const char *content_type, + const char *content); + +#ifdef DEBUG_SLP +const void msn_slpmsg_show(MsnMessage *msg); +#endif + +#endif /* _MSN_SLPMSG_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/slpsession.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/slpsession.c Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,71 @@ +/** + * @file slpsession.h SLP Session functions + * + * gaim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "slpsession.h" + +/************************************************************************** + * SLP Session + **************************************************************************/ + +MsnSlpSession * +msn_slp_session_new(MsnSlpCall *slpcall) +{ + MsnSlpSession *slpsession; + + g_return_val_if_fail(slpcall != NULL, NULL); + + slpsession = g_new0(MsnSlpSession, 1); + + slpsession->slpcall = slpcall; + slpsession->id = slpcall->session_id; + slpsession->call_id = slpcall->id; + slpsession->app_id = slpcall->app_id; + + slpcall->slplink->slp_sessions = + g_list_append(slpcall->slplink->slp_sessions, slpsession); + + return slpsession; +} + +void +msn_slp_session_destroy(MsnSlpSession *slpsession) +{ + g_return_if_fail(slpsession != NULL); + + if (slpsession->call_id != NULL) + g_free(slpsession->call_id); + + slpsession->slpcall->slplink->slp_sessions = + g_list_remove(slpsession->slpcall->slplink->slp_sessions, slpsession); + + g_free(slpsession); +} + +void +msn_slp_session_send_slpmsg(MsnSlpSession *slpsession, MsnSlpMessage *slpmsg) +{ + slpmsg->slpsession = slpsession; + +#if 0 + slpmsg->session_id = slpsession->id; + slpmsg->app_id = slpsession->app_id; +#endif + + msn_slplink_send_slpmsg(slpsession->slpcall->slplink, slpmsg); +} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/slpsession.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/slpsession.h Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,44 @@ +/** + * @file slpsession.h SLP Session functions + * + * gaim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _MSN_SLPSESSION_H_ +#define _MSN_SLPSESSION_H_ + +typedef struct _MsnSlpSession MsnSlpSession; + +#include "slpcall.h" +#include "slpsession.h" +#include "slpmsg.h" + +struct _MsnSlpSession +{ + /* MsnSlpLink *slplink; */ + MsnSlpCall *slpcall; + + long id; + + long app_id; + char *call_id; +}; + +MsnSlpSession *msn_slp_session_new(MsnSlpCall *slpcall); +void msn_slp_session_destroy(MsnSlpSession *slpsession); +void msn_slpsession_send_slpmsg(MsnSlpSession *slpsession, + MsnSlpMessage *slpmsg); +#endif /* _MSN_SLPSESSION_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/state.c --- a/src/protocols/msn/state.c Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/state.c Sun Jun 06 02:39:08 2004 +0000 @@ -36,6 +36,40 @@ N_("Available") }; +void +msn_change_status(MsnSession *session, MsnAwayType state) +{ + MsnCmdProc *cmdproc; + MsnUser *user; + MsnObject *msnobj; + const char *state_text; + + cmdproc = session->notification->cmdproc; + user = session->user; + state_text = msn_state_get_text(state); + + g_return_if_fail(session != NULL); + + msnobj = msn_user_get_object(user); + + if (msnobj == NULL) + { + msn_cmdproc_send(cmdproc, "CHG", "%s %d", state_text, + MSN_CLIENT_ID); + } + else + { + char *msnobj_str; + + msnobj_str = msn_object_to_string(msnobj); + + msn_cmdproc_send(cmdproc, "CHG", "%s %d %s", state_text, + MSN_CLIENT_ID, gaim_url_encode(msnobj_str)); + + g_free(msnobj_str); + } +} + const char * msn_away_get_text(MsnAwayType type) { @@ -43,3 +77,12 @@ return _(away_text[type]); } + +const char * +msn_state_get_text(MsnAwayType state) +{ + static char *status_text[] = + { "NLN", "NLN", "BSY", "IDL", "BRB", "AWY", "PHN", "LUN", "HDN", "HDN" }; + + return status_text[state]; +} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/state.h --- a/src/protocols/msn/state.h Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/state.h Sun Jun 06 02:39:08 2004 +0000 @@ -42,6 +42,14 @@ #define MSN_AWAY_TYPE(x) (((x) >> 1) & 0x0F) /** + * Changes the status of the user. + * + * @param session The MSN session. + * @param state The new state. + */ +void msn_change_status(MsnSession *session, MsnAwayType state); + +/** * Returns the string representation of an away type. * * @param type The away type. @@ -50,4 +58,6 @@ */ const char *msn_away_get_text(MsnAwayType type); +const char *msn_state_get_text(MsnAwayType state); + #endif /* _MSN_STATE_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/switchboard.c --- a/src/protocols/msn/switchboard.c Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/switchboard.c Sun Jun 06 02:39:08 2004 +0000 @@ -20,12 +20,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "msn.h" -#include "msnslp.h" #include "prefs.h" #include "switchboard.h" +#include "notification.h" #include "utils.h" -static MsnTable *cbs_table = NULL; +#include "error.h" + +static MsnTable *cbs_table; /************************************************************************** * Utility functions @@ -45,6 +47,90 @@ msn_message_destroy(msg); } +void +msn_switchboard_add_user(MsnSwitchBoard *swboard, const char *user) +{ + MsnCmdProc *cmdproc; + GaimAccount *account; + + g_return_if_fail(swboard != NULL); + + cmdproc = swboard->servconn->cmdproc; + account = swboard->servconn->session->account; + + swboard->users = g_list_prepend(swboard->users, g_strdup(user)); + swboard->current_users++; + + /* gaim_debug_info("msn", "user=[%s], total=%d\n", user, + * swboard->current_users); */ + + if (swboard->current_users > 1 || swboard->total_users > 1) + { + if (swboard->conv == NULL || + gaim_conversation_get_type(swboard->conv) != GAIM_CONV_CHAT) + { + GList *l; + + /* gaim_debug_info("msn", "[chat] Switching to chat.\n"); */ + + if (swboard->conv != NULL) + gaim_conversation_destroy(swboard->conv); + + cmdproc->session->conv_seq++; + swboard->chat_id = cmdproc->session->conv_seq; + + swboard->conv = serv_got_joined_chat(account->gc, + swboard->chat_id, + "MSN Chat"); + + for (l = swboard->users; l != NULL; l = l->next) + { + const char *tmp_user; + + tmp_user = l->data; + + /* gaim_debug_info("msn", "[chat] Adding [%s].\n", + * tmp_user); */ + + gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->conv), + tmp_user, NULL); + } + + if (!swboard->invited) + { + /* gaim_debug_info("msn", "[chat] " + "Not invited, so we add im_user [%s].\n", + swboard->im_user); */ + + gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->conv), + swboard->im_user, NULL); + } + + /* gaim_debug_info("msn", "[chat] We add ourselves.\n"); */ + + gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->conv), + gaim_account_get_username(account), + NULL); + + g_free(swboard->im_user); + swboard->im_user = NULL; + } + else if (gaim_conversation_get_type(swboard->conv) == GAIM_CONV_CHAT) + { + gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->conv), user, NULL); + } + } + else if (swboard->conv == NULL) + { + swboard->conv = gaim_find_conversation_with_account(user, account); + } + else + { + gaim_debug_warning("msn", "This should happen!" + "(msn_switchboard_add_user)\n"); + } +} + /************************************************************************** * Switchboard Commands **************************************************************************/ @@ -52,35 +138,28 @@ ans_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSwitchBoard *swboard; +#if 1 MsnSession *session; + session = cmdproc->session; swboard = cmdproc->servconn->data; - session = cmdproc->session; /* send_clientcaps(swboard); */ - if (0 && session->protocol_ver >= 9) + if (session->protocol_ver >= 9) { - MsnUser *local_user, *remote_user; + GList *l; - remote_user = msn_user_new(session, - msn_user_get_passport(msn_switchboard_get_user(swboard)), - NULL); - local_user = msn_user_new(session, - gaim_account_get_username(session->account), - NULL); - - if (msn_user_get_object(remote_user) != NULL) + /* But we alredy know the switchboard... */ + /* What if there is more than one user? */ + for (l = swboard->users; l != NULL; l = l->next) { - swboard->slp_session = msn_slp_session_new(swboard, TRUE); - - msn_slp_session_request_user_display(swboard->slp_session, - local_user, remote_user, - msn_user_get_object(remote_user)); + msn_request_buddy_icon(session->account->gc, l->data); } } +#endif - swboard->joined = TRUE; + swboard->ready = TRUE; } static void @@ -88,17 +167,18 @@ { GaimAccount *account; MsnSwitchBoard *swboard; - const char *user = cmd->params[0]; + const char *user; account = cmdproc->session->account; swboard = cmdproc->servconn->data; + user = cmd->params[0]; if (swboard->hidden) return; - if (swboard->chat != NULL) + if (swboard->current_users > 1) { - gaim_conv_chat_remove_user(GAIM_CONV_CHAT(swboard->chat), user, NULL); + gaim_conv_chat_remove_user(GAIM_CONV_CHAT(swboard->conv), user, NULL); } else { @@ -138,7 +218,7 @@ g_free(str); } - msn_switchboard_destroy(swboard); + msn_switchboard_disconnect(swboard); } } @@ -153,88 +233,56 @@ gc = account->gc; swboard = cmdproc->servconn->data; - swboard->total_users = atoi(cmd->params[2]) + 1; - - if (swboard->total_users > 2) - { - if (swboard->chat == NULL) - { - GaimConversation *conv; - - conv = gaim_find_conversation_with_account( - msn_user_get_passport(swboard->user), account); + swboard->total_users = atoi(cmd->params[2]); - cmdproc->session->last_chat_id++; - swboard->chat_id = cmdproc->session->last_chat_id; - swboard->chat = serv_got_joined_chat(gc, swboard->chat_id, - "MSN Chat"); - - gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->chat), - gaim_account_get_username(account), NULL); - - gaim_conversation_destroy(conv); - } - - gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->chat), cmd->params[3], NULL); - } + msn_switchboard_add_user(swboard, cmd->params[3]); } static void joi_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { + MsnSession *session; GaimAccount *account; GaimConnection *gc; MsnSwitchBoard *swboard; const char *passport; - account = cmdproc->session->account; - gc = account->gc; - swboard = cmdproc->servconn->data; passport = cmd->params[0]; - if (swboard->total_users == 2 && swboard->chat == NULL) - { - GaimConversation *conv; - - conv = gaim_find_conversation_with_account( - msn_user_get_passport(swboard->user), account); + session = cmdproc->session; + account = session->account; + gc = account->gc; + swboard = cmdproc->servconn->data; - cmdproc->session->last_chat_id++; - swboard->chat_id = cmdproc->session->last_chat_id; - swboard->chat = serv_got_joined_chat(gc, swboard->chat_id, "MSN Chat"); - gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->chat), - msn_user_get_passport(swboard->user), NULL); - gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->chat), - gaim_account_get_username(account), NULL); + msn_switchboard_add_user(swboard, passport); + + swboard->user_joined = TRUE; - msn_user_unref(swboard->user); + /* msn_cmdproc_process_queue(cmdproc); */ - gaim_conversation_destroy(conv); - } - - if (swboard->chat != NULL) - gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->chat), passport, NULL); + msn_switchboard_process_queue(swboard); + + send_clientcaps(swboard); - swboard->total_users++; - - swboard->joined = TRUE; - - msn_cmdproc_process_queue(cmdproc); - - send_clientcaps(swboard); +#if 1 + if (session->protocol_ver >= 9) + /* But we alredy know the switchboard... */ + msn_request_buddy_icon(gc, passport); +#endif } static void -msg_cmd_post(MsnCmdProc *cmdproc, char *payload, size_t len) +msg_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len) { - MsnMessage *msg = msn_message_new(); + MsnMessage *msg; + + msg = msn_message_new_from_cmd(cmdproc->session, cmd); msn_message_parse_payload(msg, payload, len); + /* msn_message_show_readable(msg, "SB RECV", FALSE); */ - msg->passport = cmdproc->temp; + msg->remote_user = g_strdup(cmd->params[0]); msn_cmdproc_process_msg(cmdproc, msg); - g_free(cmdproc->temp); - cmdproc->temp = NULL; msn_message_destroy(msg); } @@ -242,23 +290,35 @@ static void msg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - cmdproc->payload_cb = msg_cmd_post; cmdproc->servconn->payload_len = atoi(cmd->params[2]); - cmdproc->temp = g_strdup(cmd->params[0]); + cmdproc->last_cmd->payload_cb = msg_cmd_post; } static void nak_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { /* - * TODO: Investigate this, as it seems to occur frequently with - * the old prpl. - * - * shx: This will only happend in the new protocol when we ask for it - * in the message flags. + gaim_notify_error(cmdproc->session->account->gc, NULL, + _("A MSN message may not have been received."), NULL); */ - gaim_notify_error(cmdproc->servconn->session->account->gc, NULL, - _("An MSN message may not have been received."), NULL); +} + +static void +ack_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ +#if 0 + MsnMessage *msg; + const char *body; + + msg = msn_message_new(); + msn_message_parse_payload(msg, cmd->trans->payload, cmd->trans->payload_len); + + body = msn_message_get_body(msg); + + gaim_debug_info("msn", "ACK: {%s}\n", body); + + msn_message_destroy(msg); +#endif } static void @@ -267,16 +327,13 @@ GaimConnection *gc; MsnSwitchBoard *swboard; - gc = cmdproc->servconn->session->account->gc; + gc = cmdproc->session->account->gc; swboard = cmdproc->servconn->data; - if (swboard->chat != NULL) - { - serv_got_chat_left(gc, - gaim_conv_chat_get_id(GAIM_CONV_CHAT(swboard->chat))); - } + if (swboard->current_users > 1) + serv_got_chat_left(gc, swboard->chat_id); - msn_switchboard_destroy(swboard); + msn_switchboard_disconnect(swboard); } static void @@ -286,8 +343,20 @@ swboard = cmdproc->servconn->data; - msn_cmdproc_send(swboard->cmdproc, "CAL", "%s", - msn_user_get_passport(swboard->user)); +#if 0 + GList *l; + + for (l = swboard->users; l != NULL; l = l->next) + { + const char *user; + user = l->data; + + msn_cmdproc_send(cmdproc, "CAL", "%s", user); + } +#endif + + swboard->ready = TRUE; + msn_cmdproc_process_queue(cmdproc); } /************************************************************************** @@ -314,7 +383,7 @@ body_enc = gaim_escape_html(body_str); g_free(body_str); - passport = msg->passport; + passport = msg->remote_user; if (!strcmp(passport, "messenger@microsoft.com") && strstr(body, "immediate security update")) @@ -346,11 +415,10 @@ body_final = body_enc; } - if (swboard->chat != NULL) + if (swboard->current_users > 1) { - serv_got_chat_in(gc, - gaim_conv_chat_get_id(GAIM_CONV_CHAT(swboard->chat)), - passport, 0, body_final, time(NULL)); + serv_got_chat_in(gc, swboard->chat_id, passport, 0, body_final, + time(NULL)); } else serv_got_im(gc, passport, body_final, 0, time(NULL)); @@ -363,14 +431,14 @@ { GaimConnection *gc; MsnSwitchBoard *swboard; + const char *value; char *passport; - const char *value; gc = cmdproc->session->account->gc; swboard = cmdproc->servconn->data; - passport = msg->passport; + passport = msg->remote_user; - if (swboard->chat == NULL && + if (swboard->current_users == 1 && (value = msn_message_get_attr(msg, "TypingUser")) != NULL) { serv_got_typing(gc, passport, MSN_TYPING_RECV_TIMEOUT, @@ -388,10 +456,10 @@ GHashTable *clientcaps; const char *value; + char *passport = msg->sender; + session = cmdproc->session; - swboard = cmdproc->servconn->data; - - user = msn_user_new(session, msg->passport, NULL); + swboard = cmdproc->servconn->swboard; clientcaps = msn_message_get_hashtable_from_body(msg); #endif @@ -403,7 +471,7 @@ MsnCmdProc *cmdproc; MsnTransaction *trans; char *payload; - size_t payload_len; + gsize payload_len; g_return_if_fail(swboard != NULL); g_return_if_fail(msg != NULL); @@ -412,22 +480,56 @@ payload = msn_message_gen_payload(msg, &payload_len); + /* msn_message_show_readable(msg, "SB SEND", FALSE); */ + trans = msn_transaction_new("MSG", "%c %d", msn_message_get_flag(msg), payload_len); + if (msg->ack_cb != NULL) + msn_transaction_add_cb(trans, "ACK", msg->ack_cb, msg->ack_data); + trans->payload = payload; trans->payload_len = payload_len; - if (!g_queue_is_empty(cmdproc->txqueue) || !swboard->joined) - msn_cmdproc_queue_trans(cmdproc, trans); - else - msn_cmdproc_send_trans(cmdproc, trans); + msg->trans = trans; + + msn_cmdproc_send_trans(cmdproc, trans); +} + +void +msn_switchboard_queue_msg(MsnSwitchBoard *swboard, MsnMessage *msg) +{ + g_return_if_fail(swboard != NULL); + g_return_if_fail(msg != NULL); + + gaim_debug_info("msn", "Appending message to queue.\n"); + + g_queue_push_tail(swboard->im_queue, msg); + + msn_message_ref(msg); +} + +void +msn_switchboard_process_queue(MsnSwitchBoard *swboard) +{ + MsnMessage *msg; + + g_return_if_fail(swboard != NULL); + + gaim_debug_info("msn", "Processing queue\n"); + + while ((msg = g_queue_pop_head(swboard->im_queue)) != NULL) + { + gaim_debug_info("msn", "Sending message\n"); + msn_switchboard_send_msg(swboard, msg); + msn_message_unref(msg); + } } /************************************************************************** * Connect stuff **************************************************************************/ -static gboolean +static void connect_cb(MsnServConn *servconn) { MsnSwitchBoard *swboard; @@ -435,15 +537,15 @@ GaimAccount *account; cmdproc = servconn->cmdproc; - g_return_val_if_fail(cmdproc != NULL, FALSE); + g_return_if_fail(cmdproc != NULL); + + cmdproc->ready = TRUE; account = servconn->session->account; swboard = servconn->data; - g_return_val_if_fail(swboard != NULL, FALSE); + g_return_if_fail(swboard != NULL); - /* swboard->user_joined = TRUE; */ - - swboard->in_use = TRUE; + swboard->user_joined = TRUE; if (msn_switchboard_is_invited(swboard)) { @@ -457,11 +559,6 @@ gaim_account_get_username(account), swboard->auth_key); } - - if (swboard->cmdproc->error) - return FALSE; - - return TRUE; } static void @@ -470,9 +567,9 @@ MsnSwitchBoard *swboard; swboard = servconn->data; + g_return_if_fail(swboard != NULL); - if (!swboard->destroying) - msn_switchboard_destroy(swboard); + msn_switchboard_destroy(swboard); } void @@ -480,23 +577,26 @@ { cbs_table = msn_table_new(); - /* Register the command callbacks. */ - msn_table_add_cmd(cbs_table, NULL, "ACK", NULL); - msn_table_add_cmd(cbs_table, "ANS", "ANS", ans_cmd); msn_table_add_cmd(cbs_table, "ANS", "IRO", iro_cmd); + msn_table_add_cmd(cbs_table, "MSG", "ACK", ack_cmd); msn_table_add_cmd(cbs_table, "MSG", "NAK", nak_cmd); msn_table_add_cmd(cbs_table, "USR", "USR", usr_cmd); - msn_table_add_cmd(cbs_table, "CAL", "CAL", NULL); - msn_table_add_cmd(cbs_table, NULL, "MSG", msg_cmd); msn_table_add_cmd(cbs_table, NULL, "JOI", joi_cmd); msn_table_add_cmd(cbs_table, NULL, "BYE", bye_cmd); msn_table_add_cmd(cbs_table, NULL, "OUT", out_cmd); +#if 0 + /* They might skip the history */ + msn_table_add_cmd(cbs_table, NULL, "ACK", NULL); +#endif + + msn_table_add_error(cbs_table, "MSG", NULL); + /* Register the message type callbacks. */ msn_table_add_msg_type(cbs_table, "text/plain", plain_msg); @@ -506,9 +606,13 @@ clientcaps_msg); msn_table_add_msg_type(cbs_table, "text/x-clientinfo", clientcaps_msg); -#if 0 msn_table_add_msg_type(cbs_table, "application/x-msnmsgrp2p", msn_p2p_msg); + msn_table_add_msg_type(cbs_table, "text/x-mms-emoticon", + msn_emoticon_msg); +#if 0 + msn_table_add_msg_type(cbs_table, "text/x-msmmsginvite", + msn_invite_msg); #endif } @@ -529,12 +633,15 @@ swboard = g_new0(MsnSwitchBoard, 1); + swboard->session = session; swboard->servconn = servconn = msn_servconn_new(session, MSN_SERVER_SB); - cmdproc = swboard->cmdproc = servconn->cmdproc; + cmdproc = servconn->cmdproc; msn_servconn_set_connect_cb(servconn, connect_cb); msn_servconn_set_disconnect_cb(servconn, disconnect_cb); + swboard->im_queue = g_queue_new(); + if (session->http_method) servconn->http_data->server_type = "SB"; @@ -551,18 +658,18 @@ msn_switchboard_destroy(MsnSwitchBoard *swboard) { MsnSession *session; + MsnMessage *msg; + GList *l; g_return_if_fail(swboard != NULL); - g_return_if_fail(!swboard->destroying); + + if (swboard->destroying) + return; swboard->destroying = TRUE; - session = swboard->servconn->session; - if (swboard->servconn->connected) - msn_switchboard_disconnect(swboard); - - if (swboard->user != NULL) - msn_user_unref(swboard->user); + if (swboard->im_user != NULL) + g_free(swboard->im_user); if (swboard->auth_key != NULL) g_free(swboard->auth_key); @@ -570,30 +677,77 @@ if (swboard->session_id != NULL) g_free(swboard->session_id); + for (l = swboard->users; l != NULL; l = l->next) + g_free(l->data); + + session = swboard->session; session->switches = g_list_remove(session->switches, swboard); - msn_servconn_destroy(swboard->servconn); + if (swboard->servconn != NULL) + msn_servconn_destroy(swboard->servconn); + + while ((msg = g_queue_pop_head(swboard->im_queue)) != NULL) + msn_message_destroy(msg); + + g_queue_free(swboard->im_queue); g_free(swboard); } +#if 0 void -msn_switchboard_set_user(MsnSwitchBoard *swboard, MsnUser *user) +msn_switchboard_set_user(MsnSwitchBoard *swboard, const char *user) { g_return_if_fail(swboard != NULL); - swboard->user = user; + if (swboard->user != NULL) + g_free(swboard->user); - msn_user_ref(user); + swboard->user = g_strdup(user); } -MsnUser * -msn_switchboard_get_user(const MsnSwitchBoard *swboard) +const char * +msn_switchboard_get_user(MsnSwitchBoard *swboard) { g_return_val_if_fail(swboard != NULL, NULL); return swboard->user; } +#endif + +#if 0 +static void +got_cal(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + MsnSwitchBoard *swboard; + const char *user; + + swboard = cmdproc->servconn->data; + + user = cmd->params[0]; + + msn_switchboard_add_user(swboard, user); +} +#endif + +void +msn_switchboard_request_add_user(MsnSwitchBoard *swboard, const char *user) +{ + MsnTransaction *trans; + MsnCmdProc *cmdproc; + + g_return_if_fail(swboard != NULL); + + cmdproc = swboard->servconn->cmdproc; + + trans = msn_transaction_new("CAL", "%s", user); + /* msn_transaction_add_cb(trans, "CAL", got_cal, NULL); */ + + if (swboard->ready) + msn_cmdproc_send_trans(cmdproc, trans); + else + msn_cmdproc_queue_trans(cmdproc, trans); +} void msn_switchboard_set_auth_key(MsnSwitchBoard *swboard, const char *key) @@ -605,7 +759,7 @@ } const char * -msn_switchboard_get_auth_key(const MsnSwitchBoard *swboard) +msn_switchboard_get_auth_key(MsnSwitchBoard *swboard) { g_return_val_if_fail(swboard != NULL, NULL); @@ -625,7 +779,7 @@ } const char * -msn_switchboard_get_session_id(const MsnSwitchBoard *swboard) +msn_switchboard_get_session_id(MsnSwitchBoard *swboard) { g_return_val_if_fail(swboard != NULL, NULL); @@ -641,7 +795,7 @@ } gboolean -msn_switchboard_is_invited(const MsnSwitchBoard *swboard) +msn_switchboard_is_invited(MsnSwitchBoard *swboard) { g_return_val_if_fail(swboard != NULL, FALSE); @@ -653,19 +807,47 @@ { g_return_val_if_fail(swboard != NULL, FALSE); - if (msn_servconn_connect(swboard->servconn, host, port)) - swboard->in_use = TRUE; - - return swboard->in_use; + return msn_servconn_connect(swboard->servconn, host, port); } void msn_switchboard_disconnect(MsnSwitchBoard *swboard) { g_return_if_fail(swboard != NULL); - g_return_if_fail(swboard->servconn->connected); msn_servconn_disconnect(swboard->servconn); +} - swboard->in_use = FALSE; +static void +got_swboard(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + MsnSwitchBoard *swboard; + swboard = cmd->trans->data; + char *host; + int port; + + msn_switchboard_set_auth_key(swboard, cmd->params[4]); + + msn_parse_socket(cmd->params[2], &host, &port); + + if (swboard->session->http_method) + port = 80; + + msn_switchboard_connect(swboard, host, port); } + +void +msn_switchboard_request(MsnSwitchBoard *swboard) +{ + MsnCmdProc *cmdproc; + MsnTransaction *trans; + + g_return_if_fail(swboard != NULL); + + cmdproc = swboard->session->notification->cmdproc; + + trans = msn_transaction_new("XFR", "%s", "SB"); + msn_transaction_add_cb(trans, "XFR", got_swboard, swboard); + + msn_cmdproc_send_trans(cmdproc, trans); +} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/switchboard.h --- a/src/protocols/msn/switchboard.h Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/switchboard.h Sun Jun 06 02:39:08 2004 +0000 @@ -27,16 +27,15 @@ #include "conversation.h" #include "msg.h" -#include "msnslp.h" +#include "user.h" + #include "servconn.h" -#include "cmdproc.h" -#include "user.h" struct _MsnSwitchBoard { + MsnSession *session; MsnServConn *servconn; - MsnCmdProc *cmdproc; - MsnUser *user; + char *im_user; char *auth_key; char *session_id; @@ -44,21 +43,21 @@ gboolean invited; gboolean destroying; - GaimConversation *chat; - - gboolean in_use; - gboolean joined; + GaimConversation *conv; - int total_users; + gboolean ready; /* When it's actually usable */ + /* gboolean in_use; */ - gboolean msg; - int msglen; + int current_users; + int total_users; + GList *users; int chat_id; gboolean hidden; - MsnSlpSession *slp_session; + gboolean user_joined; + GQueue *im_queue; }; /** @@ -87,13 +86,14 @@ */ void msn_switchboard_destroy(MsnSwitchBoard *swboard); +#if 0 /** * Sets the user the switchboard is supposed to connect to. * * @param swboard The switchboard. * @param user The user. */ -void msn_switchboard_set_user(MsnSwitchBoard *swboard, MsnUser *user); +void msn_switchboard_set_user(MsnSwitchBoard *swboard, const char *user); /** * Returns the user the switchboard is supposed to connect to. @@ -102,7 +102,8 @@ * * @return The user. */ -MsnUser *msn_switchboard_get_user(const MsnSwitchBoard *swboard); +const char *msn_switchboard_get_user(MsnSwitchBoard *swboard); +#endif /** * Sets the auth key the switchboard must use when connecting. @@ -119,7 +120,7 @@ * * @return The auth key. */ -const char *msn_switchboard_get_auth_key(const MsnSwitchBoard *swboard); +const char *msn_switchboard_get_auth_key(MsnSwitchBoard *swboard); /** * Sets the session ID the switchboard must use when connecting. @@ -136,7 +137,7 @@ * * @return The session ID. */ -const char *msn_switchboard_get_session_id(const MsnSwitchBoard *swboard); +const char *msn_switchboard_get_session_id(MsnSwitchBoard *swboard); /** * Sets whether or not the user was invited to this switchboard. @@ -153,7 +154,7 @@ * * @return @c TRUE if invited, @c FALSE otherwise. */ -gboolean msn_switchboard_is_invited(const MsnSwitchBoard *swboard); +gboolean msn_switchboard_is_invited(MsnSwitchBoard *swboard); /** * Connects to a switchboard. @@ -166,21 +167,25 @@ */ gboolean msn_switchboard_connect(MsnSwitchBoard *swboard, const char *host, int port); +void msn_switchboard_disconnect(MsnSwitchBoard *swboard); +void msn_switchboard_send_msg(MsnSwitchBoard *swboard, MsnMessage *msg); -/** - * Disconnects from a switchboard. - * - * @param swboard The switchboard. - */ -void msn_switchboard_disconnect(MsnSwitchBoard *swboard); +gboolean msn_switchboard_chat_leave(MsnSwitchBoard *swboard); +gboolean msn_switchboard_chat_invite(MsnSwitchBoard *swboard, const char *who); + +void msn_switchboard_request(MsnSwitchBoard *swboard); +void msn_switchboard_request_add_user(MsnSwitchBoard *swboard, const char *user); +void msn_switchboard_queue_msg(MsnSwitchBoard *swboard, MsnMessage *msg); +void msn_switchboard_process_queue(MsnSwitchBoard *swboard); /** - * Sends a message to a switchboard. + * Processes application/x-msnmsgrp2p messages. * - * @param swboard The switchboard. - * @param msg The message to send. + * @param cmdproc The command processor. + * @param msg The message. */ -void msn_switchboard_send_msg(MsnSwitchBoard *swboard, - MsnMessage *msg); +void msn_p2p_msg(MsnCmdProc *cmdproc, MsnMessage *msg); +void msn_emoticon_msg(MsnCmdProc *cmdproc, MsnMessage *msg); +void msn_invite_msg(MsnCmdProc *cmdproc, MsnMessage *msg); #endif /* _MSN_SWITCHBOARD_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/sync.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/sync.c Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,227 @@ +#include "msn.h" +#include "sync.h" +#include "state.h" + +static MsnTable *cbs_table; + +static void +blp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + GaimConnection *gc = cmdproc->session->account->gc; + const char *list_name; + + list_name = cmd->params[0]; + + if (!g_ascii_strcasecmp(list_name, "AL")) + { + /* + * If the current setting is AL, messages from users who + * are not in BL will be delivered. + * + * In other words, deny some. + */ + gc->account->perm_deny = GAIM_PRIVACY_DENY_USERS; + } + else + { + /* If the current setting is BL, only messages from people + * who are in the AL will be delivered. + * + * In other words, permit some. + */ + gc->account->perm_deny = GAIM_PRIVACY_ALLOW_USERS; + } +} + +static void +prp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + MsnSession *session = cmdproc->session; + const char *type, *value; + + type = cmd->params[0]; + value = cmd->params[1]; + + if (cmd->param_count == 2) + { + if (!strcmp(type, "PHH")) + msn_user_set_home_phone(session->user, gaim_url_decode(value)); + else if (!strcmp(type, "PHW")) + msn_user_set_work_phone(session->user, gaim_url_decode(value)); + else if (!strcmp(type, "PHM")) + msn_user_set_mobile_phone(session->user, gaim_url_decode(value)); + } + else + { + if (!strcmp(type, "PHH")) + msn_user_set_home_phone(session->user, NULL); + else if (!strcmp(type, "PHW")) + msn_user_set_work_phone(session->user, NULL); + else if (!strcmp(type, "PHM")) + msn_user_set_mobile_phone(session->user, NULL); + } +} + +static void +lsg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + MsnSession *session = cmdproc->session; + MsnGroup *group; + GaimGroup *g; + const char *name; + int group_id; + + group_id = atoi(cmd->params[0]); + name = gaim_url_decode(cmd->params[1]); + + group = msn_group_new(session->userlist, group_id, name); + + if ((g = gaim_find_group(name)) == NULL) + { + g = gaim_group_new(name); + gaim_blist_add_group(g, NULL); + } +} + +static void +lst_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + MsnSession *session = cmdproc->session; + GaimAccount *account = session->account; + GaimConnection *gc = gaim_account_get_connection(account); + char *passport = NULL; + const char *friend = NULL; + int list_op; + MsnUser *user; + + passport = cmd->params[0]; + friend = gaim_url_decode(cmd->params[1]); + list_op = atoi(cmd->params[2]); + + user = msn_user_new(session->userlist, passport, friend); + + msn_userlist_add_user(session->userlist, user); + + session->sync->last_user = user; + + /* TODO: This can be improved */ + + if (list_op & MSN_LIST_FL_OP) + { + char **c; + char **tokens; + const char *group_nums; + GSList *group_ids; + + group_nums = cmd->params[3]; + + group_ids = NULL; + + tokens = g_strsplit(group_nums, ",", -1); + + for (c = tokens; *c != NULL; c++) + { + int id; + + id = atoi(*c); + group_ids = g_slist_append(group_ids, GINT_TO_POINTER(id)); + } + + g_strfreev(tokens); + + msn_got_lst_user(session, user, list_op, group_ids); + + g_slist_free(group_ids); + } + else + { + msn_got_lst_user(session, user, list_op, NULL); + } + + session->sync->num_users++; + + if (session->sync->num_users == session->sync->total_users) + { + cmdproc->cbs_table = session->sync->old_cbs_table; + + msn_user_set_buddy_icon(session->user, + gaim_account_get_buddy_icon(session->account)); + + msn_change_status(session, MSN_ONLINE); + + gaim_connection_set_state(gc, GAIM_CONNECTED); + serv_finish_login(gc); + + msn_sync_destroy(session->sync); + session->sync = NULL; + } +} + +static void +bpr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + MsnSync *sync = cmdproc->session->sync; + const char *type, *value; + MsnUser *user; + + user = sync->last_user; + + type = cmd->params[0]; + value = cmd->params[1]; + + if (value) + { + if (!strcmp(type, "MOB")) + { + if (!strcmp(value, "Y")) + user->mobile = TRUE; + } + else if (!strcmp(type, "PHH")) + msn_user_set_home_phone(user, gaim_url_decode(value)); + else if (!strcmp(type, "PHW")) + msn_user_set_work_phone(user, gaim_url_decode(value)); + else if (!strcmp(type, "PHM")) + msn_user_set_mobile_phone(user, gaim_url_decode(value)); + } +} + +void +msn_sync_init(void) +{ + /* TODO: check prp, blp, bpr */ + + cbs_table = msn_table_new(); + + /* Syncing */ + msn_table_add_cmd(cbs_table, NULL, "GTC", NULL); + msn_table_add_cmd(cbs_table, NULL, "BLP", blp_cmd); + msn_table_add_cmd(cbs_table, NULL, "PRP", prp_cmd); + msn_table_add_cmd(cbs_table, NULL, "LSG", lsg_cmd); + msn_table_add_cmd(cbs_table, NULL, "LST", lst_cmd); + msn_table_add_cmd(cbs_table, NULL, "BPR", bpr_cmd); +} + +void +msn_sync_end(void) +{ + msn_table_destroy(cbs_table); +} + +MsnSync * +msn_sync_new(MsnSession *session) +{ + MsnSync *sync; + + sync = g_new0(MsnSync, 1); + + sync->session = session; + sync->cbs_table = cbs_table; + + return sync; +} + +void +msn_sync_destroy(MsnSync *sync) +{ + g_free(sync); +} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/sync.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/sync.h Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,29 @@ +#ifndef _MSN_SYNC_H_ +#define _MSN_SYNC_H_ + +typedef struct _MsnSync MsnSync; + +#include "session.h" +#include "table.h" +#include "user.h" + +struct _MsnSync +{ + MsnSession *session; + MsnTable *cbs_table; + MsnTable *old_cbs_table; + + int num_users; + int total_users; + int num_groups; + int total_groups; + MsnUser *last_user; +}; + +void msn_sync_init(void); +void msn_sync_end(void); + +MsnSync * msn_sync_new(MsnSession *session); +void msn_sync_destroy(MsnSync *sync); + +#endif /* _MSN_SYNC_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/table.h --- a/src/protocols/msn/table.h Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/table.h Sun Jun 06 02:39:08 2004 +0000 @@ -28,7 +28,6 @@ #include "transaction.h" #include "msg.h" -typedef void (*MsnTransCb)(MsnCmdProc *cmdproc, MsnCommand *cmd); typedef void (*MsnErrorCb)(MsnCmdProc *cmdproc, MsnTransaction *trans, int error); typedef void (*MsnMsgCb)(MsnCmdProc *cmdproc, MsnMessage *msg); diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/transaction.c --- a/src/protocols/msn/transaction.c Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/transaction.c Sun Jun 06 02:39:08 2004 +0000 @@ -90,6 +90,47 @@ } void +msn_transaction_queue_cmd(MsnTransaction *trans, MsnCommand *cmd) +{ + gaim_debug_info("msn", "queueing command.\n"); + trans->pendent_cmd = cmd; + msn_command_ref(cmd); +} + +void +msn_transaction_unqueue_cmd(MsnTransaction *trans, MsnCmdProc *cmdproc) +{ + gaim_debug_info("msn", "unqueueing command.\n"); + MsnCommand *cmd = trans->pendent_cmd; + g_return_if_fail(cmd != NULL); + + msn_cmdproc_process_cmd(cmdproc, cmd); + msn_command_unref(cmd); + + trans->pendent_cmd = NULL; +} + +#if 0 +void +msn_transaction_queue(MsnTransaction *trans, MsnTransaction *elem) +{ + if (trans->queue == NULL) + trans->queue = g_queue_new(); + + g_queue_push_tail(trans->queue, elem); +} + +void +msn_transaction_unqueue(MsnTransaction *trans, MsnCmdProc *cmdproc) +{ + MsnTransaction *elem; + + while ((elem = g_queue_pop_head(trans->queue)) != NULL) + msn_cmdproc_send_trans(cmdproc, elem); +} +#endif + +void msn_transaction_set_payload(MsnTransaction *trans, const char *payload, int payload_len) { @@ -99,3 +140,26 @@ trans->payload = g_strdup(payload); trans->payload_len = payload_len ? payload_len : strlen(trans->payload); } + +void +msn_transaction_set_data(MsnTransaction *trans, void *data) +{ + g_return_if_fail(trans != NULL); + + trans->data = data; +} + +void +msn_transaction_add_cb(MsnTransaction *trans, char *answer, + MsnTransCb cb, void *data) +{ + g_return_if_fail(trans != NULL); + g_return_if_fail(answer != NULL); + + if (trans->callbacks == NULL) + trans->callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); + + g_hash_table_insert(trans->callbacks, answer, cb); + + trans->data = data; +} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/transaction.h --- a/src/protocols/msn/transaction.h Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/transaction.h Sun Jun 06 02:39:08 2004 +0000 @@ -27,6 +27,8 @@ #include "command.h" #include "cmdproc.h" +typedef void (*MsnTransCb)(MsnCmdProc *cmdproc, MsnCommand *cmd); + /** * A transaction. A command that will initiate the transaction. */ @@ -49,11 +51,15 @@ MsnTransaction *msn_transaction_new(const char *command, const char *format, ...); - void msn_transaction_destroy(MsnTransaction *trans); char *msn_transaction_to_string(MsnTransaction *trans); +void msn_transaction_queue_cmd(MsnTransaction *trans, MsnCommand *cmd); +void msn_transaction_unqueue_cmd(MsnTransaction *trans, MsnCmdProc *cmdproc); void msn_transaction_set_payload(MsnTransaction *trans, const char *payload, int payload_len); +void msn_transaction_set_data(MsnTransaction *trans, void *data); +void msn_transaction_add_cb(MsnTransaction *trans, char *answer, + MsnTransCb cb, void *data); #endif /* _MSN_TRANSACTION_H */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/user.c --- a/src/protocols/msn/user.c Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/user.c Sun Jun 06 02:39:08 2004 +0000 @@ -23,22 +23,16 @@ #include "user.h" MsnUser * -msn_user_new(MsnSession *session, const char *passport, const char *name) +msn_user_new(MsnUserList *userlist, const char *passport, + const char *store_name) { MsnUser *user; - user = msn_users_find_with_passport(session->users, passport); - - if (user == NULL) - { - user = g_new0(MsnUser, 1); + user = g_new0(MsnUser, 1); - user->session = session; + user->userlist = userlist; - msn_user_set_passport(user, passport); - - msn_users_add(session->users, user); - } + msn_user_set_passport(user, passport); /* * XXX This seems to reset the friendly name from what it should be @@ -49,8 +43,6 @@ msn_user_set_name(user, name); #endif - msn_user_ref(user); - return user; } @@ -59,15 +51,6 @@ { g_return_if_fail(user != NULL); - if (user->ref_count > 0) { - msn_user_unref(user); - - return; - } - - if (user->session != NULL && user->session->users != NULL) - msn_users_remove(user->session->users, user); - if (user->clientcaps != NULL) g_hash_table_destroy(user->clientcaps); @@ -77,45 +60,27 @@ if (user->msnobj != NULL) msn_object_destroy(user->msnobj); - if (user->passport != NULL) g_free(user->passport); - if (user->name != NULL) g_free(user->name); + if (user->passport != NULL) + g_free(user->passport); + + if (user->friendly_name != NULL) + g_free(user->friendly_name); + + if (user->store_name != NULL) + g_free(user->store_name); - if (user->phone.home != NULL) g_free(user->phone.home); - if (user->phone.work != NULL) g_free(user->phone.work); - if (user->phone.mobile != NULL) g_free(user->phone.mobile); + if (user->phone.home != NULL) + g_free(user->phone.home); + + if (user->phone.work != NULL) + g_free(user->phone.work); + + if (user->phone.mobile != NULL) + g_free(user->phone.mobile); g_free(user); } -MsnUser * -msn_user_ref(MsnUser *user) -{ - g_return_val_if_fail(user != NULL, NULL); - - user->ref_count++; - - return user; -} - -MsnUser * -msn_user_unref(MsnUser *user) -{ - g_return_val_if_fail(user != NULL, NULL); - - if (user->ref_count <= 0) - return NULL; - - user->ref_count--; - - if (user->ref_count == 0) { - msn_user_destroy(user); - - return NULL; - } - - return user; -} - void msn_user_set_passport(MsnUser *user, const char *passport) { @@ -128,14 +93,25 @@ } void -msn_user_set_name(MsnUser *user, const char *name) +msn_user_set_friendly_name(MsnUser *user, const char *name) { g_return_if_fail(user != NULL); - if (user->name != NULL) - g_free(user->name); + if (user->friendly_name != NULL) + g_free(user->friendly_name); + + user->friendly_name = g_strdup(name); +} - user->name = g_strdup(name); +void +msn_user_set_store_name(MsnUser *user, const char *name) +{ + g_return_if_fail(user != NULL); + + if (user->store_name != NULL) + g_free(user->store_name); + + user->store_name = g_strdup(name); } void @@ -148,24 +124,29 @@ g_return_if_fail(user != NULL); if (filename == NULL || stat(filename, &st) == -1) + { msn_user_set_object(user, NULL); + } else if ((fp = fopen(filename, "rb")) != NULL) { unsigned char *buf; SHA_CTX ctx; - size_t len; + gsize len; char *base64; unsigned char digest[20]; if (msnobj == NULL) { - msnobj = msn_object_new(); + msnobj = msn_object_new(TRUE); + msn_object_set_local(msnobj); msn_object_set_type(msnobj, MSN_OBJECT_USERTILE); - msn_object_set_location(msnobj, "TFR2C.tmp"); + msn_object_set_location(msnobj, "TFR2C2.tmp"); msn_object_set_creator(msnobj, msn_user_get_passport(user)); msn_user_set_object(user, msnobj); } + + msn_object_set_real_location(msnobj, filename); buf = g_malloc(st.st_size); len = fread(buf, 1, st.st_size, fp); @@ -215,21 +196,38 @@ } void -msn_user_set_group_ids(MsnUser *user, GList *ids) -{ - g_return_if_fail(user != NULL); - - user->group_ids = ids; -} - -void msn_user_add_group_id(MsnUser *user, int id) { + MsnUserList *userlist; + GaimAccount *account; + GaimBuddy *b; + GaimGroup *g; + const char *passport; + const char *group_name; + g_return_if_fail(user != NULL); g_return_if_fail(id > -1); - if (!g_list_find(user->group_ids, GINT_TO_POINTER(id))) - user->group_ids = g_list_append(user->group_ids, GINT_TO_POINTER(id)); + user->group_ids = g_list_append(user->group_ids, GINT_TO_POINTER(id)); + + userlist = user->userlist; + account = userlist->session->account; + passport = msn_user_get_passport(user); + + group_name = msn_userlist_find_group_name(userlist, id); + + g = gaim_find_group(group_name); + + b = gaim_find_buddy_in_group(account, passport, g); + + if (b == NULL) + { + b = gaim_buddy_new(account, passport, NULL); + + gaim_blist_add_buddy(b, NULL, g, NULL); + } + + b->proto_data = user; } void @@ -240,6 +238,7 @@ user->group_ids = g_list_remove(user->group_ids, GINT_TO_POINTER(id)); } + void msn_user_set_home_phone(MsnUser *user, const char *number) { @@ -282,6 +281,19 @@ msn_object_destroy(user->msnobj); user->msnobj = obj; + + if (user->list_op & MSN_LIST_FL_OP) + { + /* TODO: I think we need better buddy icon core functions */ + GaimAccount *account; + const char *username; + + account = user->userlist->session->account; + username = msn_object_get_creator(obj);; + + if (gaim_find_conversation_with_account(username, account) != NULL) + msn_request_buddy_icon(account->gc, username); + } } void @@ -305,19 +317,19 @@ } const char * -msn_user_get_name(const MsnUser *user) +msn_user_get_friendly_name(const MsnUser *user) { g_return_val_if_fail(user != NULL, NULL); - return user->name; + return user->friendly_name; } -GList * -msn_user_get_group_ids(const MsnUser *user) +const char * +msn_user_get_store_name(const MsnUser *user) { g_return_val_if_fail(user != NULL, NULL); - return user->group_ids; + return user->store_name; } const char * @@ -359,80 +371,3 @@ return user->clientcaps; } - -MsnUsers * -msn_users_new(void) -{ - MsnUsers *users = g_new0(MsnUsers, 1); - - return users; -} - -void -msn_users_destroy(MsnUsers *users) -{ - GList *l, *l_next = NULL; - - g_return_if_fail(users != NULL); - - for (l = users->users; l != NULL; l = l_next) { - l_next = l->next; - - msn_user_destroy(l->data); - - users->users = g_list_remove(users->users, l->data); - } - - g_free(users); -} - -void -msn_users_add(MsnUsers *users, MsnUser *user) -{ - g_return_if_fail(users != NULL); - g_return_if_fail(user != NULL); - - users->users = g_list_append(users->users, user); - - users->count++; -} - -void -msn_users_remove(MsnUsers *users, MsnUser *user) -{ - g_return_if_fail(users != NULL); - g_return_if_fail(user != NULL); - - users->users = g_list_remove(users->users, user); - - users->count--; -} - -size_t -msn_users_get_count(const MsnUsers *users) -{ - g_return_val_if_fail(users != NULL, 0); - - return users->count; -} - -MsnUser * -msn_users_find_with_passport(MsnUsers *users, const char *passport) -{ - GList *l; - - g_return_val_if_fail(users != NULL, NULL); - g_return_val_if_fail(passport != NULL, NULL); - - for (l = users->users; l != NULL; l = l->next) { - MsnUser *user = (MsnUser *)l->data; - - if (user->passport != NULL && - !g_ascii_strcasecmp(passport, user->passport)) { - - return user; - } - } - - return NULL; -} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/user.h --- a/src/protocols/msn/user.h Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/user.h Sun Jun 06 02:39:08 2004 +0000 @@ -23,49 +23,44 @@ #define _MSN_USER_H_ typedef struct _MsnUser MsnUser; -typedef struct _MsnUsers MsnUsers; #include "session.h" -#include "msnobject.h" +#include "object.h" + +#include "userlist.h" /** * A user. */ struct _MsnUser { - MsnSession *session; /**< The MSN session. */ +#if 0 + MsnSession *session; /**< The MSN session. */ +#endif + MsnUserList *userlist; - char *passport; /**< The passport account. */ - char *name; /**< The friendly name. */ + char *passport; /**< The passport account. */ + char *store_name; /**< The name stored in the server. */ + char *friendly_name; /**< The friendly name. */ struct { - char *home; /**< Home phone number. */ - char *work; /**< Work phone number. */ - char *mobile; /**< Mobile phone number. */ + char *home; /**< Home phone number. */ + char *work; /**< Work phone number. */ + char *mobile; /**< Mobile phone number. */ } phone; - gboolean authorized; /**< Authorized to add this user. */ - gboolean mobile; /**< Signed up with MSN Mobile. */ + gboolean authorized; /**< Authorized to add this user. */ + gboolean mobile; /**< Signed up with MSN Mobile. */ - GList *group_ids; /**< The group IDs. */ - - size_t ref_count; /**< The reference count. */ - - MsnObject *msnobj; /**< The user's MSN Object. */ + GList *group_ids; /**< The group IDs. */ - GHashTable *clientcaps; /**< The client's capabilities. */ -}; + MsnObject *msnobj; /**< The user's MSN Object. */ -/** - * A collection of users. - */ -struct _MsnUsers -{ - size_t count; /**< The number of users. */ + GHashTable *clientcaps; /**< The client's capabilities. */ - GList *users; /**< The list of users. */ + int list_op; }; /**************************************************************************/ @@ -76,14 +71,14 @@ /** * Creates a new user structure. * - * @param session The MSN session. - * @param passport The initial passport. - * @param name The initial friendly name. + * @param session The MSN session. + * @param passport The initial passport. + * @param stored_name The initial stored name. * * @return A new user structure. */ -MsnUser *msn_user_new(MsnSession *session, const char *passport, - const char *name); +MsnUser *msn_user_new(MsnUserList *userlist, const char *passport, + const char *store_name); /** * Destroys a user structure. @@ -93,26 +88,6 @@ void msn_user_destroy(MsnUser *user); /** - * Increments the reference count on a user. - * - * @param user The user. - * - * @return @a user - */ -MsnUser *msn_user_ref(MsnUser *user); - -/** - * Decrements the reference count on a user. - * - * This will destroy the structure if the count hits 0. - * - * @param user The user. - * - * @return @a user, or @c NULL if the new count is 0. - */ -MsnUser *msn_user_unref(MsnUser *user); - -/** * Sets the passport account for a user. * * @param user The user. @@ -126,7 +101,15 @@ * @param user The user. * @param name The friendly name. */ -void msn_user_set_name(MsnUser *user, const char *name); +void msn_user_set_friendly_name(MsnUser *user, const char *name); + +/** + * Sets the store name for a user. + * + * @param user The user. + * @param name The store name. + */ +void msn_user_set_store_name(MsnUser *user, const char *name); /** * Sets the buddy icon for a local user. @@ -217,16 +200,16 @@ * * @return The friendly name. */ -const char *msn_user_get_name(const MsnUser *user); +const char *msn_user_get_friendly_name(const MsnUser *user); /** - * Returns the group IDs for a user. + * Returns the store name for a user. * * @param user The user. * - * @return The group IDs. + * @return The store name. */ -GList *msn_user_get_group_ids(const MsnUser *user); +const char *msn_user_get_store_name(const MsnUser *user); /** * Returns the home phone number for a user. @@ -275,60 +258,4 @@ /*@}*/ -/**************************************************************************/ -/** @name User List API */ -/**************************************************************************/ -/*@{*/ - -/** - * Creates a new MsnUsers structure. - * - * @return A new MsnUsers structure. - */ -MsnUsers *msn_users_new(void); - -/** - * Destroys a users list. - * - * @param users The users list. - */ -void msn_users_destroy(MsnUsers *users); - -/** - * Adds a user to a users list. - * - * @param users The users list. - * @param user The user. - */ -void msn_users_add(MsnUsers *users, MsnUser *user); - -/** - * Removes a user from a users list. - * - * @param users The users list. - * @param user The user. - */ -void msn_users_remove(MsnUsers *users, MsnUser *user); - -/** - * Returns the number of users in a users list. - * - * @param users The users list. - * - * @return The number of users. - */ -size_t msn_users_get_count(const MsnUsers *users); - -/** - * Finds a user with the specified passport. - * - * @param users A list of users. - * @param passport The passport. - * - * @return The user if found, or @c NULL otherwise. - */ -MsnUser *msn_users_find_with_passport(MsnUsers *users, const char *passport); - -/*@}*/ - #endif /* _MSN_USER_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/userlist.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/userlist.c Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,603 @@ +#include "msn.h" +#include "userlist.h" + +const char *lists[] = { "FL", "AL", "BL", "RL" }; + +typedef struct +{ + GaimConnection *gc; + char *who; + +} MsnPermitAdd; + +/************************************************************************** + * Callbacks + **************************************************************************/ +static void +msn_accept_add_cb(MsnPermitAdd *pa) +{ + if (g_list_find(gaim_connections_get_all(), pa->gc) != NULL) + { + MsnSession *session = pa->gc->proto_data; + MsnUserList *userlist = session->userlist; + + msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_AL, NULL); + + /* TODO: This ask for the alias, right? */ + gaim_account_notify_added(pa->gc->account, NULL, pa->who, NULL, NULL); + } + + g_free(pa->who); + g_free(pa); +} + +static void +msn_cancel_add_cb(MsnPermitAdd *pa) +{ + if (g_list_find(gaim_connections_get_all(), pa->gc) != NULL) + { + MsnSession *session = pa->gc->proto_data; + MsnUserList *userlist = session->userlist; + + msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_BL, NULL); + } + + g_free(pa->who); + g_free(pa); +} + +static void +got_new_entry(GaimConnection *gc, const char *passport, + const char *friendly) +{ + MsnPermitAdd *pa; + char *msg; + + pa = g_new0(MsnPermitAdd, 1); + pa->who = g_strdup(passport); + pa->gc = gc; + + msg = g_strdup_printf( + _("The user %s (%s) wants to add %s to his or her buddy list."), + passport, friendly, gaim_account_get_username(gc->account)); + + gaim_request_action(gc, NULL, msg, NULL, 0, pa, 2, + _("Authorize"), G_CALLBACK(msn_accept_add_cb), + _("Deny"), G_CALLBACK(msn_cancel_add_cb)); + + g_free(msg); +} + +/************************************************************************** + * Utility functions + **************************************************************************/ + +static gboolean +user_is_in_group(MsnUser *user, int group_id) +{ + if (user == NULL) + return FALSE; + + if (group_id < 0) + return FALSE; + + if (g_list_find(user->group_ids, GINT_TO_POINTER(group_id))) + return TRUE; + + return FALSE; +} + +static gboolean +user_is_there(MsnUser *user, int list_id, int group_id) +{ + int list_op; + + if (user == NULL) + return FALSE; + + list_op = 1 << list_id; + + if (!(user->list_op & list_op)) + return FALSE; + + if (list_id == MSN_LIST_FL) + { + if (group_id >= 0) + return user_is_in_group(user, group_id); + } + + return TRUE; +} + +static const char* +get_store_name(MsnUser *user) +{ + const char *store_name; + + g_return_val_if_fail(user != NULL, NULL); + + if ((store_name = msn_user_get_store_name(user)) != NULL) + return gaim_url_encode(store_name); + + return msn_user_get_passport(user); +} + +static void +msn_request_add_group(MsnUserList *userlist, const char *who, + const char *old_group_name, const char *new_group_name) +{ + MsnCmdProc *cmdproc; + MsnTransaction *trans; + + cmdproc = userlist->session->notification->cmdproc; + MsnMoveBuddy *data = g_new0(MsnMoveBuddy, 1); + + data->who = g_strdup(who); + + if (old_group_name) + data->old_group_name = g_strdup(old_group_name); + + trans = msn_transaction_new("ADG", "%s %d", + gaim_url_encode(new_group_name), + 0); + + msn_transaction_set_data(trans, data); + + msn_cmdproc_send_trans(cmdproc, trans); +} + +/************************************************************************** + * Server functions + **************************************************************************/ + +MsnListId +msn_get_list_id(const char *list) +{ + if (list[0] == 'F') + return MSN_LIST_FL; + else if (list[0] == 'A') + return MSN_LIST_AL; + else if (list[0] == 'B') + return MSN_LIST_BL; + else if (list[0] == 'R') + return MSN_LIST_RL; + + return -1; +} + +void +msn_got_add_user(MsnSession *session, MsnUser *user, + MsnListId list_id, int group_id) +{ + GaimAccount *account; + const char *passport; + const char *friendly; + + account = session->account; + + passport = msn_user_get_passport(user); + friendly = msn_user_get_friendly_name(user); + + if (list_id == MSN_LIST_FL) + { + GaimConnection *gc = gaim_account_get_connection(account); + + serv_got_alias(gc, passport, friendly); + + if (group_id >= 0) + { + msn_user_add_group_id(user, group_id); + return; + } + else + { + /* session->sync->fl_users_count++; */ + } + } + else if (list_id == MSN_LIST_AL) + { + gaim_privacy_permit_add(account, passport, TRUE); + } + else if (list_id == MSN_LIST_BL) + { + gaim_privacy_deny_add(account, passport, TRUE); + } + else if (list_id == MSN_LIST_RL) + { + GaimConnection *gc = gaim_account_get_connection(account); + + gaim_debug_info("msn", + "%s has added you to his or her contact list.\n", + passport); + + if (!(user->list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP))) + got_new_entry(gc, passport, friendly); + } + + user->list_op |= (1 << list_id); + /* gaim_user_add_list_id (user, list_id); */ +} + +void +msn_got_rem_user(MsnSession *session, MsnUser *user, + MsnListId list_id, int group_id) +{ + GaimAccount *account; + const char *passport; + + account = session->account; + + passport = msn_user_get_passport(user); + + if (list_id == MSN_LIST_FL) + { + /* TODO: When is the user totally removed? */ + if (group_id >= 0) + { + msn_user_remove_group_id(user, group_id); + return; + } + else + { + /* session->sync->fl_users_count--; */ + } + } + else if (list_id == MSN_LIST_AL) + { + gaim_privacy_permit_remove(account, passport, TRUE); + } + else if (list_id == MSN_LIST_BL) + { + gaim_privacy_deny_remove(account, passport, TRUE); + } + else if (list_id == MSN_LIST_RL) + { + gaim_debug_info("msn", + "%s has removed you from his or her contact list.\n", + passport); + } + + user->list_op &= ~(1 << list_id); + /* gaim_user_remove_list_id (user, list_id); */ + + if (user->list_op == 0) + { + gaim_debug_info("msn", "Buddy '%s' shall be deleted?.\n", + passport); + + } +} + +void +msn_got_lst_user(MsnSession *session, MsnUser *user, + int list_op, GSList *group_ids) +{ + GaimConnection *gc; + GaimAccount *account; + const char *passport; + const char *store; + + account = session->account; + gc = gaim_account_get_connection(account); + + passport = msn_user_get_passport(user); + store = msn_user_get_store_name(user); + + if (list_op & MSN_LIST_FL_OP) + { + GSList *c; + for (c = group_ids; c != NULL; c = g_slist_next(c)) + { + int group_id; + group_id = GPOINTER_TO_INT(c->data); + msn_user_add_group_id(user, group_id); + } + + /* FIXME: It might be a real alias */ + /* serv_got_alias(gc, passport, store); */ + } + + if (list_op & MSN_LIST_AL_OP) + { + /* These are users who are allowed to see our status. */ + + if (g_slist_find_custom(account->deny, passport, + (GCompareFunc)strcmp)) + { + gaim_privacy_deny_remove(gc->account, passport, TRUE); + } + + gaim_privacy_permit_add(account, passport, TRUE); + } + + if (list_op & MSN_LIST_BL_OP) + { + /* These are users who are not allowed to see our status. */ + + if (g_slist_find_custom(account->permit, passport, + (GCompareFunc)strcmp)) + { + gaim_privacy_permit_remove(gc->account, passport, TRUE); + } + + gaim_privacy_deny_add(account, passport, TRUE); + } + + if (list_op & MSN_LIST_RL_OP) + { + /* These are users who have us on their contact list. */ + /* TODO: what does store name is when this happens? */ + + if (!(list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP))) + got_new_entry(gc, passport, store); + } + + user->list_op = list_op; +} + +/************************************************************************** + * UserList functions + **************************************************************************/ + +MsnUserList* +msn_userlist_new(MsnSession *session) +{ + MsnUserList *userlist; + + userlist = g_new0(MsnUserList, 1); + + userlist->session = session; + + return userlist; +} + +void +msn_userlist_destroy(MsnUserList *userlist) +{ + GList *l; + + for (l = userlist->users; l != NULL; l = l->next) + { + msn_user_destroy(l->data); + } + + g_list_free(userlist->users); + + for (l = userlist->groups; l != NULL; l = l->next) + { + msn_group_destroy(l->data); + } + + g_list_free(userlist->groups); +} + +void +msn_userlist_add_user(MsnUserList *userlist, MsnUser *user) +{ + userlist->users = g_list_append(userlist->users, user); +} + +void +msn_userlist_remove_user(MsnUserList *userlist, MsnUser *user) +{ + userlist->users = g_list_remove(userlist->users, user); +} + +MsnUser * +msn_userlist_find_user(MsnUserList *userlist, const char *passport) +{ + GList *l; + + g_return_val_if_fail(passport != NULL, NULL); + + for (l = userlist->users; l != NULL; l = l->next) + { + MsnUser *user = (MsnUser *)l->data; + + g_return_val_if_fail(user->passport != NULL, NULL); + + if (!strcmp(passport, user->passport)) + return user; + } + + return NULL; +} + +void +msn_userlist_add_group(MsnUserList *userlist, MsnGroup *group) +{ + userlist->groups = g_list_append(userlist->groups, group); +} + +void +msn_userlist_remove_group(MsnUserList *userlist, MsnGroup *group) +{ + userlist->groups = g_list_remove(userlist->groups, group); +} + +MsnGroup * +msn_userlist_find_group_with_id(MsnUserList *userlist, int id) +{ + GList *l; + + g_return_val_if_fail(userlist != NULL, NULL); + g_return_val_if_fail(id >= 0, NULL); + + for (l = userlist->groups; l != NULL; l = l->next) + { + MsnGroup *group = l->data; + + if (group->id == id) + return group; + } + + return NULL; +} + +MsnGroup * +msn_userlist_find_group_with_name(MsnUserList *userlist, const char *name) +{ + GList *l; + + g_return_val_if_fail(userlist != NULL, NULL); + g_return_val_if_fail(name != NULL, NULL); + + for (l = userlist->groups; l != NULL; l = l->next) + { + MsnGroup *group = l->data; + + if ((group->name != NULL) && !g_ascii_strcasecmp(name, group->name)) + return group; + } + + return NULL; +} + +int +msn_userlist_find_group_id(MsnUserList *userlist, const char *group_name) +{ + MsnGroup *group; + + group = msn_userlist_find_group_with_name(userlist, group_name); + + if (group != NULL) + return msn_group_get_id(group); + else + return -1; +} + +const char * +msn_userlist_find_group_name(MsnUserList *userlist, int group_id) +{ + MsnGroup *group; + + group = msn_userlist_find_group_with_id(userlist, group_id); + + if (group != NULL) + return msn_group_get_name(group); + else + return NULL; +} + +void +msn_userlist_rename_group_id(MsnUserList *userlist, int group_id, + const char *new_name) +{ + MsnGroup *group; + + group = msn_userlist_find_group_with_id(userlist, group_id); + + if (group != NULL) + msn_group_set_name(group, new_name); +} + +void +msn_userlist_remove_group_id(MsnUserList *userlist, int group_id) +{ + MsnGroup *group; + + group = msn_userlist_find_group_with_id(userlist, group_id); + + if (group != NULL) + msn_userlist_remove_group(userlist, group); +} + +void +msn_userlist_rem_buddy(MsnUserList *userlist, + const char *who, int list_id, const char *group_name) +{ + MsnUser *user; + int group_id; + const char *list; + + user = msn_userlist_find_user(userlist, who); + group_id = -1; + + if (group_name != NULL) + { + group_id = msn_userlist_find_group_id(userlist, group_name); + + if (group_id < 0) + { + /* Whoa, there is no such group. */ + gaim_debug_error("msn", "Group doesn't exist: %s\n", group_name); + return; + } + } + + /* First we're going to check if not there. */ + if (!(user_is_there(user, list_id, group_id))) + { + list = lists[list_id]; + gaim_debug_error("msn", "User '%s' is not there: %s\n", + who, list); + return; + } + + /* Then request the rem to the server. */ + list = lists[list_id]; + + msn_notification_rem_buddy(userlist->session->notification, list, who, group_id); +} + +void +msn_userlist_add_buddy(MsnUserList *userlist, + const char *who, int list_id, + const char *group_name) +{ + MsnUser *user; + int group_id; + const char *list; + const char *store_name; + + group_id = -1; + + if (group_name != NULL) + { + group_id = msn_userlist_find_group_id(userlist, group_name); + + if (group_id < 0) + { + /* Whoa, we must add that group first. */ + msn_request_add_group(userlist, who, NULL, group_name); + return; + } + } + + user = msn_userlist_find_user(userlist, who); + + /* First we're going to check if it's alredy there. */ + if (user_is_there(user, list_id, group_id)) + { + list = lists[list_id]; + gaim_debug_error("msn", "User '%s' is alredy there: %s\n", + who, list); + return; + } + + store_name = (user != NULL) ? get_store_name(user) : who; + + /* Then request the add to the server. */ + list = lists[list_id]; + + msn_notification_add_buddy(userlist->session->notification, list, who, + store_name, group_id); +} + +void +msn_userlist_move_buddy(MsnUserList *userlist, const char *who, + const char *old_group_name, const char *new_group_name) +{ + int new_group_id; + + new_group_id = msn_userlist_find_group_id(userlist, new_group_name); + + if (new_group_id < 0) + { + msn_request_add_group(userlist, who, old_group_name, new_group_name); + return; + } + + msn_userlist_rem_buddy(userlist, who, MSN_LIST_FL, old_group_name); + msn_userlist_add_buddy(userlist, who, MSN_LIST_FL, new_group_name); +} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/userlist.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/userlist.h Sun Jun 06 02:39:08 2004 +0000 @@ -0,0 +1,76 @@ +#ifndef _MSN_USERLIST_H_ +#define _MSN_USERLIST_H_ + +typedef struct _MsnUserList MsnUserList; + +#include "cmdproc.h" +#include "user.h" +#include "group.h" + +typedef enum +{ + MSN_LIST_FL, + MSN_LIST_AL, + MSN_LIST_BL, + MSN_LIST_RL + +} MsnListId; + +typedef struct +{ + char *who; + char *old_group_name; + +} MsnMoveBuddy; + +struct _MsnUserList +{ + MsnSession *session; + + /* MsnUsers *users; */ + /* MsnGroups *groups; */ + + GList *users; + GList *groups; + + int fl_users_count; + +}; + +MsnListId msn_get_list_id(const char *list); + +void msn_got_add_user(MsnSession *session, MsnUser *user, + MsnListId list_id, int group_id); +void msn_got_rem_user(MsnSession *session, MsnUser *user, + MsnListId list_id, int group_id); +void msn_got_lst_user(MsnSession *session, MsnUser *user, + int list_op, GSList *group_ids); + +MsnUserList *msn_userlist_new(MsnSession *session); +void msn_userlist_destroy(MsnUserList *userlist); +void msn_userlist_add_user(MsnUserList *userlist, MsnUser *user); +void msn_userlist_remove_user(MsnUserList *userlist, MsnUser *user); +MsnUser *msn_userlist_find_user(MsnUserList *userlist, + const char *passport); +void msn_userlist_add_group(MsnUserList *userlist, MsnGroup *group); +void msn_userlist_remove_group(MsnUserList *userlist, MsnGroup *group); +MsnGroup *msn_userlist_find_group_with_id(MsnUserList *userlist, int id); +MsnGroup *msn_userlist_find_group_with_name(MsnUserList *userlist, + const char *name); +int msn_userlist_find_group_id(MsnUserList *userlist, + const char *group_name); +const char *msn_userlist_find_group_name(MsnUserList *userlist, + int group_id); +void msn_userlist_rename_group_id(MsnUserList *userlist, int group_id, + const char *new_name); +void msn_userlist_remove_group_id(MsnUserList *userlist, int group_id); + +void msn_userlist_rem_buddy(MsnUserList *userlist, const char *who, + int list_id, const char *group_name); +void msn_userlist_add_buddy(MsnUserList *userlist, const char *who, + int list_id, const char *group_name); +void msn_userlist_move_buddy(MsnUserList *userlist, const char *who, + const char *old_group_name, + const char *new_group_name); + +#endif /* _MSN_USERLIST_H_ */ diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/utils.c --- a/src/protocols/msn/utils.c Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/utils.c Sun Jun 06 02:39:08 2004 +0000 @@ -314,3 +314,24 @@ g_free(fontface); g_free(msg); } + +void +msn_parse_socket(const char *str, char **ret_host, int *ret_port) +{ + char *host; + char *c; + int port; + + host = g_strdup(str); + + if ((c = strchr(host, ':')) != NULL) + { + *c = '\0'; + port = atoi(c + 1); + } + else + port = 1863; + + *ret_host = host; + *ret_port = port; +} diff -r 5655dcd94d0f -r 502707ca1836 src/protocols/msn/utils.h --- a/src/protocols/msn/utils.h Sun Jun 06 02:16:08 2004 +0000 +++ b/src/protocols/msn/utils.h Sun Jun 06 02:39:08 2004 +0000 @@ -44,4 +44,6 @@ */ void msn_import_html(const char *html, char **attributes, char **message); +void msn_parse_socket(const char *str, char **ret_host, int *ret_port); + #endif /* _MSN_UTILS_H_ */