Mercurial > pidgin
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 |