comparison plugins/msn/msn.c @ 1985:008a4cc4a82c

[gaim-migrate @ 1995] hi. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Mon, 11 Jun 2001 09:21:18 +0000
parents e90a0164436c
children 00ef734e92e1
comparison
equal deleted inserted replaced
1984:e90a0164436c 1985:008a4cc4a82c
1 /*
2 * gaim - MSN Protocol Plugin
3 *
4 * Copyright (C) 2000, Rob Flynn <rob@tgflinux.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22 #include "config.h" 1 #include "config.h"
23 2
24 #include <netdb.h> 3 #include <stdlib.h>
25 #include <gtk/gtk.h> 4 #include <gtk/gtk.h>
5 #include <string.h>
6 #include <stdio.h>
26 #include <unistd.h> 7 #include <unistd.h>
27 #include <errno.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <time.h>
34 #include <fcntl.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <ctype.h> 8 #include <ctype.h>
39 #include "multi.h" 9 #include "gaim.h"
40 #include "prpl.h" 10 #include "prpl.h"
41 #include "gaim.h"
42 #include "proxy.h" 11 #include "proxy.h"
43 #include "md5.h" 12 #include "md5.h"
44 13
45 #include "pixmaps/msn_online.xpm" 14 #include "pixmaps/msn_online.xpm"
46 #include "pixmaps/msn_away.xpm" 15 #include "pixmaps/msn_away.xpm"
47 #include "pixmaps/ok.xpm"
48 #include "pixmaps/cancel.xpm"
49
50 #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"
51 16
52 #define MSN_BUF_LEN 8192 17 #define MSN_BUF_LEN 8192
18 #define MIME_HEADER "MIME-Version: 1.0\r\n" \
19 "Content-Type: text/plain; charset=UTF-8\r\n" \
20 "X-MMS-IM-Format: FN=MS%20Sans%20Serif; EF=; CO=0; PF=0\r\n\r\n"
53 21
54 #define MSN_ONLINE 1 22 #define MSN_ONLINE 1
55 #define MSN_BUSY 2 23 #define MSN_BUSY 2
56 #define MSN_IDLE 3 24 #define MSN_IDLE 3
57 #define MSN_BRB 4 25 #define MSN_BRB 4
59 #define MSN_PHONE 6 27 #define MSN_PHONE 6
60 #define MSN_LUNCH 7 28 #define MSN_LUNCH 7
61 #define MSN_OFFLINE 8 29 #define MSN_OFFLINE 8
62 #define MSN_HIDDEN 9 30 #define MSN_HIDDEN 9
63 31
64 #define MSN_SIGNON_GOT_XFR 0x0001 32 #define USEROPT_HOTMAIL 0
65 #define MSN_SIGNON_SENT_USR 0x0002 33
66 34 struct msn_data {
67 #define USEROPT_HOTMAIL 0 35 int fd;
68 36 int trId;
69 struct mod_usr_opt { 37 int inpa;
70 struct aim_user *user; 38 GSList *switches;
71 int opt; 39 GSList *xfrs;
40 GSList *fl;
41 gboolean imported;
72 }; 42 };
73 43
74 struct msn_ask_add_permit { 44 struct msn_switchboard {
45 struct gaim_connection *gc;
46 int fd;
47 int inpa;
48 char *sessid;
49 char *auth;
50 int trId;
51 int total;
52 char *user;
53 char *txqueue;
54 };
55
56 struct msn_xfr {
75 struct gaim_connection *gc; 57 struct gaim_connection *gc;
76 char *user; 58 char *user;
77 char *friendly; 59 char *what;
78 }; 60 };
79 61
80 struct msn_data { 62 static void msn_login_callback(gpointer, gint, GdkInputCondition);
81 int fd; 63 static void msn_login_xfr_connect(gpointer, gint, GdkInputCondition);
82 64
83 char protocol[6]; 65 #define GET_NEXT(tmp) while (*(tmp) && !isspace(*(tmp))) \
84 char *friendly; 66 (tmp)++; \
85 gchar *policy; 67 *(tmp)++ = 0; \
86 int inpa; 68 while (*(tmp) && isspace(*(tmp))) \
87 int status; 69 (tmp)++;
88 int away; 70
89 time_t last_trid; 71 char *name()
90 }; 72 {
91 73 return "MSN";
92 struct msn_name_dlg { 74 }
93 GtkWidget *window; 75
94 GtkWidget *menu; 76 char *description()
95 struct aim_user *user; 77 {
96 GtkWidget *entry; 78 return "Allows gaim to use the MSN protocol.";
97 GtkWidget *ok; 79 }
98 GtkWidget *cancel; 80
99 }; 81 static char *msn_name()
100 82 {
101 struct msn_conn { 83 return "MSN";
102 gchar *user; 84 }
103 int inpa; 85
104 int fd; 86 static char *msn_normalize(const char *s)
105 struct gaim_connection *gc; 87 {
106 char *secret; 88 static char buf[BUF_LEN];
107 char *session; 89
108 time_t last_trid; 90 g_return_val_if_fail(s != NULL, NULL);
109 char *txqueue; 91
110 }; 92 g_snprintf(buf, sizeof(buf), "%s%s", s, strchr(s, '@') ? "" : "@hotmail.com");
111 93
112 static GSList *msn_connections = NULL; 94 return buf;
113 95 }
114 static unsigned long long globalc = 0; 96
115 static void msn_callback(gpointer data, gint source, GdkInputCondition condition); 97 static int msn_write(int fd, void *data, int len)
116 static void msn_add_permit(struct gaim_connection *gc, char *who); 98 {
117 static void process_hotmail_msg(struct gaim_connection *gc, gchar *msgdata); 99 debug_printf("C: %s", data);
118 static void msn_des_win(GtkWidget *a, GtkWidget *b); 100 return write(fd, data, len);
119 static void msn_newmail_dialog(const char *text); 101 }
120 static char *msn_normalize(const char *s); 102
121 103 static char *url_encode(const char *msg)
122 static char tochar(char *h) 104 {
123 { 105 static char buf[MSN_BUF_LEN];
124 char tmp; 106 int i, j = 0;
125 char b = 0; 107
126 int v = 0; 108 bzero(buf, sizeof(buf));
127 int i; 109 for (i = 0; i < strlen(msg); i++) {
128 110 if ((msg[i] < 33) || (msg[i] > 126)) {
129 for (i = strlen(h); i > 0; i--) { 111 char tmp[5];
130 tmp = tolower(h[strlen(h) - i]); 112 int k;
131 113 buf[j++] = '%';
132 if (tmp >= '0' && tmp <= '9') 114 g_snprintf(tmp, sizeof(tmp), "%02x", msg[i]);
133 b = tmp - '0'; 115 for (k = 0; tmp[k]; k++)
134 else if (tmp >= 'a' && tmp <= 'f') 116 buf[j++] = tmp[k];
135 b = (tmp - 'a') + 10; 117 } else
136 118 buf[j++] = msg[i];
137 if (i > 1) 119 }
138 v =+ ((i-1) * 16) * b;
139 else
140 v += b;
141 }
142
143 return v;
144 }
145
146 static char *url_encode(unsigned char *text, int dospace)
147 {
148 static char newtext[MSN_BUF_LEN*2];
149 char *temp = (char *)malloc(4);
150 int i = 0;
151 int j = 0;
152
153 bzero(newtext, MSN_BUF_LEN*2);
154
155 for (j = 0; j < strlen(text); j++)
156 {
157 if ((text[j] < 33) || (text[j] > 126) || (text[j] == 32 && dospace==1))
158 {
159 /* Other wise, we should escape this booger */
160 newtext[i++] = '%';
161 sprintf(temp, "%02x", text[j]);
162 newtext[i++] = temp[0];
163 newtext[i++] = temp[1];
164 }
165 else
166 {
167 /* It's ok to store this one, sarge */
168 newtext[i++] = text[j];
169 }
170 }
171
172 newtext[i] = 0;
173
174 free(temp);
175
176 return newtext;
177 }
178
179 static char *url_decode(char *text)
180 {
181 static char newtext[MSN_BUF_LEN];
182 char *buf;
183 int c = 0;
184 int i = 0;
185 int j = 0;
186
187 bzero(newtext, MSN_BUF_LEN);
188
189 for (i = 0; i < strlen(text); i++) {
190 if (text[i] == '%')
191 c++;
192 }
193
194 buf = (char *)malloc(strlen(text) + c + 1);
195
196 for (i = 0, j = 0 ; text[i] != 0; i++) {
197 if (text[i] != '%') {
198 buf[j++] = text[i];
199 } else {
200 char hex[3];
201 hex[0] = text[++i];
202 hex[1] = text[++i];
203 hex[2] = 0;
204
205 buf[j++] = tochar(hex);
206 }
207 }
208
209 buf[j] = 0; 120 buf[j] = 0;
210 121
211 for (i = 0; i < strlen(buf); i++) 122 return buf;
212 newtext[i] = buf[i]; 123 }
213 124
214 free(buf); 125 static char *handle_errcode(char *buf, gboolean show)
215 126 {
216 return newtext; 127 int errcode;
217 } 128 static char msg[MSN_BUF_LEN];
218 129
219 static void msn_accept_add_permit(gpointer w, struct msn_ask_add_permit *ap) 130 buf[4] = 0;
220 { 131 errcode = atoi(buf);
221 msn_add_permit(ap->gc, ap->user); 132
222 /* leak if we don't free these? */ 133 switch (errcode) {
223 g_free(ap->user); 134 case 200:
224 g_free(ap->friendly); 135 g_snprintf(msg, sizeof(msg), "Syntax Error (probably a Gaim bug)");
225 g_free(ap); 136 break;
226 } 137 case 201:
227 138 g_snprintf(msg, sizeof(msg), "Invalid Parameter (probably a Gaim bug)");
228 static void msn_cancel_add_permit(gpointer w, struct msn_ask_add_permit *ap) 139 break;
229 { 140 case 205:
230 g_free(ap->user); 141 g_snprintf(msg, sizeof(msg), "Invalid User");
231 g_free(ap->friendly); 142 break;
232 g_free(ap); 143 case 206:
233 } 144 g_snprintf(msg, sizeof(msg), "Fully Qualified Domain Name missing");
234 145 break;
235 static void free_msn_conn(struct msn_conn *mc) 146 case 207:
236 { 147 g_snprintf(msg, sizeof(msg), "Already Login");
237 if (mc->user) 148 break;
238 free(mc->user); 149 case 208:
239 150 g_snprintf(msg, sizeof(msg), "Invalid Username");
240 if (mc->secret) 151 break;
241 free(mc->secret); 152 case 209:
242 153 g_snprintf(msg, sizeof(msg), "Invalid Friendly Name");
243 if (mc->session) 154 break;
244 free(mc->session); 155 case 210:
245 156 g_snprintf(msg, sizeof(msg), "List Full");
246 if (mc->txqueue) 157 break;
247 free(mc->txqueue); 158 case 215:
248 159 g_snprintf(msg, sizeof(msg), "Already there");
249 gdk_input_remove(mc->inpa); 160 break;
250 close(mc->fd); 161 case 216:
251 162 g_snprintf(msg, sizeof(msg), "Not on list");
252 msn_connections = g_slist_remove(msn_connections, mc); 163 break;
253 164 case 218:
254 g_free(mc); 165 g_snprintf(msg, sizeof(msg), "Already in the mode");
255 } 166 break;
256 167 case 219:
257 168 g_snprintf(msg, sizeof(msg), "Already in opposite list");
258 static struct msn_conn *find_msn_conn_by_user(gchar * user) 169 break;
259 { 170 case 280:
260 struct msn_conn *mc; 171 g_snprintf(msg, sizeof(msg), "Switchboard failed");
261 GSList *conns = msn_connections; 172 break;
262 173 case 281:
263 while (conns) { 174 g_snprintf(msg, sizeof(msg), "Notify Transfer failed");
264 mc = (struct msn_conn *)conns->data; 175 break;
265 176
266 if (mc != NULL) { 177 case 300:
267 if (strcasecmp(mc->user, user) == 0) { 178 g_snprintf(msg, sizeof(msg), "Required fields missing");
268 return mc; 179 break;
269 } 180 case 302:
270 } 181 g_snprintf(msg, sizeof(msg), "Not logged in");
271 182 break;
272 conns = g_slist_next(conns); 183
184 case 500:
185 g_snprintf(msg, sizeof(msg), "Internal server error");
186 break;
187 case 501:
188 g_snprintf(msg, sizeof(msg), "Database server error");
189 break;
190 case 510:
191 g_snprintf(msg, sizeof(msg), "File operation error");
192 break;
193 case 520:
194 g_snprintf(msg, sizeof(msg), "Memory allocation error");
195 break;
196
197 case 600:
198 g_snprintf(msg, sizeof(msg), "Server busy");
199 break;
200 case 601:
201 g_snprintf(msg, sizeof(msg), "Server unavailable");
202 break;
203 case 602:
204 g_snprintf(msg, sizeof(msg), "Peer Notification server down");
205 break;
206 case 603:
207 g_snprintf(msg, sizeof(msg), "Database connect error");
208 break;
209 case 604:
210 g_snprintf(msg, sizeof(msg), "Server is going down (abandon ship)");
211 break;
212
213 case 707:
214 g_snprintf(msg, sizeof(msg), "Error creating connection");
215 break;
216 case 711:
217 g_snprintf(msg, sizeof(msg), "Unable to write");
218 break;
219 case 712:
220 g_snprintf(msg, sizeof(msg), "Session overload");
221 break;
222 case 713:
223 g_snprintf(msg, sizeof(msg), "User is too active");
224 break;
225 case 714:
226 g_snprintf(msg, sizeof(msg), "Too many sessions");
227 break;
228 case 715:
229 g_snprintf(msg, sizeof(msg), "Not expected");
230 break;
231 case 717:
232 g_snprintf(msg, sizeof(msg), "Bad friend file");
233 break;
234
235 case 911:
236 g_snprintf(msg, sizeof(msg), "Authentication failed");
237 break;
238 case 913:
239 g_snprintf(msg, sizeof(msg), "Not allowed when offline");
240 break;
241 case 920:
242 g_snprintf(msg, sizeof(msg), "Not accepting new users");
243 break;
244
245 default:
246 g_snprintf(msg, sizeof(msg), "Unknown Error Code");
247 break;
248 }
249
250 if (show)
251 do_error_dialog(msg, "MSN Error");
252
253 return msg;
254 }
255
256 static void handle_hotmail(struct gaim_connection *gc, char *data)
257 {
258 char *mailct, *mailp, *from = NULL, *subj = NULL, notice[MSN_BUF_LEN];
259
260 if (gc->user->proto_opt[USEROPT_HOTMAIL][0] != '1') return;
261 mailct = strstr(data, "Content-Type: ");
262 mailp = strstr(mailct, ";");
263 if (mailct && mailp && (mailp > mailct) &&
264 !strncmp(mailct, "Content-Type: text/x-msmsgsemailnotification", mailp - mailct - 1)) {
265 from = strstr(mailp, "From: ");
266 subj = strstr(mailp, "Subject: ");
267 }
268
269 if (!from || !subj)
270 return;
271
272 from += strlen("From: ");
273 mailp = strstr(from, "\r\n");
274 if (!mailp) return;
275 *mailp = 0;
276
277 subj += strlen("Subject: ");
278 mailp = strstr(from, "\r\n");
279 if (!mailp) return;
280 *mailp = 0;
281
282 g_snprintf(notice, sizeof(notice), "Mail from %s, re: %s", from, subj);
283 do_error_dialog(notice, "New MSN Mail");
284 }
285
286 static struct msn_switchboard *msn_find_switch(struct gaim_connection *gc, char *id)
287 {
288 struct msn_data *md = gc->proto_data;
289 GSList *m = md->switches;
290
291 while (m) {
292 struct msn_switchboard *ms = m->data;
293 m = m->next;
294 if (ms->total == 1 && !g_strcasecmp(ms->user, id))
295 return ms;
273 } 296 }
274 297
275 return NULL; 298 return NULL;
276 } 299 }
277 300
278 static struct msn_conn *find_msn_conn_by_trid(time_t trid) 301 static void msn_kill_switch(struct msn_switchboard *ms)
279 { 302 {
280 struct msn_conn *mc; 303 struct gaim_connection *gc = ms->gc;
281 GSList *conns = msn_connections; 304 struct msn_data *md = gc->proto_data;
282 305
283 while (conns) { 306 gdk_input_remove(ms->inpa);
284 mc = (struct msn_conn *)conns->data; 307 close(ms->fd);
285 308 if (ms->sessid)
286 if (mc != NULL) { 309 g_free(ms->sessid);
287 310 g_free(ms->auth);
288 debug_printf("Comparing: %d <==> %d\n", mc->last_trid, trid); 311 if (ms->user)
289 if (mc->last_trid == trid) { 312 g_free(ms->user);
290 return mc; 313 if (ms->txqueue)
291 } 314 ms->txqueue = NULL;
292 } 315
293 316 md->switches = g_slist_remove(md->switches, ms);
294 conns = g_slist_next(conns); 317
295 } 318 g_free(ms);
296 319 }
297 return NULL; 320
298 } 321 static void msn_switchboard_callback(gpointer data, gint source, GdkInputCondition cond)
299 322 {
300 static char *msn_name() 323 struct msn_switchboard *ms = data;
301 { 324 struct gaim_connection *gc = ms->gc;
302 return "MSN"; 325 struct msn_data *md = gc->proto_data;
303 }
304
305 char *name()
306 {
307 return "MSN";
308 }
309
310 char *description()
311 {
312 return "Allows gaim to use the MSN protocol. For some reason, this frightens me.";
313 }
314
315 static time_t trId(struct msn_data *md)
316 {
317 md->last_trid = time((time_t *)NULL) + globalc++;
318 return md->last_trid;
319 }
320
321 static void msn_write(int fd, char *buf)
322 {
323 write(fd, buf, strlen(buf));
324 debug_printf("MSN(%d) <== %s", fd, buf);
325 }
326
327 static void msn_add_request(struct gaim_connection *gc, char *buf)
328 {
329 char **res;
330
331 res = g_strsplit(buf, " ", 0);
332
333 if (!strcasecmp(res[2], "RL")) {
334 struct msn_ask_add_permit *ap = g_new0(struct msn_ask_add_permit, 1);
335
336 snprintf(buf, MSN_BUF_LEN, "The user %s (%s) wants to add you to their buddylist.", res[4], url_decode(res[5]));
337
338 ap->user = g_strdup(res[4]);
339
340 ap->friendly = g_strdup(url_decode(res[5]));
341 ap->gc = gc;
342
343 do_ask_dialog(buf, ap, (GtkFunction) msn_accept_add_permit, (GtkFunction) msn_cancel_add_permit);
344 }
345
346 g_strfreev(res);
347 }
348
349 static void msn_answer_callback(gpointer data, gint source, GdkInputCondition condition)
350 {
351 struct msn_conn *mc = data;
352 char buf[MSN_BUF_LEN];
353
354 if (source == -1) {
355 g_free(mc->session);
356 g_free(mc->secret);
357 g_free(mc->user);
358 g_free(mc);
359 return;
360 }
361
362 if (mc->fd != source)
363 mc->fd = source;
364
365 g_snprintf(buf, MSN_BUF_LEN, "ANS 1 %s %s %s\n",mc->gc->username, mc->secret, mc->session);
366 msn_write(mc->fd, buf);
367
368 mc->inpa = gdk_input_add(mc->fd, GDK_INPUT_READ, msn_callback, mc->gc);
369
370 /* Append our connection */
371 msn_connections = g_slist_append(msn_connections, mc);
372 }
373
374 static void msn_invite_callback(gpointer data, gint source, GdkInputCondition condition)
375 {
376 struct msn_conn *mc = data;
377 struct msn_data *md = (struct msn_data *)mc->gc->proto_data;
378 char buf[MSN_BUF_LEN]; 326 char buf[MSN_BUF_LEN];
379 int i = 0; 327 int i = 0;
328
329 bzero(buf, sizeof(buf));
330 while ((read(ms->fd, buf + i, 1) > 0) && (buf[i++] != '\n'))
331 if (i == sizeof(buf))
332 i--; /* yes i know this loses data but we shouldn't get messages this long
333 and it's better than possibly writing past our buffer */
334 if (i == 0 || buf[i - 1] != '\n') {
335 msn_kill_switch(ms);
336 return;
337 }
338 debug_printf("S: %s", buf);
339 g_strchomp(buf);
340
341 if (!g_strncasecmp(buf, "ACK", 3)) {
342 } else if (!g_strncasecmp(buf, "ANS", 3)) {
343 } else if (!g_strncasecmp(buf, "BYE", 3)) {
344 msn_kill_switch(ms);
345 } else if (!g_strncasecmp(buf, "CAL", 3)) {
346 } else if (!g_strncasecmp(buf, "IRO", 3)) {
347 } else if (!g_strncasecmp(buf, "JOI", 3)) {
348 if (ms->txqueue) {
349 g_snprintf(buf, sizeof(buf), "MSG %d N %d\r\n%s%s", ++ms->trId,
350 strlen(MIME_HEADER) + strlen(url_encode(ms->txqueue)),
351 MIME_HEADER, url_encode(ms->txqueue));
352 g_free(ms->txqueue);
353 ms->txqueue = NULL;
354 if (msn_write(ms->fd, buf, strlen(buf)) < 0)
355 msn_kill_switch(ms);
356 }
357 } else if (!g_strncasecmp(buf, "MSG", 3)) {
358 char *user, *tmp = buf;
359 int length;
360 char *msg, *skiphead, *utf, *final;
361 int len;
362
363 GET_NEXT(tmp);
364 user = tmp;
365
366 GET_NEXT(tmp);
367
368 GET_NEXT(tmp);
369 length = atoi(tmp);
370
371 msg = g_new0(char, MAX(length + 1, MSN_BUF_LEN));
372
373 if (read(ms->fd, msg, length) != length) {
374 g_free(msg);
375 hide_login_progress(gc, "Unable to read message");
376 signoff(gc);
377 return;
380 378
381 bzero(buf, MSN_BUF_LEN); 379 }
382 do { 380
383 if (read(source, buf + i, 1) != 1) { 381 skiphead = strstr(msg, "\r\n\r\n");
384 free_msn_conn(mc); 382 if (!skiphead || !skiphead[4]) {
383 g_free(msg);
385 return; 384 return;
386 } 385 }
387 } while (buf[i++] != '\n'); 386 skiphead += 4;
388 387 utf = utf8_to_str(skiphead);
389 g_strchomp(buf); 388 len = MAX(strlen(utf) + 1, BUF_LEN);
390 389 final = g_malloc(len);
391 debug_printf("MSN(%d) ==> %s\n", source, buf); 390 g_snprintf(final, len, "%s", utf);
392 391 g_free(utf);
393 if (!strncmp("USR ", buf, 4)) { 392
394 char **res; 393 serv_got_im(gc, user, final, 0, time(NULL));
395 394
396 res = g_strsplit(buf, " ", 0); 395 g_free(final);
397 debug_printf("%s\n",res[2]); 396 g_free(msg);
398 if (strcasecmp("OK", res[2])) { 397 } else if (!g_strncasecmp(buf, "NAK", 3)) {
399 g_strfreev(res); 398 do_error_dialog("A message may not have been received.", "MSN Error");
400 close(mc->fd); 399 } else if (!g_strncasecmp(buf, "NLN", 3)) {
400 } else if (!g_strncasecmp(buf, "OUT", 3)) {
401 } else if (!g_strncasecmp(buf, "USR", 3)) {
402 /* good, we got USR, now we need to find out who we want to talk to */
403 struct msn_xfr *mx;
404
405 if (!md->xfrs)
401 return; 406 return;
402 } 407 mx = md->xfrs->data;
403 408 md->xfrs = g_slist_remove(md->xfrs, mx);
404 /* We've authorized. Let's send an invite request */ 409
405 g_snprintf(buf, MSN_BUF_LEN, "CAL %ld %s\n", trId(md), mc->user); 410 g_snprintf(buf, sizeof(buf), "CAL %d %s\n", ++ms->trId, mx->user);
406 msn_write(source, buf); 411 ms->txqueue = mx->what;
407 return; 412 g_free(mx->user);
408 } 413 g_free(mx);
409 414 if (msn_write(ms->fd, buf, strlen(buf)) < 0)
410 else if (!strncmp("JOI ", buf, 4)) { 415 msn_kill_switch(ms);
411 /* Looks like they just joined! Write their queued message */ 416 } else if (isdigit(*buf)) {
412 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); 417 handle_errcode(buf, TRUE);
413 418 } else {
414 msn_write(source, buf); 419 debug_printf("Unhandled message!\n");
415 420 }
416 gdk_input_remove(mc->inpa); 421 }
417 mc->inpa = gdk_input_add(mc->fd, GDK_INPUT_READ, msn_callback, mc->gc); 422
418 423 static void msn_rng_connect(gpointer data, gint source, GdkInputCondition cond)
419 return; 424 {
420 425 struct msn_switchboard *ms = data;
421 } 426 struct gaim_connection *gc = ms->gc;
422 } 427 struct msn_data *md;
423
424 static void msn_xfr_callback(gpointer data, gint source, GdkInputCondition condition)
425 {
426 struct msn_conn *mc = data;
427 char buf[MSN_BUF_LEN]; 428 char buf[MSN_BUF_LEN];
428 429
429 if (source == -1) 430 if (source == -1 || !g_slist_find(connections, gc)) {
430 return; 431 g_free(ms->sessid);
431 432 g_free(ms->auth);
432 if (mc->fd != source) 433 g_free(ms);
433 mc->fd = source; 434 return;
434 435 }
435 mc->inpa = gdk_input_add(mc->fd, GDK_INPUT_READ, msn_invite_callback, mc); 436
436 g_snprintf(buf, MSN_BUF_LEN, "USR %ld %s %s\n", mc->last_trid, mc->gc->username, mc->secret); 437 md = gc->proto_data;
437 msn_write(mc->fd, buf); 438
438 } 439 if (md->fd != source)
439 440 md->fd = source;
440 static void msn_callback(gpointer data, gint source, GdkInputCondition condition) 441
442 g_snprintf(buf, sizeof(buf), "ANS %d %s %s %s\n", ++ms->trId, gc->username, ms->auth, ms->sessid);
443 if (msn_write(ms->fd, buf, strlen(buf)) < 0) {
444 close(ms->fd);
445 g_free(ms->sessid);
446 g_free(ms->auth);
447 g_free(ms);
448 return;
449 }
450
451 md->switches = g_slist_append(md->switches, ms);
452 ms->inpa = gdk_input_add(ms->fd, GDK_INPUT_READ, msn_switchboard_callback, ms);
453 }
454
455 static void msn_ss_xfr_connect(gpointer data, gint source, GdkInputCondition cond)
456 {
457 struct msn_switchboard *ms = data;
458 struct gaim_connection *gc = ms->gc;
459 struct msn_data *md;
460 char buf[MSN_BUF_LEN];
461
462 if (source == -1 || !g_slist_find(connections, gc)) {
463 g_free(ms->auth);
464 g_free(ms);
465 return;
466 }
467
468 if (ms->fd != source)
469 ms->fd = source;
470
471 md = gc->proto_data;
472
473 g_snprintf(buf, sizeof(buf), "USR %d %s %s\n", ++ms->trId, gc->username, ms->auth);
474 if (msn_write(ms->fd, buf, strlen(buf)) < 0) {
475 g_free(ms->auth);
476 g_free(ms);
477 return;
478 }
479
480 md->switches = g_slist_append(md->switches, ms);
481 ms->inpa = gdk_input_add(ms->fd, GDK_INPUT_READ, msn_switchboard_callback, ms);
482 }
483
484 static void msn_callback(gpointer data, gint source, GdkInputCondition cond)
441 { 485 {
442 struct gaim_connection *gc = data; 486 struct gaim_connection *gc = data;
443 struct msn_data *md = (struct msn_data *)gc->proto_data; 487 struct msn_data *md = gc->proto_data;
444 char buf[MSN_BUF_LEN]; 488 char buf[MSN_BUF_LEN];
445 int i = 0; 489 int i = 0;
446 int num; 490
447 491 bzero(buf, sizeof(buf));
448 bzero(buf, MSN_BUF_LEN); 492 while ((read(md->fd, buf + i, 1) > 0) && (buf[i++] != '\n'))
449 493 if (i == sizeof(buf))
450 do { 494 i--; /* yes i know this loses data but we shouldn't get messages this long
451 if (read(source, buf + i, 1) != 1) { 495 and it's better than possibly writing past our buffer */
452 if (md->fd == source) { 496 if (i == 0 || buf[i - 1] != '\n') {
453 hide_login_progress(gc, "Read error"); 497 hide_login_progress(gc, "Error reading from server");
498 signoff(gc);
499 return;
500 }
501 debug_printf("S: %s", buf);
502 g_strchomp(buf);
503
504 if (!g_strncasecmp(buf, "ADD", 3)) {
505 } else if (!g_strncasecmp(buf, "BLP", 3)) {
506 } else if (!g_strncasecmp(buf, "BPR", 3)) {
507 } else if (!g_strncasecmp(buf, "CHG", 3)) {
508 } else if (!g_strncasecmp(buf, "FLN", 3)) {
509 char *usr = buf;
510
511 GET_NEXT(usr);
512 serv_got_update(gc, usr, 0, 0, 0, 0, 0, 0);
513 } else if (!g_strncasecmp(buf, "GTC", 3)) {
514 } else if (!g_strncasecmp(buf, "INF", 3)) {
515 } else if (!g_strncasecmp(buf, "ILN", 3)) {
516 char *state, *user, *tmp = buf;
517 int status = UC_NORMAL;
518
519 GET_NEXT(tmp);
520
521 GET_NEXT(tmp);
522 state = tmp;
523
524 GET_NEXT(tmp);
525 user = tmp;
526
527 GET_NEXT(tmp);
528
529 if (!g_strcasecmp(state, "BSY")) {
530 status |= (MSN_BUSY << 5);
531 } else if (!g_strcasecmp(state, "IDL")) {
532 status |= (MSN_IDLE << 5);
533 } else if (!g_strcasecmp(state, "BRB")) {
534 status |= (MSN_BRB << 5);
535 } else if (!g_strcasecmp(state, "AWY")) {
536 status = UC_UNAVAILABLE;
537 } else if (!g_strcasecmp(state, "PHN")) {
538 status |= (MSN_PHONE << 5);
539 } else if (!g_strcasecmp(state, "LUN")) {
540 status |= (MSN_LUNCH << 5);
541 }
542
543 serv_got_update(gc, user, 1, 0, 0, 0, status, 0);
544 } else if (!g_strncasecmp(buf, "LST", 3)) {
545 char *which, *who, *tmp = buf;
546
547 GET_NEXT(tmp);
548 GET_NEXT(tmp);
549 which = tmp;
550
551 GET_NEXT(tmp);
552 GET_NEXT(tmp);
553 GET_NEXT(tmp);
554 GET_NEXT(tmp);
555 who = tmp;
556
557 GET_NEXT(tmp);
558
559 if (!g_strcasecmp(which, "FL"))
560 md->fl = g_slist_append(md->fl, g_strdup(who));
561 else if (!md->imported && bud_list_cache_exists(gc)) {
562 do_import(NULL, gc);
563 md->imported = TRUE;
564 }
565 } else if (!g_strncasecmp(buf, "MSG", 3)) {
566 char *user, *tmp = buf;
567 int length;
568 char *msg, *skiphead, *utf, *final;
569 int len;
570
571 GET_NEXT(tmp);
572 user = tmp;
573
574 GET_NEXT(tmp);
575
576 GET_NEXT(tmp);
577 length = atoi(tmp);
578
579 msg = g_new0(char, MAX(length + 1, MSN_BUF_LEN));
580
581 if (read(md->fd, msg, length) != length) {
582 g_free(msg);
583 hide_login_progress(gc, "Unable to read message");
584 signoff(gc);
585 return;
586 }
587
588 if (!g_strcasecmp(user, "hotmail")) {
589 handle_hotmail(gc, msg);
590 g_free(msg);
591 return;
592 }
593
594 skiphead = strstr(msg, "\r\n\r\n");
595 if (!skiphead || !skiphead[4]) {
596 g_free(msg);
597 return;
598 }
599 skiphead += 4;
600 utf = utf8_to_str(skiphead);
601 len = MAX(strlen(utf) + 1, BUF_LEN);
602 final = g_malloc(len);
603 g_snprintf(final, len, "%s", utf);
604 g_free(utf);
605
606 serv_got_im(gc, user, final, 0, time(NULL));
607
608 g_free(final);
609 g_free(msg);
610 } else if (!g_strncasecmp(buf, "NLN", 3)) {
611 char *state, *user, *tmp = buf;
612 int status = UC_NORMAL;
613
614 GET_NEXT(tmp);
615 state = tmp;
616
617 GET_NEXT(tmp);
618 user = tmp;
619
620 GET_NEXT(tmp);
621
622 if (!g_strcasecmp(state, "BSY")) {
623 status |= (MSN_BUSY << 5);
624 } else if (!g_strcasecmp(state, "IDL")) {
625 status |= (MSN_IDLE << 5);
626 } else if (!g_strcasecmp(state, "BRB")) {
627 status |= (MSN_BRB << 5);
628 } else if (!g_strcasecmp(state, "AWY")) {
629 status = UC_UNAVAILABLE;
630 } else if (!g_strcasecmp(state, "PHN")) {
631 status |= (MSN_PHONE << 5);
632 } else if (!g_strcasecmp(state, "LUN")) {
633 status |= (MSN_LUNCH << 5);
634 }
635
636 serv_got_update(gc, user, 1, 0, 0, 0, status, 0);
637 } else if (!g_strncasecmp(buf, "OUT", 3)) {
638 } else if (!g_strncasecmp(buf, "PRP", 3)) {
639 } else if (!g_strncasecmp(buf, "REM", 3)) {
640 } else if (!g_strncasecmp(buf, "RNG", 3)) {
641 struct msn_switchboard *ms;
642 char *sessid, *ssaddr, *auth;
643 int port, i = 0;
644 char *tmp = buf;
645
646 GET_NEXT(tmp);
647 sessid = tmp;
648
649 GET_NEXT(tmp);
650 ssaddr = tmp;
651
652 GET_NEXT(tmp);
653
654 GET_NEXT(tmp);
655 auth = tmp;
656
657 GET_NEXT(tmp);
658
659 while (ssaddr[i] && ssaddr[i] != ':') i++;
660 if (ssaddr[i] == ':') {
661 char *x = &ssaddr[i + 1];
662 ssaddr[i] = 0;
663 port = atoi(x);
664 } else
665 port = 1863;
666
667 ms = g_new0(struct msn_switchboard, 1);
668 ms->sessid = g_strdup(sessid);
669 ms->auth = g_strdup(auth);
670 ms->gc = gc;
671 ms->fd = proxy_connect(ssaddr, port, msn_rng_connect, ms);
672 } else if (!g_strncasecmp(buf, "SYN", 3)) {
673 } else if (!g_strncasecmp(buf, "USR", 3)) {
674 } else if (!g_strncasecmp(buf, "XFR", 3)) {
675 char *host = strstr(buf, "SB");
676 int port;
677 int i = 0;
678 gboolean switchboard = TRUE;
679 char *tmp;
680
681 if (!host) {
682 host = strstr(buf, "NS");
683 if (!host) {
684 hide_login_progress(gc, "Got invalid XFR\n");
454 signoff(gc); 685 signoff(gc);
455 return; 686 return;
456 } 687 }
457 688 switchboard = FALSE;
458 close(source); 689 }
459 690
460 return; 691 GET_NEXT(host);
461 } 692 while (host[i] && host[i] != ':') i++;
462 693 if (host[i] == ':') {
463 } while (buf[i++] != '\n'); 694 tmp = &host[i + 1];
464 695 host[i] = 0;
465 g_strchomp(buf); 696 while (isdigit(*tmp)) tmp++;
466 697 *tmp++ = 0;
467 debug_printf("MSN(%d) ==> %s\n", source, buf); 698 port = atoi(&host[i + 1]);
468 699 } else {
469 if (!strncmp("NLN ", buf, 4) || !strncmp("ILN ", buf, 4)) { 700 port = 1863;
470 int status; 701 tmp = host;
471 int query; 702 GET_NEXT(tmp);
472 char **res; 703 }
473 704
474 res = g_strsplit(buf, " ", 0); 705 if (switchboard) {
475 706 struct msn_switchboard *ms = g_new0(struct msn_switchboard, 1);
476 if (!strcmp(res[0], "NLN")) 707
477 query = 1; 708 GET_NEXT(tmp);
478 else 709
479 query = 2; 710 ms->gc = gc;
480 711 ms->auth = g_strdup(tmp);
481 if (!strcasecmp(res[query], "NLN")) 712 ms->fd = proxy_connect(host, port, msn_ss_xfr_connect, ms);
482 status = UC_NORMAL; 713 } else {
483 else if (!strcasecmp(res[query], "BSY")) 714 close(md->fd);
484 status = UC_NORMAL | (MSN_BUSY << 5); 715 gdk_input_remove(md->inpa);
485 else if (!strcasecmp(res[query], "IDL")) 716 md->inpa = 0;
486 status = UC_NORMAL | (MSN_IDLE << 5); 717 md->fd = 0;
487 else if (!strcasecmp(res[query], "BRB")) 718 md->fd = proxy_connect(host, port, msn_login_xfr_connect, gc);
488 status = UC_NORMAL | (MSN_BRB << 5); 719 }
489 else if (!strcasecmp(res[query], "AWY")) 720 } else if (isdigit(*buf)) {
490 status = UC_UNAVAILABLE; 721 handle_errcode(buf, TRUE);
491 else if (!strcasecmp(res[query], "PHN")) 722 } else {
492 status = UC_NORMAL | (MSN_PHONE << 5); 723 debug_printf("Unhandled message!\n");
493 else if (!strcasecmp(res[query], "LUN")) 724 }
494 status = UC_NORMAL | (MSN_LUNCH << 5); 725 }
495 else 726
496 status = UC_NORMAL; 727 static void msn_login_xfr_connect(gpointer data, gint source, GdkInputCondition cond)
497
498 serv_got_update(gc, res[query+1], 1, 0, 0, 0, status, 0);
499
500 g_strfreev(res);
501
502 return;
503
504 } else if (!strncmp("REA ", buf, 4)) {
505 char **res;
506
507 res = g_strsplit(buf, " ", 0);
508
509 /* Kill the old one */
510 g_free(md->friendly);
511
512 /* Set the new one */
513 md->friendly = g_strdup(res[4]);
514
515 /* And free up some memory. That's all, folks. */
516 g_strfreev(res);
517 } else if (!strncmp("BYE ", buf, 4)) {
518 char **res;
519 struct msn_conn *mc;
520
521 res = g_strsplit(buf, " ", 0);
522
523 mc = find_msn_conn_by_user(res[1]);
524
525 if (mc) {
526 /* Looks like we need to close up some stuff :-) */
527 free_msn_conn(mc);
528 }
529
530 g_strfreev(res);
531 return;
532 } else if (!strncmp("MSG ", buf, 4)) {
533 /* We are receiving an incoming message */
534 gchar **res;
535 gchar *user;
536 gchar *msgdata;
537 int size;
538 char rahc[MSN_BUF_LEN * 2];
539
540 res = g_strsplit(buf, " ", 0);
541
542 user = g_strdup(res[1]);
543 size = atoi(res[3]);
544
545 /* Ok, we know who we're receiving a message from as well as
546 * how big the message is */
547
548 msgdata = (gchar *)g_malloc(sizeof(gchar) *(size + 1));
549 num = recv(source, msgdata, size, 0);
550 msgdata[size] = 0;
551
552 if (num < size)
553 debug_printf("MSN: Uhh .. we gots a problem!. Expected %d but got %d.\n", size, num);
554
555 /* We should ignore messages from the user Hotmail */
556 if (!strcasecmp("hotmail", res[1])) {
557 process_hotmail_msg(gc,msgdata);
558 g_strfreev(res);
559 g_free(msgdata);
560 return;
561 }
562
563 /* Check to see if any body is in the message */
564 if (!strcmp(strstr(msgdata, "\r\n\r\n") + 4, "\r\n")) {
565 g_strfreev(res);
566 g_free(msgdata);
567 return;
568 }
569
570 /* Otherwise, everything is ok. Let's show the message. Skipping,
571 * of course, the header. */
572
573 g_snprintf(rahc, sizeof(rahc), "%s", strstr(msgdata, "\r\n\r\n") + 4);
574 serv_got_im(gc, res[1], rahc, 0, time((time_t)NULL));
575
576 g_strfreev(res);
577 g_free(msgdata);
578
579 return;
580 } else if (!strncmp("RNG ", buf, 4)) {
581 /* Ok, someone wants to talk to us. Ring ring? Hi!!! */
582 gchar **address;
583 gchar **res;
584 struct msn_conn *mc = g_new0(struct msn_conn, 1);
585 struct aim_user *user = gc->user;
586 mc->gc = gc;
587
588 res = g_strsplit(buf, " ", 0);
589 address = g_strsplit(res[2], ":", 0);
590
591 /* Set up our struct with user and input watcher */
592 mc->user = g_strdup(res[5]);
593 mc->secret = g_strdup(res[4]);
594 mc->session = g_strdup(res[1]);
595
596 mc->fd = proxy_connect(address[0], atoi(address[1]), msn_answer_callback, mc);
597 g_strfreev(address);
598 g_strfreev(res);
599 if (!user->gc || (mc->fd < 0)) {
600 /* Looks like we had an error connecting. */
601 g_free(mc->session);
602 g_free(mc->secret);
603 g_free(mc->user);
604 g_free(mc);
605 return;
606 }
607 return;
608 } else if (!strncmp("XFR ", buf, 4)) {
609 char **res;
610 struct msn_conn *mc;
611
612 res = g_strsplit(buf, " ", 0);
613
614 debug_printf("Last trid is: %d\n", md->last_trid);
615 debug_printf("This TrId is: %d\n", atoi(res[1]));
616
617 mc = find_msn_conn_by_trid(atoi(res[1]));
618
619 if (!mc) {
620 g_strfreev(res);
621 return;
622 }
623
624 strcpy(buf, res[3]);
625
626 mc->secret = g_strdup(res[5]);
627 mc->session = g_strdup(res[1]);
628
629 g_strfreev(res);
630
631 res = g_strsplit(buf, ":", 0);
632
633 /* Now we have the host and port */
634 debug_printf("Connecting to: %s:%s\n", res[0], res[1]);
635
636 if (mc->inpa)
637 gdk_input_remove(mc->inpa);
638
639 mc->fd = proxy_connect(res[0], atoi(res[1]), msn_xfr_callback, mc);
640 g_strfreev(res);
641
642 return;
643 } else if (!strncmp("LST ", buf, 4)) {
644 char **res;
645
646 res = g_strsplit(buf, " ", 0);
647
648 /* If we have zero buddies, abort */
649 if (atoi(res[5]) == 0) {
650 g_strfreev(res);
651 return;
652 }
653
654 /* First, let's check the list type */
655 if (!strcmp("FL", res[2])) {
656 /* We're dealing with a forward list. Add them
657 * to our buddylist and continue along our
658 * merry little way */
659
660 struct buddy *b;
661
662 b = find_buddy(gc, res[6]);
663
664 if (!b)
665 add_buddy(gc, "Buddies", res[6], res[7]);
666 }
667
668 g_strfreev(res);
669
670 return;
671 } else if (!strncmp("FLN ", buf, 4)) {
672 /* Someone signed off */
673 char **res;
674
675 res = g_strsplit(buf, " ", 0);
676
677 serv_got_update(gc, res[1], 0, 0, 0, 0, 0, 0);
678
679 g_strfreev(res);
680
681 return;
682 } else if (!strncmp("ADD ", buf, 4)) {
683 msn_add_request(gc,buf);
684 return;
685 } if ( (!strncmp("NLN ", buf, 4)) || (!strncmp("ILN ", buf, 4))) {
686 int status;
687 int query;
688 char **res;
689
690 res = g_strsplit(buf, " ", 0);
691
692 if (strcasecmp(res[0], "NLN") == 0)
693 query = 1;
694 else
695 query = 2;
696
697 if (!strcasecmp(res[query], "NLN"))
698 status = UC_NORMAL;
699 else if (!strcasecmp(res[query], "BSY"))
700 status = UC_NORMAL | (MSN_BUSY << 5);
701 else if (!strcasecmp(res[query], "IDL"))
702 status = UC_NORMAL | (MSN_IDLE << 5);
703 else if (!strcasecmp(res[query], "BRB"))
704 status = UC_NORMAL | (MSN_BRB << 5);
705 else if (!strcasecmp(res[query], "AWY"))
706 status = UC_UNAVAILABLE;
707 else if (!strcasecmp(res[query], "PHN"))
708 status = UC_NORMAL | (MSN_PHONE << 5);
709 else if (!strcasecmp(res[query], "LUN"))
710 status = UC_NORMAL | (MSN_LUNCH << 5);
711 else
712 status = UC_NORMAL;
713
714 serv_got_update(gc, res[query+1], 1, 0, 0, 0, status, 0);
715
716 g_strfreev(res);
717 return;
718 }
719
720 }
721
722 static void msn_login_callback(gpointer data, gint source, GdkInputCondition condition)
723 { 728 {
724 struct gaim_connection *gc = data; 729 struct gaim_connection *gc = data;
725 struct msn_data *md = (struct msn_data *)gc->proto_data; 730 struct msn_data *md;
731 char buf[MSN_BUF_LEN];
732
733 if (!g_slist_find(connections, gc))
734 return;
735
736 md = gc->proto_data;
737
738 if (md->fd != source)
739 md->fd = source;
740
741 if (md->fd == -1) {
742 hide_login_progress(gc, "Unable to connect to Notification Server");
743 signoff(gc);
744 return;
745 }
746
747 g_snprintf(buf, sizeof(buf), "USR %d MD5 I %s\n", ++md->trId, gc->username);
748 if (msn_write(md->fd, buf, strlen(buf)) < 0) {
749 hide_login_progress(gc, "Unable to talk to Notification Server");
750 signoff(gc);
751 return;
752 }
753
754 md->inpa = gdk_input_add(md->fd, GDK_INPUT_READ, msn_login_callback, gc);
755 }
756
757 static void msn_login_callback(gpointer data, gint source, GdkInputCondition cond)
758 {
759 struct gaim_connection *gc = data;
760 struct msn_data *md = gc->proto_data;
726 char buf[MSN_BUF_LEN]; 761 char buf[MSN_BUF_LEN];
727 int i = 0; 762 int i = 0;
728 763
729 if (source == -1) { 764 bzero(buf, sizeof(buf));
765 while ((read(md->fd, buf + i, 1) > 0) && (buf[i++] != '\n'))
766 if (i == sizeof(buf))
767 i--; /* yes i know this loses data but we shouldn't get messages this long
768 and it's better than possibly writing past our buffer */
769 if (i == 0 || buf[i - 1] != '\n') {
770 hide_login_progress(gc, "Error reading from server");
730 signoff(gc); 771 signoff(gc);
731 return; 772 return;
732 } 773 }
733 774 debug_printf("S: %s", buf);
734 if (md->fd != source) { 775 g_strchomp(buf);
735 debug_printf("Eric, you fucked up.\n"); 776
736 md->fd = source; 777 if (!g_strncasecmp(buf, "VER", 3)) {
737 } 778 /* we got VER, check to see that MSNP2 is in the list, then send INF */
738 779 if (!strstr(buf, "MSNP2")) {
739 if (!gc->inpa) { 780 hide_login_progress(gc, "Protocol not supported");
740 if (md->inpa > 0)
741 gdk_input_remove(md->inpa);
742 md->inpa = 0;
743
744 gc->inpa = gdk_input_add(md->fd, GDK_INPUT_READ, msn_login_callback, gc);
745
746 if (md->status & MSN_SIGNON_GOT_XFR) {
747 /* Looks like we were transfered here. Just send a sign on */
748 set_login_progress(gc, 3, "Signing On");
749 g_snprintf(buf, MSN_BUF_LEN, "USR %ld %s I %s\n", md->last_trid, md->policy, gc->username);
750 msn_write(md->fd, buf);
751
752 /* Reset this bit */
753 md->status ^= MSN_SIGNON_GOT_XFR;
754 } else {
755 /* Otherwise, send an initial request */
756 set_login_progress(gc, 2, "Verifying");
757
758 g_snprintf(md->protocol, 6, "MSNP2");
759
760 g_snprintf(buf, MSN_BUF_LEN, "VER %ld %s\n", trId(md), md->protocol);
761 msn_write(md->fd, buf);
762 }
763
764 return;
765 }
766
767 bzero(buf, MSN_BUF_LEN);
768
769 do {
770 if (read(source, buf + i, 1) != 1) {
771 hide_login_progress(gc, "Read error");
772 signoff(gc); 781 signoff(gc);
773 return; 782 return;
774 } 783 }
775 } while (buf[i++] != '\n'); 784
776 785 g_snprintf(buf, sizeof(buf), "INF %d\n", ++md->trId);
777 g_strchomp(buf); 786 if (msn_write(md->fd, buf, strlen(buf)) < 0) {
778 787 hide_login_progress(gc, "Unable to request INF\n");
779 debug_printf("MSN ==> %s\n", buf);
780
781 /* Check to see what was just sent back to us. We should be seeing a VER tag. */
782 if (!strncmp("VER ", buf, 4) && (!strstr("MSNP2", buf))) {
783 /* Now that we got our ver, we should send a policy request */
784 g_snprintf(buf, MSN_BUF_LEN, "INF %ld\n", trId(md));
785 msn_write(md->fd, buf);
786
787 return;
788 } else if (!strncmp("INF ", buf, 4)) {
789 char **res;
790
791 /* Make a copy of our resulting policy */
792 res = g_strsplit(buf, " ", 0);
793 md->policy = g_strdup(res[2]);
794
795 /* And send our signon packet */
796 set_login_progress(gc, 3, "Signing On");
797
798 g_snprintf(buf, MSN_BUF_LEN, "USR %ld %s I %s\n", trId(md), md->policy, gc->username);
799 msn_write(md->fd, buf);
800
801 g_strfreev(res);
802
803 return;
804 } else if (!strncmp("ADD ", buf, 4)) {
805 msn_add_request(gc,buf);
806 return;
807 } else if (!strncmp("XFR ", buf, 4)) {
808 char **res;
809 struct aim_user *user = gc->user;
810
811 res = g_strsplit(buf, " ", 0);
812
813 strcpy(buf, res[3]);
814
815 g_strfreev(res);
816
817 res = g_strsplit(buf, ":", 0);
818
819 close(md->fd);
820
821 set_login_progress(gc, 3, "Connecting to Auth");
822
823
824 md->status |= MSN_SIGNON_GOT_XFR;
825
826 gdk_input_remove(gc->inpa);
827 gc->inpa = 0;
828
829 /* Now we have the host and port */
830 md->fd = proxy_connect(res[0], atoi(res[1]), msn_login_callback, gc);
831 if (!user->gc || (md->fd < 0)) {
832 g_strfreev(res);
833 hide_login_progress(gc, "Error connecting to server");
834 signoff(gc); 788 signoff(gc);
835 return; 789 return;
836 } 790 }
837 791 } else if (!g_strncasecmp(buf, "INF", 3)) {
838 g_strfreev(res); 792 /* check to make sure we can use md5 */
839 return; 793 if (!strstr(buf, "MD5")) {
840 } else if (!strncmp("USR ", buf, 4)) { 794 hide_login_progress(gc, "Unable to login using MD5");
841 if (md->status & MSN_SIGNON_SENT_USR) { 795 signoff(gc);
842 char **res; 796 return;
843 797 }
844 res = g_strsplit(buf, " ", 0); 798
845 799 g_snprintf(buf, sizeof(buf), "USR %d MD5 I %s\n", ++md->trId, gc->username);
846 if (strcasecmp("OK", res[2])) { 800 if (msn_write(md->fd, buf, strlen(buf)) < 0) {
847 hide_login_progress(gc, "Error signing on"); 801 hide_login_progress(gc, "Unable to send USR\n");
802 signoff(gc);
803 return;
804 }
805
806 set_login_progress(gc, 3, "Requesting to send password");
807 } else if (!g_strncasecmp(buf, "USR", 3)) {
808 /* so here, we're either getting the challenge or the OK */
809 if (strstr(buf, "OK")) {
810 g_snprintf(buf, sizeof(buf), "SYN %d 0\n", ++md->trId);
811 if (msn_write(md->fd, buf, strlen(buf)) < 0) {
812 hide_login_progress(gc, "Unable to write");
848 signoff(gc); 813 signoff(gc);
849 } else { 814 return;
850 md->friendly = g_strdup(url_decode(res[4]));
851
852 /* Ok, ok. Your account is FINALLY online. Ya think Microsoft
853 * could have had any more steps involved? */
854
855 set_login_progress(gc, 4, "Fetching config");
856
857 /* Sync our buddylist */
858 g_snprintf(buf, MSN_BUF_LEN, "SYN %ld 0\n", trId(md));
859 msn_write(md->fd, buf);
860
861 /* And set ourselves online */
862 g_snprintf(buf, MSN_BUF_LEN, "CHG %ld NLN\n", trId(md));
863 msn_write(md->fd, buf);
864
865 account_online(gc);
866 serv_finish_login(gc);
867
868 if (bud_list_cache_exists(gc))
869 do_import(NULL, gc);
870
871 gdk_input_remove(gc->inpa);
872 gc->inpa = gdk_input_add(md->fd, GDK_INPUT_READ, msn_callback, gc);
873 } 815 }
874 816
875 g_strfreev(res); 817 g_snprintf(buf, sizeof(buf), "CHG %d NLN\n", ++md->trId);
876 } else { 818 if (msn_write(md->fd, buf, strlen(buf)) < 0) {
877 char **res; 819 hide_login_progress(gc, "Unable to write");
820 signoff(gc);
821 return;
822 }
823
824 account_online(gc);
825 serv_finish_login(gc);
826
827 gdk_input_remove(md->inpa);
828 md->inpa = gdk_input_add(md->fd, GDK_INPUT_READ, msn_callback, gc);
829 } else if (strstr(buf, "MD5")) {
830 char *challenge = buf;
878 char buf2[MSN_BUF_LEN]; 831 char buf2[MSN_BUF_LEN];
879 md5_state_t st; 832 md5_state_t st;
880 md5_byte_t di[16]; 833 md5_byte_t di[16];
881 834 int spaces = 4;
882 res = g_strsplit(buf, " ", 0); 835 int i;
883 836
884 /* Make a copy of our MD5 Hash key */ 837 while (spaces) {
885 strcpy(buf, res[4]); 838 if (isspace(*challenge)) {
886 839 spaces--;
887 /* Generate our secret with our key and password */ 840 while (isspace(challenge[1]))
888 snprintf(buf2, MSN_BUF_LEN, "%s%s", buf, gc->password); 841 challenge++;
842 }
843 challenge++;
844 }
845
846 g_snprintf(buf2, sizeof(buf2), "%s%s", challenge, gc->password);
889 847
890 md5_init(&st); 848 md5_init(&st);
891 md5_append(&st, (const md5_byte_t *)buf2, strlen(buf2)); 849 md5_append(&st, (const md5_byte_t *)buf2, strlen(buf2));
892 md5_finish(&st, di); 850 md5_finish(&st, di);
893 851
894 /* Now that we have the MD5 Hash, lets' hex encode this bad boy. I smoke bad crack. */ 852 g_snprintf(buf, sizeof(buf), "USR %d MD5 S ", ++md->trId);
895 sprintf(buf, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", 853 for (i = 0; i < 16; i++) {
896 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], 854 g_snprintf(buf2, sizeof(buf2), "%02x", di[i]);
897 di[13],di[14],di[15]); 855 strcat(buf, buf2);
898 856 }
899 /* And now, send our final sign on packet */ 857 strcat(buf, "\n");
900 g_snprintf(buf2, MSN_BUF_LEN, "USR %s %s S %s\n", res[1], md->policy, buf); 858
901 msn_write(md->fd, buf2); 859 if (msn_write(md->fd, buf, strlen(buf)) < 0) {
902 860 hide_login_progress(gc, "Unable to send password");
903 md->status |= MSN_SIGNON_SENT_USR; 861 signoff(gc);
904 862 return;
905 g_strfreev(res); 863 }
906 } 864
907 865 set_login_progress(gc, 4, "Password sent");
908 return; 866 }
909 } 867 } else if (!g_strncasecmp(buf, "XFR", 3)) {
868 char *host = strstr(buf, "NS");
869 int port;
870 int i = 0;
871
872 if (!host) {
873 hide_login_progress(gc, "Got invalid XFR\n");
874 signoff(gc);
875 return;
876 }
877
878 GET_NEXT(host);
879 while (host[i] && host[i] != ':') i++;
880 if (host[i] == ':') {
881 char *x = &host[i + 1];
882 host[i] = 0;
883 port = atoi(x);
884 } else
885 port = 1863;
886
887 close(md->fd);
888 gdk_input_remove(md->inpa);
889 md->inpa = 0;
890 md->fd = 0;
891 md->fd = proxy_connect(host, port, msn_login_xfr_connect, gc);
892 } else {
893 if (isdigit(*buf))
894 hide_login_progress(gc, handle_errcode(buf, FALSE));
895 else
896 hide_login_progress(gc, "Unable to parse message");
897 signoff(gc);
898 return;
899 }
900 }
901
902 static void msn_login_connect(gpointer data, gint source, GdkInputCondition cond)
903 {
904 struct gaim_connection *gc = data;
905 struct msn_data *md;
906 char buf[1024];
907
908 if (!g_slist_find(connections, gc))
909 return;
910
911 md = gc->proto_data;
912
913 if (md->fd != source)
914 md->fd = source;
915
916 if (md->fd == -1) {
917 hide_login_progress(gc, "Unable to connect");
918 signoff(gc);
919 return;
920 }
921
922 g_snprintf(buf, sizeof(buf), "VER %d MSNP2\n", ++md->trId);
923 if (msn_write(md->fd, buf, strlen(buf)) < 0) {
924 hide_login_progress(gc, "Unable to write to server");
925 signoff(gc);
926 return;
927 }
928
929 md->inpa = gdk_input_add(md->fd, GDK_INPUT_READ, msn_login_callback, gc);
930 set_login_progress(gc, 2, "Synching with server");
910 } 931 }
911 932
912 static void msn_login(struct aim_user *user) 933 static void msn_login(struct aim_user *user)
913 { 934 {
914 struct gaim_connection *gc = new_gaim_conn(user); 935 struct gaim_connection *gc = new_gaim_conn(user);
915 struct msn_data *md = gc->proto_data = g_new0(struct msn_data, 1); 936 struct msn_data *md = gc->proto_data = g_new0(struct msn_data, 1);
916 937
917 gc->inpa = 0;
918
919 set_login_progress(gc, 1, "Connecting"); 938 set_login_progress(gc, 1, "Connecting");
920 939
921 while (gtk_events_pending()) 940 g_snprintf(gc->username, sizeof(gc->username), "%s", msn_normalize(gc->username));
922 gtk_main_iteration(); 941
923 942 md->fd = proxy_connect("messenger.hotmail.com", 1863, msn_login_connect, gc);
924 if (!g_slist_find(connections, gc)) 943 }
925 return; 944
926 945 static void msn_close(struct gaim_connection *gc)
927 md->status = 0; 946 {
928 947 struct msn_data *md = gc->proto_data;
929 sprintf(gc->username, "%s", msn_normalize(gc->username)); 948 close(md->fd);
930 md->fd = proxy_connect("messenger.hotmail.com", 1863, msn_login_callback, gc); 949 if (md->inpa)
931 if (!user->gc || (md->fd < 0)) { 950 gdk_input_remove(md->inpa);
932 hide_login_progress(gc, "Error connecting to server"); 951 while (md->switches)
933 signoff(gc); 952 msn_kill_switch(md->switches->data);
934 return; 953 while (md->xfrs) {
935 } 954 struct msn_xfr *mx = md->xfrs->data;
955 md->xfrs = g_slist_remove(md->xfrs, mx);
956 g_free(mx->user);
957 g_free(mx->what);
958 g_free(mx);
959 }
960 while (md->fl) {
961 char *tmp = md->fl->data;
962 md->fl = g_slist_remove(md->fl, tmp);
963 g_free(tmp);
964 }
965 g_free(md);
936 } 966 }
937 967
938 static void msn_send_im(struct gaim_connection *gc, char *who, char *message, int away) 968 static void msn_send_im(struct gaim_connection *gc, char *who, char *message, int away)
939 { 969 {
940 struct msn_conn *mc; 970 struct msn_data *md = gc->proto_data;
941 struct msn_data *md = (struct msn_data *)gc->proto_data; 971 struct msn_switchboard *ms = msn_find_switch(gc, who);
942 char buf[MSN_BUF_LEN]; 972 char buf[MSN_BUF_LEN];
943 973
944 if (!g_strcasecmp(who, gc->username)) { 974 if (ms) {
945 do_error_dialog("You can not send a message to yourself!", "Gaim: MSN Error"); 975 g_snprintf(buf, sizeof(buf), "MSG %d N %d\r\n%s%s", ++ms->trId,
946 return; 976 strlen(MIME_HEADER) + strlen(url_encode(message)),
947 } 977 MIME_HEADER, url_encode(message));
948 978 if (msn_write(ms->fd, buf, strlen(buf)) < 0)
949 mc = find_msn_conn_by_user(who); 979 msn_kill_switch(ms);
950
951 /* If we're not already in a conversation with
952 * this person then we have to do some tricky things. */
953
954 if (!mc) {
955 /* Request a new switchboard connection */
956 g_snprintf(buf, MSN_BUF_LEN, "XFR %ld SB\n", trId(md));
957 msn_write(md->fd, buf);
958
959 mc = g_new0(struct msn_conn, 1);
960
961 mc->user = g_strdup(who);
962 mc->gc = gc;
963 mc->last_trid = md->last_trid;
964 mc->txqueue = g_strdup(message);
965
966 /* Append our connection */
967 msn_connections = g_slist_append(msn_connections, mc);
968 } else { 980 } else {
969 g_snprintf(buf, MSN_BUF_LEN, "MSG %ld N %d\r\n%s%s", trId(md), 981 struct msn_xfr *mx;
970 strlen(message) + strlen(MIME_HEADER), MIME_HEADER, message); 982 g_snprintf(buf, MSN_BUF_LEN, "XFR %d SB\n", ++md->trId);
971 983 if (msn_write(md->fd, buf, strlen(buf)) < 0) {
972 msn_write(mc->fd, url_encode(buf, 0)); 984 hide_login_progress(gc, "Write error");
973 } 985 signoff(gc);
974 986 return;
975 } 987 }
976 988
977 static void msn_add_buddy(struct gaim_connection *gc, char *who) 989 mx = g_new0(struct msn_xfr, 1);
978 { 990 md->xfrs = g_slist_append(md->xfrs, mx);
979 struct msn_data *md = (struct msn_data *)gc->proto_data; 991 mx->user = g_strdup(who);
980 char buf[MSN_BUF_LEN - 1]; 992 mx->what = g_strdup(message);
981 993 mx->gc = gc;
982 snprintf(buf, MSN_BUF_LEN, "ADD %ld FL %s %s\n", trId(md), who, who); 994 }
983 msn_write(md->fd, buf); 995 }
984 } 996
985 997 static GList *msn_away_states()
986 static void msn_remove_buddy(struct gaim_connection *gc, char *who)
987 {
988 struct msn_data *md = (struct msn_data *)gc->proto_data;
989 char buf[MSN_BUF_LEN - 1];
990
991 snprintf(buf, MSN_BUF_LEN, "REM %ld FL %s\n", trId(md), who);
992 msn_write(md->fd, buf);
993 }
994
995 static void msn_rem_permit(struct gaim_connection *gc, char *who)
996 {
997 struct msn_data *md = (struct msn_data *)gc->proto_data;
998 char buf[MSN_BUF_LEN - 1];
999
1000 snprintf(buf, MSN_BUF_LEN, "REM %ld AL %s\n", trId(md), who);
1001 msn_write(md->fd, buf);
1002 }
1003
1004 static void msn_add_permit(struct gaim_connection *gc, char *who)
1005 {
1006 struct msn_data *md = (struct msn_data *)gc->proto_data;
1007 char buf[MSN_BUF_LEN - 1];
1008
1009 snprintf(buf, MSN_BUF_LEN, "ADD %ld AL %s %s\n", trId(md), who, who);
1010 msn_write(md->fd, buf);
1011 }
1012
1013 static void msn_rem_deny(struct gaim_connection *gc, char *who)
1014 {
1015 struct msn_data *md = (struct msn_data *)gc->proto_data;
1016 char buf[MSN_BUF_LEN - 1];
1017
1018 snprintf(buf, MSN_BUF_LEN, "REM %ld BL %s\n", trId(md), who);
1019 msn_write(md->fd, buf);
1020 }
1021
1022 static void msn_add_deny(struct gaim_connection *gc, char *who)
1023 {
1024 struct msn_data *md = (struct msn_data *)gc->proto_data;
1025 char buf[MSN_BUF_LEN - 1];
1026
1027 snprintf(buf, MSN_BUF_LEN, "ADD %ld BL %s %s\n", trId(md), who, who);
1028 msn_write(md->fd, buf);
1029 }
1030
1031 static GList *msn_away_states()
1032 { 998 {
1033 GList *m = NULL; 999 GList *m = NULL;
1034 1000
1035 m = g_list_append(m, "Available"); 1001 m = g_list_append(m, "Available");
1036 m = g_list_append(m, "Away From Computer"); 1002 m = g_list_append(m, "Away From Computer");
1037 m = g_list_append(m, "Be Right Back"); 1003 m = g_list_append(m, "Be Right Back");
1038 m = g_list_append(m, "Busy"); 1004 m = g_list_append(m, "Busy");
1039 m = g_list_append(m, "On The Phone"); 1005 m = g_list_append(m, "On The Phone");
1040 m = g_list_append(m, "Out To Lunch"); 1006 m = g_list_append(m, "Out To Lunch");
1041 1007
1042 return m; 1008 return m;
1043 } 1009 }
1044 1010
1045 static void msn_set_away(struct gaim_connection *gc, char *state, char *msg) 1011 static void msn_set_away(struct gaim_connection *gc, char *state, char *msg)
1046 { 1012 {
1047 struct msn_data *md = (struct msn_data *)gc->proto_data; 1013 struct msn_data *md = gc->proto_data;
1048 char buf[MSN_BUF_LEN - 1]; 1014 char buf[MSN_BUF_LEN];
1049 1015 char *away;
1050 1016
1051 gc->away = NULL; 1017 gc->away = NULL;
1052 1018
1053 if (msg) { 1019 if (msg) {
1054 gc->away = ""; 1020 gc->away = "";
1055 snprintf(buf, MSN_BUF_LEN, "CHG %ld AWY\n", trId(md)); 1021 away = "AWY";
1056 } else if (state) { 1022 } else if (state) {
1057 char away[4];
1058
1059 gc->away = ""; 1023 gc->away = "";
1060 1024
1061 if (!strcmp(state, "Available")) 1025 if (!strcmp(state, "Away From Computer"))
1062 sprintf(away, "NLN"); 1026 away = "AWY";
1063 else if (!strcmp(state, "Away From Computer"))
1064 sprintf(away, "AWY");
1065 else if (!strcmp(state, "Be Right Back")) 1027 else if (!strcmp(state, "Be Right Back"))
1066 sprintf(away, "BRB"); 1028 away = "BRB";
1067 else if (!strcmp(state, "Busy")) 1029 else if (!strcmp(state, "Busy"))
1068 sprintf(away, "BSY"); 1030 away = "BSY";
1069 else if (!strcmp(state, "On The Phone")) 1031 else if (!strcmp(state, "On The Phone"))
1070 sprintf(away, "PHN"); 1032 away = "PHN";
1071 else if (!strcmp(state, "Out To Lunch")) 1033 else if (!strcmp(state, "Out To Lunch"))
1072 sprintf(away, "LUN"); 1034 away = "LUN";
1073 else 1035 else {
1074 sprintf(away, "NLN"); 1036 gc->away = NULL;
1075 1037 away = "NLN";
1076 snprintf(buf, MSN_BUF_LEN, "CHG %ld %s\n", trId(md), away); 1038 }
1077 } else if (gc->is_idle) 1039 } else if (gc->is_idle)
1078 snprintf(buf, MSN_BUF_LEN, "CHG %ld IDL\n", trId(md)); 1040 away = "IDL";
1079 else 1041 else
1080 snprintf(buf, MSN_BUF_LEN, "CHG %ld NLN\n", trId(md)); 1042 away = "NLN";
1081 1043
1082 msn_write(md->fd, buf); 1044 g_snprintf(buf, sizeof(buf), "CHG %d %s\n", ++md->trId, away);
1083 } 1045 if (msn_write(md->fd, buf, strlen(buf)) < 0) {
1084 1046 hide_login_progress(gc, "Write error");
1047 signoff(gc);
1048 return;
1049 }
1050 }
1085 1051
1086 static void msn_set_idle(struct gaim_connection *gc, int idle) 1052 static void msn_set_idle(struct gaim_connection *gc, int idle)
1087 { 1053 {
1088 struct msn_data *md = (struct msn_data *)gc->proto_data; 1054 struct msn_data *md = gc->proto_data;
1089 char buf[MSN_BUF_LEN - 1]; 1055 char buf[MSN_BUF_LEN];
1090 1056
1057 if (gc->away)
1058 return;
1091 if (idle) 1059 if (idle)
1092 snprintf(buf, MSN_BUF_LEN, "CHG %ld IDL\n", trId(md)); 1060 g_snprintf(buf, sizeof(buf), "CHG %d IDL\n", ++md->trId);
1093 else 1061 else
1094 snprintf(buf, MSN_BUF_LEN, "CHG %ld NLN\n", trId(md)); 1062 g_snprintf(buf, sizeof(buf), "CHG %d NLN\n", ++md->trId);
1095 1063 if (msn_write(md->fd, buf, strlen(buf)) < 0) {
1096 msn_write(md->fd, buf); 1064 hide_login_progress(gc, "Write error");
1097 } 1065 signoff(gc);
1098 1066 return;
1099 static void msn_close(struct gaim_connection *gc) 1067 }
1100 { 1068 }
1101 struct msn_data *md = (struct msn_data *)gc->proto_data; 1069
1102 char buf[MSN_BUF_LEN]; 1070 static char **msn_list_icon(int uc)
1103 struct msn_conn *mc = NULL; 1071 {
1104 1072 if (uc == UC_NORMAL)
1105 while (msn_connections) { 1073 return msn_online_xpm;
1106 mc = (struct msn_conn *)msn_connections->data; 1074
1107 1075 return msn_away_xpm;
1108 free_msn_conn(mc);
1109 }
1110
1111 if (md->fd) {
1112 g_snprintf(buf, MSN_BUF_LEN, "OUT\n");
1113 msn_write(md->fd, buf);
1114 close(md->fd);
1115 }
1116
1117 if (gc->inpa)
1118 gdk_input_remove(gc->inpa);
1119
1120 if (md->friendly)
1121 g_free(md->friendly);
1122
1123 g_free(gc->proto_data);
1124 } 1076 }
1125 1077
1126 static char *msn_get_away_text(int s) 1078 static char *msn_get_away_text(int s)
1127 { 1079 {
1128 switch (s) { 1080 switch (s) {
1137 case MSN_LUNCH : 1089 case MSN_LUNCH :
1138 return "Out to lunch"; 1090 return "Out to lunch";
1139 case MSN_IDLE : 1091 case MSN_IDLE :
1140 return "Idle"; 1092 return "Idle";
1141 default: 1093 default:
1142 return NULL; 1094 return "Available";
1143 } 1095 }
1144 } 1096 }
1145 1097
1146 static void msn_buddy_menu(GtkWidget *menu, struct gaim_connection *gc, char *who) 1098 static void msn_buddy_menu(GtkWidget *menu, struct gaim_connection *gc, char *who)
1147 { 1099 {
1148 struct buddy *b = find_buddy(gc, who); 1100 struct buddy *b = find_buddy(gc, who);
1149 char buf[MSN_BUF_LEN]; 1101 char buf[MSN_BUF_LEN];
1150 GtkWidget *button; 1102 GtkWidget *button;
1151 1103
1152 if (!(b->uc >> 5)) 1104 if (!b || !(b->uc >> 5))
1153 return; 1105 return;
1154 1106
1155 g_snprintf(buf, MSN_BUF_LEN, "Status: %s", msn_get_away_text(b->uc >> 5)); 1107 g_snprintf(buf, sizeof(buf), "Status: %s", msn_get_away_text(b->uc >> 5));
1156 1108
1157 button = gtk_menu_item_new_with_label(buf); 1109 button = gtk_menu_item_new_with_label(buf);
1158 gtk_menu_append(GTK_MENU(menu), button); 1110 gtk_menu_append(GTK_MENU(menu), button);
1159 gtk_widget_show(button); 1111 gtk_widget_show(button);
1160 } 1112 }
1161 1113
1162 static void msn_newmail_dialog(const char *text) 1114 struct mod_usr_opt {
1163 { 1115 struct aim_user *user;
1164 GtkWidget *window; 1116 int opt;
1165 GtkWidget *vbox; 1117 };
1166 GtkWidget *label;
1167 GtkWidget *hbox;
1168 GtkWidget *button;
1169
1170 window = gtk_window_new(GTK_WINDOW_DIALOG);
1171 gtk_window_set_wmclass(GTK_WINDOW(window), "prompt", "Gaim");
1172 gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, TRUE);
1173 gtk_window_set_title(GTK_WINDOW(window), _("Gaim-MSN: New Mail"));
1174 gtk_widget_realize(window);
1175 aol_icon(window->window);
1176
1177 vbox = gtk_vbox_new(FALSE, 5);
1178 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
1179 gtk_container_add(GTK_CONTAINER(window), vbox);
1180
1181 label = gtk_label_new(text);
1182 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
1183
1184 hbox = gtk_hbox_new(FALSE, 5);
1185 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1186
1187 button = picture_button(window, _("OK"), ok_xpm);
1188 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1189 gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(msn_des_win), window);
1190
1191 gtk_widget_show_all(window);
1192 }
1193
1194 static void msn_des_win(GtkWidget *a, GtkWidget *b)
1195 {
1196 gtk_widget_destroy(b);
1197 }
1198 1118
1199 static void mod_opt(GtkWidget *b, struct mod_usr_opt *m) 1119 static void mod_opt(GtkWidget *b, struct mod_usr_opt *m)
1200 { 1120 {
1201 if (m->user) { 1121 if (m->user) {
1202 if (m->user->proto_opt[m->opt][0] == '1') 1122 if (m->user->proto_opt[m->opt][0] == '1')
1214 static GtkWidget *msn_protoopt_button(const char *text, struct aim_user *u, int option, GtkWidget *box) 1134 static GtkWidget *msn_protoopt_button(const char *text, struct aim_user *u, int option, GtkWidget *box)
1215 { 1135 {
1216 GtkWidget *button; 1136 GtkWidget *button;
1217 struct mod_usr_opt *muo = g_new0(struct mod_usr_opt, 1); 1137 struct mod_usr_opt *muo = g_new0(struct mod_usr_opt, 1);
1218 button = gtk_check_button_new_with_label(text); 1138 button = gtk_check_button_new_with_label(text);
1219 if (u) { 1139 if (u)
1220 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), (u->proto_opt[option][0] == '1')); 1140 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), (u->proto_opt[option][0] == '1'));
1221 }
1222 gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0); 1141 gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
1223 muo->user = u; 1142 muo->user = u;
1224 muo->opt = option; 1143 muo->opt = option;
1225 gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(mod_opt), muo); 1144 gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(mod_opt), muo);
1226 gtk_signal_connect(GTK_OBJECT(button), "destroy", GTK_SIGNAL_FUNC(free_muo), muo); 1145 gtk_signal_connect(GTK_OBJECT(button), "destroy", GTK_SIGNAL_FUNC(free_muo), muo);
1227 gtk_widget_show(button); 1146 gtk_widget_show(button);
1147
1228 return button; 1148 return button;
1229 } 1149 }
1230 1150
1231 static void msn_user_opts(GtkWidget* book, struct aim_user *user) 1151 static void msn_user_opts(GtkWidget* book, struct aim_user *user)
1232 { 1152 {
1233 /* so here, we create the new notebook page */
1234 GtkWidget *vbox; 1153 GtkWidget *vbox;
1235 1154
1236 vbox = gtk_vbox_new(FALSE, 5); 1155 vbox = gtk_vbox_new(FALSE, 5);
1237 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); 1156 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
1238 gtk_notebook_append_page(GTK_NOTEBOOK(book), vbox, gtk_label_new("MSN Options")); 1157 gtk_notebook_append_page(GTK_NOTEBOOK(book), vbox, gtk_label_new("MSN Options"));
1239 gtk_widget_show(vbox); 1158 gtk_widget_show(vbox);
1240 1159
1241 msn_protoopt_button("Notify me of new HotMail",user,USEROPT_HOTMAIL,vbox); 1160 msn_protoopt_button("Notify me of new HotMail",user,USEROPT_HOTMAIL,vbox);
1242 } 1161 }
1243 1162
1244 /* 1163 static void msn_add_buddy(struct gaim_connection *gc, char *who)
1245 Process messages from Hotmail service. right now we just check for new 1164 {
1246 mail notifications, if the user has checking enabled. 1165 struct msn_data *md = gc->proto_data;
1247 */ 1166 char buf[MSN_BUF_LEN];
1248 1167 GSList *l = md->fl;
1249 static void process_hotmail_msg(struct gaim_connection *gc, gchar *msgdata) 1168
1250 { 1169 while (l) {
1251 gchar *mailnotice; 1170 if (!g_strcasecmp(who, l->data))
1252 char *mailfrom,*mailsubj,*mailct,*mailp; 1171 break;
1253 1172 l = l->next;
1254 if (gc->user->proto_opt[USEROPT_HOTMAIL][0] != '1') return; 1173 }
1255 mailfrom=NULL; mailsubj=NULL; mailct=NULL; mailp=NULL; 1174 if (l)
1256 mailct = strstr(msgdata,"Content-Type: "); 1175 return;
1257 mailp = strstr(mailct,";"); 1176
1258 if ((mailct != NULL) && (mailp != NULL) && (mailp > mailct) && 1177 g_snprintf(buf, sizeof(buf), "ADD %d FL %s %s\n", ++md->trId, who, who);
1259 !strncmp(mailct,"Content-Type: text/x-msmsgsemailnotification",(mailp-mailct)-1)) { 1178 if (msn_write(md->fd, buf, strlen(buf)) < 0) {
1260 mailfrom=strstr(mailp,"From: "); 1179 hide_login_progress(gc, "Write error");
1261 mailsubj=strstr(mailp,"Subject: "); 1180 signoff(gc);
1262 } 1181 return;
1263 1182 }
1264 if (mailfrom != NULL && mailsubj != NULL) { 1183 }
1265 mailfrom += 6; 1184
1266 mailp=strstr(mailfrom,"\r\n"); 1185 static void msn_rem_buddy(struct gaim_connection *gc, char *who)
1267 if (mailp==NULL) return; 1186 {
1268 *mailp = 0; 1187 struct msn_data *md = gc->proto_data;
1269 mailsubj += 9; 1188 char buf[MSN_BUF_LEN];
1270 mailp=strstr(mailsubj,"\r\n"); 1189
1271 if (mailp==NULL) return; 1190 g_snprintf(buf, sizeof(buf), "REM %d FL %s\n", ++md->trId, who);
1272 *mailp = 0; 1191 if (msn_write(md->fd, buf, strlen(buf)) < 0) {
1273 mailnotice = (gchar *)g_malloc(sizeof(gchar) *(strlen(mailfrom)+strlen(mailsubj)+128)); 1192 hide_login_progress(gc, "Write error");
1274 sprintf(mailnotice,"Mail from %s, re: %s",mailfrom,mailsubj); 1193 signoff(gc);
1275 msn_newmail_dialog(mailnotice); 1194 return;
1276 g_free(mailnotice); 1195 }
1277 }
1278 }
1279
1280 static char *msn_normalize(const char *s)
1281 {
1282 static char buf[BUF_LEN];
1283 char *t, *u;
1284 int x = 0;
1285
1286 g_return_val_if_fail((s != NULL), NULL);
1287
1288 u = t = g_strdup(s);
1289
1290 g_strdown(t);
1291
1292 while (*t && (x < BUF_LEN - 1)) {
1293 if (*t != ' ')
1294 buf[x++] = *t;
1295 t++;
1296 }
1297 buf[x] = '\0';
1298 g_free(u);
1299
1300 if (!strchr(buf, '@')) {
1301 strcat(buf, "@hotmail.com"); /* if they don't specify something, it will be hotmail.com.
1302 msn.com is valid too, but hey, if they wanna use it,
1303 they gotta enter it themselves. */
1304 } else if ((u = strchr(strchr(buf, '@'), '/')) != NULL) {
1305 *u = '\0';
1306 }
1307
1308 return buf;
1309 }
1310
1311 static void do_change_name(GtkWidget *w, struct msn_name_dlg *b)
1312 {
1313 struct gaim_connection *gc = b->user->gc;
1314 struct msn_data *md = (struct msn_data *)gc->proto_data;
1315 char buf[MSN_BUF_LEN - 1];
1316 const gchar *newname;
1317 char *temp;
1318
1319 newname = gtk_entry_get_text(GTK_ENTRY(b->entry));
1320
1321 temp = strdup(newname);
1322
1323 snprintf(buf, MSN_BUF_LEN, "REA %ld %s %s\n", trId(md), gc->username, url_encode(temp, 1));
1324
1325 free(temp);
1326
1327 msn_write(md->fd, buf);
1328
1329 msn_des_win(NULL, b->window);
1330
1331 return;
1332 }
1333
1334 static void show_change_name(struct gaim_connection *gc)
1335 {
1336 GtkWidget *label;
1337 GtkWidget *vbox;
1338 GtkWidget *buttons;
1339 GtkWidget *hbox;
1340 struct aim_user *tmp;
1341 gchar *buf;
1342 struct msn_data *md;
1343
1344 struct msn_name_dlg *b = g_new0(struct msn_name_dlg, 1);
1345 if (!g_slist_find(connections, gc))
1346 gc = connections->data;
1347
1348 tmp = gc->user;
1349 b->user = tmp;
1350
1351 md = (struct msn_data *)gc->proto_data;
1352
1353 b->window = gtk_window_new(GTK_WINDOW_DIALOG);
1354 gtk_window_set_wmclass(GTK_WINDOW(b->window), "msn_change_name", "Gaim");
1355
1356 gtk_window_set_title(GTK_WINDOW(b->window), _("Gaim - Change MSN Name"));
1357 gtk_signal_connect(GTK_OBJECT(b->window), "destroy", GTK_SIGNAL_FUNC(msn_des_win), b->window);
1358 gtk_widget_realize(b->window);
1359 aol_icon(b->window->window);
1360
1361 vbox = gtk_vbox_new(FALSE, 5);
1362 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
1363 gtk_container_add(GTK_CONTAINER(b->window), vbox);
1364 gtk_widget_show(vbox);
1365
1366 hbox = gtk_hbox_new(FALSE, 5);
1367 gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
1368 gtk_widget_show(hbox);
1369 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
1370
1371 buf = g_malloc(256);
1372 g_snprintf(buf, 256, "New name for %s (%s):", tmp->username, url_decode(md->friendly));
1373 label = gtk_label_new(buf);
1374 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
1375 gtk_widget_show(label);
1376 g_free(buf);
1377
1378 b->entry = gtk_entry_new();
1379 gtk_box_pack_start(GTK_BOX(hbox), b->entry, FALSE, FALSE, 5);
1380 gtk_widget_show(b->entry);
1381
1382 buttons = gtk_hbox_new(FALSE, 5);
1383 gtk_box_pack_start(GTK_BOX(vbox), buttons, FALSE, FALSE, 0);
1384 gtk_widget_show(buttons);
1385
1386 b->cancel = picture_button(b->window, _("Cancel"), cancel_xpm);
1387 gtk_box_pack_end(GTK_BOX(buttons), b->cancel, FALSE, FALSE, 0);
1388 gtk_signal_connect(GTK_OBJECT(b->cancel), "clicked", GTK_SIGNAL_FUNC(msn_des_win), b->window);
1389
1390 b->ok = picture_button(b->window, _("Ok"), ok_xpm);
1391 gtk_box_pack_end(GTK_BOX(buttons), b->ok, FALSE, FALSE, 0);
1392 gtk_signal_connect(GTK_OBJECT(b->ok), "clicked", GTK_SIGNAL_FUNC(do_change_name), b);
1393
1394
1395 gtk_widget_show(b->window);
1396
1397
1398 }
1399
1400 static void msn_do_action(struct gaim_connection *gc, char *act)
1401 {
1402 if (!strcmp(act, "Change Name"))
1403 show_change_name(gc);
1404 }
1405
1406 static GList *msn_actions()
1407 {
1408 GList *m = NULL;
1409
1410 m = g_list_append(m, "Change Name");
1411
1412 return m;
1413 }
1414
1415 static char **msn_list_icon(int uc)
1416 {
1417 if (uc == UC_UNAVAILABLE)
1418 return msn_away_xpm;
1419 else if (uc == UC_NORMAL)
1420 return msn_online_xpm;
1421
1422 return msn_away_xpm;
1423 } 1196 }
1424 1197
1425 static struct prpl *my_protocol = NULL; 1198 static struct prpl *my_protocol = NULL;
1426 1199
1427 static void msn_init(struct prpl *ret) 1200 static void msn_init(struct prpl *ret)
1432 ret->buddy_menu = msn_buddy_menu; 1205 ret->buddy_menu = msn_buddy_menu;
1433 ret->user_opts = msn_user_opts; 1206 ret->user_opts = msn_user_opts;
1434 ret->login = msn_login; 1207 ret->login = msn_login;
1435 ret->close = msn_close; 1208 ret->close = msn_close;
1436 ret->send_im = msn_send_im; 1209 ret->send_im = msn_send_im;
1437 ret->set_info = NULL;
1438 ret->get_info = NULL;
1439 ret->away_states = msn_away_states; 1210 ret->away_states = msn_away_states;
1440 ret->set_away = msn_set_away; 1211 ret->set_away = msn_set_away;
1441 ret->get_away_msg = NULL;
1442 ret->set_dir = NULL;
1443 ret->get_dir = NULL;
1444 ret->dir_search = NULL;
1445 ret->set_idle = msn_set_idle; 1212 ret->set_idle = msn_set_idle;
1446 ret->change_passwd = NULL;
1447 ret->add_buddy = msn_add_buddy; 1213 ret->add_buddy = msn_add_buddy;
1448 ret->add_buddies = NULL; 1214 ret->remove_buddy = msn_rem_buddy;
1449 ret->remove_buddy = msn_remove_buddy;
1450 ret->add_permit = msn_add_permit;
1451 ret->rem_permit = msn_rem_permit;
1452 ret->add_deny = msn_add_deny;
1453 ret->rem_deny = msn_rem_deny;
1454 ret->warn = NULL;
1455 ret->accept_chat = NULL;
1456 ret->join_chat = NULL;
1457 ret->chat_invite = NULL;
1458 ret->chat_leave = NULL;
1459 ret->chat_whisper = NULL;
1460 ret->chat_send = NULL;
1461 ret->keepalive = NULL;
1462 ret->actions = msn_actions;
1463 ret->do_action = msn_do_action;
1464 ret->normalize = msn_normalize; 1215 ret->normalize = msn_normalize;
1465 1216
1466 my_protocol = ret; 1217 my_protocol = ret;
1467 } 1218 }
1468 1219
1469 char *gaim_plugin_init(GModule * handle) 1220 char *gaim_plugin_init(GModule *handle)
1470 { 1221 {
1471 load_protocol(msn_init, sizeof(struct prpl)); 1222 load_protocol(msn_init, sizeof(struct prpl));
1472 return NULL; 1223 return NULL;
1473 } 1224 }
1474 1225