# HG changeset patch # User Eric Warmenhoven # Date 992251278 0 # Node ID 008a4cc4a82cc2ba3c3a4539acafaaf8888b75fa # Parent e90a0164436cfaf2cb56eccac2a0e5ad04d56150 [gaim-migrate @ 1995] hi. committer: Tailor Script diff -r e90a0164436c -r 008a4cc4a82c ChangeLog --- a/ChangeLog Sun Jun 10 20:20:44 2001 +0000 +++ b/ChangeLog Mon Jun 11 09:21:18 2001 +0000 @@ -4,6 +4,7 @@ * Fixed a segfault with Oscar's account confirmation (Thanks, Adam) * Updated the German translation (Thanks, Dominik) + * Some MSN changes version 0.11.0-pre13 (06/06/2001): * Can view/set chat topic in Jabber (thanks faceprint) diff -r e90a0164436c -r 008a4cc4a82c plugins/jabber/jabber.c --- a/plugins/jabber/jabber.c Sun Jun 10 20:20:44 2001 +0000 +++ b/plugins/jabber/jabber.c Mon Jun 11 09:21:18 2001 +0000 @@ -537,47 +537,6 @@ return FALSE; } -static unsigned char *utf8_to_str(unsigned char *in) -{ - int n = 0,i = 0; - int inlen; - unsigned char *result; - - if (!in) - return NULL; - - inlen = strlen(in); - - result = (unsigned char*)malloc(inlen+1); - - while(n <= inlen-1) { - long c = (long)in[n]; - if(c<0x80) - result[i++] = (char)c; - else { - if((c&0xC0) == 0xC0) - result[i++] = (char)(((c&0x03)<<6)|(((unsigned char)in[++n])&0x3F)); - else if((c&0xE0) == 0xE0) { - if (n + 2 <= inlen) { - result[i] = (char)(((c&0xF)<<4)|(((unsigned char)in[++n])&0x3F)); - result[i] = (char)(((unsigned char)result[i]) |(((unsigned char)in[++n])&0x3F)); - i++; - } else n += 2; - } - else if((c&0xF0) == 0xF0) - n += 3; - else if((c&0xF8) == 0xF8) - n += 4; - else if((c&0xFC) == 0xFC) - n += 5; - } - n++; - } - result[i] = '\0'; - - return result; -} - static void jabber_handlemessage(gjconn j, jpacket p) { xmlnode y, xmlns, subj; @@ -631,7 +590,7 @@ } if (msg) - free(msg); + g_free(msg); } else if (!strcasecmp(type, "error")) { if ((y = xmlnode_get_tag(p->x, "error"))) { @@ -676,7 +635,7 @@ jd->pending_chats = g_slist_remove(jd->pending_chats, jc); } else { /* no, we're not supposed to be. */ - free(msg); + g_free(msg); return; } } @@ -712,8 +671,8 @@ } } - free(msg); - free(topic); + g_free(msg); + g_free(topic); } else { debug_printf("unhandled message %s\n", type); diff -r e90a0164436c -r 008a4cc4a82c plugins/msn/msn.c --- a/plugins/msn/msn.c Sun Jun 10 20:20:44 2001 +0000 +++ b/plugins/msn/msn.c Mon Jun 11 09:21:18 2001 +0000 @@ -1,55 +1,23 @@ -/* - * gaim - MSN Protocol Plugin - * - * Copyright (C) 2000, Rob Flynn - * - * 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 "config.h" -#include +#include #include -#include -#include -#include -#include #include -#include #include -#include -#include -#include -#include -#include +#include #include -#include "multi.h" +#include "gaim.h" #include "prpl.h" -#include "gaim.h" #include "proxy.h" #include "md5.h" #include "pixmaps/msn_online.xpm" #include "pixmaps/msn_away.xpm" -#include "pixmaps/ok.xpm" -#include "pixmaps/cancel.xpm" - -#define MIME_HEADER "MIME-Version: 1.0\r\nContent-Type: text/plain; charset=UTF-8\r\nX-MMS-IM-Format: FN=MS%20Sans%20Serif; EF=; CO=0; CS=0; PF=0\r\n\r\n" #define MSN_BUF_LEN 8192 +#define MIME_HEADER "MIME-Version: 1.0\r\n" \ + "Content-Type: text/plain; charset=UTF-8\r\n" \ + "X-MMS-IM-Format: FN=MS%20Sans%20Serif; EF=; CO=0; PF=0\r\n\r\n" #define MSN_ONLINE 1 #define MSN_BUSY 2 @@ -61,246 +29,44 @@ #define MSN_OFFLINE 8 #define MSN_HIDDEN 9 -#define MSN_SIGNON_GOT_XFR 0x0001 -#define MSN_SIGNON_SENT_USR 0x0002 - -#define USEROPT_HOTMAIL 0 - -struct mod_usr_opt { - struct aim_user *user; - int opt; -}; - -struct msn_ask_add_permit { - struct gaim_connection *gc; - char *user; - char *friendly; -}; +#define USEROPT_HOTMAIL 0 struct msn_data { int fd; - - char protocol[6]; - char *friendly; - gchar *policy; + int trId; int inpa; - int status; - int away; - time_t last_trid; + GSList *switches; + GSList *xfrs; + GSList *fl; + gboolean imported; }; -struct msn_name_dlg { - GtkWidget *window; - GtkWidget *menu; - struct aim_user *user; - GtkWidget *entry; - GtkWidget *ok; - GtkWidget *cancel; -}; - -struct msn_conn { - gchar *user; +struct msn_switchboard { + struct gaim_connection *gc; + int fd; int inpa; - int fd; - struct gaim_connection *gc; - char *secret; - char *session; - time_t last_trid; + char *sessid; + char *auth; + int trId; + int total; + char *user; char *txqueue; }; -static GSList *msn_connections = NULL; - -static unsigned long long globalc = 0; -static void msn_callback(gpointer data, gint source, GdkInputCondition condition); -static void msn_add_permit(struct gaim_connection *gc, char *who); -static void process_hotmail_msg(struct gaim_connection *gc, gchar *msgdata); -static void msn_des_win(GtkWidget *a, GtkWidget *b); -static void msn_newmail_dialog(const char *text); -static char *msn_normalize(const char *s); - -static char tochar(char *h) -{ - char tmp; - char b = 0; - int v = 0; - int i; - - for (i = strlen(h); i > 0; i--) { - tmp = tolower(h[strlen(h) - i]); - - if (tmp >= '0' && tmp <= '9') - b = tmp - '0'; - else if (tmp >= 'a' && tmp <= 'f') - b = (tmp - 'a') + 10; - - if (i > 1) - v =+ ((i-1) * 16) * b; - else - v += b; - } - - return v; -} - -static char *url_encode(unsigned char *text, int dospace) -{ - static char newtext[MSN_BUF_LEN*2]; - char *temp = (char *)malloc(4); - int i = 0; - int j = 0; - - bzero(newtext, MSN_BUF_LEN*2); - - for (j = 0; j < strlen(text); j++) - { - if ((text[j] < 33) || (text[j] > 126) || (text[j] == 32 && dospace==1)) - { - /* Other wise, we should escape this booger */ - newtext[i++] = '%'; - sprintf(temp, "%02x", text[j]); - newtext[i++] = temp[0]; - newtext[i++] = temp[1]; - } - else - { - /* It's ok to store this one, sarge */ - newtext[i++] = text[j]; - } - } - - newtext[i] = 0; - - free(temp); - - return newtext; -} - -static char *url_decode(char *text) -{ - static char newtext[MSN_BUF_LEN]; - char *buf; - int c = 0; - int i = 0; - int j = 0; - - bzero(newtext, MSN_BUF_LEN); - - for (i = 0; i < strlen(text); i++) { - if (text[i] == '%') - c++; - } - - buf = (char *)malloc(strlen(text) + c + 1); - - for (i = 0, j = 0 ; text[i] != 0; i++) { - if (text[i] != '%') { - buf[j++] = text[i]; - } else { - char hex[3]; - hex[0] = text[++i]; - hex[1] = text[++i]; - hex[2] = 0; +struct msn_xfr { + struct gaim_connection *gc; + char *user; + char *what; +}; - buf[j++] = tochar(hex); - } - } - - buf[j] = 0; - - for (i = 0; i < strlen(buf); i++) - newtext[i] = buf[i]; - - free(buf); - - return newtext; -} - -static void msn_accept_add_permit(gpointer w, struct msn_ask_add_permit *ap) -{ - msn_add_permit(ap->gc, ap->user); - /* leak if we don't free these? */ - g_free(ap->user); - g_free(ap->friendly); - g_free(ap); -} - -static void msn_cancel_add_permit(gpointer w, struct msn_ask_add_permit *ap) -{ - g_free(ap->user); - g_free(ap->friendly); - g_free(ap); -} - -static void free_msn_conn(struct msn_conn *mc) -{ - if (mc->user) - free(mc->user); - - if (mc->secret) - free(mc->secret); - - if (mc->session) - free(mc->session); - - if (mc->txqueue) - free(mc->txqueue); - - gdk_input_remove(mc->inpa); - close(mc->fd); - - msn_connections = g_slist_remove(msn_connections, mc); +static void msn_login_callback(gpointer, gint, GdkInputCondition); +static void msn_login_xfr_connect(gpointer, gint, GdkInputCondition); - g_free(mc); -} - - -static struct msn_conn *find_msn_conn_by_user(gchar * user) -{ - struct msn_conn *mc; - GSList *conns = msn_connections; - - while (conns) { - mc = (struct msn_conn *)conns->data; - - if (mc != NULL) { - if (strcasecmp(mc->user, user) == 0) { - return mc; - } - } - - conns = g_slist_next(conns); - } - - return NULL; -} - -static struct msn_conn *find_msn_conn_by_trid(time_t trid) -{ - struct msn_conn *mc; - GSList *conns = msn_connections; - - while (conns) { - mc = (struct msn_conn *)conns->data; - - if (mc != NULL) { - - debug_printf("Comparing: %d <==> %d\n", mc->last_trid, trid); - if (mc->last_trid == trid) { - return mc; - } - } - - conns = g_slist_next(conns); - } - - return NULL; -} - -static char *msn_name() -{ - return "MSN"; -} +#define GET_NEXT(tmp) while (*(tmp) && !isspace(*(tmp))) \ + (tmp)++; \ + *(tmp)++ = 0; \ + while (*(tmp) && isspace(*(tmp))) \ + (tmp)++; char *name() { @@ -309,604 +75,859 @@ char *description() { - return "Allows gaim to use the MSN protocol. For some reason, this frightens me."; + return "Allows gaim to use the MSN protocol."; +} + +static char *msn_name() +{ + return "MSN"; +} + +static char *msn_normalize(const char *s) +{ + static char buf[BUF_LEN]; + + g_return_val_if_fail(s != NULL, NULL); + + g_snprintf(buf, sizeof(buf), "%s%s", s, strchr(s, '@') ? "" : "@hotmail.com"); + + return buf; +} + +static int msn_write(int fd, void *data, int len) +{ + debug_printf("C: %s", data); + return write(fd, data, len); +} + +static char *url_encode(const char *msg) +{ + static char buf[MSN_BUF_LEN]; + int i, j = 0; + + bzero(buf, sizeof(buf)); + for (i = 0; i < strlen(msg); i++) { + if ((msg[i] < 33) || (msg[i] > 126)) { + char tmp[5]; + int k; + buf[j++] = '%'; + g_snprintf(tmp, sizeof(tmp), "%02x", msg[i]); + for (k = 0; tmp[k]; k++) + buf[j++] = tmp[k]; + } else + buf[j++] = msg[i]; + } + buf[j] = 0; + + return buf; } -static time_t trId(struct msn_data *md) +static char *handle_errcode(char *buf, gboolean show) { - md->last_trid = time((time_t *)NULL) + globalc++; - return md->last_trid; -} + int errcode; + static char msg[MSN_BUF_LEN]; + + buf[4] = 0; + errcode = atoi(buf); + + switch (errcode) { + case 200: + g_snprintf(msg, sizeof(msg), "Syntax Error (probably a Gaim bug)"); + break; + case 201: + g_snprintf(msg, sizeof(msg), "Invalid Parameter (probably a Gaim bug)"); + break; + case 205: + g_snprintf(msg, sizeof(msg), "Invalid User"); + break; + case 206: + g_snprintf(msg, sizeof(msg), "Fully Qualified Domain Name missing"); + break; + case 207: + g_snprintf(msg, sizeof(msg), "Already Login"); + break; + case 208: + g_snprintf(msg, sizeof(msg), "Invalid Username"); + break; + case 209: + g_snprintf(msg, sizeof(msg), "Invalid Friendly Name"); + break; + case 210: + g_snprintf(msg, sizeof(msg), "List Full"); + break; + case 215: + g_snprintf(msg, sizeof(msg), "Already there"); + break; + case 216: + g_snprintf(msg, sizeof(msg), "Not on list"); + break; + case 218: + g_snprintf(msg, sizeof(msg), "Already in the mode"); + break; + case 219: + g_snprintf(msg, sizeof(msg), "Already in opposite list"); + break; + case 280: + g_snprintf(msg, sizeof(msg), "Switchboard failed"); + break; + case 281: + g_snprintf(msg, sizeof(msg), "Notify Transfer failed"); + break; + + case 300: + g_snprintf(msg, sizeof(msg), "Required fields missing"); + break; + case 302: + g_snprintf(msg, sizeof(msg), "Not logged in"); + break; -static void msn_write(int fd, char *buf) -{ - write(fd, buf, strlen(buf)); - debug_printf("MSN(%d) <== %s", fd, buf); + case 500: + g_snprintf(msg, sizeof(msg), "Internal server error"); + break; + case 501: + g_snprintf(msg, sizeof(msg), "Database server error"); + break; + case 510: + g_snprintf(msg, sizeof(msg), "File operation error"); + break; + case 520: + g_snprintf(msg, sizeof(msg), "Memory allocation error"); + break; + + case 600: + g_snprintf(msg, sizeof(msg), "Server busy"); + break; + case 601: + g_snprintf(msg, sizeof(msg), "Server unavailable"); + break; + case 602: + g_snprintf(msg, sizeof(msg), "Peer Notification server down"); + break; + case 603: + g_snprintf(msg, sizeof(msg), "Database connect error"); + break; + case 604: + g_snprintf(msg, sizeof(msg), "Server is going down (abandon ship)"); + break; + + case 707: + g_snprintf(msg, sizeof(msg), "Error creating connection"); + break; + case 711: + g_snprintf(msg, sizeof(msg), "Unable to write"); + break; + case 712: + g_snprintf(msg, sizeof(msg), "Session overload"); + break; + case 713: + g_snprintf(msg, sizeof(msg), "User is too active"); + break; + case 714: + g_snprintf(msg, sizeof(msg), "Too many sessions"); + break; + case 715: + g_snprintf(msg, sizeof(msg), "Not expected"); + break; + case 717: + g_snprintf(msg, sizeof(msg), "Bad friend file"); + break; + + case 911: + g_snprintf(msg, sizeof(msg), "Authentication failed"); + break; + case 913: + g_snprintf(msg, sizeof(msg), "Not allowed when offline"); + break; + case 920: + g_snprintf(msg, sizeof(msg), "Not accepting new users"); + break; + + default: + g_snprintf(msg, sizeof(msg), "Unknown Error Code"); + break; + } + + if (show) + do_error_dialog(msg, "MSN Error"); + + return msg; } -static void msn_add_request(struct gaim_connection *gc, char *buf) +static void handle_hotmail(struct gaim_connection *gc, char *data) { - char **res; + char *mailct, *mailp, *from = NULL, *subj = NULL, notice[MSN_BUF_LEN]; - res = g_strsplit(buf, " ", 0); + if (gc->user->proto_opt[USEROPT_HOTMAIL][0] != '1') return; + mailct = strstr(data, "Content-Type: "); + mailp = strstr(mailct, ";"); + if (mailct && mailp && (mailp > mailct) && + !strncmp(mailct, "Content-Type: text/x-msmsgsemailnotification", mailp - mailct - 1)) { + from = strstr(mailp, "From: "); + subj = strstr(mailp, "Subject: "); + } - if (!strcasecmp(res[2], "RL")) { - struct msn_ask_add_permit *ap = g_new0(struct msn_ask_add_permit, 1); + if (!from || !subj) + return; - snprintf(buf, MSN_BUF_LEN, "The user %s (%s) wants to add you to their buddylist.", res[4], url_decode(res[5])); + from += strlen("From: "); + mailp = strstr(from, "\r\n"); + if (!mailp) return; + *mailp = 0; - ap->user = g_strdup(res[4]); + subj += strlen("Subject: "); + mailp = strstr(from, "\r\n"); + if (!mailp) return; + *mailp = 0; - ap->friendly = g_strdup(url_decode(res[5])); - ap->gc = gc; + g_snprintf(notice, sizeof(notice), "Mail from %s, re: %s", from, subj); + do_error_dialog(notice, "New MSN Mail"); +} - do_ask_dialog(buf, ap, (GtkFunction) msn_accept_add_permit, (GtkFunction) msn_cancel_add_permit); +static struct msn_switchboard *msn_find_switch(struct gaim_connection *gc, char *id) +{ + struct msn_data *md = gc->proto_data; + GSList *m = md->switches; + + while (m) { + struct msn_switchboard *ms = m->data; + m = m->next; + if (ms->total == 1 && !g_strcasecmp(ms->user, id)) + return ms; } - g_strfreev(res); + return NULL; +} + +static void msn_kill_switch(struct msn_switchboard *ms) +{ + struct gaim_connection *gc = ms->gc; + struct msn_data *md = gc->proto_data; + + gdk_input_remove(ms->inpa); + close(ms->fd); + if (ms->sessid) + g_free(ms->sessid); + g_free(ms->auth); + if (ms->user) + g_free(ms->user); + if (ms->txqueue) + ms->txqueue = NULL; + + md->switches = g_slist_remove(md->switches, ms); + + g_free(ms); } -static void msn_answer_callback(gpointer data, gint source, GdkInputCondition condition) +static void msn_switchboard_callback(gpointer data, gint source, GdkInputCondition cond) { - struct msn_conn *mc = data; + struct msn_switchboard *ms = data; + struct gaim_connection *gc = ms->gc; + struct msn_data *md = gc->proto_data; + char buf[MSN_BUF_LEN]; + int i = 0; + + bzero(buf, sizeof(buf)); + while ((read(ms->fd, buf + i, 1) > 0) && (buf[i++] != '\n')) + if (i == sizeof(buf)) + i--; /* yes i know this loses data but we shouldn't get messages this long + and it's better than possibly writing past our buffer */ + if (i == 0 || buf[i - 1] != '\n') { + msn_kill_switch(ms); + return; + } + debug_printf("S: %s", buf); + g_strchomp(buf); + + if (!g_strncasecmp(buf, "ACK", 3)) { + } else if (!g_strncasecmp(buf, "ANS", 3)) { + } else if (!g_strncasecmp(buf, "BYE", 3)) { + msn_kill_switch(ms); + } else if (!g_strncasecmp(buf, "CAL", 3)) { + } else if (!g_strncasecmp(buf, "IRO", 3)) { + } else if (!g_strncasecmp(buf, "JOI", 3)) { + if (ms->txqueue) { + g_snprintf(buf, sizeof(buf), "MSG %d N %d\r\n%s%s", ++ms->trId, + strlen(MIME_HEADER) + strlen(url_encode(ms->txqueue)), + MIME_HEADER, url_encode(ms->txqueue)); + g_free(ms->txqueue); + ms->txqueue = NULL; + if (msn_write(ms->fd, buf, strlen(buf)) < 0) + msn_kill_switch(ms); + } + } else if (!g_strncasecmp(buf, "MSG", 3)) { + char *user, *tmp = buf; + int length; + char *msg, *skiphead, *utf, *final; + int len; + + GET_NEXT(tmp); + user = tmp; + + GET_NEXT(tmp); + + GET_NEXT(tmp); + length = atoi(tmp); + + msg = g_new0(char, MAX(length + 1, MSN_BUF_LEN)); + + if (read(ms->fd, msg, length) != length) { + g_free(msg); + hide_login_progress(gc, "Unable to read message"); + signoff(gc); + return; + + } + + skiphead = strstr(msg, "\r\n\r\n"); + if (!skiphead || !skiphead[4]) { + g_free(msg); + return; + } + skiphead += 4; + utf = utf8_to_str(skiphead); + len = MAX(strlen(utf) + 1, BUF_LEN); + final = g_malloc(len); + g_snprintf(final, len, "%s", utf); + g_free(utf); + + serv_got_im(gc, user, final, 0, time(NULL)); + + g_free(final); + g_free(msg); + } else if (!g_strncasecmp(buf, "NAK", 3)) { + do_error_dialog("A message may not have been received.", "MSN Error"); + } else if (!g_strncasecmp(buf, "NLN", 3)) { + } else if (!g_strncasecmp(buf, "OUT", 3)) { + } else if (!g_strncasecmp(buf, "USR", 3)) { + /* good, we got USR, now we need to find out who we want to talk to */ + struct msn_xfr *mx; + + if (!md->xfrs) + return; + mx = md->xfrs->data; + md->xfrs = g_slist_remove(md->xfrs, mx); + + g_snprintf(buf, sizeof(buf), "CAL %d %s\n", ++ms->trId, mx->user); + ms->txqueue = mx->what; + g_free(mx->user); + g_free(mx); + if (msn_write(ms->fd, buf, strlen(buf)) < 0) + msn_kill_switch(ms); + } else if (isdigit(*buf)) { + handle_errcode(buf, TRUE); + } else { + debug_printf("Unhandled message!\n"); + } +} + +static void msn_rng_connect(gpointer data, gint source, GdkInputCondition cond) +{ + struct msn_switchboard *ms = data; + struct gaim_connection *gc = ms->gc; + struct msn_data *md; char buf[MSN_BUF_LEN]; - if (source == -1) { - g_free(mc->session); - g_free(mc->secret); - g_free(mc->user); - g_free(mc); + if (source == -1 || !g_slist_find(connections, gc)) { + g_free(ms->sessid); + g_free(ms->auth); + g_free(ms); return; } - if (mc->fd != source) - mc->fd = source; + md = gc->proto_data; + + if (md->fd != source) + md->fd = source; - g_snprintf(buf, MSN_BUF_LEN, "ANS 1 %s %s %s\n",mc->gc->username, mc->secret, mc->session); - msn_write(mc->fd, buf); + g_snprintf(buf, sizeof(buf), "ANS %d %s %s %s\n", ++ms->trId, gc->username, ms->auth, ms->sessid); + if (msn_write(ms->fd, buf, strlen(buf)) < 0) { + close(ms->fd); + g_free(ms->sessid); + g_free(ms->auth); + g_free(ms); + return; + } - mc->inpa = gdk_input_add(mc->fd, GDK_INPUT_READ, msn_callback, mc->gc); - - /* Append our connection */ - msn_connections = g_slist_append(msn_connections, mc); + md->switches = g_slist_append(md->switches, ms); + ms->inpa = gdk_input_add(ms->fd, GDK_INPUT_READ, msn_switchboard_callback, ms); } -static void msn_invite_callback(gpointer data, gint source, GdkInputCondition condition) +static void msn_ss_xfr_connect(gpointer data, gint source, GdkInputCondition cond) { - struct msn_conn *mc = data; - struct msn_data *md = (struct msn_data *)mc->gc->proto_data; + struct msn_switchboard *ms = data; + struct gaim_connection *gc = ms->gc; + struct msn_data *md; + char buf[MSN_BUF_LEN]; + + if (source == -1 || !g_slist_find(connections, gc)) { + g_free(ms->auth); + g_free(ms); + return; + } + + if (ms->fd != source) + ms->fd = source; + + md = gc->proto_data; + + g_snprintf(buf, sizeof(buf), "USR %d %s %s\n", ++ms->trId, gc->username, ms->auth); + if (msn_write(ms->fd, buf, strlen(buf)) < 0) { + g_free(ms->auth); + g_free(ms); + return; + } + + md->switches = g_slist_append(md->switches, ms); + ms->inpa = gdk_input_add(ms->fd, GDK_INPUT_READ, msn_switchboard_callback, ms); +} + +static void msn_callback(gpointer data, gint source, GdkInputCondition cond) +{ + struct gaim_connection *gc = data; + struct msn_data *md = gc->proto_data; char buf[MSN_BUF_LEN]; int i = 0; - - bzero(buf, MSN_BUF_LEN); - do { - if (read(source, buf + i, 1) != 1) { - free_msn_conn(mc); - return; - } - } while (buf[i++] != '\n'); + bzero(buf, sizeof(buf)); + while ((read(md->fd, buf + i, 1) > 0) && (buf[i++] != '\n')) + if (i == sizeof(buf)) + i--; /* yes i know this loses data but we shouldn't get messages this long + and it's better than possibly writing past our buffer */ + if (i == 0 || buf[i - 1] != '\n') { + hide_login_progress(gc, "Error reading from server"); + signoff(gc); + return; + } + debug_printf("S: %s", buf); g_strchomp(buf); - debug_printf("MSN(%d) ==> %s\n", source, buf); + if (!g_strncasecmp(buf, "ADD", 3)) { + } else if (!g_strncasecmp(buf, "BLP", 3)) { + } else if (!g_strncasecmp(buf, "BPR", 3)) { + } else if (!g_strncasecmp(buf, "CHG", 3)) { + } else if (!g_strncasecmp(buf, "FLN", 3)) { + char *usr = buf; + + GET_NEXT(usr); + serv_got_update(gc, usr, 0, 0, 0, 0, 0, 0); + } else if (!g_strncasecmp(buf, "GTC", 3)) { + } else if (!g_strncasecmp(buf, "INF", 3)) { + } else if (!g_strncasecmp(buf, "ILN", 3)) { + char *state, *user, *tmp = buf; + int status = UC_NORMAL; + + GET_NEXT(tmp); + + GET_NEXT(tmp); + state = tmp; - if (!strncmp("USR ", buf, 4)) { - char **res; + GET_NEXT(tmp); + user = tmp; + + GET_NEXT(tmp); + + if (!g_strcasecmp(state, "BSY")) { + status |= (MSN_BUSY << 5); + } else if (!g_strcasecmp(state, "IDL")) { + status |= (MSN_IDLE << 5); + } else if (!g_strcasecmp(state, "BRB")) { + status |= (MSN_BRB << 5); + } else if (!g_strcasecmp(state, "AWY")) { + status = UC_UNAVAILABLE; + } else if (!g_strcasecmp(state, "PHN")) { + status |= (MSN_PHONE << 5); + } else if (!g_strcasecmp(state, "LUN")) { + status |= (MSN_LUNCH << 5); + } + + serv_got_update(gc, user, 1, 0, 0, 0, status, 0); + } else if (!g_strncasecmp(buf, "LST", 3)) { + char *which, *who, *tmp = buf; - res = g_strsplit(buf, " ", 0); - debug_printf("%s\n",res[2]); - if (strcasecmp("OK", res[2])) { - g_strfreev(res); - close(mc->fd); + GET_NEXT(tmp); + GET_NEXT(tmp); + which = tmp; + + GET_NEXT(tmp); + GET_NEXT(tmp); + GET_NEXT(tmp); + GET_NEXT(tmp); + who = tmp; + + GET_NEXT(tmp); + + if (!g_strcasecmp(which, "FL")) + md->fl = g_slist_append(md->fl, g_strdup(who)); + else if (!md->imported && bud_list_cache_exists(gc)) { + do_import(NULL, gc); + md->imported = TRUE; + } + } else if (!g_strncasecmp(buf, "MSG", 3)) { + char *user, *tmp = buf; + int length; + char *msg, *skiphead, *utf, *final; + int len; + + GET_NEXT(tmp); + user = tmp; + + GET_NEXT(tmp); + + GET_NEXT(tmp); + length = atoi(tmp); + + msg = g_new0(char, MAX(length + 1, MSN_BUF_LEN)); + + if (read(md->fd, msg, length) != length) { + g_free(msg); + hide_login_progress(gc, "Unable to read message"); + signoff(gc); + return; + } + + if (!g_strcasecmp(user, "hotmail")) { + handle_hotmail(gc, msg); + g_free(msg); return; } - /* We've authorized. Let's send an invite request */ - g_snprintf(buf, MSN_BUF_LEN, "CAL %ld %s\n", trId(md), mc->user); - msn_write(source, buf); - return; - } + skiphead = strstr(msg, "\r\n\r\n"); + if (!skiphead || !skiphead[4]) { + g_free(msg); + return; + } + skiphead += 4; + utf = utf8_to_str(skiphead); + len = MAX(strlen(utf) + 1, BUF_LEN); + final = g_malloc(len); + g_snprintf(final, len, "%s", utf); + g_free(utf); + + serv_got_im(gc, user, final, 0, time(NULL)); + + g_free(final); + g_free(msg); + } else if (!g_strncasecmp(buf, "NLN", 3)) { + char *state, *user, *tmp = buf; + int status = UC_NORMAL; + + GET_NEXT(tmp); + state = tmp; + + GET_NEXT(tmp); + user = tmp; + + GET_NEXT(tmp); + + if (!g_strcasecmp(state, "BSY")) { + status |= (MSN_BUSY << 5); + } else if (!g_strcasecmp(state, "IDL")) { + status |= (MSN_IDLE << 5); + } else if (!g_strcasecmp(state, "BRB")) { + status |= (MSN_BRB << 5); + } else if (!g_strcasecmp(state, "AWY")) { + status = UC_UNAVAILABLE; + } else if (!g_strcasecmp(state, "PHN")) { + status |= (MSN_PHONE << 5); + } else if (!g_strcasecmp(state, "LUN")) { + status |= (MSN_LUNCH << 5); + } + + serv_got_update(gc, user, 1, 0, 0, 0, status, 0); + } else if (!g_strncasecmp(buf, "OUT", 3)) { + } else if (!g_strncasecmp(buf, "PRP", 3)) { + } else if (!g_strncasecmp(buf, "REM", 3)) { + } else if (!g_strncasecmp(buf, "RNG", 3)) { + struct msn_switchboard *ms; + char *sessid, *ssaddr, *auth; + int port, i = 0; + char *tmp = buf; + + GET_NEXT(tmp); + sessid = tmp; + + GET_NEXT(tmp); + ssaddr = tmp; + + GET_NEXT(tmp); + + GET_NEXT(tmp); + auth = tmp; + + GET_NEXT(tmp); - else if (!strncmp("JOI ", buf, 4)) { - /* Looks like they just joined! Write their queued message */ - g_snprintf(buf, MSN_BUF_LEN, "MSG %ld N %d\r\n%s%s", trId(md), strlen(mc->txqueue) + strlen(MIME_HEADER), MIME_HEADER, mc->txqueue); + while (ssaddr[i] && ssaddr[i] != ':') i++; + if (ssaddr[i] == ':') { + char *x = &ssaddr[i + 1]; + ssaddr[i] = 0; + port = atoi(x); + } else + port = 1863; - msn_write(source, buf); + ms = g_new0(struct msn_switchboard, 1); + ms->sessid = g_strdup(sessid); + ms->auth = g_strdup(auth); + ms->gc = gc; + ms->fd = proxy_connect(ssaddr, port, msn_rng_connect, ms); + } else if (!g_strncasecmp(buf, "SYN", 3)) { + } else if (!g_strncasecmp(buf, "USR", 3)) { + } else if (!g_strncasecmp(buf, "XFR", 3)) { + char *host = strstr(buf, "SB"); + int port; + int i = 0; + gboolean switchboard = TRUE; + char *tmp; + + if (!host) { + host = strstr(buf, "NS"); + if (!host) { + hide_login_progress(gc, "Got invalid XFR\n"); + signoff(gc); + return; + } + switchboard = FALSE; + } - gdk_input_remove(mc->inpa); - mc->inpa = gdk_input_add(mc->fd, GDK_INPUT_READ, msn_callback, mc->gc); + GET_NEXT(host); + while (host[i] && host[i] != ':') i++; + if (host[i] == ':') { + tmp = &host[i + 1]; + host[i] = 0; + while (isdigit(*tmp)) tmp++; + *tmp++ = 0; + port = atoi(&host[i + 1]); + } else { + port = 1863; + tmp = host; + GET_NEXT(tmp); + } + + if (switchboard) { + struct msn_switchboard *ms = g_new0(struct msn_switchboard, 1); - return; + GET_NEXT(tmp); + ms->gc = gc; + ms->auth = g_strdup(tmp); + ms->fd = proxy_connect(host, port, msn_ss_xfr_connect, ms); + } else { + close(md->fd); + gdk_input_remove(md->inpa); + md->inpa = 0; + md->fd = 0; + md->fd = proxy_connect(host, port, msn_login_xfr_connect, gc); + } + } else if (isdigit(*buf)) { + handle_errcode(buf, TRUE); + } else { + debug_printf("Unhandled message!\n"); } } -static void msn_xfr_callback(gpointer data, gint source, GdkInputCondition condition) +static void msn_login_xfr_connect(gpointer data, gint source, GdkInputCondition cond) { - struct msn_conn *mc = data; + struct gaim_connection *gc = data; + struct msn_data *md; char buf[MSN_BUF_LEN]; - if (source == -1) + if (!g_slist_find(connections, gc)) return; - if (mc->fd != source) - mc->fd = source; + md = gc->proto_data; + + if (md->fd != source) + md->fd = source; - mc->inpa = gdk_input_add(mc->fd, GDK_INPUT_READ, msn_invite_callback, mc); - g_snprintf(buf, MSN_BUF_LEN, "USR %ld %s %s\n", mc->last_trid, mc->gc->username, mc->secret); - msn_write(mc->fd, buf); + if (md->fd == -1) { + hide_login_progress(gc, "Unable to connect to Notification Server"); + signoff(gc); + return; + } + + g_snprintf(buf, sizeof(buf), "USR %d MD5 I %s\n", ++md->trId, gc->username); + if (msn_write(md->fd, buf, strlen(buf)) < 0) { + hide_login_progress(gc, "Unable to talk to Notification Server"); + signoff(gc); + return; + } + + md->inpa = gdk_input_add(md->fd, GDK_INPUT_READ, msn_login_callback, gc); } -static void msn_callback(gpointer data, gint source, GdkInputCondition condition) +static void msn_login_callback(gpointer data, gint source, GdkInputCondition cond) { struct gaim_connection *gc = data; - struct msn_data *md = (struct msn_data *)gc->proto_data; + struct msn_data *md = gc->proto_data; char buf[MSN_BUF_LEN]; int i = 0; - int num; + + bzero(buf, sizeof(buf)); + while ((read(md->fd, buf + i, 1) > 0) && (buf[i++] != '\n')) + if (i == sizeof(buf)) + i--; /* yes i know this loses data but we shouldn't get messages this long + and it's better than possibly writing past our buffer */ + if (i == 0 || buf[i - 1] != '\n') { + hide_login_progress(gc, "Error reading from server"); + signoff(gc); + return; + } + debug_printf("S: %s", buf); + g_strchomp(buf); + + if (!g_strncasecmp(buf, "VER", 3)) { + /* we got VER, check to see that MSNP2 is in the list, then send INF */ + if (!strstr(buf, "MSNP2")) { + hide_login_progress(gc, "Protocol not supported"); + signoff(gc); + return; + } - bzero(buf, MSN_BUF_LEN); - - do { - if (read(source, buf + i, 1) != 1) { - if (md->fd == source) { - hide_login_progress(gc, "Read error"); + g_snprintf(buf, sizeof(buf), "INF %d\n", ++md->trId); + if (msn_write(md->fd, buf, strlen(buf)) < 0) { + hide_login_progress(gc, "Unable to request INF\n"); + signoff(gc); + return; + } + } else if (!g_strncasecmp(buf, "INF", 3)) { + /* check to make sure we can use md5 */ + if (!strstr(buf, "MD5")) { + hide_login_progress(gc, "Unable to login using MD5"); + signoff(gc); + return; + } + + g_snprintf(buf, sizeof(buf), "USR %d MD5 I %s\n", ++md->trId, gc->username); + if (msn_write(md->fd, buf, strlen(buf)) < 0) { + hide_login_progress(gc, "Unable to send USR\n"); + signoff(gc); + return; + } + + set_login_progress(gc, 3, "Requesting to send password"); + } else if (!g_strncasecmp(buf, "USR", 3)) { + /* so here, we're either getting the challenge or the OK */ + if (strstr(buf, "OK")) { + g_snprintf(buf, sizeof(buf), "SYN %d 0\n", ++md->trId); + if (msn_write(md->fd, buf, strlen(buf)) < 0) { + hide_login_progress(gc, "Unable to write"); signoff(gc); return; } - close(source); - - return; - } - - } while (buf[i++] != '\n'); - - g_strchomp(buf); - - debug_printf("MSN(%d) ==> %s\n", source, buf); + g_snprintf(buf, sizeof(buf), "CHG %d NLN\n", ++md->trId); + if (msn_write(md->fd, buf, strlen(buf)) < 0) { + hide_login_progress(gc, "Unable to write"); + signoff(gc); + return; + } - if (!strncmp("NLN ", buf, 4) || !strncmp("ILN ", buf, 4)) { - int status; - int query; - char **res; - - res = g_strsplit(buf, " ", 0); - - if (!strcmp(res[0], "NLN")) - query = 1; - else - query = 2; + account_online(gc); + serv_finish_login(gc); - if (!strcasecmp(res[query], "NLN")) - status = UC_NORMAL; - else if (!strcasecmp(res[query], "BSY")) - status = UC_NORMAL | (MSN_BUSY << 5); - else if (!strcasecmp(res[query], "IDL")) - status = UC_NORMAL | (MSN_IDLE << 5); - else if (!strcasecmp(res[query], "BRB")) - status = UC_NORMAL | (MSN_BRB << 5); - else if (!strcasecmp(res[query], "AWY")) - status = UC_UNAVAILABLE; - else if (!strcasecmp(res[query], "PHN")) - status = UC_NORMAL | (MSN_PHONE << 5); - else if (!strcasecmp(res[query], "LUN")) - status = UC_NORMAL | (MSN_LUNCH << 5); - else - status = UC_NORMAL; + gdk_input_remove(md->inpa); + md->inpa = gdk_input_add(md->fd, GDK_INPUT_READ, msn_callback, gc); + } else if (strstr(buf, "MD5")) { + char *challenge = buf; + char buf2[MSN_BUF_LEN]; + md5_state_t st; + md5_byte_t di[16]; + int spaces = 4; + int i; - serv_got_update(gc, res[query+1], 1, 0, 0, 0, status, 0); - - g_strfreev(res); - - return; - - } else if (!strncmp("REA ", buf, 4)) { - char **res; - - res = g_strsplit(buf, " ", 0); - - /* Kill the old one */ - g_free(md->friendly); + while (spaces) { + if (isspace(*challenge)) { + spaces--; + while (isspace(challenge[1])) + challenge++; + } + challenge++; + } - /* Set the new one */ - md->friendly = g_strdup(res[4]); + g_snprintf(buf2, sizeof(buf2), "%s%s", challenge, gc->password); + + md5_init(&st); + md5_append(&st, (const md5_byte_t *)buf2, strlen(buf2)); + md5_finish(&st, di); - /* And free up some memory. That's all, folks. */ - g_strfreev(res); - } else if (!strncmp("BYE ", buf, 4)) { - char **res; - struct msn_conn *mc; + g_snprintf(buf, sizeof(buf), "USR %d MD5 S ", ++md->trId); + for (i = 0; i < 16; i++) { + g_snprintf(buf2, sizeof(buf2), "%02x", di[i]); + strcat(buf, buf2); + } + strcat(buf, "\n"); - res = g_strsplit(buf, " ", 0); - - mc = find_msn_conn_by_user(res[1]); + if (msn_write(md->fd, buf, strlen(buf)) < 0) { + hide_login_progress(gc, "Unable to send password"); + signoff(gc); + return; + } - if (mc) { - /* Looks like we need to close up some stuff :-) */ - free_msn_conn(mc); + set_login_progress(gc, 4, "Password sent"); } - - g_strfreev(res); - return; - } else if (!strncmp("MSG ", buf, 4)) { - /* We are receiving an incoming message */ - gchar **res; - gchar *user; - gchar *msgdata; - int size; - char rahc[MSN_BUF_LEN * 2]; - - res = g_strsplit(buf, " ", 0); - - user = g_strdup(res[1]); - size = atoi(res[3]); - - /* Ok, we know who we're receiving a message from as well as - * how big the message is */ + } else if (!g_strncasecmp(buf, "XFR", 3)) { + char *host = strstr(buf, "NS"); + int port; + int i = 0; - msgdata = (gchar *)g_malloc(sizeof(gchar) *(size + 1)); - num = recv(source, msgdata, size, 0); - msgdata[size] = 0; - - if (num < size) - debug_printf("MSN: Uhh .. we gots a problem!. Expected %d but got %d.\n", size, num); - - /* We should ignore messages from the user Hotmail */ - if (!strcasecmp("hotmail", res[1])) { - process_hotmail_msg(gc,msgdata); - g_strfreev(res); - g_free(msgdata); - return; - } - - /* Check to see if any body is in the message */ - if (!strcmp(strstr(msgdata, "\r\n\r\n") + 4, "\r\n")) { - g_strfreev(res); - g_free(msgdata); + if (!host) { + hide_login_progress(gc, "Got invalid XFR\n"); + signoff(gc); return; } - /* Otherwise, everything is ok. Let's show the message. Skipping, - * of course, the header. */ - - g_snprintf(rahc, sizeof(rahc), "%s", strstr(msgdata, "\r\n\r\n") + 4); - serv_got_im(gc, res[1], rahc, 0, time((time_t)NULL)); - - g_strfreev(res); - g_free(msgdata); - - return; - } else if (!strncmp("RNG ", buf, 4)) { - /* Ok, someone wants to talk to us. Ring ring? Hi!!! */ - gchar **address; - gchar **res; - struct msn_conn *mc = g_new0(struct msn_conn, 1); - struct aim_user *user = gc->user; - mc->gc = gc; - - res = g_strsplit(buf, " ", 0); - address = g_strsplit(res[2], ":", 0); - - /* Set up our struct with user and input watcher */ - mc->user = g_strdup(res[5]); - mc->secret = g_strdup(res[4]); - mc->session = g_strdup(res[1]); - - mc->fd = proxy_connect(address[0], atoi(address[1]), msn_answer_callback, mc); - g_strfreev(address); - g_strfreev(res); - if (!user->gc || (mc->fd < 0)) { - /* Looks like we had an error connecting. */ - g_free(mc->session); - g_free(mc->secret); - g_free(mc->user); - g_free(mc); - return; - } - return; - } else if (!strncmp("XFR ", buf, 4)) { - char **res; - struct msn_conn *mc; - - res = g_strsplit(buf, " ", 0); - - debug_printf("Last trid is: %d\n", md->last_trid); - debug_printf("This TrId is: %d\n", atoi(res[1])); - - mc = find_msn_conn_by_trid(atoi(res[1])); - - if (!mc) { - g_strfreev(res); - return; - } - - strcpy(buf, res[3]); - - mc->secret = g_strdup(res[5]); - mc->session = g_strdup(res[1]); - - g_strfreev(res); - - res = g_strsplit(buf, ":", 0); - - /* Now we have the host and port */ - debug_printf("Connecting to: %s:%s\n", res[0], res[1]); - - if (mc->inpa) - gdk_input_remove(mc->inpa); - - mc->fd = proxy_connect(res[0], atoi(res[1]), msn_xfr_callback, mc); - g_strfreev(res); + GET_NEXT(host); + while (host[i] && host[i] != ':') i++; + if (host[i] == ':') { + char *x = &host[i + 1]; + host[i] = 0; + port = atoi(x); + } else + port = 1863; - return; - } else if (!strncmp("LST ", buf, 4)) { - char **res; - - res = g_strsplit(buf, " ", 0); - - /* If we have zero buddies, abort */ - if (atoi(res[5]) == 0) { - g_strfreev(res); - return; - } - - /* First, let's check the list type */ - if (!strcmp("FL", res[2])) { - /* We're dealing with a forward list. Add them - * to our buddylist and continue along our - * merry little way */ - - struct buddy *b; - - b = find_buddy(gc, res[6]); - - if (!b) - add_buddy(gc, "Buddies", res[6], res[7]); - } - - g_strfreev(res); - - return; - } else if (!strncmp("FLN ", buf, 4)) { - /* Someone signed off */ - char **res; - - res = g_strsplit(buf, " ", 0); - - serv_got_update(gc, res[1], 0, 0, 0, 0, 0, 0); - - g_strfreev(res); - - return; - } else if (!strncmp("ADD ", buf, 4)) { - msn_add_request(gc,buf); - return; - } if ( (!strncmp("NLN ", buf, 4)) || (!strncmp("ILN ", buf, 4))) { - int status; - int query; - char **res; - - res = g_strsplit(buf, " ", 0); - - if (strcasecmp(res[0], "NLN") == 0) - query = 1; + close(md->fd); + gdk_input_remove(md->inpa); + md->inpa = 0; + md->fd = 0; + md->fd = proxy_connect(host, port, msn_login_xfr_connect, gc); + } else { + if (isdigit(*buf)) + hide_login_progress(gc, handle_errcode(buf, FALSE)); else - query = 2; - - if (!strcasecmp(res[query], "NLN")) - status = UC_NORMAL; - else if (!strcasecmp(res[query], "BSY")) - status = UC_NORMAL | (MSN_BUSY << 5); - else if (!strcasecmp(res[query], "IDL")) - status = UC_NORMAL | (MSN_IDLE << 5); - else if (!strcasecmp(res[query], "BRB")) - status = UC_NORMAL | (MSN_BRB << 5); - else if (!strcasecmp(res[query], "AWY")) - status = UC_UNAVAILABLE; - else if (!strcasecmp(res[query], "PHN")) - status = UC_NORMAL | (MSN_PHONE << 5); - else if (!strcasecmp(res[query], "LUN")) - status = UC_NORMAL | (MSN_LUNCH << 5); - else - status = UC_NORMAL; - - serv_got_update(gc, res[query+1], 1, 0, 0, 0, status, 0); - - g_strfreev(res); + hide_login_progress(gc, "Unable to parse message"); + signoff(gc); return; } - } -static void msn_login_callback(gpointer data, gint source, GdkInputCondition condition) +static void msn_login_connect(gpointer data, gint source, GdkInputCondition cond) { struct gaim_connection *gc = data; - struct msn_data *md = (struct msn_data *)gc->proto_data; - char buf[MSN_BUF_LEN]; - int i = 0; + struct msn_data *md; + char buf[1024]; + + if (!g_slist_find(connections, gc)) + return; - if (source == -1) { + md = gc->proto_data; + + if (md->fd != source) + md->fd = source; + + if (md->fd == -1) { + hide_login_progress(gc, "Unable to connect"); signoff(gc); return; } - if (md->fd != source) { - debug_printf("Eric, you fucked up.\n"); - md->fd = source; - } - - if (!gc->inpa) { - if (md->inpa > 0) - gdk_input_remove(md->inpa); - md->inpa = 0; - - gc->inpa = gdk_input_add(md->fd, GDK_INPUT_READ, msn_login_callback, gc); - - if (md->status & MSN_SIGNON_GOT_XFR) { - /* Looks like we were transfered here. Just send a sign on */ - set_login_progress(gc, 3, "Signing On"); - g_snprintf(buf, MSN_BUF_LEN, "USR %ld %s I %s\n", md->last_trid, md->policy, gc->username); - msn_write(md->fd, buf); - - /* Reset this bit */ - md->status ^= MSN_SIGNON_GOT_XFR; - } else { - /* Otherwise, send an initial request */ - set_login_progress(gc, 2, "Verifying"); - - g_snprintf(md->protocol, 6, "MSNP2"); - - g_snprintf(buf, MSN_BUF_LEN, "VER %ld %s\n", trId(md), md->protocol); - msn_write(md->fd, buf); - } - + g_snprintf(buf, sizeof(buf), "VER %d MSNP2\n", ++md->trId); + if (msn_write(md->fd, buf, strlen(buf)) < 0) { + hide_login_progress(gc, "Unable to write to server"); + signoff(gc); return; } - bzero(buf, MSN_BUF_LEN); - - do { - if (read(source, buf + i, 1) != 1) { - hide_login_progress(gc, "Read error"); - signoff(gc); - return; - } - } while (buf[i++] != '\n'); - - g_strchomp(buf); - - debug_printf("MSN ==> %s\n", buf); - - /* Check to see what was just sent back to us. We should be seeing a VER tag. */ - if (!strncmp("VER ", buf, 4) && (!strstr("MSNP2", buf))) { - /* Now that we got our ver, we should send a policy request */ - g_snprintf(buf, MSN_BUF_LEN, "INF %ld\n", trId(md)); - msn_write(md->fd, buf); - - return; - } else if (!strncmp("INF ", buf, 4)) { - char **res; - - /* Make a copy of our resulting policy */ - res = g_strsplit(buf, " ", 0); - md->policy = g_strdup(res[2]); - - /* And send our signon packet */ - set_login_progress(gc, 3, "Signing On"); - - g_snprintf(buf, MSN_BUF_LEN, "USR %ld %s I %s\n", trId(md), md->policy, gc->username); - msn_write(md->fd, buf); - - g_strfreev(res); - - return; - } else if (!strncmp("ADD ", buf, 4)) { - msn_add_request(gc,buf); - return; - } else if (!strncmp("XFR ", buf, 4)) { - char **res; - struct aim_user *user = gc->user; - - res = g_strsplit(buf, " ", 0); - - strcpy(buf, res[3]); - - g_strfreev(res); - - res = g_strsplit(buf, ":", 0); - - close(md->fd); - - set_login_progress(gc, 3, "Connecting to Auth"); - - - md->status |= MSN_SIGNON_GOT_XFR; - - gdk_input_remove(gc->inpa); - gc->inpa = 0; - - /* Now we have the host and port */ - md->fd = proxy_connect(res[0], atoi(res[1]), msn_login_callback, gc); - if (!user->gc || (md->fd < 0)) { - g_strfreev(res); - hide_login_progress(gc, "Error connecting to server"); - signoff(gc); - return; - } - - g_strfreev(res); - return; - } else if (!strncmp("USR ", buf, 4)) { - if (md->status & MSN_SIGNON_SENT_USR) { - char **res; - - res = g_strsplit(buf, " ", 0); - - if (strcasecmp("OK", res[2])) { - hide_login_progress(gc, "Error signing on"); - signoff(gc); - } else { - md->friendly = g_strdup(url_decode(res[4])); - - /* Ok, ok. Your account is FINALLY online. Ya think Microsoft - * could have had any more steps involved? */ - - set_login_progress(gc, 4, "Fetching config"); - - /* Sync our buddylist */ - g_snprintf(buf, MSN_BUF_LEN, "SYN %ld 0\n", trId(md)); - msn_write(md->fd, buf); - - /* And set ourselves online */ - g_snprintf(buf, MSN_BUF_LEN, "CHG %ld NLN\n", trId(md)); - msn_write(md->fd, buf); - - account_online(gc); - serv_finish_login(gc); - - if (bud_list_cache_exists(gc)) - do_import(NULL, gc); - - gdk_input_remove(gc->inpa); - gc->inpa = gdk_input_add(md->fd, GDK_INPUT_READ, msn_callback, gc); - } - - g_strfreev(res); - } else { - char **res; - char buf2[MSN_BUF_LEN]; - md5_state_t st; - md5_byte_t di[16]; - - res = g_strsplit(buf, " ", 0); - - /* Make a copy of our MD5 Hash key */ - strcpy(buf, res[4]); - - /* Generate our secret with our key and password */ - snprintf(buf2, MSN_BUF_LEN, "%s%s", buf, gc->password); - - md5_init(&st); - md5_append(&st, (const md5_byte_t *)buf2, strlen(buf2)); - md5_finish(&st, di); - - /* Now that we have the MD5 Hash, lets' hex encode this bad boy. I smoke bad crack. */ - sprintf(buf, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - di[0],di[1],di[2],di[3],di[4],di[5],di[6],di[7],di[8],di[9],di[10],di[11],di[12], - di[13],di[14],di[15]); - - /* And now, send our final sign on packet */ - g_snprintf(buf2, MSN_BUF_LEN, "USR %s %s S %s\n", res[1], md->policy, buf); - msn_write(md->fd, buf2); - - md->status |= MSN_SIGNON_SENT_USR; - - g_strfreev(res); - } - - return; - } + md->inpa = gdk_input_add(md->fd, GDK_INPUT_READ, msn_login_callback, gc); + set_login_progress(gc, 2, "Synching with server"); } static void msn_login(struct aim_user *user) @@ -914,213 +935,144 @@ struct gaim_connection *gc = new_gaim_conn(user); struct msn_data *md = gc->proto_data = g_new0(struct msn_data, 1); - gc->inpa = 0; - set_login_progress(gc, 1, "Connecting"); - while (gtk_events_pending()) - gtk_main_iteration(); + g_snprintf(gc->username, sizeof(gc->username), "%s", msn_normalize(gc->username)); - if (!g_slist_find(connections, gc)) - return; - - md->status = 0; + md->fd = proxy_connect("messenger.hotmail.com", 1863, msn_login_connect, gc); +} - sprintf(gc->username, "%s", msn_normalize(gc->username)); - md->fd = proxy_connect("messenger.hotmail.com", 1863, msn_login_callback, gc); - if (!user->gc || (md->fd < 0)) { - hide_login_progress(gc, "Error connecting to server"); - signoff(gc); - return; +static void msn_close(struct gaim_connection *gc) +{ + struct msn_data *md = gc->proto_data; + close(md->fd); + if (md->inpa) + gdk_input_remove(md->inpa); + while (md->switches) + msn_kill_switch(md->switches->data); + while (md->xfrs) { + struct msn_xfr *mx = md->xfrs->data; + md->xfrs = g_slist_remove(md->xfrs, mx); + g_free(mx->user); + g_free(mx->what); + g_free(mx); } + while (md->fl) { + char *tmp = md->fl->data; + md->fl = g_slist_remove(md->fl, tmp); + g_free(tmp); + } + g_free(md); } static void msn_send_im(struct gaim_connection *gc, char *who, char *message, int away) { - struct msn_conn *mc; - struct msn_data *md = (struct msn_data *)gc->proto_data; + struct msn_data *md = gc->proto_data; + struct msn_switchboard *ms = msn_find_switch(gc, who); char buf[MSN_BUF_LEN]; - if (!g_strcasecmp(who, gc->username)) { - do_error_dialog("You can not send a message to yourself!", "Gaim: MSN Error"); - return; - } - - mc = find_msn_conn_by_user(who); - - /* If we're not already in a conversation with - * this person then we have to do some tricky things. */ - - if (!mc) { - /* Request a new switchboard connection */ - g_snprintf(buf, MSN_BUF_LEN, "XFR %ld SB\n", trId(md)); - msn_write(md->fd, buf); - - mc = g_new0(struct msn_conn, 1); + if (ms) { + g_snprintf(buf, sizeof(buf), "MSG %d N %d\r\n%s%s", ++ms->trId, + strlen(MIME_HEADER) + strlen(url_encode(message)), + MIME_HEADER, url_encode(message)); + if (msn_write(ms->fd, buf, strlen(buf)) < 0) + msn_kill_switch(ms); + } else { + struct msn_xfr *mx; + g_snprintf(buf, MSN_BUF_LEN, "XFR %d SB\n", ++md->trId); + if (msn_write(md->fd, buf, strlen(buf)) < 0) { + hide_login_progress(gc, "Write error"); + signoff(gc); + return; + } - mc->user = g_strdup(who); - mc->gc = gc; - mc->last_trid = md->last_trid; - mc->txqueue = g_strdup(message); - - /* Append our connection */ - msn_connections = g_slist_append(msn_connections, mc); - } else { - g_snprintf(buf, MSN_BUF_LEN, "MSG %ld N %d\r\n%s%s", trId(md), - strlen(message) + strlen(MIME_HEADER), MIME_HEADER, message); - - msn_write(mc->fd, url_encode(buf, 0)); + mx = g_new0(struct msn_xfr, 1); + md->xfrs = g_slist_append(md->xfrs, mx); + mx->user = g_strdup(who); + mx->what = g_strdup(message); + mx->gc = gc; } - -} - -static void msn_add_buddy(struct gaim_connection *gc, char *who) -{ - struct msn_data *md = (struct msn_data *)gc->proto_data; - char buf[MSN_BUF_LEN - 1]; - - snprintf(buf, MSN_BUF_LEN, "ADD %ld FL %s %s\n", trId(md), who, who); - msn_write(md->fd, buf); } -static void msn_remove_buddy(struct gaim_connection *gc, char *who) -{ - struct msn_data *md = (struct msn_data *)gc->proto_data; - char buf[MSN_BUF_LEN - 1]; - - snprintf(buf, MSN_BUF_LEN, "REM %ld FL %s\n", trId(md), who); - msn_write(md->fd, buf); -} - -static void msn_rem_permit(struct gaim_connection *gc, char *who) -{ - struct msn_data *md = (struct msn_data *)gc->proto_data; - char buf[MSN_BUF_LEN - 1]; - - snprintf(buf, MSN_BUF_LEN, "REM %ld AL %s\n", trId(md), who); - msn_write(md->fd, buf); -} - -static void msn_add_permit(struct gaim_connection *gc, char *who) -{ - struct msn_data *md = (struct msn_data *)gc->proto_data; - char buf[MSN_BUF_LEN - 1]; - - snprintf(buf, MSN_BUF_LEN, "ADD %ld AL %s %s\n", trId(md), who, who); - msn_write(md->fd, buf); -} - -static void msn_rem_deny(struct gaim_connection *gc, char *who) -{ - struct msn_data *md = (struct msn_data *)gc->proto_data; - char buf[MSN_BUF_LEN - 1]; - - snprintf(buf, MSN_BUF_LEN, "REM %ld BL %s\n", trId(md), who); - msn_write(md->fd, buf); -} - -static void msn_add_deny(struct gaim_connection *gc, char *who) -{ - struct msn_data *md = (struct msn_data *)gc->proto_data; - char buf[MSN_BUF_LEN - 1]; - - snprintf(buf, MSN_BUF_LEN, "ADD %ld BL %s %s\n", trId(md), who, who); - msn_write(md->fd, buf); -} - -static GList *msn_away_states() +static GList *msn_away_states() { GList *m = NULL; - m = g_list_append(m, "Available"); - m = g_list_append(m, "Away From Computer"); - m = g_list_append(m, "Be Right Back"); - m = g_list_append(m, "Busy"); - m = g_list_append(m, "On The Phone"); - m = g_list_append(m, "Out To Lunch"); + m = g_list_append(m, "Available"); + m = g_list_append(m, "Away From Computer"); + m = g_list_append(m, "Be Right Back"); + m = g_list_append(m, "Busy"); + m = g_list_append(m, "On The Phone"); + m = g_list_append(m, "Out To Lunch"); return m; } static void msn_set_away(struct gaim_connection *gc, char *state, char *msg) { - struct msn_data *md = (struct msn_data *)gc->proto_data; - char buf[MSN_BUF_LEN - 1]; - + struct msn_data *md = gc->proto_data; + char buf[MSN_BUF_LEN]; + char *away; gc->away = NULL; - + if (msg) { gc->away = ""; - snprintf(buf, MSN_BUF_LEN, "CHG %ld AWY\n", trId(md)); + away = "AWY"; } else if (state) { - char away[4]; - gc->away = ""; - if (!strcmp(state, "Available")) - sprintf(away, "NLN"); - else if (!strcmp(state, "Away From Computer")) - sprintf(away, "AWY"); + if (!strcmp(state, "Away From Computer")) + away = "AWY"; else if (!strcmp(state, "Be Right Back")) - sprintf(away, "BRB"); + away = "BRB"; else if (!strcmp(state, "Busy")) - sprintf(away, "BSY"); + away = "BSY"; else if (!strcmp(state, "On The Phone")) - sprintf(away, "PHN"); + away = "PHN"; else if (!strcmp(state, "Out To Lunch")) - sprintf(away, "LUN"); - else - sprintf(away, "NLN"); - - snprintf(buf, MSN_BUF_LEN, "CHG %ld %s\n", trId(md), away); + away = "LUN"; + else { + gc->away = NULL; + away = "NLN"; + } } else if (gc->is_idle) - snprintf(buf, MSN_BUF_LEN, "CHG %ld IDL\n", trId(md)); + away = "IDL"; else - snprintf(buf, MSN_BUF_LEN, "CHG %ld NLN\n", trId(md)); + away = "NLN"; - msn_write(md->fd, buf); + g_snprintf(buf, sizeof(buf), "CHG %d %s\n", ++md->trId, away); + if (msn_write(md->fd, buf, strlen(buf)) < 0) { + hide_login_progress(gc, "Write error"); + signoff(gc); + return; + } } - static void msn_set_idle(struct gaim_connection *gc, int idle) { - struct msn_data *md = (struct msn_data *)gc->proto_data; - char buf[MSN_BUF_LEN - 1]; + struct msn_data *md = gc->proto_data; + char buf[MSN_BUF_LEN]; + if (gc->away) + return; if (idle) - snprintf(buf, MSN_BUF_LEN, "CHG %ld IDL\n", trId(md)); + g_snprintf(buf, sizeof(buf), "CHG %d IDL\n", ++md->trId); else - snprintf(buf, MSN_BUF_LEN, "CHG %ld NLN\n", trId(md)); - - msn_write(md->fd, buf); + g_snprintf(buf, sizeof(buf), "CHG %d NLN\n", ++md->trId); + if (msn_write(md->fd, buf, strlen(buf)) < 0) { + hide_login_progress(gc, "Write error"); + signoff(gc); + return; + } } -static void msn_close(struct gaim_connection *gc) +static char **msn_list_icon(int uc) { - struct msn_data *md = (struct msn_data *)gc->proto_data; - char buf[MSN_BUF_LEN]; - struct msn_conn *mc = NULL; - - while (msn_connections) { - mc = (struct msn_conn *)msn_connections->data; - - free_msn_conn(mc); - } + if (uc == UC_NORMAL) + return msn_online_xpm; - if (md->fd) { - g_snprintf(buf, MSN_BUF_LEN, "OUT\n"); - msn_write(md->fd, buf); - close(md->fd); - } - - if (gc->inpa) - gdk_input_remove(gc->inpa); - - if (md->friendly) - g_free(md->friendly); - - g_free(gc->proto_data); + return msn_away_xpm; } static char *msn_get_away_text(int s) @@ -1139,62 +1091,30 @@ case MSN_IDLE : return "Idle"; default: - return NULL; + return "Available"; } } - + static void msn_buddy_menu(GtkWidget *menu, struct gaim_connection *gc, char *who) { struct buddy *b = find_buddy(gc, who); char buf[MSN_BUF_LEN]; GtkWidget *button; - if (!(b->uc >> 5)) + if (!b || !(b->uc >> 5)) return; - g_snprintf(buf, MSN_BUF_LEN, "Status: %s", msn_get_away_text(b->uc >> 5)); - + g_snprintf(buf, sizeof(buf), "Status: %s", msn_get_away_text(b->uc >> 5)); + button = gtk_menu_item_new_with_label(buf); gtk_menu_append(GTK_MENU(menu), button); - gtk_widget_show(button); + gtk_widget_show(button); } -static void msn_newmail_dialog(const char *text) -{ - GtkWidget *window; - GtkWidget *vbox; - GtkWidget *label; - GtkWidget *hbox; - GtkWidget *button; - - window = gtk_window_new(GTK_WINDOW_DIALOG); - gtk_window_set_wmclass(GTK_WINDOW(window), "prompt", "Gaim"); - gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, TRUE); - gtk_window_set_title(GTK_WINDOW(window), _("Gaim-MSN: New Mail")); - gtk_widget_realize(window); - aol_icon(window->window); - - vbox = gtk_vbox_new(FALSE, 5); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); - gtk_container_add(GTK_CONTAINER(window), vbox); - - label = gtk_label_new(text); - gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0); - - hbox = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - button = picture_button(window, _("OK"), ok_xpm); - gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0); - gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(msn_des_win), window); - - gtk_widget_show_all(window); -} - -static void msn_des_win(GtkWidget *a, GtkWidget *b) -{ - gtk_widget_destroy(b); -} +struct mod_usr_opt { + struct aim_user *user; + int opt; +}; static void mod_opt(GtkWidget *b, struct mod_usr_opt *m) { @@ -1216,21 +1136,20 @@ GtkWidget *button; struct mod_usr_opt *muo = g_new0(struct mod_usr_opt, 1); button = gtk_check_button_new_with_label(text); - if (u) { + if (u) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), (u->proto_opt[option][0] == '1')); - } gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0); muo->user = u; muo->opt = option; gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(mod_opt), muo); gtk_signal_connect(GTK_OBJECT(button), "destroy", GTK_SIGNAL_FUNC(free_muo), muo); gtk_widget_show(button); + return button; } static void msn_user_opts(GtkWidget* book, struct aim_user *user) { - /* so here, we create the new notebook page */ GtkWidget *vbox; vbox = gtk_vbox_new(FALSE, 5); @@ -1241,185 +1160,39 @@ msn_protoopt_button("Notify me of new HotMail",user,USEROPT_HOTMAIL,vbox); } -/* - Process messages from Hotmail service. right now we just check for new - mail notifications, if the user has checking enabled. -*/ - -static void process_hotmail_msg(struct gaim_connection *gc, gchar *msgdata) +static void msn_add_buddy(struct gaim_connection *gc, char *who) { - gchar *mailnotice; - char *mailfrom,*mailsubj,*mailct,*mailp; + struct msn_data *md = gc->proto_data; + char buf[MSN_BUF_LEN]; + GSList *l = md->fl; - if (gc->user->proto_opt[USEROPT_HOTMAIL][0] != '1') return; - mailfrom=NULL; mailsubj=NULL; mailct=NULL; mailp=NULL; - mailct = strstr(msgdata,"Content-Type: "); - mailp = strstr(mailct,";"); - if ((mailct != NULL) && (mailp != NULL) && (mailp > mailct) && - !strncmp(mailct,"Content-Type: text/x-msmsgsemailnotification",(mailp-mailct)-1)) { - mailfrom=strstr(mailp,"From: "); - mailsubj=strstr(mailp,"Subject: "); + while (l) { + if (!g_strcasecmp(who, l->data)) + break; + l = l->next; } - - if (mailfrom != NULL && mailsubj != NULL) { - mailfrom += 6; - mailp=strstr(mailfrom,"\r\n"); - if (mailp==NULL) return; - *mailp = 0; - mailsubj += 9; - mailp=strstr(mailsubj,"\r\n"); - if (mailp==NULL) return; - *mailp = 0; - mailnotice = (gchar *)g_malloc(sizeof(gchar) *(strlen(mailfrom)+strlen(mailsubj)+128)); - sprintf(mailnotice,"Mail from %s, re: %s",mailfrom,mailsubj); - msn_newmail_dialog(mailnotice); - g_free(mailnotice); + if (l) + return; + + g_snprintf(buf, sizeof(buf), "ADD %d FL %s %s\n", ++md->trId, who, who); + if (msn_write(md->fd, buf, strlen(buf)) < 0) { + hide_login_progress(gc, "Write error"); + signoff(gc); + return; } } -static char *msn_normalize(const char *s) -{ - static char buf[BUF_LEN]; - char *t, *u; - int x = 0; - - g_return_val_if_fail((s != NULL), NULL); - - u = t = g_strdup(s); - - g_strdown(t); - - while (*t && (x < BUF_LEN - 1)) { - if (*t != ' ') - buf[x++] = *t; - t++; - } - buf[x] = '\0'; - g_free(u); - - if (!strchr(buf, '@')) { - strcat(buf, "@hotmail.com"); /* if they don't specify something, it will be hotmail.com. - msn.com is valid too, but hey, if they wanna use it, - they gotta enter it themselves. */ - } else if ((u = strchr(strchr(buf, '@'), '/')) != NULL) { - *u = '\0'; - } - - return buf; -} - -static void do_change_name(GtkWidget *w, struct msn_name_dlg *b) +static void msn_rem_buddy(struct gaim_connection *gc, char *who) { - struct gaim_connection *gc = b->user->gc; - struct msn_data *md = (struct msn_data *)gc->proto_data; - char buf[MSN_BUF_LEN - 1]; - const gchar *newname; - char *temp; - - newname = gtk_entry_get_text(GTK_ENTRY(b->entry)); - - temp = strdup(newname); - - snprintf(buf, MSN_BUF_LEN, "REA %ld %s %s\n", trId(md), gc->username, url_encode(temp, 1)); - - free(temp); - - msn_write(md->fd, buf); - - msn_des_win(NULL, b->window); - - return; -} - -static void show_change_name(struct gaim_connection *gc) -{ - GtkWidget *label; - GtkWidget *vbox; - GtkWidget *buttons; - GtkWidget *hbox; - struct aim_user *tmp; - gchar *buf; - struct msn_data *md; - - struct msn_name_dlg *b = g_new0(struct msn_name_dlg, 1); - if (!g_slist_find(connections, gc)) - gc = connections->data; - - tmp = gc->user; - b->user = tmp; + struct msn_data *md = gc->proto_data; + char buf[MSN_BUF_LEN]; - md = (struct msn_data *)gc->proto_data; - - b->window = gtk_window_new(GTK_WINDOW_DIALOG); - gtk_window_set_wmclass(GTK_WINDOW(b->window), "msn_change_name", "Gaim"); - - gtk_window_set_title(GTK_WINDOW(b->window), _("Gaim - Change MSN Name")); - gtk_signal_connect(GTK_OBJECT(b->window), "destroy", GTK_SIGNAL_FUNC(msn_des_win), b->window); - gtk_widget_realize(b->window); - aol_icon(b->window->window); - - vbox = gtk_vbox_new(FALSE, 5); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); - gtk_container_add(GTK_CONTAINER(b->window), vbox); - gtk_widget_show(vbox); - - hbox = gtk_hbox_new(FALSE, 5); - gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); - gtk_widget_show(hbox); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); - - buf = g_malloc(256); - g_snprintf(buf, 256, "New name for %s (%s):", tmp->username, url_decode(md->friendly)); - label = gtk_label_new(buf); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); - gtk_widget_show(label); - g_free(buf); - - b->entry = gtk_entry_new(); - gtk_box_pack_start(GTK_BOX(hbox), b->entry, FALSE, FALSE, 5); - gtk_widget_show(b->entry); - - buttons = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(vbox), buttons, FALSE, FALSE, 0); - gtk_widget_show(buttons); - - b->cancel = picture_button(b->window, _("Cancel"), cancel_xpm); - gtk_box_pack_end(GTK_BOX(buttons), b->cancel, FALSE, FALSE, 0); - gtk_signal_connect(GTK_OBJECT(b->cancel), "clicked", GTK_SIGNAL_FUNC(msn_des_win), b->window); - - b->ok = picture_button(b->window, _("Ok"), ok_xpm); - gtk_box_pack_end(GTK_BOX(buttons), b->ok, FALSE, FALSE, 0); - gtk_signal_connect(GTK_OBJECT(b->ok), "clicked", GTK_SIGNAL_FUNC(do_change_name), b); - - - gtk_widget_show(b->window); - - -} - -static void msn_do_action(struct gaim_connection *gc, char *act) -{ - if (!strcmp(act, "Change Name")) - show_change_name(gc); -} - -static GList *msn_actions() -{ - GList *m = NULL; - - m = g_list_append(m, "Change Name"); - - return m; -} - -static char **msn_list_icon(int uc) -{ - if (uc == UC_UNAVAILABLE) - return msn_away_xpm; - else if (uc == UC_NORMAL) - return msn_online_xpm; - - return msn_away_xpm; + g_snprintf(buf, sizeof(buf), "REM %d FL %s\n", ++md->trId, who); + if (msn_write(md->fd, buf, strlen(buf)) < 0) { + hide_login_progress(gc, "Write error"); + signoff(gc); + return; + } } static struct prpl *my_protocol = NULL; @@ -1434,39 +1207,17 @@ ret->login = msn_login; ret->close = msn_close; ret->send_im = msn_send_im; - ret->set_info = NULL; - ret->get_info = NULL; ret->away_states = msn_away_states; ret->set_away = msn_set_away; - ret->get_away_msg = NULL; - ret->set_dir = NULL; - ret->get_dir = NULL; - ret->dir_search = NULL; ret->set_idle = msn_set_idle; - ret->change_passwd = NULL; ret->add_buddy = msn_add_buddy; - ret->add_buddies = NULL; - ret->remove_buddy = msn_remove_buddy; - ret->add_permit = msn_add_permit; - ret->rem_permit = msn_rem_permit; - ret->add_deny = msn_add_deny; - ret->rem_deny = msn_rem_deny; - ret->warn = NULL; - ret->accept_chat = NULL; - ret->join_chat = NULL; - ret->chat_invite = NULL; - ret->chat_leave = NULL; - ret->chat_whisper = NULL; - ret->chat_send = NULL; - ret->keepalive = NULL; - ret->actions = msn_actions; - ret->do_action = msn_do_action; + ret->remove_buddy = msn_rem_buddy; ret->normalize = msn_normalize; my_protocol = ret; } -char *gaim_plugin_init(GModule * handle) +char *gaim_plugin_init(GModule *handle) { load_protocol(msn_init, sizeof(struct prpl)); return NULL; diff -r e90a0164436c -r 008a4cc4a82c src/gaim.h --- a/src/gaim.h Sun Jun 10 20:20:44 2001 +0000 +++ b/src/gaim.h Mon Jun 11 09:21:18 2001 +0000 @@ -633,6 +633,7 @@ extern void strncpy_withhtml(gchar *, const gchar *, size_t); extern void away_on_login(char *); extern void system_log(enum log_event, struct gaim_connection *, struct buddy *, int); +extern unsigned char *utf8_to_str(unsigned char *); /* Functions in server.c */ /* input to serv */ diff -r e90a0164436c -r 008a4cc4a82c src/oscar.c --- a/src/oscar.c Sun Jun 10 20:20:44 2001 +0000 +++ b/src/oscar.c Mon Jun 11 09:21:18 2001 +0000 @@ -1710,7 +1710,7 @@ break; } ir->curframe = (ir->curframe + 1) % g_list_length(frames); - delay = gdk_pixbuf_frame_get_delay_time(frame); + delay = MAX(gdk_pixbuf_frame_get_delay_time(frame), 13); ir->timer = gtk_timeout_add(delay * 10, redraw_anim, ir); return FALSE; } @@ -1858,7 +1858,8 @@ gdk_pixbuf_render_pixmap_and_mask(buf, &pm, &bm, 0); if (gdk_pixbuf_animation_get_num_frames(ir->anim) > 1) { - int delay = gdk_pixbuf_frame_get_delay_time(frames->data); + int delay = + MAX(gdk_pixbuf_frame_get_delay_time(frames->data), 13); ir->curframe = 1; ir->timer = gtk_timeout_add(delay * 10, redraw_anim, ir); } @@ -3265,7 +3266,7 @@ gdk_pixbuf_render_pixmap_and_mask(buf, &pm, &bm, 0); if (gdk_pixbuf_animation_get_num_frames(ir->anim) > 1) { - int delay = gdk_pixbuf_frame_get_delay_time(frames->data); + int delay = MAX(gdk_pixbuf_frame_get_delay_time(frames->data), 13); ir->curframe = 1; ir->timer = gtk_timeout_add(delay * 10, redraw_anim, ir); } diff -r e90a0164436c -r 008a4cc4a82c src/util.c --- a/src/util.c Sun Jun 10 20:20:44 2001 +0000 +++ b/src/util.c Mon Jun 11 09:21:18 2001 +0000 @@ -1524,6 +1524,47 @@ fclose(fd); } +unsigned char *utf8_to_str(unsigned char *in) +{ + int n = 0,i = 0; + int inlen; + unsigned char *result; + + if (!in) + return NULL; + + inlen = strlen(in); + + result = g_malloc(inlen+1); + + while(n <= inlen-1) { + long c = (long)in[n]; + if(c<0x80) + result[i++] = (char)c; + else { + if((c&0xC0) == 0xC0) + result[i++] = (char)(((c&0x03)<<6)|(((unsigned char)in[++n])&0x3F)); + else if((c&0xE0) == 0xE0) { + if (n + 2 <= inlen) { + result[i] = (char)(((c&0xF)<<4)|(((unsigned char)in[++n])&0x3F)); + result[i] = (char)(((unsigned char)result[i]) |(((unsigned char)in[++n])&0x3F)); + i++; + } else n += 2; + } + else if((c&0xF0) == 0xF0) + n += 3; + else if((c&0xF8) == 0xF8) + n += 4; + else if((c&0xFC) == 0xFC) + n += 5; + } + n++; + } + result[i] = '\0'; + + return result; +} + time_t get_time(int year, int month, int day, int hour, int min, int sec) { struct tm tm;