1 /*
2
3 silcpurple.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2004 - 2007 Pekka Riikonen
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 */
19
20 #include "internal.h"
21 #include "silc.h"
22 #include "silcclient.h"
23 #include "silcpurple.h"
24 #include "version.h"
25 #include "wb.h"
26 #include "core.h"
27
28 extern SilcClientOperations ops;
29 static PurplePlugin *silc_plugin = NULL;
30
31 /* Error log message callback */
32
silcpurple_log_error(SilcLogType type,char * message,void * context)33 static SilcBool silcpurple_log_error(SilcLogType type, char *message,
34 void *context)
35 {
36 silc_say(NULL, NULL, SILC_CLIENT_MESSAGE_ERROR, message);
37 return TRUE;
38 }
39
40 static const char *
silcpurple_list_icon(PurpleAccount * a,PurpleBuddy * b)41 silcpurple_list_icon(PurpleAccount *a, PurpleBuddy *b)
42 {
43 return (const char *)"silc";
44 }
45
46 static GList *
silcpurple_away_states(PurpleAccount * account)47 silcpurple_away_states(PurpleAccount *account)
48 {
49 PurpleStatusType *type;
50 GList *types = NULL;
51
52 type = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE, SILCPURPLE_STATUS_ID_AVAILABLE, NULL, TRUE, TRUE, FALSE);
53 types = g_list_append(types, type);
54 type = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE, SILCPURPLE_STATUS_ID_HYPER, _("Hyper Active"), TRUE, TRUE, FALSE);
55 types = g_list_append(types, type);
56 type = purple_status_type_new_full(PURPLE_STATUS_AWAY, SILCPURPLE_STATUS_ID_AWAY, NULL, TRUE, TRUE, FALSE);
57 types = g_list_append(types, type);
58 type = purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE, SILCPURPLE_STATUS_ID_BUSY, _("Busy"), TRUE, TRUE, FALSE);
59 types = g_list_append(types, type);
60 type = purple_status_type_new_full(PURPLE_STATUS_AWAY, SILCPURPLE_STATUS_ID_INDISPOSED, _("Indisposed"), TRUE, TRUE, FALSE);
61 types = g_list_append(types, type);
62 type = purple_status_type_new_full(PURPLE_STATUS_AWAY, SILCPURPLE_STATUS_ID_PAGE, _("Wake Me Up"), TRUE, TRUE, FALSE);
63 types = g_list_append(types, type);
64 type = purple_status_type_new_full(PURPLE_STATUS_OFFLINE, SILCPURPLE_STATUS_ID_OFFLINE, NULL, TRUE, TRUE, FALSE);
65 types = g_list_append(types, type);
66
67 return types;
68 }
69
70 static void
silcpurple_set_status(PurpleAccount * account,PurpleStatus * status)71 silcpurple_set_status(PurpleAccount *account, PurpleStatus *status)
72 {
73 PurpleConnection *gc = purple_account_get_connection(account);
74 SilcPurple sg = NULL;
75 SilcUInt32 mode;
76 SilcBuffer idp;
77 unsigned char mb[4];
78 const char *state;
79
80 if (gc != NULL)
81 sg = gc->proto_data;
82
83 if (status == NULL)
84 return;
85
86 state = purple_status_get_id(status);
87
88 if (state == NULL)
89 return;
90
91 if ((sg == NULL) || (sg->conn == NULL))
92 return;
93
94 mode = sg->conn->local_entry->mode;
95 mode &= ~(SILC_UMODE_GONE |
96 SILC_UMODE_HYPER |
97 SILC_UMODE_BUSY |
98 SILC_UMODE_INDISPOSED |
99 SILC_UMODE_PAGE);
100
101 if (purple_strequal(state, "hyper"))
102 mode |= SILC_UMODE_HYPER;
103 else if (purple_strequal(state, "away"))
104 mode |= SILC_UMODE_GONE;
105 else if (purple_strequal(state, "busy"))
106 mode |= SILC_UMODE_BUSY;
107 else if (purple_strequal(state, "indisposed"))
108 mode |= SILC_UMODE_INDISPOSED;
109 else if (purple_strequal(state, "page"))
110 mode |= SILC_UMODE_PAGE;
111
112 /* Send UMODE */
113 idp = silc_id_payload_encode(sg->conn->local_id, SILC_ID_CLIENT);
114 SILC_PUT32_MSB(mode, mb);
115 silc_client_command_send(sg->client, sg->conn, SILC_COMMAND_UMODE,
116 silcpurple_command_reply, NULL, 2,
117 1, idp->data, silc_buffer_len(idp),
118 2, mb, sizeof(mb));
119 silc_buffer_free(idp);
120 }
121
122
123 /*************************** Connection Routines *****************************/
124
125 static void
silcpurple_keepalive(PurpleConnection * gc)126 silcpurple_keepalive(PurpleConnection *gc)
127 {
128 SilcPurple sg = gc->proto_data;
129 silc_packet_send(sg->conn->stream, SILC_PACKET_HEARTBEAT, 0,
130 NULL, 0);
131 }
132
133 #if __SILC_TOOLKIT_VERSION < SILC_VERSION(1,1,1)
134 static gboolean
silcpurple_scheduler(gpointer * context)135 silcpurple_scheduler(gpointer *context)
136 {
137 SilcClient client = (SilcClient)context;
138 silc_client_run_one(client);
139 return TRUE;
140 }
141 #else
142 typedef struct {
143 SilcPurple sg;
144 SilcUInt32 fd;
145 guint tag;
146 } *SilcPurpleTask;
147
148 /* A timeout occurred. Call SILC scheduler. */
149
150 static gboolean
silcpurple_scheduler_timeout(gpointer context)151 silcpurple_scheduler_timeout(gpointer context)
152 {
153 SilcPurpleTask task = (SilcPurpleTask)context;
154 silc_client_run_one(task->sg->client);
155 silc_dlist_del(task->sg->tasks, task);
156 silc_free(task);
157 return FALSE;
158 }
159
160 /* An fd task event occurred. Call SILC scheduler. */
161
162 static void
silcpurple_scheduler_fd(gpointer data,gint fd,PurpleInputCondition cond)163 silcpurple_scheduler_fd(gpointer data, gint fd, PurpleInputCondition cond)
164 {
165 SilcClient client = (SilcClient)data;
166 silc_client_run_one(client);
167 }
168
169 /* SILC Scheduler notify callback. This is called whenever task is added to
170 or deleted from SILC scheduler. It's also called when fd task events
171 change. Here we add same tasks to glib's main loop. */
172
173 static void
silcpurple_scheduler(SilcSchedule schedule,SilcBool added,SilcTask task,SilcBool fd_task,SilcUInt32 fd,SilcTaskEvent event,long seconds,long useconds,void * context)174 silcpurple_scheduler(SilcSchedule schedule,
175 SilcBool added, SilcTask task,
176 SilcBool fd_task, SilcUInt32 fd,
177 SilcTaskEvent event,
178 long seconds, long useconds,
179 void *context)
180 {
181 SilcClient client = (SilcClient)context;
182 PurpleConnection *gc = client->application;
183 SilcPurple sg = gc->proto_data;
184 SilcPurpleTask ptask = NULL;
185
186 if (added) {
187 if (fd_task) {
188 /* Add fd or change fd events */
189 PurpleInputCondition e = 0;
190
191 silc_dlist_start(sg->tasks);
192 while ((ptask = silc_dlist_get(sg->tasks)))
193 if (ptask->fd == fd) {
194 purple_input_remove(ptask->tag);
195 break;
196 }
197
198 if (event & SILC_TASK_READ)
199 e |= PURPLE_INPUT_READ;
200 if (event & SILC_TASK_WRITE)
201 e |= PURPLE_INPUT_WRITE;
202
203 if (e) {
204 if (!ptask) {
205 ptask = silc_calloc(1, sizeof(*ptask));
206 ptask->fd = fd;
207 silc_dlist_add(sg->tasks, ptask);
208 }
209 ptask->tag = purple_input_add(fd, e, silcpurple_scheduler_fd,
210 client);
211 } else if (ptask) {
212 silc_dlist_del(sg->tasks, ptask);
213 silc_free(ptask);
214 }
215 } else {
216 /* Add timeout */
217 ptask = silc_calloc(1, sizeof(*ptask));
218 ptask->sg = sg;
219 ptask->tag = purple_timeout_add((seconds * 1000) +
220 (useconds / 1000),
221 silcpurple_scheduler_timeout,
222 ptask);
223 silc_dlist_add(sg->tasks, ptask);
224 }
225 } else {
226 if (fd_task) {
227 /* Remove fd */
228 silc_dlist_start(sg->tasks);
229 while ((ptask = silc_dlist_get(sg->tasks)))
230 if (ptask->fd == fd) {
231 purple_input_remove(ptask->tag);
232 silc_dlist_del(sg->tasks, ptask);
233 silc_free(ptask);
234 break;
235 }
236 }
237 }
238 }
239 #endif /* __SILC_TOOLKIT_VERSION */
240
241 static void
silcpurple_connect_cb(SilcClient client,SilcClientConnection conn,SilcClientConnectionStatus status,SilcStatus error,const char * message,void * context)242 silcpurple_connect_cb(SilcClient client, SilcClientConnection conn,
243 SilcClientConnectionStatus status, SilcStatus error,
244 const char *message, void *context)
245 {
246 PurpleConnection *gc = context;
247 SilcPurple sg;
248 SilcUInt32 mask;
249 char tz[16];
250 PurpleStoredImage *img;
251 #ifdef HAVE_SYS_UTSNAME_H
252 struct utsname u;
253 #endif
254
255 sg = gc->proto_data;
256
257 switch (status) {
258 case SILC_CLIENT_CONN_SUCCESS:
259 case SILC_CLIENT_CONN_SUCCESS_RESUME:
260 sg->conn = conn;
261
262 /* Connection created successfully */
263 purple_connection_set_state(gc, PURPLE_CONNECTED);
264
265 /* Send the server our buddy list */
266 silcpurple_send_buddylist(gc);
267
268 g_unlink(silcpurple_session_file(purple_account_get_username(sg->account)));
269
270 /* Send any UMODEs configured for account */
271 if (purple_account_get_bool(sg->account, "block-ims", FALSE)) {
272 silc_client_command_call(sg->client, sg->conn, NULL,
273 "UMODE", "+P", NULL);
274 }
275
276 /* Set default attributes */
277 mask = SILC_ATTRIBUTE_MOOD_NORMAL;
278 silc_client_attribute_add(client, conn,
279 SILC_ATTRIBUTE_STATUS_MOOD,
280 SILC_32_TO_PTR(mask),
281 sizeof(SilcUInt32));
282 mask = SILC_ATTRIBUTE_CONTACT_CHAT;
283 silc_client_attribute_add(client, conn,
284 SILC_ATTRIBUTE_PREFERRED_CONTACT,
285 SILC_32_TO_PTR(mask),
286 sizeof(SilcUInt32));
287 #ifdef HAVE_SYS_UTSNAME_H
288 if (!uname(&u)) {
289 SilcAttributeObjDevice dev;
290 memset(&dev, 0, sizeof(dev));
291 dev.type = SILC_ATTRIBUTE_DEVICE_COMPUTER;
292 dev.version = u.release;
293 dev.model = u.sysname;
294 silc_client_attribute_add(client, conn,
295 SILC_ATTRIBUTE_DEVICE_INFO,
296 (void *)&dev, sizeof(dev));
297 }
298 #endif
299 silc_timezone(tz, sizeof(tz));
300 silc_client_attribute_add(client, conn,
301 SILC_ATTRIBUTE_TIMEZONE,
302 (void *)tz, strlen(tz));
303
304 /* Set our buddy icon */
305 img = purple_buddy_icons_find_account_icon(sg->account);
306 silcpurple_buddy_set_icon(gc, img);
307 purple_imgstore_unref(img);
308
309 return;
310 break;
311
312 case SILC_CLIENT_CONN_DISCONNECTED:
313 /* Disconnected */
314 if (sg->resuming && !sg->detaching)
315 g_unlink(silcpurple_session_file(purple_account_get_username(sg->account)));
316
317 /* Close the connection */
318 if (!sg->detaching)
319 purple_connection_error_reason(gc,
320 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
321 _("Disconnected by server"));
322 else
323 /* TODO: Does this work correctly? Maybe we need to set wants_to_die? */
324 purple_account_disconnect(purple_connection_get_account(gc));
325 break;
326
327 case SILC_CLIENT_CONN_ERROR:
328 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
329 _("Error connecting to SILC Server"));
330 g_unlink(silcpurple_session_file(purple_account_get_username(sg->account)));
331 break;
332
333 case SILC_CLIENT_CONN_ERROR_KE:
334 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
335 _("Key Exchange failed"));
336 break;
337
338 case SILC_CLIENT_CONN_ERROR_AUTH:
339 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
340 _("Authentication failed"));
341 break;
342
343 case SILC_CLIENT_CONN_ERROR_RESUME:
344 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
345 _("Resuming detached session failed. "
346 "Press Reconnect to create new connection."));
347 g_unlink(silcpurple_session_file(purple_account_get_username(sg->account)));
348 break;
349
350 case SILC_CLIENT_CONN_ERROR_TIMEOUT:
351 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
352 _("Connection timed out"));
353 break;
354 }
355
356 /* Error */
357 sg->conn = NULL;
358 }
359
360 static void
silcpurple_stream_created(SilcSocketStreamStatus status,SilcStream stream,void * context)361 silcpurple_stream_created(SilcSocketStreamStatus status, SilcStream stream,
362 void *context)
363 {
364 PurpleConnection *gc = context;
365 SilcPurple sg;
366 SilcClient client;
367 SilcClientConnectionParams params;
368 const char *dfile;
369
370 sg = gc->proto_data;
371
372 if (status != SILC_SOCKET_OK) {
373 purple_connection_error_reason(gc,
374 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
375 _("Connection failed"));
376 silc_pkcs_public_key_free(sg->public_key);
377 silc_pkcs_private_key_free(sg->private_key);
378 silc_free(sg);
379 gc->proto_data = NULL;
380 return;
381 }
382
383 client = sg->client;
384
385 /* Get session detachment data, if available */
386 memset(¶ms, 0, sizeof(params));
387 dfile = silcpurple_session_file(purple_account_get_username(sg->account));
388 params.detach_data = (unsigned char *)silc_file_readfile(dfile, ¶ms.detach_data_len);
389 if (params.detach_data)
390 params.detach_data[params.detach_data_len] = 0;
391 params.ignore_requested_attributes = FALSE;
392 params.pfs = purple_account_get_bool(sg->account, "pfs", FALSE);
393
394 /* Progress */
395 if (params.detach_data) {
396 purple_connection_update_progress(gc, _("Resuming session"), 2, 5);
397 sg->resuming = TRUE;
398 } else {
399 purple_connection_update_progress(gc, _("Performing key exchange"), 2, 5);
400 }
401
402 /* Perform SILC Key Exchange. */
403 silc_client_key_exchange(client, ¶ms, sg->public_key,
404 sg->private_key, stream, SILC_CONN_SERVER,
405 silcpurple_connect_cb, gc);
406
407 silc_free(params.detach_data);
408 }
409
410 static void
silcpurple_login_connected(gpointer data,gint source,const gchar * error_message)411 silcpurple_login_connected(gpointer data, gint source, const gchar *error_message)
412 {
413 PurpleConnection *gc = data;
414 SilcPurple sg;
415
416 g_return_if_fail(gc != NULL);
417
418 sg = gc->proto_data;
419
420 if (source < 0) {
421 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
422 _("Connection failed"));
423 silc_pkcs_public_key_free(sg->public_key);
424 silc_pkcs_private_key_free(sg->private_key);
425 silc_free(sg);
426 gc->proto_data = NULL;
427 return;
428 }
429
430 silc_hash_alloc((unsigned char *)"sha1", &sg->sha1hash);
431
432 /* Wrap socket to TCP stream */
433 silc_socket_tcp_stream_create(source, TRUE, FALSE,
434 sg->client->schedule,
435 silcpurple_stream_created, gc);
436 }
437
silcpurple_continue_running(SilcPurple sg)438 static void silcpurple_continue_running(SilcPurple sg)
439 {
440 PurpleConnection *gc = sg->gc;
441 PurpleAccount *account = purple_connection_get_account(gc);
442
443 /* Connect to the SILC server */
444 if (purple_proxy_connect(gc, account,
445 purple_account_get_string(account, "server",
446 "silc.silcnet.org"),
447 purple_account_get_int(account, "port", 706),
448 silcpurple_login_connected, gc) == NULL)
449 {
450 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
451 _("Unable to connect"));
452 gc->proto_data = NULL;
453 silc_free(sg);
454 return;
455 }
456 }
457
silcpurple_got_password_cb(PurpleConnection * gc,PurpleRequestFields * fields)458 static void silcpurple_got_password_cb(PurpleConnection *gc, PurpleRequestFields *fields)
459 {
460 SilcPurple sg = (SilcPurple)gc->proto_data;
461 PurpleAccount *account = purple_connection_get_account(gc);
462 char pkd[256], prd[256];
463 const char *password;
464 gboolean remember;
465
466 /* The password prompt dialog doesn't get disposed if the account disconnects */
467 if (!PURPLE_CONNECTION_IS_VALID(gc))
468 return;
469
470 password = purple_request_fields_get_string(fields, "password");
471 remember = purple_request_fields_get_bool(fields, "remember");
472
473 if (!password || !*password)
474 {
475 purple_notify_error(gc, NULL, _("Password is required to sign on."), NULL);
476 gc->proto_data = NULL;
477 silc_free(sg);
478 return;
479 }
480
481 if (remember)
482 purple_account_set_remember_password(account, TRUE);
483
484 purple_account_set_password(account, password);
485
486 /* Load SILC key pair */
487 g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir());
488 g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir());
489 if (!silc_load_key_pair((char *)purple_account_get_string(account, "public-key", pkd),
490 (char *)purple_account_get_string(account, "private-key", prd),
491 password,
492 &sg->public_key, &sg->private_key)) {
493 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
494 _("Unable to load SILC key pair"));
495 gc->proto_data = NULL;
496 silc_free(sg);
497 return;
498 }
499 silcpurple_continue_running(sg);
500 }
501
silcpurple_no_password_cb(PurpleConnection * gc,PurpleRequestFields * fields)502 static void silcpurple_no_password_cb(PurpleConnection *gc, PurpleRequestFields *fields)
503 {
504 SilcPurple sg;
505 /* The password prompt dialog doesn't get disposed if the account disconnects */
506 if (!PURPLE_CONNECTION_IS_VALID(gc))
507 return;
508 sg = gc->proto_data;
509 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
510 _("Unable to load SILC key pair"));
511 gc->proto_data = NULL;
512 silc_free(sg);
513 }
514
silcpurple_running(SilcClient client,void * context)515 static void silcpurple_running(SilcClient client, void *context)
516 {
517 SilcPurple sg = context;
518 PurpleConnection *gc = sg->gc;
519 PurpleAccount *account = purple_connection_get_account(gc);
520 char pkd[256], prd[256];
521
522
523 /* Progress */
524 purple_connection_update_progress(gc, _("Connecting to SILC Server"), 1, 5);
525
526 /* Load SILC key pair */
527 g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir());
528 g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir());
529 if (!silc_load_key_pair((char *)purple_account_get_string(account, "public-key", pkd),
530 (char *)purple_account_get_string(account, "private-key", prd),
531 (gc->password == NULL) ? "" : gc->password,
532 &sg->public_key, &sg->private_key)) {
533 if (!purple_account_get_password(account)) {
534 purple_account_request_password(account, G_CALLBACK(silcpurple_got_password_cb),
535 G_CALLBACK(silcpurple_no_password_cb), gc);
536 return;
537 }
538 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
539 _("Unable to load SILC key pair"));
540 gc->proto_data = NULL;
541 silc_free(sg);
542 return;
543 }
544 silcpurple_continue_running(sg);
545 }
546
547 static void
silcpurple_login(PurpleAccount * account)548 silcpurple_login(PurpleAccount *account)
549 {
550 SilcClient client;
551 PurpleConnection *gc;
552 SilcPurple sg;
553 SilcClientParams params;
554 const char *cipher, *hmac;
555 char *username, *hostname, *realname, **up;
556 int i;
557
558 gc = account->gc;
559 if (!gc)
560 return;
561 gc->proto_data = NULL;
562
563 memset(¶ms, 0, sizeof(params));
564 strcat(params.nickname_format, "%n#a");
565
566 /* Allocate SILC client */
567 client = silc_client_alloc(&ops, ¶ms, gc, NULL);
568 if (!client) {
569 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
570 _("Out of memory"));
571 return;
572 }
573
574 /* Get username, real name and local hostname for SILC library */
575 if (!purple_account_get_username(account))
576 purple_account_set_username(account, silc_get_username());
577
578 username = (char *)purple_account_get_username(account);
579 up = g_strsplit(username, "@", 2);
580 username = g_strdup(up[0]);
581 g_strfreev(up);
582
583 if (!purple_account_get_user_info(account)) {
584 purple_account_set_user_info(account, silc_get_real_name());
585 if (!purple_account_get_user_info(account))
586 purple_account_set_user_info(account,
587 "John T. Noname");
588 }
589 realname = (char *)purple_account_get_user_info(account);
590 hostname = silc_net_localhost();
591
592 purple_connection_set_display_name(gc, username);
593
594 /* Register requested cipher and HMAC */
595 cipher = purple_account_get_string(account, "cipher",
596 SILC_DEFAULT_CIPHER);
597 for (i = 0; silc_default_ciphers[i].name; i++)
598 if (purple_strequal(silc_default_ciphers[i].name, cipher)) {
599 silc_cipher_register(&(silc_default_ciphers[i]));
600 break;
601 }
602 hmac = purple_account_get_string(account, "hmac", SILC_DEFAULT_HMAC);
603 for (i = 0; silc_default_hmacs[i].name; i++)
604 if (purple_strequal(silc_default_hmacs[i].name, hmac)) {
605 silc_hmac_register(&(silc_default_hmacs[i]));
606 break;
607 }
608
609 sg = silc_calloc(1, sizeof(*sg));
610 if (!sg)
611 return;
612 sg->client = client;
613 sg->gc = gc;
614 sg->account = account;
615 gc->proto_data = sg;
616
617 /* Init SILC client */
618 if (!silc_client_init(client, username, hostname, realname,
619 silcpurple_running, sg)) {
620 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
621 _("Unable to initialize SILC protocol"));
622 gc->proto_data = NULL;
623 silc_free(sg);
624 silc_free(hostname);
625 g_free(username);
626 return;
627 }
628 silc_free(hostname);
629 g_free(username);
630
631 /* Check the ~/.silc dir and create it, and new key pair if necessary. */
632 if (!silcpurple_check_silc_dir(gc)) {
633 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
634 _("Error loading SILC key pair"));
635 gc->proto_data = NULL;
636 silc_free(sg);
637 return;
638 }
639
640 #if __SILC_TOOLKIT_VERSION < SILC_VERSION(1,1,1)
641 /* Schedule SILC using Glib's event loop */
642 sg->scheduler = purple_timeout_add(300, (GSourceFunc)silcpurple_scheduler, client);
643 #else
644 /* Run SILC scheduler */
645 sg->tasks = silc_dlist_init();
646 silc_schedule_set_notify(client->schedule, silcpurple_scheduler,
647 client);
648 silc_client_run_one(client);
649 #endif /* __SILC_TOOLKIT_VERSION */
650 }
651
652 static int
silcpurple_close_final(gpointer * context)653 silcpurple_close_final(gpointer *context)
654 {
655 SilcPurple sg = (SilcPurple)context;
656
657 purple_debug_info("silc", "Finalizing SilcPurple %p\n", sg);
658
659 silc_client_stop(sg->client, NULL, NULL);
660 silc_client_free(sg->client);
661 if (sg->sha1hash)
662 silc_hash_free(sg->sha1hash);
663 if (sg->mimeass)
664 silc_mime_assembler_free(sg->mimeass);
665 silc_free(sg);
666 return 0;
667 }
668
669 static void
silcpurple_close(PurpleConnection * gc)670 silcpurple_close(PurpleConnection *gc)
671 {
672 SilcPurple sg = gc->proto_data;
673 #if __SILC_TOOLKIT_VERSION >= SILC_VERSION(1,1,1)
674 SilcPurpleTask task;
675 #endif /* __SILC_TOOLKIT_VERSION */
676 GHashTable *ui_info;
677 const char *ui_name = NULL, *ui_website = NULL;
678 char *quit_msg;
679
680 g_return_if_fail(sg != NULL);
681
682 ui_info = purple_core_get_ui_info();
683
684 if(ui_info) {
685 ui_name = g_hash_table_lookup(ui_info, "name");
686 ui_website = g_hash_table_lookup(ui_info, "website");
687 }
688
689 if(!ui_name || !ui_website) {
690 ui_name = "Pidgin";
691 ui_website = PURPLE_WEBSITE;
692 }
693 quit_msg = g_strdup_printf(_("Download %s: %s"),
694 ui_name, ui_website);
695
696 /* Send QUIT */
697 silc_client_command_call(sg->client, sg->conn, NULL,
698 "QUIT", quit_msg,
699 NULL);
700 g_free(quit_msg);
701
702 if (sg->conn)
703 silc_client_close_connection(sg->client, sg->conn);
704
705 #if __SILC_TOOLKIT_VERSION >= SILC_VERSION(1,1,1)
706 if (sg->conn)
707 silc_client_run_one(sg->client);
708 silc_schedule_set_notify(sg->client->schedule, NULL, NULL);
709
710 silc_dlist_start(sg->tasks);
711 while ((task = silc_dlist_get(sg->tasks))) {
712 purple_input_remove(task->tag);
713 silc_free(task);
714 }
715 silc_dlist_uninit(sg->tasks);
716 #endif /* __SILC_TOOLKIT_VERSION */
717
718 purple_timeout_remove(sg->scheduler);
719
720 purple_debug_info("silc", "Scheduling destruction of SilcPurple %p\n", sg);
721 purple_timeout_add(1, (GSourceFunc)silcpurple_close_final, sg);
722 }
723
724
725 /****************************** Protocol Actions *****************************/
726
727 static void
silcpurple_attrs_cancel(PurpleConnection * gc,PurpleRequestFields * fields)728 silcpurple_attrs_cancel(PurpleConnection *gc, PurpleRequestFields *fields)
729 {
730 /* Nothing */
731 }
732
733 static void
silcpurple_attrs_cb(PurpleConnection * gc,PurpleRequestFields * fields)734 silcpurple_attrs_cb(PurpleConnection *gc, PurpleRequestFields *fields)
735 {
736 SilcPurple sg = gc->proto_data;
737 SilcClient client = sg->client;
738 SilcClientConnection conn = sg->conn;
739 PurpleRequestField *f;
740 char *tmp;
741 SilcUInt32 tmp_len, mask;
742 SilcAttributeObjService service;
743 SilcAttributeObjDevice dev;
744 SilcVCardStruct vcard;
745 const char *val;
746
747 sg = gc->proto_data;
748 if (!sg)
749 return;
750
751 memset(&service, 0, sizeof(service));
752 memset(&dev, 0, sizeof(dev));
753 memset(&vcard, 0, sizeof(vcard));
754
755 silc_client_attribute_del(client, conn,
756 SILC_ATTRIBUTE_USER_INFO, NULL);
757 silc_client_attribute_del(client, conn,
758 SILC_ATTRIBUTE_SERVICE, NULL);
759 silc_client_attribute_del(client, conn,
760 SILC_ATTRIBUTE_STATUS_MOOD, NULL);
761 silc_client_attribute_del(client, conn,
762 SILC_ATTRIBUTE_STATUS_FREETEXT, NULL);
763 silc_client_attribute_del(client, conn,
764 SILC_ATTRIBUTE_STATUS_MESSAGE, NULL);
765 silc_client_attribute_del(client, conn,
766 SILC_ATTRIBUTE_PREFERRED_LANGUAGE, NULL);
767 silc_client_attribute_del(client, conn,
768 SILC_ATTRIBUTE_PREFERRED_CONTACT, NULL);
769 silc_client_attribute_del(client, conn,
770 SILC_ATTRIBUTE_TIMEZONE, NULL);
771 silc_client_attribute_del(client, conn,
772 SILC_ATTRIBUTE_GEOLOCATION, NULL);
773 silc_client_attribute_del(client, conn,
774 SILC_ATTRIBUTE_DEVICE_INFO, NULL);
775
776 /* Set mood */
777 mask = 0;
778 f = purple_request_fields_get_field(fields, "mood_normal");
779 if (f && purple_request_field_bool_get_value(f))
780 mask |= SILC_ATTRIBUTE_MOOD_NORMAL;
781 f = purple_request_fields_get_field(fields, "mood_happy");
782 if (f && purple_request_field_bool_get_value(f))
783 mask |= SILC_ATTRIBUTE_MOOD_HAPPY;
784 f = purple_request_fields_get_field(fields, "mood_sad");
785 if (f && purple_request_field_bool_get_value(f))
786 mask |= SILC_ATTRIBUTE_MOOD_SAD;
787 f = purple_request_fields_get_field(fields, "mood_angry");
788 if (f && purple_request_field_bool_get_value(f))
789 mask |= SILC_ATTRIBUTE_MOOD_ANGRY;
790 f = purple_request_fields_get_field(fields, "mood_jealous");
791 if (f && purple_request_field_bool_get_value(f))
792 mask |= SILC_ATTRIBUTE_MOOD_JEALOUS;
793 f = purple_request_fields_get_field(fields, "mood_ashamed");
794 if (f && purple_request_field_bool_get_value(f))
795 mask |= SILC_ATTRIBUTE_MOOD_ASHAMED;
796 f = purple_request_fields_get_field(fields, "mood_invincible");
797 if (f && purple_request_field_bool_get_value(f))
798 mask |= SILC_ATTRIBUTE_MOOD_INVINCIBLE;
799 f = purple_request_fields_get_field(fields, "mood_inlove");
800 if (f && purple_request_field_bool_get_value(f))
801 mask |= SILC_ATTRIBUTE_MOOD_INLOVE;
802 f = purple_request_fields_get_field(fields, "mood_sleepy");
803 if (f && purple_request_field_bool_get_value(f))
804 mask |= SILC_ATTRIBUTE_MOOD_SLEEPY;
805 f = purple_request_fields_get_field(fields, "mood_bored");
806 if (f && purple_request_field_bool_get_value(f))
807 mask |= SILC_ATTRIBUTE_MOOD_BORED;
808 f = purple_request_fields_get_field(fields, "mood_excited");
809 if (f && purple_request_field_bool_get_value(f))
810 mask |= SILC_ATTRIBUTE_MOOD_EXCITED;
811 f = purple_request_fields_get_field(fields, "mood_anxious");
812 if (f && purple_request_field_bool_get_value(f))
813 mask |= SILC_ATTRIBUTE_MOOD_ANXIOUS;
814 silc_client_attribute_add(client, conn,
815 SILC_ATTRIBUTE_STATUS_MOOD,
816 SILC_32_TO_PTR(mask),
817 sizeof(SilcUInt32));
818
819 /* Set preferred contact */
820 mask = 0;
821 f = purple_request_fields_get_field(fields, "contact_chat");
822 if (f && purple_request_field_bool_get_value(f))
823 mask |= SILC_ATTRIBUTE_CONTACT_CHAT;
824 f = purple_request_fields_get_field(fields, "contact_email");
825 if (f && purple_request_field_bool_get_value(f))
826 mask |= SILC_ATTRIBUTE_CONTACT_EMAIL;
827 f = purple_request_fields_get_field(fields, "contact_call");
828 if (f && purple_request_field_bool_get_value(f))
829 mask |= SILC_ATTRIBUTE_CONTACT_CALL;
830 f = purple_request_fields_get_field(fields, "contact_sms");
831 if (f && purple_request_field_bool_get_value(f))
832 mask |= SILC_ATTRIBUTE_CONTACT_SMS;
833 f = purple_request_fields_get_field(fields, "contact_mms");
834 if (f && purple_request_field_bool_get_value(f))
835 mask |= SILC_ATTRIBUTE_CONTACT_MMS;
836 f = purple_request_fields_get_field(fields, "contact_video");
837 if (f && purple_request_field_bool_get_value(f))
838 mask |= SILC_ATTRIBUTE_CONTACT_VIDEO;
839 if (mask)
840 silc_client_attribute_add(client, conn,
841 SILC_ATTRIBUTE_PREFERRED_CONTACT,
842 SILC_32_TO_PTR(mask),
843 sizeof(SilcUInt32));
844
845 /* Set status text */
846 val = NULL;
847 f = purple_request_fields_get_field(fields, "status_text");
848 if (f)
849 val = purple_request_field_string_get_value(f);
850 if (val && *val)
851 silc_client_attribute_add(client, conn,
852 SILC_ATTRIBUTE_STATUS_FREETEXT,
853 (void *)val, strlen(val));
854
855 /* Set vcard */
856 val = NULL;
857 f = purple_request_fields_get_field(fields, "vcard");
858 if (f)
859 val = purple_request_field_string_get_value(f);
860 if (val && *val) {
861 purple_account_set_string(sg->account, "vcard", val);
862 tmp = silc_file_readfile(val, &tmp_len);
863 if (tmp) {
864 tmp[tmp_len] = 0;
865 if (silc_vcard_decode((unsigned char *)tmp, tmp_len, &vcard))
866 silc_client_attribute_add(client, conn,
867 SILC_ATTRIBUTE_USER_INFO,
868 (void *)&vcard,
869 sizeof(vcard));
870 }
871 silc_vcard_free(&vcard);
872 silc_free(tmp);
873 } else {
874 purple_account_set_string(sg->account, "vcard", "");
875 }
876
877 #ifdef HAVE_SYS_UTSNAME_H
878 /* Set device info */
879 f = purple_request_fields_get_field(fields, "device");
880 if (f && purple_request_field_bool_get_value(f)) {
881 struct utsname u;
882 if (!uname(&u)) {
883 dev.type = SILC_ATTRIBUTE_DEVICE_COMPUTER;
884 dev.version = u.release;
885 dev.model = u.sysname;
886 silc_client_attribute_add(client, conn,
887 SILC_ATTRIBUTE_DEVICE_INFO,
888 (void *)&dev, sizeof(dev));
889 }
890 }
891 #endif
892
893 /* Set timezone */
894 val = NULL;
895 f = purple_request_fields_get_field(fields, "timezone");
896 if (f)
897 val = purple_request_field_string_get_value(f);
898 if (val && *val)
899 silc_client_attribute_add(client, conn,
900 SILC_ATTRIBUTE_TIMEZONE,
901 (void *)val, strlen(val));
902 }
903
904 static void
silcpurple_attrs(PurplePluginAction * action)905 silcpurple_attrs(PurplePluginAction *action)
906 {
907 PurpleConnection *gc = (PurpleConnection *) action->context;
908 SilcPurple sg = gc->proto_data;
909 SilcClient client = sg->client;
910 SilcClientConnection conn = sg->conn;
911 PurpleRequestFields *fields;
912 PurpleRequestFieldGroup *g;
913 PurpleRequestField *f;
914 SilcHashTable attrs;
915 SilcAttributePayload attr;
916 gboolean mnormal = TRUE, mhappy = FALSE, msad = FALSE,
917 mangry = FALSE, mjealous = FALSE, mashamed = FALSE,
918 minvincible = FALSE, minlove = FALSE, msleepy = FALSE,
919 mbored = FALSE, mexcited = FALSE, manxious = FALSE;
920 gboolean cemail = FALSE, ccall = FALSE, csms = FALSE,
921 cmms = FALSE, cchat = TRUE, cvideo = FALSE;
922 gboolean device = TRUE;
923 char status[1024], tz[16];
924
925 sg = gc->proto_data;
926 if (!sg)
927 return;
928
929 memset(status, 0, sizeof(status));
930
931 attrs = silc_client_attributes_get(client, conn);
932 if (attrs) {
933 if (silc_hash_table_find(attrs,
934 SILC_32_TO_PTR(SILC_ATTRIBUTE_STATUS_MOOD),
935 NULL, (void *)&attr)) {
936 SilcUInt32 mood = 0;
937 silc_attribute_get_object(attr, &mood, sizeof(mood));
938 mnormal = !mood;
939 mhappy = (mood & SILC_ATTRIBUTE_MOOD_HAPPY);
940 msad = (mood & SILC_ATTRIBUTE_MOOD_SAD);
941 mangry = (mood & SILC_ATTRIBUTE_MOOD_ANGRY);
942 mjealous = (mood & SILC_ATTRIBUTE_MOOD_JEALOUS);
943 mashamed = (mood & SILC_ATTRIBUTE_MOOD_ASHAMED);
944 minvincible = (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE);
945 minlove = (mood & SILC_ATTRIBUTE_MOOD_INLOVE);
946 msleepy = (mood & SILC_ATTRIBUTE_MOOD_SLEEPY);
947 mbored = (mood & SILC_ATTRIBUTE_MOOD_BORED);
948 mexcited = (mood & SILC_ATTRIBUTE_MOOD_EXCITED);
949 manxious = (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS);
950 }
951
952 if (silc_hash_table_find(attrs,
953 SILC_32_TO_PTR(SILC_ATTRIBUTE_PREFERRED_CONTACT),
954 NULL, (void *)&attr)) {
955 SilcUInt32 contact = 0;
956 silc_attribute_get_object(attr, &contact, sizeof(contact));
957 cemail = (contact & SILC_ATTRIBUTE_CONTACT_EMAIL);
958 ccall = (contact & SILC_ATTRIBUTE_CONTACT_CALL);
959 csms = (contact & SILC_ATTRIBUTE_CONTACT_SMS);
960 cmms = (contact & SILC_ATTRIBUTE_CONTACT_MMS);
961 cchat = (contact & SILC_ATTRIBUTE_CONTACT_CHAT);
962 cvideo = (contact & SILC_ATTRIBUTE_CONTACT_VIDEO);
963 }
964
965 if (silc_hash_table_find(attrs,
966 SILC_32_TO_PTR(SILC_ATTRIBUTE_STATUS_FREETEXT),
967 NULL, (void *)&attr))
968 silc_attribute_get_object(attr, &status, sizeof(status));
969
970 if (!silc_hash_table_find(attrs,
971 SILC_32_TO_PTR(SILC_ATTRIBUTE_DEVICE_INFO),
972 NULL, (void *)&attr))
973 device = FALSE;
974 }
975
976 fields = purple_request_fields_new();
977
978 g = purple_request_field_group_new(NULL);
979 f = purple_request_field_label_new("l3", _("Your Current Mood"));
980 purple_request_field_group_add_field(g, f);
981 f = purple_request_field_bool_new("mood_normal", _("Normal"), mnormal);
982 purple_request_field_group_add_field(g, f);
983 f = purple_request_field_bool_new("mood_happy", _("Happy"), mhappy);
984 purple_request_field_group_add_field(g, f);
985 f = purple_request_field_bool_new("mood_sad", _("Sad"), msad);
986 purple_request_field_group_add_field(g, f);
987 f = purple_request_field_bool_new("mood_angry", _("Angry"), mangry);
988 purple_request_field_group_add_field(g, f);
989 f = purple_request_field_bool_new("mood_jealous", _("Jealous"), mjealous);
990 purple_request_field_group_add_field(g, f);
991 f = purple_request_field_bool_new("mood_ashamed", _("Ashamed"), mashamed);
992 purple_request_field_group_add_field(g, f);
993 f = purple_request_field_bool_new("mood_invincible", _("Invincible"), minvincible);
994 purple_request_field_group_add_field(g, f);
995 f = purple_request_field_bool_new("mood_inlove", _("In love"), minlove);
996 purple_request_field_group_add_field(g, f);
997 f = purple_request_field_bool_new("mood_sleepy", _("Sleepy"), msleepy);
998 purple_request_field_group_add_field(g, f);
999 f = purple_request_field_bool_new("mood_bored", _("Bored"), mbored);
1000 purple_request_field_group_add_field(g, f);
1001 f = purple_request_field_bool_new("mood_excited", _("Excited"), mexcited);
1002 purple_request_field_group_add_field(g, f);
1003 f = purple_request_field_bool_new("mood_anxious", _("Anxious"), manxious);
1004 purple_request_field_group_add_field(g, f);
1005
1006 f = purple_request_field_label_new("l4", _("\nYour Preferred Contact Methods"));
1007 purple_request_field_group_add_field(g, f);
1008 f = purple_request_field_bool_new("contact_chat", _("Chat"), cchat);
1009 purple_request_field_group_add_field(g, f);
1010 f = purple_request_field_bool_new("contact_email", _("Email"), cemail);
1011 purple_request_field_group_add_field(g, f);
1012 f = purple_request_field_bool_new("contact_call", _("Phone"), ccall);
1013 purple_request_field_group_add_field(g, f);
1014 f = purple_request_field_bool_new("contact_sms", _("SMS"), csms);
1015 purple_request_field_group_add_field(g, f);
1016 f = purple_request_field_bool_new("contact_mms", _("MMS"), cmms);
1017 purple_request_field_group_add_field(g, f);
1018 f = purple_request_field_bool_new("contact_video", _("Video conferencing"), cvideo);
1019 purple_request_field_group_add_field(g, f);
1020 purple_request_fields_add_group(fields, g);
1021
1022 g = purple_request_field_group_new(NULL);
1023 f = purple_request_field_string_new("status_text", _("Your Current Status"),
1024 status[0] ? status : NULL, TRUE);
1025 purple_request_field_group_add_field(g, f);
1026 purple_request_fields_add_group(fields, g);
1027
1028 g = purple_request_field_group_new(NULL);
1029 #if 0
1030 f = purple_request_field_label_new("l2", _("Online Services"));
1031 purple_request_field_group_add_field(g, f);
1032 f = purple_request_field_bool_new("services",
1033 _("Let others see what services you are using"),
1034 TRUE);
1035 purple_request_field_group_add_field(g, f);
1036 #endif
1037 #ifdef HAVE_SYS_UTSNAME_H
1038 f = purple_request_field_bool_new("device",
1039 _("Let others see what computer you are using"),
1040 device);
1041 purple_request_field_group_add_field(g, f);
1042 #endif
1043 purple_request_fields_add_group(fields, g);
1044
1045 g = purple_request_field_group_new(NULL);
1046 f = purple_request_field_string_new("vcard", _("Your VCard File"),
1047 purple_account_get_string(sg->account, "vcard", ""),
1048 FALSE);
1049 purple_request_field_group_add_field(g, f);
1050
1051 silc_timezone(tz, sizeof(tz));
1052 f = purple_request_field_string_new("timezone", _("Timezone (UTC)"), tz, FALSE);
1053 purple_request_field_group_add_field(g, f);
1054 purple_request_fields_add_group(fields, g);
1055
1056 purple_request_fields(gc, _("User Online Status Attributes"),
1057 _("User Online Status Attributes"),
1058 _("You can let other users see your online status information "
1059 "and your personal information. Please fill the information "
1060 "you would like other users to see about yourself."),
1061 fields,
1062 _("OK"), G_CALLBACK(silcpurple_attrs_cb),
1063 _("Cancel"), G_CALLBACK(silcpurple_attrs_cancel),
1064 gc->account, NULL, NULL, gc);
1065 }
1066
1067 static void
silcpurple_detach(PurplePluginAction * action)1068 silcpurple_detach(PurplePluginAction *action)
1069 {
1070 PurpleConnection *gc = (PurpleConnection *) action->context;
1071 SilcPurple sg;
1072
1073 if (!gc)
1074 return;
1075 sg = gc->proto_data;
1076 if (!sg)
1077 return;
1078
1079 /* Call DETACH */
1080 silc_client_command_call(sg->client, sg->conn, "DETACH");
1081 sg->detaching = TRUE;
1082 }
1083
1084 static void
silcpurple_view_motd(PurplePluginAction * action)1085 silcpurple_view_motd(PurplePluginAction *action)
1086 {
1087 PurpleConnection *gc = (PurpleConnection *) action->context;
1088 SilcPurple sg;
1089 char *tmp;
1090
1091 if (!gc)
1092 return;
1093 sg = gc->proto_data;
1094 if (!sg)
1095 return;
1096
1097 if (!sg->motd) {
1098 purple_notify_error(
1099 gc, _("Message of the Day"), _("No Message of the Day available"),
1100 _("There is no Message of the Day associated with this connection"));
1101 return;
1102 }
1103
1104 tmp = g_markup_escape_text(sg->motd, -1);
1105 purple_notify_formatted(gc, NULL, _("Message of the Day"), NULL,
1106 tmp, NULL, NULL);
1107 g_free(tmp);
1108 }
1109
1110 static void
silcpurple_create_keypair_cancel(PurpleConnection * gc,PurpleRequestFields * fields)1111 silcpurple_create_keypair_cancel(PurpleConnection *gc, PurpleRequestFields *fields)
1112 {
1113 /* Nothing */
1114 }
1115
1116 static void
silcpurple_create_keypair_cb(PurpleConnection * gc,PurpleRequestFields * fields)1117 silcpurple_create_keypair_cb(PurpleConnection *gc, PurpleRequestFields *fields)
1118 {
1119 SilcPurple sg;
1120 PurpleRequestField *f;
1121 const char *val, *pkfile = NULL, *prfile = NULL;
1122 const char *pass1 = NULL, *pass2 = NULL, *un = NULL, *hn = NULL;
1123 const char *rn = NULL, *e = NULL, *o = NULL, *c = NULL;
1124 char *identifier;
1125 int keylen = SILCPURPLE_DEF_PKCS_LEN;
1126 SilcPublicKey public_key;
1127
1128 sg = gc->proto_data;
1129 if (!sg)
1130 return;
1131
1132 val = NULL;
1133 f = purple_request_fields_get_field(fields, "pass1");
1134 if (f)
1135 val = purple_request_field_string_get_value(f);
1136 if (val && *val)
1137 pass1 = val;
1138 else
1139 pass1 = "";
1140 val = NULL;
1141 f = purple_request_fields_get_field(fields, "pass2");
1142 if (f)
1143 val = purple_request_field_string_get_value(f);
1144 if (val && *val)
1145 pass2 = val;
1146 else
1147 pass2 = "";
1148
1149 if (!purple_strequal(pass1, pass2)) {
1150 purple_notify_error(
1151 gc, _("Create New SILC Key Pair"), _("Passphrases do not match"), NULL);
1152 return;
1153 }
1154
1155 val = NULL;
1156 f = purple_request_fields_get_field(fields, "key");
1157 if (f)
1158 val = purple_request_field_string_get_value(f);
1159 if (val && *val)
1160 keylen = atoi(val);
1161 f = purple_request_fields_get_field(fields, "pkfile");
1162 if (f)
1163 pkfile = purple_request_field_string_get_value(f);
1164 f = purple_request_fields_get_field(fields, "prfile");
1165 if (f)
1166 prfile = purple_request_field_string_get_value(f);
1167
1168 f = purple_request_fields_get_field(fields, "un");
1169 if (f)
1170 un = purple_request_field_string_get_value(f);
1171 f = purple_request_fields_get_field(fields, "hn");
1172 if (f)
1173 hn = purple_request_field_string_get_value(f);
1174 f = purple_request_fields_get_field(fields, "rn");
1175 if (f)
1176 rn = purple_request_field_string_get_value(f);
1177 f = purple_request_fields_get_field(fields, "e");
1178 if (f)
1179 e = purple_request_field_string_get_value(f);
1180 f = purple_request_fields_get_field(fields, "o");
1181 if (f)
1182 o = purple_request_field_string_get_value(f);
1183 f = purple_request_fields_get_field(fields, "c");
1184 if (f)
1185 c = purple_request_field_string_get_value(f);
1186
1187 identifier = silc_pkcs_silc_encode_identifier((char *)un, (char *)hn,
1188 (char *)rn, (char *)e,
1189 (char *)o, (char *)c,
1190 NULL);
1191
1192 /* Create the key pair */
1193 if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS, keylen, pkfile, prfile,
1194 identifier, pass1, &public_key, NULL,
1195 FALSE)) {
1196 purple_notify_error(
1197 gc, _("Create New SILC Key Pair"), _("Key Pair Generation failed"), NULL);
1198 return;
1199 }
1200
1201 silcpurple_show_public_key(sg, NULL, public_key, NULL, NULL);
1202
1203 silc_pkcs_public_key_free(public_key);
1204 silc_free(identifier);
1205 }
1206
1207 static void
silcpurple_create_keypair(PurplePluginAction * action)1208 silcpurple_create_keypair(PurplePluginAction *action)
1209 {
1210 PurpleConnection *gc = (PurpleConnection *) action->context;
1211 SilcPurple sg = gc->proto_data;
1212 PurpleRequestFields *fields;
1213 PurpleRequestFieldGroup *g;
1214 PurpleRequestField *f;
1215 const char *username, *realname;
1216 char *hostname, **u;
1217 char tmp[256], pkd[256], pkd2[256], prd[256], prd2[256];
1218
1219 username = purple_account_get_username(sg->account);
1220 u = g_strsplit(username, "@", 2);
1221 username = u[0];
1222 realname = purple_account_get_user_info(sg->account);
1223 hostname = silc_net_localhost();
1224 g_snprintf(tmp, sizeof(tmp), "%s@%s", username, hostname);
1225
1226 g_snprintf(pkd2, sizeof(pkd2), "%s" G_DIR_SEPARATOR_S"public_key.pub", silcpurple_silcdir());
1227 g_snprintf(prd2, sizeof(prd2), "%s" G_DIR_SEPARATOR_S"private_key.prv", silcpurple_silcdir());
1228 g_snprintf(pkd, sizeof(pkd) - 1, "%s",
1229 purple_account_get_string(gc->account, "public-key", pkd2));
1230 g_snprintf(prd, sizeof(prd) - 1, "%s",
1231 purple_account_get_string(gc->account, "private-key", prd2));
1232
1233 fields = purple_request_fields_new();
1234
1235 g = purple_request_field_group_new(NULL);
1236 f = purple_request_field_string_new("key", _("Key length"), "2048", FALSE);
1237 purple_request_field_group_add_field(g, f);
1238 f = purple_request_field_string_new("pkfile", _("Public key file"), pkd, FALSE);
1239 purple_request_field_group_add_field(g, f);
1240 f = purple_request_field_string_new("prfile", _("Private key file"), prd, FALSE);
1241 purple_request_field_group_add_field(g, f);
1242 purple_request_fields_add_group(fields, g);
1243
1244 g = purple_request_field_group_new(NULL);
1245 f = purple_request_field_string_new("un", _("Username"), username ? username : "", FALSE);
1246 purple_request_field_group_add_field(g, f);
1247 f = purple_request_field_string_new("hn", _("Hostname"), hostname ? hostname : "", FALSE);
1248 purple_request_field_group_add_field(g, f);
1249 f = purple_request_field_string_new("rn", _("Real name"), realname ? realname : "", FALSE);
1250 purple_request_field_group_add_field(g, f);
1251 f = purple_request_field_string_new("e", _("Email"), tmp, FALSE);
1252 purple_request_field_group_add_field(g, f);
1253 f = purple_request_field_string_new("o", _("Organization"), "", FALSE);
1254 purple_request_field_group_add_field(g, f);
1255 f = purple_request_field_string_new("c", _("Country"), "", FALSE);
1256 purple_request_field_group_add_field(g, f);
1257 purple_request_fields_add_group(fields, g);
1258
1259 g = purple_request_field_group_new(NULL);
1260 f = purple_request_field_string_new("pass1", _("Passphrase"), "", FALSE);
1261 purple_request_field_string_set_masked(f, TRUE);
1262 purple_request_field_group_add_field(g, f);
1263 f = purple_request_field_string_new("pass2", _("Passphrase (retype)"), "", FALSE);
1264 purple_request_field_string_set_masked(f, TRUE);
1265 purple_request_field_group_add_field(g, f);
1266 purple_request_fields_add_group(fields, g);
1267
1268 purple_request_fields(gc, _("Create New SILC Key Pair"),
1269 _("Create New SILC Key Pair"), NULL, fields,
1270 _("Generate Key Pair"), G_CALLBACK(silcpurple_create_keypair_cb),
1271 _("Cancel"), G_CALLBACK(silcpurple_create_keypair_cancel),
1272 gc->account, NULL, NULL, gc);
1273
1274 g_strfreev(u);
1275 silc_free(hostname);
1276 }
1277
1278 static void
silcpurple_change_pass(PurplePluginAction * action)1279 silcpurple_change_pass(PurplePluginAction *action)
1280 {
1281 PurpleConnection *gc = (PurpleConnection *) action->context;
1282 purple_account_request_change_password(purple_connection_get_account(gc));
1283 }
1284
1285 static void
silcpurple_change_passwd(PurpleConnection * gc,const char * old,const char * new)1286 silcpurple_change_passwd(PurpleConnection *gc, const char *old, const char *new)
1287 {
1288 char prd[256];
1289 g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.pub", silcpurple_silcdir());
1290 silc_change_private_key_passphrase(purple_account_get_string(gc->account,
1291 "private-key",
1292 prd), old ? old : "", new ? new : "");
1293 }
1294
1295 static void
silcpurple_show_set_info(PurplePluginAction * action)1296 silcpurple_show_set_info(PurplePluginAction *action)
1297 {
1298 PurpleConnection *gc = (PurpleConnection *) action->context;
1299 purple_account_request_change_user_info(purple_connection_get_account(gc));
1300 }
1301
1302 static void
silcpurple_set_info(PurpleConnection * gc,const char * text)1303 silcpurple_set_info(PurpleConnection *gc, const char *text)
1304 {
1305 }
1306
1307 static GList *
silcpurple_actions(PurplePlugin * plugin,gpointer context)1308 silcpurple_actions(PurplePlugin *plugin, gpointer context)
1309 {
1310 GList *list = NULL;
1311 PurplePluginAction *act;
1312
1313 act = purple_plugin_action_new(_("Online Status"),
1314 silcpurple_attrs);
1315 list = g_list_append(list, act);
1316
1317 act = purple_plugin_action_new(_("Detach From Server"),
1318 silcpurple_detach);
1319 list = g_list_append(list, act);
1320
1321 act = purple_plugin_action_new(_("View Message of the Day"),
1322 silcpurple_view_motd);
1323 list = g_list_append(list, act);
1324
1325 act = purple_plugin_action_new(_("Create SILC Key Pair..."),
1326 silcpurple_create_keypair);
1327 list = g_list_append(list, act);
1328
1329 act = purple_plugin_action_new(_("Change Password..."),
1330 silcpurple_change_pass);
1331 list = g_list_append(list, act);
1332
1333 act = purple_plugin_action_new(_("Set User Info..."),
1334 silcpurple_show_set_info);
1335 list = g_list_append(list, act);
1336
1337 return list;
1338 }
1339
1340
1341 /******************************* IM Routines *********************************/
1342
1343 typedef struct {
1344 char *nick;
1345 char *message;
1346 SilcUInt32 message_len;
1347 SilcMessageFlags flags;
1348 PurpleMessageFlags gflags;
1349 } *SilcPurpleIM;
1350
1351 static void
silcpurple_send_im_resolved(SilcClient client,SilcClientConnection conn,SilcStatus status,SilcDList clients,void * context)1352 silcpurple_send_im_resolved(SilcClient client,
1353 SilcClientConnection conn,
1354 SilcStatus status,
1355 SilcDList clients,
1356 void *context)
1357 {
1358 PurpleConnection *gc = client->application;
1359 SilcPurple sg = gc->proto_data;
1360 SilcPurpleIM im = context;
1361 PurpleConversation *convo;
1362 char tmp[256];
1363 SilcClientEntry client_entry;
1364 SilcDList list;
1365 gboolean free_list = FALSE;
1366
1367 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, im->nick,
1368 sg->account);
1369 if (!convo)
1370 return;
1371
1372 if (!clients)
1373 goto err;
1374
1375 if (silc_dlist_count(clients) > 1) {
1376 /* Find the correct one. The im->nick might be a formatted nick
1377 so this will find the correct one. */
1378 clients = silc_client_get_clients_local(client, conn,
1379 im->nick, FALSE);
1380 if (!clients)
1381 goto err;
1382
1383 free_list = TRUE;
1384 }
1385
1386 silc_dlist_start(clients);
1387 client_entry = silc_dlist_get(clients);
1388
1389 /* Check for images */
1390 if (im->gflags & PURPLE_MESSAGE_IMAGES) {
1391 list = silcpurple_image_message(im->message, &im->flags);
1392 if (list) {
1393 /* Send one or more MIME message. If more than one, they
1394 are MIME fragments due to over large message */
1395 SilcBuffer buf;
1396
1397 silc_dlist_start(list);
1398 while ((buf = silc_dlist_get(list)) != SILC_LIST_END)
1399 silc_client_send_private_message(client, conn,
1400 client_entry, im->flags, sg->sha1hash,
1401 buf->data,
1402 silc_buffer_len(buf));
1403 silc_mime_partial_free(list);
1404 purple_conv_im_write(PURPLE_CONV_IM(convo), conn->local_entry->nickname,
1405 im->message, 0, time(NULL));
1406 goto out;
1407 }
1408 }
1409
1410 /* Send the message */
1411 silc_client_send_private_message(client, conn, client_entry, im->flags,
1412 sg->sha1hash, (unsigned char *)im->message, im->message_len);
1413 purple_conv_im_write(PURPLE_CONV_IM(convo), conn->local_entry->nickname,
1414 im->message, 0, time(NULL));
1415 goto out;
1416
1417 err:
1418 g_snprintf(tmp, sizeof(tmp),
1419 _("User <I>%s</I> is not present in the network"), im->nick);
1420 purple_conversation_write(convo, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL));
1421
1422 out:
1423 if (free_list) {
1424 silc_client_list_free(client, conn, clients);
1425 }
1426 g_free(im->nick);
1427 g_free(im->message);
1428 silc_free(im);
1429 }
1430
1431 static int
silcpurple_send_im(PurpleConnection * gc,const char * who,const char * message,PurpleMessageFlags flags)1432 silcpurple_send_im(PurpleConnection *gc, const char *who, const char *message,
1433 PurpleMessageFlags flags)
1434 {
1435 SilcPurple sg = gc->proto_data;
1436 SilcClient client = sg->client;
1437 SilcClientConnection conn = sg->conn;
1438 SilcDList clients;
1439 SilcClientEntry client_entry;
1440 SilcMessageFlags mflags;
1441 char *msg, *tmp;
1442 int ret = 0;
1443 gboolean sign = purple_account_get_bool(sg->account, "sign-verify", FALSE);
1444 SilcDList list;
1445
1446 if (!who || !message)
1447 return 0;
1448
1449 mflags = SILC_MESSAGE_FLAG_UTF8;
1450
1451 tmp = msg = purple_unescape_html(message);
1452
1453 if (!g_ascii_strncasecmp(msg, "/me ", 4)) {
1454 msg += 4;
1455 if (!*msg) {
1456 g_free(tmp);
1457 return 0;
1458 }
1459 mflags |= SILC_MESSAGE_FLAG_ACTION;
1460 } else if (strlen(msg) > 1 && msg[0] == '/') {
1461 if (!silc_client_command_call(client, conn, msg + 1))
1462 purple_notify_error(gc, _("Call Command"),
1463 _("Cannot call command"),
1464 _("Unknown command"));
1465 g_free(tmp);
1466 return 0;
1467 }
1468
1469 if (sign)
1470 mflags |= SILC_MESSAGE_FLAG_SIGNED;
1471
1472 /* Find client entry */
1473 clients = silc_client_get_clients_local(client, conn, who, FALSE);
1474 if (!clients) {
1475 /* Resolve unknown user */
1476 SilcPurpleIM im = silc_calloc(1, sizeof(*im));
1477 if (!im) {
1478 g_free(tmp);
1479 return 0;
1480 }
1481 im->nick = g_strdup(who);
1482 im->message = g_strdup(message);
1483 im->message_len = strlen(im->message);
1484 im->flags = mflags;
1485 im->gflags = flags;
1486 silc_client_get_clients(client, conn, who, NULL,
1487 silcpurple_send_im_resolved, im);
1488 g_free(tmp);
1489 return 0;
1490 }
1491
1492 silc_dlist_start(clients);
1493 client_entry = silc_dlist_get(clients);
1494
1495 /* Check for images */
1496 if (flags & PURPLE_MESSAGE_IMAGES) {
1497 list = silcpurple_image_message(message, &mflags);
1498 if (list) {
1499 /* Send one or more MIME message. If more than one, they
1500 are MIME fragments due to over large message */
1501 SilcBuffer buf;
1502
1503 silc_dlist_start(list);
1504 while ((buf = silc_dlist_get(list)) != SILC_LIST_END)
1505 ret =
1506 silc_client_send_private_message(client, conn,
1507 client_entry, mflags, sg->sha1hash,
1508 buf->data,
1509 silc_buffer_len(buf));
1510 silc_mime_partial_free(list);
1511 g_free(tmp);
1512 silc_client_list_free(client, conn, clients);
1513 return ret;
1514 }
1515 }
1516
1517 /* Send private message directly */
1518 ret = silc_client_send_private_message(client, conn, client_entry,
1519 mflags, sg->sha1hash,
1520 (unsigned char *)msg,
1521 strlen(msg));
1522
1523 g_free(tmp);
1524 silc_client_list_free(client, conn, clients);
1525 return ret;
1526 }
1527
1528
silcpurple_blist_node_menu(PurpleBlistNode * node)1529 static GList *silcpurple_blist_node_menu(PurpleBlistNode *node) {
1530 /* split this single menu building function back into the two
1531 original: one for buddies and one for chats */
1532 if(PURPLE_BLIST_NODE_IS_CHAT(node)) {
1533 return silcpurple_chat_menu((PurpleChat *) node);
1534 } else if(PURPLE_BLIST_NODE_IS_BUDDY(node)) {
1535 return silcpurple_buddy_menu((PurpleBuddy *) node);
1536 } else {
1537 g_return_val_if_reached(NULL);
1538 }
1539 }
1540
1541 /********************************* Commands **********************************/
1542
silcpurple_cmd_chat_part(PurpleConversation * conv,const char * cmd,char ** args,char ** error,void * data)1543 static PurpleCmdRet silcpurple_cmd_chat_part(PurpleConversation *conv,
1544 const char *cmd, char **args, char **error, void *data)
1545 {
1546 PurpleConnection *gc;
1547 PurpleConversation *convo = conv;
1548 int id = 0;
1549
1550 gc = purple_conversation_get_gc(conv);
1551
1552 if (gc == NULL)
1553 return PURPLE_CMD_RET_FAILED;
1554
1555 if(args && args[0])
1556 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[0],
1557 gc->account);
1558
1559 if (convo != NULL)
1560 id = purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo));
1561
1562 if (id == 0)
1563 return PURPLE_CMD_RET_FAILED;
1564
1565 silcpurple_chat_leave(gc, id);
1566
1567 return PURPLE_CMD_RET_OK;
1568
1569 }
1570
silcpurple_cmd_chat_topic(PurpleConversation * conv,const char * cmd,char ** args,char ** error,void * data)1571 static PurpleCmdRet silcpurple_cmd_chat_topic(PurpleConversation *conv,
1572 const char *cmd, char **args, char **error, void *data)
1573 {
1574 PurpleConnection *gc;
1575 int id = 0;
1576 char *buf, *tmp, *tmp2;
1577 const char *topic;
1578
1579 gc = purple_conversation_get_gc(conv);
1580 id = purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv));
1581
1582 if (gc == NULL || id == 0)
1583 return PURPLE_CMD_RET_FAILED;
1584
1585 if (!args || !args[0]) {
1586 topic = purple_conv_chat_get_topic (PURPLE_CONV_CHAT(conv));
1587 if (topic) {
1588 tmp = g_markup_escape_text(topic, -1);
1589 tmp2 = purple_markup_linkify(tmp);
1590 buf = g_strdup_printf(_("current topic is: %s"), tmp2);
1591 g_free(tmp);
1592 g_free(tmp2);
1593 } else
1594 buf = g_strdup(_("No topic is set"));
1595 purple_conv_chat_write(PURPLE_CONV_CHAT(conv), gc->account->username, buf,
1596 PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NO_LOG, time(NULL));
1597 g_free(buf);
1598
1599 }
1600
1601 if (args && args[0] && (strlen(args[0]) > 255)) {
1602 *error = g_strdup(_("Topic too long"));
1603 return PURPLE_CMD_RET_FAILED;
1604 }
1605
1606 silcpurple_chat_set_topic(gc, id, args ? args[0] : NULL);
1607
1608 return PURPLE_CMD_RET_OK;
1609 }
1610
silcpurple_cmd_chat_join(PurpleConversation * conv,const char * cmd,char ** args,char ** error,void * data)1611 static PurpleCmdRet silcpurple_cmd_chat_join(PurpleConversation *conv,
1612 const char *cmd, char **args, char **error, void *data)
1613 {
1614 GHashTable *comp;
1615
1616 if(!args || !args[0])
1617 return PURPLE_CMD_RET_FAILED;
1618
1619 comp = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
1620
1621 g_hash_table_replace(comp, "channel", args[0]);
1622 if(args[1])
1623 g_hash_table_replace(comp, "passphrase", args[1]);
1624
1625 silcpurple_chat_join(purple_conversation_get_gc(conv), comp);
1626
1627 g_hash_table_destroy(comp);
1628 return PURPLE_CMD_RET_OK;
1629 }
1630
silcpurple_cmd_chat_list(PurpleConversation * conv,const char * cmd,char ** args,char ** error,void * data)1631 static PurpleCmdRet silcpurple_cmd_chat_list(PurpleConversation *conv,
1632 const char *cmd, char **args, char **error, void *data)
1633 {
1634 PurpleConnection *gc;
1635 gc = purple_conversation_get_gc(conv);
1636 purple_roomlist_show_with_account(purple_connection_get_account(gc));
1637 return PURPLE_CMD_RET_OK;
1638 }
1639
silcpurple_cmd_whois(PurpleConversation * conv,const char * cmd,char ** args,char ** error,void * data)1640 static PurpleCmdRet silcpurple_cmd_whois(PurpleConversation *conv,
1641 const char *cmd, char **args, char **error, void *data)
1642 {
1643 PurpleConnection *gc;
1644
1645 gc = purple_conversation_get_gc(conv);
1646
1647 if (gc == NULL)
1648 return PURPLE_CMD_RET_FAILED;
1649
1650 silcpurple_get_info(gc, args[0]);
1651
1652 return PURPLE_CMD_RET_OK;
1653 }
1654
silcpurple_cmd_msg(PurpleConversation * conv,const char * cmd,char ** args,char ** error,void * data)1655 static PurpleCmdRet silcpurple_cmd_msg(PurpleConversation *conv,
1656 const char *cmd, char **args, char **error, void *data)
1657 {
1658 int ret;
1659 PurpleConnection *gc;
1660
1661 gc = purple_conversation_get_gc(conv);
1662
1663 if (gc == NULL)
1664 return PURPLE_CMD_RET_FAILED;
1665
1666 ret = silcpurple_send_im(gc, args[0], args[1], PURPLE_MESSAGE_SEND);
1667
1668 if (ret)
1669 return PURPLE_CMD_RET_OK;
1670 else
1671 return PURPLE_CMD_RET_FAILED;
1672 }
1673
silcpurple_cmd_query(PurpleConversation * conv,const char * cmd,char ** args,char ** error,void * data)1674 static PurpleCmdRet silcpurple_cmd_query(PurpleConversation *conv,
1675 const char *cmd, char **args, char **error, void *data)
1676 {
1677 int ret = 1;
1678 PurpleConversation *convo;
1679 PurpleConnection *gc;
1680 PurpleAccount *account;
1681
1682 if (!args || !args[0]) {
1683 *error = g_strdup(_("You must specify a nick"));
1684 return PURPLE_CMD_RET_FAILED;
1685 }
1686
1687 gc = purple_conversation_get_gc(conv);
1688
1689 if (gc == NULL)
1690 return PURPLE_CMD_RET_FAILED;
1691
1692 account = purple_connection_get_account(gc);
1693
1694 convo = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, args[0]);
1695
1696 if (args[1]) {
1697 ret = silcpurple_send_im(gc, args[0], args[1], PURPLE_MESSAGE_SEND);
1698 purple_conv_im_write(PURPLE_CONV_IM(convo), purple_connection_get_display_name(gc),
1699 args[1], PURPLE_MESSAGE_SEND, time(NULL));
1700 }
1701
1702 if (ret)
1703 return PURPLE_CMD_RET_OK;
1704 else
1705 return PURPLE_CMD_RET_FAILED;
1706 }
1707
silcpurple_cmd_motd(PurpleConversation * conv,const char * cmd,char ** args,char ** error,void * data)1708 static PurpleCmdRet silcpurple_cmd_motd(PurpleConversation *conv,
1709 const char *cmd, char **args, char **error, void *data)
1710 {
1711 PurpleConnection *gc;
1712 SilcPurple sg;
1713 char *tmp;
1714
1715 gc = purple_conversation_get_gc(conv);
1716
1717 if (gc == NULL)
1718 return PURPLE_CMD_RET_FAILED;
1719
1720 sg = gc->proto_data;
1721
1722 if (sg == NULL)
1723 return PURPLE_CMD_RET_FAILED;
1724
1725 if (!sg->motd) {
1726 *error = g_strdup(_("There is no Message of the Day associated with this connection"));
1727 return PURPLE_CMD_RET_FAILED;
1728 }
1729
1730 tmp = g_markup_escape_text(sg->motd, -1);
1731 purple_notify_formatted(gc, NULL, _("Message of the Day"), NULL,
1732 tmp, NULL, NULL);
1733 g_free(tmp);
1734
1735 return PURPLE_CMD_RET_OK;
1736 }
1737
silcpurple_cmd_detach(PurpleConversation * conv,const char * cmd,char ** args,char ** error,void * data)1738 static PurpleCmdRet silcpurple_cmd_detach(PurpleConversation *conv,
1739 const char *cmd, char **args, char **error, void *data)
1740 {
1741 PurpleConnection *gc;
1742 SilcPurple sg;
1743
1744 gc = purple_conversation_get_gc(conv);
1745
1746 if (gc == NULL)
1747 return PURPLE_CMD_RET_FAILED;
1748
1749 sg = gc->proto_data;
1750
1751 if (sg == NULL)
1752 return PURPLE_CMD_RET_FAILED;
1753
1754 silc_client_command_call(sg->client, sg->conn, "DETACH");
1755 sg->detaching = TRUE;
1756
1757 return PURPLE_CMD_RET_OK;
1758 }
1759
silcpurple_cmd_cmode(PurpleConversation * conv,const char * cmd,char ** args,char ** error,void * data)1760 static PurpleCmdRet silcpurple_cmd_cmode(PurpleConversation *conv,
1761 const char *cmd, char **args, char **error, void *data)
1762 {
1763 PurpleConnection *gc;
1764 SilcPurple sg;
1765 SilcChannelEntry channel;
1766 char *silccmd, *silcargs, *msg, tmp[256];
1767 const char *chname;
1768
1769 gc = purple_conversation_get_gc(conv);
1770
1771 if (gc == NULL || !args || gc->proto_data == NULL)
1772 return PURPLE_CMD_RET_FAILED;
1773
1774 sg = gc->proto_data;
1775
1776 if (args[0])
1777 chname = args[0];
1778 else
1779 chname = purple_conversation_get_name(conv);
1780
1781 if (!args[1]) {
1782 channel = silc_client_get_channel(sg->client, sg->conn,
1783 (char *)chname);
1784 if (!channel) {
1785 *error = g_strdup_printf(_("channel %s not found"), chname);
1786 return PURPLE_CMD_RET_FAILED;
1787 }
1788 if (channel->mode) {
1789 silcpurple_get_chmode_string(channel->mode, tmp, sizeof(tmp));
1790 msg = g_strdup_printf(_("channel modes for %s: %s"), chname, tmp);
1791 } else {
1792 msg = g_strdup_printf(_("no channel modes are set on %s"), chname);
1793 }
1794 purple_conv_chat_write(PURPLE_CONV_CHAT(conv), "",
1795 msg, PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NO_LOG, time(NULL));
1796 g_free(msg);
1797 return PURPLE_CMD_RET_OK;
1798 }
1799
1800 silcargs = g_strjoinv(" ", args);
1801 silccmd = g_strconcat(cmd, " ", silcargs, NULL);
1802 g_free(silcargs);
1803 if (!silc_client_command_call(sg->client, sg->conn, silccmd)) {
1804 g_free(silccmd);
1805 *error = g_strdup_printf(_("Failed to set cmodes for %s"), args[0]);
1806 return PURPLE_CMD_RET_FAILED;
1807 }
1808 g_free(silccmd);
1809
1810 return PURPLE_CMD_RET_OK;
1811 }
1812
silcpurple_cmd_generic(PurpleConversation * conv,const char * cmd,char ** args,char ** error,void * data)1813 static PurpleCmdRet silcpurple_cmd_generic(PurpleConversation *conv,
1814 const char *cmd, char **args, char **error, void *data)
1815 {
1816 PurpleConnection *gc;
1817 SilcPurple sg;
1818 char *silccmd, *silcargs;
1819
1820 gc = purple_conversation_get_gc(conv);
1821
1822 if (gc == NULL)
1823 return PURPLE_CMD_RET_FAILED;
1824
1825 sg = gc->proto_data;
1826
1827 if (sg == NULL)
1828 return PURPLE_CMD_RET_FAILED;
1829
1830 silcargs = g_strjoinv(" ", args);
1831 silccmd = g_strconcat(cmd, " ", args ? silcargs : NULL, NULL);
1832 g_free(silcargs);
1833 if (!silc_client_command_call(sg->client, sg->conn, silccmd)) {
1834 g_free(silccmd);
1835 *error = g_strdup_printf(_("Unknown command: %s, (may be a client bug)"), cmd);
1836 return PURPLE_CMD_RET_FAILED;
1837 }
1838 g_free(silccmd);
1839
1840 return PURPLE_CMD_RET_OK;
1841 }
1842
silcpurple_cmd_quit(PurpleConversation * conv,const char * cmd,char ** args,char ** error,void * data)1843 static PurpleCmdRet silcpurple_cmd_quit(PurpleConversation *conv,
1844 const char *cmd, char **args, char **error, void *data)
1845 {
1846 PurpleConnection *gc;
1847 SilcPurple sg;
1848 GHashTable *ui_info;
1849 const char *ui_name = NULL, *ui_website = NULL;
1850 char *quit_msg;
1851
1852 gc = purple_conversation_get_gc(conv);
1853
1854 if (gc == NULL)
1855 return PURPLE_CMD_RET_FAILED;
1856
1857 sg = gc->proto_data;
1858
1859 if (sg == NULL)
1860 return PURPLE_CMD_RET_FAILED;
1861
1862 ui_info = purple_core_get_ui_info();
1863
1864 if(ui_info) {
1865 ui_name = g_hash_table_lookup(ui_info, "name");
1866 ui_website = g_hash_table_lookup(ui_info, "website");
1867 }
1868
1869 if(!ui_name || !ui_website) {
1870 ui_name = "Pidgin";
1871 ui_website = PURPLE_WEBSITE;
1872 }
1873 quit_msg = g_strdup_printf(_("Download %s: %s"),
1874 ui_name, ui_website);
1875
1876 silc_client_command_call(sg->client, sg->conn, NULL,
1877 "QUIT", (args && args[0]) ? args[0] : quit_msg, NULL);
1878 g_free(quit_msg);
1879
1880 return PURPLE_CMD_RET_OK;
1881 }
1882
silcpurple_cmd_call(PurpleConversation * conv,const char * cmd,char ** args,char ** error,void * data)1883 static PurpleCmdRet silcpurple_cmd_call(PurpleConversation *conv,
1884 const char *cmd, char **args, char **error, void *data)
1885 {
1886 PurpleConnection *gc;
1887 SilcPurple sg;
1888
1889 gc = purple_conversation_get_gc(conv);
1890
1891 if (gc == NULL)
1892 return PURPLE_CMD_RET_FAILED;
1893
1894 sg = gc->proto_data;
1895
1896 if (sg == NULL)
1897 return PURPLE_CMD_RET_FAILED;
1898
1899 if (!silc_client_command_call(sg->client, sg->conn, args[0])) {
1900 *error = g_strdup_printf(_("Unknown command: %s"), args[0]);
1901 return PURPLE_CMD_RET_FAILED;
1902 }
1903
1904 return PURPLE_CMD_RET_OK;
1905 }
1906
1907
1908 /************************** Plugin Initialization ****************************/
1909
1910 static void
silcpurple_register_commands(void)1911 silcpurple_register_commands(void)
1912 {
1913 purple_cmd_register("part", "w", PURPLE_CMD_P_PRPL,
1914 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
1915 PURPLE_CMD_FLAG_PRPL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS,
1916 "prpl-silc", silcpurple_cmd_chat_part, _("part [channel]: Leave the chat"), NULL);
1917 purple_cmd_register("leave", "w", PURPLE_CMD_P_PRPL,
1918 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
1919 PURPLE_CMD_FLAG_PRPL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS,
1920 "prpl-silc", silcpurple_cmd_chat_part, _("leave [channel]: Leave the chat"), NULL);
1921 purple_cmd_register("topic", "s", PURPLE_CMD_P_PRPL,
1922 PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
1923 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc",
1924 silcpurple_cmd_chat_topic, _("topic [<new topic>]: View or change the topic"), NULL);
1925 purple_cmd_register("join", "ws", PURPLE_CMD_P_PRPL,
1926 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
1927 PURPLE_CMD_FLAG_PRPL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS,
1928 "prpl-silc", silcpurple_cmd_chat_join,
1929 _("join <channel> [<password>]: Join a chat on this network"), NULL);
1930 purple_cmd_register("list", "", PURPLE_CMD_P_PRPL,
1931 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
1932 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc",
1933 silcpurple_cmd_chat_list, _("list: List channels on this network"), NULL);
1934 purple_cmd_register("whois", "w", PURPLE_CMD_P_PRPL,
1935 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY,
1936 "prpl-silc",
1937 silcpurple_cmd_whois, _("whois <nick>: View nick's information"), NULL);
1938 purple_cmd_register("msg", "ws", PURPLE_CMD_P_PRPL,
1939 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY,
1940 "prpl-silc", silcpurple_cmd_msg,
1941 _("msg <nick> <message>: Send a private message to a user"), NULL);
1942 purple_cmd_register("query", "ws", PURPLE_CMD_P_PRPL,
1943 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
1944 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_query,
1945 _("query <nick> [<message>]: Send a private message to a user"), NULL);
1946 purple_cmd_register("motd", "", PURPLE_CMD_P_PRPL,
1947 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
1948 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_motd,
1949 _("motd: View the server's Message Of The Day"), NULL);
1950 purple_cmd_register("detach", "", PURPLE_CMD_P_PRPL,
1951 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY,
1952 "prpl-silc", silcpurple_cmd_detach,
1953 _("detach: Detach this session"), NULL);
1954 purple_cmd_register("quit", "s", PURPLE_CMD_P_PRPL,
1955 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
1956 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_quit,
1957 _("quit [message]: Disconnect from the server, with an optional message"), NULL);
1958 purple_cmd_register("call", "s", PURPLE_CMD_P_PRPL,
1959 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY,
1960 "prpl-silc", silcpurple_cmd_call,
1961 _("call <command>: Call any silc client command"), NULL);
1962 /* These below just get passed through for the silc client library to deal
1963 * with */
1964 purple_cmd_register("kill", "ws", PURPLE_CMD_P_PRPL,
1965 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
1966 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_generic,
1967 _("kill <nick> [-pubkey|<reason>]: Kill nick"), NULL);
1968 purple_cmd_register("nick", "w", PURPLE_CMD_P_PRPL,
1969 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY,
1970 "prpl-silc", silcpurple_cmd_generic,
1971 _("nick <newnick>: Change your nickname"), NULL);
1972 purple_cmd_register("whowas", "ww", PURPLE_CMD_P_PRPL,
1973 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
1974 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_generic,
1975 _("whowas <nick>: View nick's information"), NULL);
1976 purple_cmd_register("cmode", "wws", PURPLE_CMD_P_PRPL,
1977 PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
1978 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_cmode,
1979 _("cmode <channel> [+|-<modes>] [arguments]: Change or display channel modes"), NULL);
1980 purple_cmd_register("cumode", "wws", PURPLE_CMD_P_PRPL,
1981 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
1982 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_generic,
1983 _("cumode <channel> +|-<modes> <nick>: Change nick's modes on channel"), NULL);
1984 purple_cmd_register("umode", "w", PURPLE_CMD_P_PRPL,
1985 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY,
1986 "prpl-silc", silcpurple_cmd_generic,
1987 _("umode <usermodes>: Set your modes in the network"), NULL);
1988 purple_cmd_register("oper", "s", PURPLE_CMD_P_PRPL,
1989 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY,
1990 "prpl-silc", silcpurple_cmd_generic,
1991 _("oper <nick> [-pubkey]: Get server operator privileges"), NULL);
1992 purple_cmd_register("invite", "ws", PURPLE_CMD_P_PRPL,
1993 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
1994 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_generic,
1995 _("invite <channel> [-|+]<nick>: invite nick or add/remove from channel invite list"), NULL);
1996 purple_cmd_register("kick", "wws", PURPLE_CMD_P_PRPL,
1997 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
1998 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_generic,
1999 _("kick <channel> <nick> [comment]: Kick client from channel"), NULL);
2000 purple_cmd_register("info", "w", PURPLE_CMD_P_PRPL,
2001 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
2002 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_generic,
2003 _("info [server]: View server administrative details"), NULL);
2004 purple_cmd_register("ban", "ww", PURPLE_CMD_P_PRPL,
2005 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
2006 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_generic,
2007 _("ban [<channel> +|-<nick>]: Ban client from channel"), NULL);
2008 purple_cmd_register("getkey", "w", PURPLE_CMD_P_PRPL,
2009 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY,
2010 "prpl-silc", silcpurple_cmd_generic,
2011 _("getkey <nick|server>: Retrieve client's or server's public key"), NULL);
2012 purple_cmd_register("stats", "", PURPLE_CMD_P_PRPL,
2013 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY,
2014 "prpl-silc", silcpurple_cmd_generic,
2015 _("stats: View server and network statistics"), NULL);
2016 purple_cmd_register("ping", "", PURPLE_CMD_P_PRPL,
2017 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY,
2018 "prpl-silc", silcpurple_cmd_generic,
2019 _("ping: Send PING to the connected server"), NULL);
2020 #if 0 /* Purple doesn't handle these yet */
2021 purple_cmd_register("users", "w", PURPLE_CMD_P_PRPL,
2022 PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY,
2023 "prpl-silc", silcpurple_cmd_users,
2024 _("users <channel>: List users in channel"));
2025 purple_cmd_register("names", "ww", PURPLE_CMD_P_PRPL,
2026 PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
2027 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_names,
2028 _("names [-count|-ops|-halfops|-voices|-normal] <channel(s)>: List specific users in channel(s)"));
2029 #endif
2030 }
2031
2032 static PurpleWhiteboardPrplOps silcpurple_wb_ops =
2033 {
2034 silcpurple_wb_start,
2035 silcpurple_wb_end,
2036 silcpurple_wb_get_dimensions,
2037 silcpurple_wb_set_dimensions,
2038 silcpurple_wb_get_brush,
2039 silcpurple_wb_set_brush,
2040 silcpurple_wb_send,
2041 silcpurple_wb_clear,
2042
2043 /* padding */
2044 NULL,
2045 NULL,
2046 NULL,
2047 NULL
2048 };
2049
2050 static PurplePluginProtocolInfo prpl_info =
2051 {
2052 OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME |
2053 OPT_PROTO_PASSWORD_OPTIONAL | OPT_PROTO_IM_IMAGE |
2054 OPT_PROTO_SLASH_COMMANDS_NATIVE,
2055 NULL, /* user_splits */
2056 NULL, /* protocol_options */
2057 {"jpeg,gif,png,bmp", 0, 0, 96, 96, 0, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */
2058 silcpurple_list_icon, /* list_icon */
2059 NULL, /* list_emblems */
2060 silcpurple_status_text, /* status_text */
2061 silcpurple_tooltip_text, /* tooltip_text */
2062 silcpurple_away_states, /* away_states */
2063 silcpurple_blist_node_menu, /* blist_node_menu */
2064 silcpurple_chat_info, /* chat_info */
2065 silcpurple_chat_info_defaults, /* chat_info_defaults */
2066 silcpurple_login, /* login */
2067 silcpurple_close, /* close */
2068 silcpurple_send_im, /* send_im */
2069 silcpurple_set_info, /* set_info */
2070 NULL, /* send_typing */
2071 silcpurple_get_info, /* get_info */
2072 silcpurple_set_status, /* set_status */
2073 silcpurple_idle_set, /* set_idle */
2074 silcpurple_change_passwd, /* change_passwd */
2075 silcpurple_add_buddy, /* add_buddy */
2076 NULL, /* add_buddies */
2077 silcpurple_remove_buddy, /* remove_buddy */
2078 NULL, /* remove_buddies */
2079 NULL, /* add_permit */
2080 NULL, /* add_deny */
2081 NULL, /* rem_permit */
2082 NULL, /* rem_deny */
2083 NULL, /* set_permit_deny */
2084 silcpurple_chat_join, /* join_chat */
2085 NULL, /* reject_chat */
2086 silcpurple_get_chat_name, /* get_chat_name */
2087 silcpurple_chat_invite, /* chat_invite */
2088 silcpurple_chat_leave, /* chat_leave */
2089 NULL, /* chat_whisper */
2090 silcpurple_chat_send, /* chat_send */
2091 silcpurple_keepalive, /* keepalive */
2092 NULL, /* register_user */
2093 NULL, /* get_cb_info */
2094 NULL, /* get_cb_away */
2095 NULL, /* alias_buddy */
2096 NULL, /* group_buddy */
2097 NULL, /* rename_group */
2098 NULL, /* buddy_free */
2099 NULL, /* convo_closed */
2100 NULL, /* normalize */
2101 silcpurple_buddy_set_icon, /* set_buddy_icon */
2102 NULL, /* remove_group */
2103 NULL, /* get_cb_real_name */
2104 silcpurple_chat_set_topic, /* set_chat_topic */
2105 NULL, /* find_blist_chat */
2106 silcpurple_roomlist_get_list, /* roomlist_get_list */
2107 silcpurple_roomlist_cancel, /* roomlist_cancel */
2108 NULL, /* roomlist_expand_category */
2109 NULL, /* can_receive_file */
2110 silcpurple_ftp_send_file, /* send_file */
2111 silcpurple_ftp_new_xfer, /* new_xfer */
2112 NULL, /* offline_message */
2113 &silcpurple_wb_ops, /* whiteboard_prpl_ops */
2114 NULL, /* send_raw */
2115 NULL, /* roomlist_room_serialize */
2116 NULL, /* unregister_user */
2117 NULL, /* send_attention */
2118 NULL, /* get_attention_types */
2119 sizeof(PurplePluginProtocolInfo), /* struct_size */
2120 NULL, /* get_account_text_table */
2121 NULL, /* initiate_media */
2122 NULL, /* get_media_caps */
2123 NULL, /* get_moods */
2124 NULL, /* set_public_alias */
2125 NULL, /* get_public_alias */
2126 NULL, /* add_buddy_with_invite */
2127 NULL, /* add_buddies_with_invite */
2128 NULL, /* get_cb_alias */
2129 NULL, /* chat_can_receive_file */
2130 NULL, /* chat_send_file */
2131 };
2132
2133 static PurplePluginInfo info =
2134 {
2135 PURPLE_PLUGIN_MAGIC,
2136 PURPLE_MAJOR_VERSION,
2137 PURPLE_MINOR_VERSION,
2138 PURPLE_PLUGIN_PROTOCOL, /**< type */
2139 NULL, /**< ui_requirement */
2140 0, /**< flags */
2141 NULL, /**< dependencies */
2142 PURPLE_PRIORITY_DEFAULT, /**< priority */
2143
2144 "prpl-silc", /**< id */
2145 "SILC", /**< name */
2146 "1.1", /**< version */
2147 /** summary */
2148 N_("SILC Protocol Plugin"),
2149 /** description */
2150 N_("Secure Internet Live Conferencing (SILC) Protocol"),
2151 "Pekka Riikonen", /**< author */
2152 "http://silcnet.org/", /**< homepage */
2153
2154 NULL, /**< load */
2155 NULL, /**< unload */
2156 NULL, /**< destroy */
2157
2158 NULL, /**< ui_info */
2159 &prpl_info, /**< extra_info */
2160 NULL, /**< prefs_info */
2161 silcpurple_actions,
2162
2163 /* padding */
2164 NULL,
2165 NULL,
2166 NULL,
2167 NULL
2168 };
2169
2170 #if 0
2171 static SilcBool silcpurple_debug_cb(char *file, char *function, int line,
2172 char *message, void *context)
2173 {
2174 purple_debug_info("SILC", "%s:%d:%s - %s\n", file ? file : "(null)", line, function ? function : "(null)", message ? message : "(null)");
2175 return TRUE;
2176 }
2177 #endif
2178
2179 static void
init_plugin(PurplePlugin * plugin)2180 init_plugin(PurplePlugin *plugin)
2181 {
2182 PurpleAccountOption *option;
2183 PurpleAccountUserSplit *split;
2184 char tmp[256];
2185 int i;
2186 PurpleKeyValuePair *kvp;
2187 GList *list = NULL;
2188
2189 silc_plugin = plugin;
2190
2191 split = purple_account_user_split_new(_("Network"), "silcnet.org", '@');
2192 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
2193
2194 /* Account options */
2195 option = purple_account_option_string_new(_("Connect server"),
2196 "server",
2197 "silc.silcnet.org");
2198 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
2199 option = purple_account_option_int_new(_("Port"), "port", 706);
2200 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
2201 g_snprintf(tmp, sizeof(tmp), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir());
2202 option = purple_account_option_string_new(_("Public Key file"),
2203 "public-key", tmp);
2204 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
2205 g_snprintf(tmp, sizeof(tmp), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir());
2206 option = purple_account_option_string_new(_("Private Key file"),
2207 "private-key", tmp);
2208 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
2209
2210 for (i = 0; silc_default_ciphers[i].name; i++) {
2211 kvp = g_new0(PurpleKeyValuePair, 1);
2212 kvp->key = g_strdup(silc_default_ciphers[i].name);
2213 kvp->value = g_strdup(silc_default_ciphers[i].name);
2214 list = g_list_append(list, kvp);
2215 }
2216 option = purple_account_option_list_new(_("Cipher"), "cipher", list);
2217 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
2218
2219 list = NULL;
2220 for (i = 0; silc_default_hmacs[i].name; i++) {
2221 kvp = g_new0(PurpleKeyValuePair, 1);
2222 kvp->key = g_strdup(silc_default_hmacs[i].name);
2223 kvp->value = g_strdup(silc_default_hmacs[i].name);
2224 list = g_list_append(list, kvp);
2225 }
2226 option = purple_account_option_list_new(_("HMAC"), "hmac", list);
2227 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
2228
2229 option = purple_account_option_bool_new(_("Use Perfect Forward Secrecy"),
2230 "pfs", FALSE);
2231 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
2232
2233 option = purple_account_option_bool_new(_("Public key authentication"),
2234 "pubkey-auth", FALSE);
2235 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
2236 option = purple_account_option_bool_new(_("Block IMs without Key Exchange"),
2237 "block-ims", FALSE);
2238 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
2239 option = purple_account_option_bool_new(_("Block messages to whiteboard"),
2240 "block-wb", FALSE);
2241 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
2242 option = purple_account_option_bool_new(_("Automatically open whiteboard"),
2243 "open-wb", FALSE);
2244 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
2245 option = purple_account_option_bool_new(_("Digitally sign and verify all messages"),
2246 "sign-verify", FALSE);
2247 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
2248
2249 purple_prefs_remove("/plugins/prpl/silc");
2250
2251 silc_log_set_callback(SILC_LOG_ERROR, silcpurple_log_error, NULL);
2252 silcpurple_register_commands();
2253
2254 #if 0
2255 silc_log_debug(TRUE);
2256 silc_log_set_debug_string("*client*");
2257 silc_log_quick(TRUE);
2258 silc_log_set_debug_callbacks(silcpurple_debug_cb, NULL, NULL, NULL);
2259 #endif
2260
2261 }
2262
2263 PURPLE_INIT_PLUGIN(silc, init_plugin, info);
2264