comparison libpurple/protocols/silc10/silc.c @ 17567:ba1b50f114f6

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