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);