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