Mercurial > pidgin
comparison libpurple/protocols/silc/silc.c @ 21044:6b02dba5bf41
Patch from Pekka Riikone to fix various SILC issues.
Fixes: #3103
author | Ethan Blanton <elb@pidgin.im> |
---|---|
date | Mon, 29 Oct 2007 00:19:53 +0000 |
parents | 9683da821d15 |
children | 6de09629f091 |
comparison
equal
deleted
inserted
replaced
21043:6b9e304272e4 | 21044:6b02dba5bf41 |
---|---|
126 SilcPurple sg = gc->proto_data; | 126 SilcPurple sg = gc->proto_data; |
127 silc_packet_send(sg->conn->stream, SILC_PACKET_HEARTBEAT, 0, | 127 silc_packet_send(sg->conn->stream, SILC_PACKET_HEARTBEAT, 0, |
128 NULL, 0); | 128 NULL, 0); |
129 } | 129 } |
130 | 130 |
131 #if __SILC_TOOLKIT_VERSION < SILC_VERSION(1,1,1) | |
131 static gboolean | 132 static gboolean |
132 silcpurple_scheduler(gpointer *context) | 133 silcpurple_scheduler(gpointer *context) |
133 { | 134 { |
134 SilcClient client = (SilcClient)context; | 135 SilcClient client = (SilcClient)context; |
135 silc_client_run_one(client); | 136 silc_client_run_one(client); |
136 return TRUE; | 137 return TRUE; |
137 } | 138 } |
139 #else | |
140 typedef struct { | |
141 SilcPurple sg; | |
142 SilcUInt32 fd; | |
143 guint tag; | |
144 } *SilcPurpleTask; | |
145 | |
146 /* A timeout occurred. Call SILC scheduler. */ | |
147 | |
148 static gboolean | |
149 silcpurple_scheduler_timeout(gpointer context) | |
150 { | |
151 SilcPurpleTask task = (SilcPurpleTask)context; | |
152 silc_client_run_one(task->sg->client); | |
153 silc_dlist_del(task->sg->tasks, task); | |
154 silc_free(task); | |
155 return FALSE; | |
156 } | |
157 | |
158 /* An fd task event occurred. Call SILC scheduler. */ | |
159 | |
160 static void | |
161 silcpurple_scheduler_fd(gpointer data, gint fd, PurpleInputCondition cond) | |
162 { | |
163 SilcClient client = (SilcClient)data; | |
164 silc_client_run_one(client); | |
165 } | |
166 | |
167 /* SILC Scheduler notify callback. This is called whenever task is added to | |
168 or deleted from SILC scheduler. It's also called when fd task events | |
169 change. Here we add same tasks to glib's main loop. */ | |
170 | |
171 static void | |
172 silcpurple_scheduler(SilcSchedule schedule, | |
173 SilcBool added, SilcTask task, | |
174 SilcBool fd_task, SilcUInt32 fd, | |
175 SilcTaskEvent event, | |
176 long seconds, long useconds, | |
177 void *context) | |
178 { | |
179 SilcClient client = (SilcClient)context; | |
180 PurpleConnection *gc = client->application; | |
181 SilcPurple sg = gc->proto_data; | |
182 SilcPurpleTask ptask = NULL; | |
183 | |
184 if (added) { | |
185 if (fd_task) { | |
186 /* Add fd or change fd events */ | |
187 PurpleInputCondition e = 0; | |
188 | |
189 silc_dlist_start(sg->tasks); | |
190 while ((ptask = silc_dlist_get(sg->tasks))) | |
191 if (ptask->fd == fd) { | |
192 purple_input_remove(ptask->tag); | |
193 break; | |
194 } | |
195 | |
196 if (event & SILC_TASK_READ) | |
197 e |= PURPLE_INPUT_READ; | |
198 if (event & SILC_TASK_WRITE) | |
199 e |= PURPLE_INPUT_WRITE; | |
200 | |
201 if (e) { | |
202 if (!ptask) { | |
203 ptask = silc_calloc(1, sizeof(*ptask)); | |
204 ptask->fd = fd; | |
205 silc_dlist_add(sg->tasks, ptask); | |
206 } | |
207 ptask->tag = purple_input_add(fd, e, silcpurple_scheduler_fd, | |
208 client); | |
209 } else if (ptask) { | |
210 silc_dlist_del(sg->tasks, ptask); | |
211 silc_free(ptask); | |
212 } | |
213 } else { | |
214 /* Add timeout */ | |
215 ptask = silc_calloc(1, sizeof(*ptask)); | |
216 ptask->sg = sg; | |
217 ptask->tag = purple_timeout_add((seconds * 1000) + | |
218 (useconds / 1000), | |
219 silcpurple_scheduler_timeout, | |
220 ptask); | |
221 silc_dlist_add(sg->tasks, ptask); | |
222 } | |
223 } else { | |
224 if (fd_task) { | |
225 /* Remove fd */ | |
226 silc_dlist_start(sg->tasks); | |
227 while ((ptask = silc_dlist_get(sg->tasks))) | |
228 if (ptask->fd == fd) { | |
229 purple_input_remove(ptask->tag); | |
230 silc_dlist_del(sg->tasks, ptask); | |
231 silc_free(ptask); | |
232 break; | |
233 } | |
234 } | |
235 } | |
236 } | |
237 #endif /* __SILC_TOOLKIT_VERSION */ | |
138 | 238 |
139 static void | 239 static void |
140 silcpurple_connect_cb(SilcClient client, SilcClientConnection conn, | 240 silcpurple_connect_cb(SilcClient client, SilcClientConnection conn, |
141 SilcClientConnectionStatus status, SilcStatus error, | 241 SilcClientConnectionStatus status, SilcStatus error, |
142 const char *message, void *context) | 242 const char *message, void *context) |
314 silc_free(sg); | 414 silc_free(sg); |
315 gc->proto_data = NULL; | 415 gc->proto_data = NULL; |
316 return; | 416 return; |
317 } | 417 } |
318 | 418 |
419 silc_hash_alloc("sha1", &sg->sha1hash); | |
420 | |
319 /* Wrap socket to TCP stream */ | 421 /* Wrap socket to TCP stream */ |
320 silc_socket_tcp_stream_create(source, TRUE, FALSE, | 422 silc_socket_tcp_stream_create(source, TRUE, FALSE, |
321 sg->client->schedule, | 423 sg->client->schedule, |
322 silcpurple_stream_created, gc); | 424 silcpurple_stream_created, gc); |
323 } | 425 } |
324 | 426 |
325 static void silcpurple_running(SilcClient client, void *context) | 427 static void silcpurple_running(SilcClient client, void *context) |
326 { | 428 { |
327 PurpleAccount *account = context; | 429 SilcPurple sg = context; |
328 PurpleConnection *gc = account->gc; | 430 PurpleConnection *gc = sg->gc; |
329 SilcPurple sg; | 431 PurpleAccount *account = purple_connection_get_account(gc); |
330 char pkd[256], prd[256]; | 432 char pkd[256], prd[256]; |
331 | |
332 sg = silc_calloc(1, sizeof(*sg)); | |
333 if (!sg) | |
334 return; | |
335 memset(sg, 0, sizeof(*sg)); | |
336 sg->client = client; | |
337 sg->gc = gc; | |
338 sg->account = account; | |
339 sg->scheduler = SILC_PTR_TO_32(gc->proto_data); | |
340 gc->proto_data = sg; | |
341 | 433 |
342 /* Progress */ | 434 /* Progress */ |
343 purple_connection_update_progress(gc, _("Connecting to SILC Server"), 1, 5); | 435 purple_connection_update_progress(gc, _("Connecting to SILC Server"), 1, 5); |
344 | 436 |
345 /* Load SILC key pair */ | 437 /* Load SILC key pair */ |
373 static void | 465 static void |
374 silcpurple_login(PurpleAccount *account) | 466 silcpurple_login(PurpleAccount *account) |
375 { | 467 { |
376 SilcClient client; | 468 SilcClient client; |
377 PurpleConnection *gc; | 469 PurpleConnection *gc; |
470 SilcPurple sg; | |
378 SilcClientParams params; | 471 SilcClientParams params; |
379 const char *cipher, *hmac; | 472 const char *cipher, *hmac; |
380 char *username, *hostname, *realname, **up; | 473 char *username, *hostname, *realname, **up; |
381 guint scheduler; | |
382 int i; | 474 int i; |
383 | 475 |
384 gc = account->gc; | 476 gc = account->gc; |
385 if (!gc) | 477 if (!gc) |
386 return; | 478 return; |
429 if (!strcmp(silc_default_hmacs[i].name, hmac)) { | 521 if (!strcmp(silc_default_hmacs[i].name, hmac)) { |
430 silc_hmac_register(&(silc_default_hmacs[i])); | 522 silc_hmac_register(&(silc_default_hmacs[i])); |
431 break; | 523 break; |
432 } | 524 } |
433 | 525 |
526 sg = silc_calloc(1, sizeof(*sg)); | |
527 if (!sg) | |
528 return; | |
529 sg->client = client; | |
530 sg->gc = gc; | |
531 sg->account = account; | |
532 gc->proto_data = sg; | |
533 | |
434 /* Init SILC client */ | 534 /* Init SILC client */ |
435 if (!silc_client_init(client, username, hostname, realname, | 535 if (!silc_client_init(client, username, hostname, realname, |
436 silcpurple_running, account)) { | 536 silcpurple_running, sg)) { |
437 gc->wants_to_die = TRUE; | 537 gc->wants_to_die = TRUE; |
438 purple_connection_error(gc, _("Cannot initialize SILC protocol")); | 538 purple_connection_error(gc, _("Cannot initialize SILC protocol")); |
539 gc->proto_data = NULL; | |
540 silc_free(sg); | |
439 return; | 541 return; |
440 } | 542 } |
441 | 543 |
442 /* Check the ~/.silc dir and create it, and new key pair if necessary. */ | 544 /* Check the ~/.silc dir and create it, and new key pair if necessary. */ |
443 if (!silcpurple_check_silc_dir(gc)) { | 545 if (!silcpurple_check_silc_dir(gc)) { |
444 gc->wants_to_die = TRUE; | 546 gc->wants_to_die = TRUE; |
445 purple_connection_error(gc, _("Error loading SILC key pair")); | 547 purple_connection_error(gc, _("Error loading SILC key pair")); |
446 return; | 548 gc->proto_data = NULL; |
447 } | 549 silc_free(sg); |
448 | 550 return; |
551 } | |
552 | |
553 #if __SILC_TOOLKIT_VERSION < SILC_VERSION(1,1,1) | |
449 /* Schedule SILC using Glib's event loop */ | 554 /* Schedule SILC using Glib's event loop */ |
450 scheduler = purple_timeout_add(300, (GSourceFunc)silcpurple_scheduler, client); | 555 sg->scheduler = purple_timeout_add(300, (GSourceFunc)silcpurple_scheduler, client); |
451 gc->proto_data = SILC_32_TO_PTR(scheduler); | 556 #else |
557 /* Run SILC scheduler */ | |
558 sg->tasks = silc_dlist_init(); | |
559 silc_schedule_set_notify(client->schedule, silcpurple_scheduler, | |
560 client); | |
561 silc_client_run_one(client); | |
562 #endif /* __SILC_TOOLKIT_VERSION */ | |
452 } | 563 } |
453 | 564 |
454 static int | 565 static int |
455 silcpurple_close_final(gpointer *context) | 566 silcpurple_close_final(gpointer *context) |
456 { | 567 { |
457 SilcPurple sg = (SilcPurple)context; | 568 SilcPurple sg = (SilcPurple)context; |
569 | |
458 silc_client_stop(sg->client, NULL, NULL); | 570 silc_client_stop(sg->client, NULL, NULL); |
459 silc_client_free(sg->client); | 571 silc_client_free(sg->client); |
572 if (sg->sha1hash) | |
573 silc_hash_free(sg->sha1hash); | |
460 if (sg->mimeass) | 574 if (sg->mimeass) |
461 silc_mime_assembler_free(sg->mimeass); | 575 silc_mime_assembler_free(sg->mimeass); |
462 silc_free(sg); | 576 silc_free(sg); |
463 return 0; | 577 return 0; |
464 } | 578 } |
465 | 579 |
466 static void | 580 static void |
467 silcpurple_close(PurpleConnection *gc) | 581 silcpurple_close(PurpleConnection *gc) |
468 { | 582 { |
469 SilcPurple sg = gc->proto_data; | 583 SilcPurple sg = gc->proto_data; |
584 #if __SILC_TOOLKIT_VERSION >= SILC_VERSION(1,1,1) | |
585 SilcPurpleTask task; | |
586 #endif /* __SILC_TOOLKIT_VERSION */ | |
470 | 587 |
471 g_return_if_fail(sg != NULL); | 588 g_return_if_fail(sg != NULL); |
472 | 589 |
473 /* Send QUIT */ | 590 /* Send QUIT */ |
474 silc_client_command_call(sg->client, sg->conn, NULL, | 591 silc_client_command_call(sg->client, sg->conn, NULL, |
475 "QUIT", "Download Pidgin: " PURPLE_WEBSITE, NULL); | 592 "QUIT", "Download Pidgin: " PURPLE_WEBSITE, |
593 NULL); | |
476 | 594 |
477 if (sg->conn) | 595 if (sg->conn) |
478 silc_client_close_connection(sg->client, sg->conn); | 596 silc_client_close_connection(sg->client, sg->conn); |
597 | |
598 #if __SILC_TOOLKIT_VERSION >= SILC_VERSION(1,1,1) | |
599 if (sg->conn) | |
600 silc_client_run_one(sg->client); | |
601 silc_schedule_set_notify(sg->client->schedule, NULL, NULL); | |
602 | |
603 silc_dlist_start(sg->tasks); | |
604 while ((task = silc_dlist_get(sg->tasks))) { | |
605 purple_input_remove(task->tag); | |
606 silc_free(task); | |
607 } | |
608 silc_dlist_uninit(sg->tasks); | |
609 #endif /* __SILC_TOOLKIT_VERSION */ | |
479 | 610 |
480 purple_timeout_remove(sg->scheduler); | 611 purple_timeout_remove(sg->scheduler); |
481 purple_timeout_add(1, (GSourceFunc)silcpurple_close_final, sg); | 612 purple_timeout_add(1, (GSourceFunc)silcpurple_close_final, sg); |
482 } | 613 } |
483 | 614 |
1153 SilcBuffer buf; | 1284 SilcBuffer buf; |
1154 | 1285 |
1155 silc_dlist_start(list); | 1286 silc_dlist_start(list); |
1156 while ((buf = silc_dlist_get(list)) != SILC_LIST_END) | 1287 while ((buf = silc_dlist_get(list)) != SILC_LIST_END) |
1157 silc_client_send_private_message(client, conn, | 1288 silc_client_send_private_message(client, conn, |
1158 client_entry, im->flags, NULL, | 1289 client_entry, im->flags, sg->sha1hash, |
1159 buf->data, | 1290 buf->data, |
1160 silc_buffer_len(buf)); | 1291 silc_buffer_len(buf)); |
1161 silc_mime_partial_free(list); | 1292 silc_mime_partial_free(list); |
1162 purple_conv_im_write(PURPLE_CONV_IM(convo), conn->local_entry->nickname, | 1293 purple_conv_im_write(PURPLE_CONV_IM(convo), conn->local_entry->nickname, |
1163 im->message, 0, time(NULL)); | 1294 im->message, 0, time(NULL)); |
1165 } | 1296 } |
1166 } | 1297 } |
1167 | 1298 |
1168 /* Send the message */ | 1299 /* Send the message */ |
1169 silc_client_send_private_message(client, conn, client_entry, im->flags, | 1300 silc_client_send_private_message(client, conn, client_entry, im->flags, |
1170 NULL, (unsigned char *)im->message, im->message_len); | 1301 sg->sha1hash, (unsigned char *)im->message, im->message_len); |
1171 purple_conv_im_write(PURPLE_CONV_IM(convo), conn->local_entry->nickname, | 1302 purple_conv_im_write(PURPLE_CONV_IM(convo), conn->local_entry->nickname, |
1172 im->message, 0, time(NULL)); | 1303 im->message, 0, time(NULL)); |
1173 goto out; | 1304 goto out; |
1174 | 1305 |
1175 err: | 1306 err: |
1257 | 1388 |
1258 silc_dlist_start(list); | 1389 silc_dlist_start(list); |
1259 while ((buf = silc_dlist_get(list)) != SILC_LIST_END) | 1390 while ((buf = silc_dlist_get(list)) != SILC_LIST_END) |
1260 ret = | 1391 ret = |
1261 silc_client_send_private_message(client, conn, | 1392 silc_client_send_private_message(client, conn, |
1262 client_entry, mflags, NULL, | 1393 client_entry, mflags, sg->sha1hash, |
1263 buf->data, | 1394 buf->data, |
1264 silc_buffer_len(buf)); | 1395 silc_buffer_len(buf)); |
1265 silc_mime_partial_free(list); | 1396 silc_mime_partial_free(list); |
1266 g_free(tmp); | 1397 g_free(tmp); |
1267 silc_client_list_free(client, conn, clients); | 1398 silc_client_list_free(client, conn, clients); |
1269 } | 1400 } |
1270 } | 1401 } |
1271 | 1402 |
1272 /* Send private message directly */ | 1403 /* Send private message directly */ |
1273 ret = silc_client_send_private_message(client, conn, client_entry, | 1404 ret = silc_client_send_private_message(client, conn, client_entry, |
1274 mflags, NULL, | 1405 mflags, sg->sha1hash, |
1275 (unsigned char *)msg, | 1406 (unsigned char *)msg, |
1276 strlen(msg)); | 1407 strlen(msg)); |
1277 | 1408 |
1278 g_free(tmp); | 1409 g_free(tmp); |
1279 silc_client_list_free(client, conn, clients); | 1410 silc_client_list_free(client, conn, clients); |