| |
1 /** |
| |
2 * @file session.c MSN session functions |
| |
3 * |
| |
4 * purple |
| |
5 * |
| |
6 * Purple is the legal property of its developers, whose names are too numerous |
| |
7 * to list here. Please refer to the COPYRIGHT file distributed with this |
| |
8 * source distribution. |
| |
9 * |
| |
10 * This program is free software; you can redistribute it and/or modify |
| |
11 * it under the terms of the GNU General Public License as published by |
| |
12 * the Free Software Foundation; either version 2 of the License, or |
| |
13 * (at your option) any later version. |
| |
14 * |
| |
15 * This program is distributed in the hope that it will be useful, |
| |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |
18 * GNU General Public License for more details. |
| |
19 * |
| |
20 * You should have received a copy of the GNU General Public License |
| |
21 * along with this program; if not, write to the Free Software |
| |
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA |
| |
23 */ |
| |
24 #include "msn.h" |
| |
25 #include "session.h" |
| |
26 #include "notification.h" |
| |
27 |
| |
28 #include "dialog.h" |
| |
29 |
| |
30 MsnSession * |
| |
31 msn_session_new(PurpleAccount *account) |
| |
32 { |
| |
33 MsnSession *session; |
| |
34 |
| |
35 g_return_val_if_fail(account != NULL, NULL); |
| |
36 |
| |
37 session = g_new0(MsnSession, 1); |
| |
38 |
| |
39 session->account = account; |
| |
40 session->notification = msn_notification_new(session); |
| |
41 session->userlist = msn_userlist_new(session); |
| |
42 |
| |
43 session->user = msn_user_new(session->userlist, |
| |
44 purple_account_get_username(account), NULL); |
| |
45 |
| |
46 session->protocol_ver = 9; |
| |
47 session->conv_seq = 1; |
| |
48 |
| |
49 return session; |
| |
50 } |
| |
51 |
| |
52 void |
| |
53 msn_session_destroy(MsnSession *session) |
| |
54 { |
| |
55 g_return_if_fail(session != NULL); |
| |
56 |
| |
57 session->destroying = TRUE; |
| |
58 |
| |
59 if (session->connected) |
| |
60 msn_session_disconnect(session); |
| |
61 |
| |
62 if (session->notification != NULL) |
| |
63 msn_notification_destroy(session->notification); |
| |
64 |
| |
65 while (session->switches != NULL) |
| |
66 msn_switchboard_destroy(session->switches->data); |
| |
67 |
| |
68 while (session->slplinks != NULL) |
| |
69 msn_slplink_destroy(session->slplinks->data); |
| |
70 |
| |
71 msn_userlist_destroy(session->userlist); |
| |
72 |
| |
73 g_free(session->passport_info.kv); |
| |
74 g_free(session->passport_info.sid); |
| |
75 g_free(session->passport_info.mspauth); |
| |
76 g_free(session->passport_info.client_ip); |
| |
77 |
| |
78 if (session->passport_info.file != NULL) |
| |
79 { |
| |
80 g_unlink(session->passport_info.file); |
| |
81 g_free(session->passport_info.file); |
| |
82 } |
| |
83 |
| |
84 if (session->sync != NULL) |
| |
85 msn_sync_destroy(session->sync); |
| |
86 |
| |
87 if (session->nexus != NULL) |
| |
88 msn_nexus_destroy(session->nexus); |
| |
89 |
| |
90 if (session->user != NULL) |
| |
91 msn_user_destroy(session->user); |
| |
92 |
| |
93 g_free(session); |
| |
94 } |
| |
95 |
| |
96 gboolean |
| |
97 msn_session_connect(MsnSession *session, const char *host, int port, |
| |
98 gboolean http_method) |
| |
99 { |
| |
100 g_return_val_if_fail(session != NULL, FALSE); |
| |
101 g_return_val_if_fail(!session->connected, TRUE); |
| |
102 |
| |
103 session->connected = TRUE; |
| |
104 session->http_method = http_method; |
| |
105 |
| |
106 if (session->notification == NULL) |
| |
107 { |
| |
108 purple_debug_error("msn", "This shouldn't happen\n"); |
| |
109 g_return_val_if_reached(FALSE); |
| |
110 } |
| |
111 |
| |
112 if (msn_notification_connect(session->notification, host, port)) |
| |
113 { |
| |
114 return TRUE; |
| |
115 } |
| |
116 |
| |
117 return FALSE; |
| |
118 } |
| |
119 |
| |
120 void |
| |
121 msn_session_disconnect(MsnSession *session) |
| |
122 { |
| |
123 g_return_if_fail(session != NULL); |
| |
124 g_return_if_fail(session->connected); |
| |
125 |
| |
126 session->connected = FALSE; |
| |
127 |
| |
128 while (session->switches != NULL) |
| |
129 msn_switchboard_close(session->switches->data); |
| |
130 |
| |
131 if (session->notification != NULL) |
| |
132 msn_notification_close(session->notification); |
| |
133 } |
| |
134 |
| |
135 /* TODO: This must go away when conversation is redesigned */ |
| |
136 MsnSwitchBoard * |
| |
137 msn_session_find_swboard(MsnSession *session, const char *username) |
| |
138 { |
| |
139 GList *l; |
| |
140 |
| |
141 g_return_val_if_fail(session != NULL, NULL); |
| |
142 g_return_val_if_fail(username != NULL, NULL); |
| |
143 |
| |
144 for (l = session->switches; l != NULL; l = l->next) |
| |
145 { |
| |
146 MsnSwitchBoard *swboard; |
| |
147 |
| |
148 swboard = l->data; |
| |
149 |
| |
150 if ((swboard->im_user != NULL) && !strcmp(username, swboard->im_user)) |
| |
151 return swboard; |
| |
152 } |
| |
153 |
| |
154 return NULL; |
| |
155 } |
| |
156 |
| |
157 MsnSwitchBoard * |
| |
158 msn_session_find_swboard_with_conv(MsnSession *session, PurpleConversation *conv) |
| |
159 { |
| |
160 GList *l; |
| |
161 |
| |
162 g_return_val_if_fail(session != NULL, NULL); |
| |
163 g_return_val_if_fail(conv != NULL, NULL); |
| |
164 |
| |
165 for (l = session->switches; l != NULL; l = l->next) |
| |
166 { |
| |
167 MsnSwitchBoard *swboard; |
| |
168 |
| |
169 swboard = l->data; |
| |
170 |
| |
171 if (swboard->conv == conv) |
| |
172 return swboard; |
| |
173 } |
| |
174 |
| |
175 return NULL; |
| |
176 } |
| |
177 |
| |
178 MsnSwitchBoard * |
| |
179 msn_session_find_swboard_with_id(const MsnSession *session, int chat_id) |
| |
180 { |
| |
181 GList *l; |
| |
182 |
| |
183 g_return_val_if_fail(session != NULL, NULL); |
| |
184 g_return_val_if_fail(chat_id >= 0, NULL); |
| |
185 |
| |
186 for (l = session->switches; l != NULL; l = l->next) |
| |
187 { |
| |
188 MsnSwitchBoard *swboard; |
| |
189 |
| |
190 swboard = l->data; |
| |
191 |
| |
192 if (swboard->chat_id == chat_id) |
| |
193 return swboard; |
| |
194 } |
| |
195 |
| |
196 return NULL; |
| |
197 } |
| |
198 |
| |
199 MsnSwitchBoard * |
| |
200 msn_session_get_swboard(MsnSession *session, const char *username, |
| |
201 MsnSBFlag flag) |
| |
202 { |
| |
203 MsnSwitchBoard *swboard; |
| |
204 |
| |
205 g_return_val_if_fail(session != NULL, NULL); |
| |
206 |
| |
207 swboard = msn_session_find_swboard(session, username); |
| |
208 |
| |
209 if (swboard == NULL) |
| |
210 { |
| |
211 swboard = msn_switchboard_new(session); |
| |
212 swboard->im_user = g_strdup(username); |
| |
213 msn_switchboard_request(swboard); |
| |
214 msn_switchboard_request_add_user(swboard, username); |
| |
215 } |
| |
216 |
| |
217 swboard->flag |= flag; |
| |
218 |
| |
219 return swboard; |
| |
220 } |
| |
221 |
| |
222 static void |
| |
223 msn_session_sync_users(MsnSession *session) |
| |
224 { |
| |
225 PurpleBlistNode *gnode, *cnode, *bnode; |
| |
226 PurpleConnection *gc = purple_account_get_connection(session->account); |
| |
227 |
| |
228 g_return_if_fail(gc != NULL); |
| |
229 |
| |
230 /* The core used to use msn_add_buddy to add all buddies before |
| |
231 * being logged in. This no longer happens, so we manually iterate |
| |
232 * over the whole buddy list to identify sync issues. */ |
| |
233 |
| |
234 for (gnode = purple_blist_get_root(); gnode; gnode = gnode->next) { |
| |
235 PurpleGroup *group = (PurpleGroup *)gnode; |
| |
236 const char *group_name = group->name; |
| |
237 if(!PURPLE_BLIST_NODE_IS_GROUP(gnode)) |
| |
238 continue; |
| |
239 for(cnode = gnode->child; cnode; cnode = cnode->next) { |
| |
240 if(!PURPLE_BLIST_NODE_IS_CONTACT(cnode)) |
| |
241 continue; |
| |
242 for(bnode = cnode->child; bnode; bnode = bnode->next) { |
| |
243 PurpleBuddy *b; |
| |
244 if(!PURPLE_BLIST_NODE_IS_BUDDY(bnode)) |
| |
245 continue; |
| |
246 b = (PurpleBuddy *)bnode; |
| |
247 if(purple_buddy_get_account(b) == purple_connection_get_account(gc)) { |
| |
248 MsnUser *remote_user; |
| |
249 gboolean found = FALSE; |
| |
250 |
| |
251 remote_user = msn_userlist_find_user(session->userlist, purple_buddy_get_name(b)); |
| |
252 |
| |
253 if ((remote_user != NULL) && (remote_user->list_op & MSN_LIST_FL_OP)) |
| |
254 { |
| |
255 int group_id; |
| |
256 GList *l; |
| |
257 |
| |
258 group_id = msn_userlist_find_group_id(remote_user->userlist, |
| |
259 group_name); |
| |
260 |
| |
261 for (l = remote_user->group_ids; l != NULL; l = l->next) |
| |
262 { |
| |
263 if (group_id == GPOINTER_TO_INT(l->data)) |
| |
264 { |
| |
265 found = TRUE; |
| |
266 break; |
| |
267 } |
| |
268 } |
| |
269 |
| |
270 } |
| |
271 |
| |
272 if (!found) |
| |
273 { |
| |
274 /* The user was not on the server list or not in that group |
| |
275 * on the server list */ |
| |
276 msn_show_sync_issue(session, purple_buddy_get_name(b), group_name); |
| |
277 } |
| |
278 } |
| |
279 } |
| |
280 } |
| |
281 } |
| |
282 } |
| |
283 |
| |
284 void |
| |
285 msn_session_set_error(MsnSession *session, MsnErrorType error, |
| |
286 const char *info) |
| |
287 { |
| |
288 PurpleConnection *gc; |
| |
289 char *msg; |
| |
290 |
| |
291 gc = purple_account_get_connection(session->account); |
| |
292 |
| |
293 switch (error) |
| |
294 { |
| |
295 case MSN_ERROR_SERVCONN: |
| |
296 msg = g_strdup(info); |
| |
297 break; |
| |
298 case MSN_ERROR_UNSUPPORTED_PROTOCOL: |
| |
299 msg = g_strdup(_("Our protocol is not supported by the " |
| |
300 "server.")); |
| |
301 break; |
| |
302 case MSN_ERROR_HTTP_MALFORMED: |
| |
303 msg = g_strdup(_("Error parsing HTTP.")); |
| |
304 break; |
| |
305 case MSN_ERROR_SIGN_OTHER: |
| |
306 gc->wants_to_die = TRUE; |
| |
307 msg = g_strdup(_("You have signed on from another location.")); |
| |
308 break; |
| |
309 case MSN_ERROR_SERV_UNAVAILABLE: |
| |
310 msg = g_strdup(_("The MSN servers are temporarily " |
| |
311 "unavailable. Please wait and try " |
| |
312 "again.")); |
| |
313 break; |
| |
314 case MSN_ERROR_SERV_DOWN: |
| |
315 msg = g_strdup(_("The MSN servers are going down " |
| |
316 "temporarily.")); |
| |
317 break; |
| |
318 case MSN_ERROR_AUTH: |
| |
319 gc->wants_to_die = TRUE; |
| |
320 msg = g_strdup_printf(_("Unable to authenticate: %s"), |
| |
321 (info == NULL ) ? |
| |
322 _("Unknown error") : info); |
| |
323 break; |
| |
324 case MSN_ERROR_BAD_BLIST: |
| |
325 msg = g_strdup(_("Your MSN buddy list is temporarily " |
| |
326 "unavailable. Please wait and try " |
| |
327 "again.")); |
| |
328 break; |
| |
329 default: |
| |
330 msg = g_strdup(_("Unknown error.")); |
| |
331 break; |
| |
332 } |
| |
333 |
| |
334 msn_session_disconnect(session); |
| |
335 |
| |
336 purple_connection_error(gc, msg); |
| |
337 |
| |
338 g_free(msg); |
| |
339 } |
| |
340 |
| |
341 static const char * |
| |
342 get_login_step_text(MsnSession *session) |
| |
343 { |
| |
344 const char *steps_text[] = { |
| |
345 _("Connecting"), |
| |
346 _("Handshaking"), |
| |
347 _("Transferring"), |
| |
348 _("Handshaking"), |
| |
349 _("Starting authentication"), |
| |
350 _("Getting cookie"), |
| |
351 _("Authenticating"), |
| |
352 _("Sending cookie"), |
| |
353 _("Retrieving buddy list") |
| |
354 }; |
| |
355 |
| |
356 return steps_text[session->login_step]; |
| |
357 } |
| |
358 |
| |
359 void |
| |
360 msn_session_set_login_step(MsnSession *session, MsnLoginStep step) |
| |
361 { |
| |
362 PurpleConnection *gc; |
| |
363 |
| |
364 /* Prevent the connection progress going backwards, eg. if we get |
| |
365 * transferred several times during login */ |
| |
366 if (session->login_step > step) |
| |
367 return; |
| |
368 |
| |
369 /* If we're already logged in, we're probably here because of a |
| |
370 * mid-session XFR from the notification server, so we don't want to |
| |
371 * popup the connection progress dialog */ |
| |
372 if (session->logged_in) |
| |
373 return; |
| |
374 |
| |
375 gc = session->account->gc; |
| |
376 |
| |
377 session->login_step = step; |
| |
378 |
| |
379 purple_connection_update_progress(gc, get_login_step_text(session), step, |
| |
380 MSN_LOGIN_STEPS); |
| |
381 } |
| |
382 |
| |
383 void |
| |
384 msn_session_finish_login(MsnSession *session) |
| |
385 { |
| |
386 PurpleAccount *account; |
| |
387 PurpleConnection *gc; |
| |
388 PurpleStoredImage *img; |
| |
389 const char *passport; |
| |
390 |
| |
391 if (session->logged_in) |
| |
392 return; |
| |
393 |
| |
394 account = session->account; |
| |
395 gc = purple_account_get_connection(account); |
| |
396 |
| |
397 img = purple_buddy_icons_find_account_icon(session->account); |
| |
398 msn_user_set_buddy_icon(session->user, img); |
| |
399 purple_imgstore_unref(img); |
| |
400 |
| |
401 session->logged_in = TRUE; |
| |
402 |
| |
403 msn_change_status(session); |
| |
404 |
| |
405 purple_connection_set_state(gc, PURPLE_CONNECTED); |
| |
406 |
| |
407 /* Sync users */ |
| |
408 msn_session_sync_users(session); |
| |
409 /* It seems that some accounts that haven't accessed hotmail for a while |
| |
410 * and @msn.com accounts don't automatically get the initial email |
| |
411 * notification so we always request it on login |
| |
412 */ |
| |
413 |
| |
414 passport = purple_normalize(account, purple_account_get_username(account)); |
| |
415 |
| |
416 if ((strstr(passport, "@hotmail.") != NULL) || |
| |
417 (strstr(passport, "@msn.com") != NULL)) |
| |
418 { |
| |
419 msn_cmdproc_send(session->notification->cmdproc, "URL", "%s", "INBOX"); |
| |
420 } |
| |
421 } |