comparison src/protocols/silc/silc.c @ 8849:50d0f76639e7

[gaim-migrate @ 9616] Let there be SILC. committer: Tailor Script <tailor@pidgin.im>
author Ethan Blanton <elb@pidgin.im>
date Sat, 01 May 2004 19:34:44 +0000
parents
children 4f7c365c5c5a
comparison
equal deleted inserted replaced
8848:56e6b9bdcdbc 8849:50d0f76639e7
1 /*
2
3 silcgaim.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2004 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 "silcgaim.h"
23
24 extern SilcClientOperations ops;
25 static GaimPlugin *silc_plugin = NULL;
26
27 static const char *
28 silcgaim_list_icon(GaimAccount *a, GaimBuddy *b)
29 {
30 return (const char *)"silc";
31 }
32
33 static void
34 silcgaim_list_emblems(GaimBuddy *b, char **se, char **sw,
35 char **nw, char **ne)
36 {
37 }
38
39 static GList *
40 silcgaim_away_states(GaimConnection *gc)
41 {
42 GList *st = NULL;
43
44 st = g_list_append(st, _("Online"));
45 st = g_list_append(st, _("Hyper Active"));
46 st = g_list_append(st, _("Away"));
47 st = g_list_append(st, _("Busy"));
48 st = g_list_append(st, _("Indisposed"));
49 st = g_list_append(st, _("Wake Me Up"));
50
51 return st;
52 }
53
54 static void
55 silcgaim_set_away(GaimConnection *gc, const char *state, const char *msg)
56 {
57 SilcGaim sg = gc->proto_data;
58 SilcUInt32 mode;
59 SilcBuffer idp;
60 unsigned char mb[4];
61
62 if (!state)
63 return;
64 if (!sg->conn)
65 return;
66
67 mode = sg->conn->local_entry->mode;
68 mode &= ~(SILC_UMODE_GONE |
69 SILC_UMODE_HYPER |
70 SILC_UMODE_BUSY |
71 SILC_UMODE_INDISPOSED |
72 SILC_UMODE_PAGE);
73
74 if (!strcmp(state, _("Hyper Active")))
75 mode |= SILC_UMODE_HYPER;
76 else if (!strcmp(state, _("Away")))
77 mode |= SILC_UMODE_GONE;
78 else if (!strcmp(state, _("Busy")))
79 mode |= SILC_UMODE_BUSY;
80 else if (!strcmp(state, _("Indisposed")))
81 mode |= SILC_UMODE_INDISPOSED;
82 else if (!strcmp(state, _("Wake Me Up")))
83 mode |= SILC_UMODE_PAGE;
84
85 /* Send UMODE */
86 idp = silc_id_payload_encode(sg->conn->local_id, SILC_ID_CLIENT);
87 SILC_PUT32_MSB(mode, mb);
88 silc_client_command_send(sg->client, sg->conn, SILC_COMMAND_UMODE,
89 ++sg->conn->cmd_ident, 2,
90 1, idp->data, idp->len,
91 2, mb, sizeof(mb));
92 silc_buffer_free(idp);
93 }
94
95
96 /*************************** Connection Routines *****************************/
97
98 static void
99 silcgaim_keepalive(GaimConnection *gc)
100 {
101 SilcGaim sg = gc->proto_data;
102 silc_client_send_packet(sg->client, sg->conn, SILC_PACKET_HEARTBEAT,
103 NULL, 0);
104 }
105
106 static int
107 silcgaim_scheduler(gpointer *context)
108 {
109 SilcGaim sg = (SilcGaim)context;
110 silc_client_run_one(sg->client);
111 return 1;
112 }
113
114 static void
115 silcgaim_nickname_parse(const char *nickname,
116 char **ret_nickname)
117 {
118 silc_parse_userfqdn(nickname, ret_nickname, NULL);
119 }
120
121 static void
122 silcgaim_login_connected(gpointer data, gint source, GaimInputCondition cond)
123 {
124 GaimConnection *gc = data;
125 SilcGaim sg = gc->proto_data;
126 SilcClient client = sg->client;
127 SilcClientConnection conn;
128 GaimAccount *account = sg->account;
129 SilcClientConnectionParams params;
130 const char *dfile;
131
132 if (source < 0) {
133 gaim_connection_error(gc, _("Connection failed"));
134 return;
135 }
136 if (!g_list_find(gaim_connections_get_all(), gc)) {
137 close(source);
138 g_source_remove(sg->scheduler);
139 silc_client_stop(sg->client);
140 silc_client_free(sg->client);
141 silc_free(sg);
142 return;
143 }
144
145 /* Get session detachment data, if available */
146 memset(&params, 0, sizeof(params));
147 dfile = silcgaim_session_file(gaim_account_get_username(sg->account));
148 params.detach_data = silc_file_readfile(dfile, &params.detach_data_len);
149 if (params.detach_data)
150 params.detach_data[params.detach_data_len] = 0;
151
152 /* Add connection to SILC client library */
153 conn = silc_client_add_connection(
154 sg->client, &params,
155 (char *)gaim_account_get_string(account, "server",
156 "silc.silcnet.org"),
157 gaim_account_get_int(account, "port", 706), sg);
158 if (!conn) {
159 gaim_connection_error(gc, _("Cannot initialize SILC Client connection"));
160 gc->proto_data = NULL;
161 return;
162 }
163 sg->conn = conn;
164
165 /* Progress */
166 if (params.detach_data) {
167 gaim_connection_update_progress(gc, _("Resuming session"), 2, 5);
168 sg->resuming = TRUE;
169 } else {
170 gaim_connection_update_progress(gc, _("Performing key exchange"), 2, 5);
171 }
172
173 /* Perform SILC Key Exchange. The "silc_connected" will be called
174 eventually. */
175 silc_client_start_key_exchange(sg->client, sg->conn, source);
176
177 /* Set default attributes */
178 if (!gaim_account_get_bool(account, "reject-attrs", FALSE)) {
179 SilcUInt32 mask;
180 const char *tmp;
181 #ifdef HAVE_SYS_UTSNAME_H
182 struct utsname u;
183 #endif
184
185 mask = SILC_ATTRIBUTE_MOOD_NORMAL;
186 silc_client_attribute_add(client, conn,
187 SILC_ATTRIBUTE_STATUS_MOOD,
188 SILC_32_TO_PTR(mask),
189 sizeof(SilcUInt32));
190 mask = SILC_ATTRIBUTE_CONTACT_CHAT;
191 silc_client_attribute_add(client, conn,
192 SILC_ATTRIBUTE_PREFERRED_CONTACT,
193 SILC_32_TO_PTR(mask),
194 sizeof(SilcUInt32));
195 #ifdef HAVE_SYS_UTSNAME_H
196 if (!uname(&u)) {
197 SilcAttributeObjDevice dev;
198 memset(&dev, 0, sizeof(dev));
199 dev.type = SILC_ATTRIBUTE_DEVICE_COMPUTER;
200 dev.version = u.release;
201 dev.model = u.sysname;
202 silc_client_attribute_add(client, conn,
203 SILC_ATTRIBUTE_DEVICE_INFO,
204 (void *)&dev, sizeof(dev));
205 }
206 #endif
207 #ifdef _WIN32
208 tmp = _tzname[0];
209 #else
210 tmp = tzname[0];
211 #endif
212 silc_client_attribute_add(client, conn,
213 SILC_ATTRIBUTE_TIMEZONE,
214 (void *)tmp, strlen(tmp));
215 }
216
217 silc_free(params.detach_data);
218 }
219
220 static void
221 silcgaim_login(GaimAccount *account)
222 {
223 SilcGaim sg;
224 SilcClient client;
225 SilcClientParams params;
226 GaimConnection *gc;
227
228 gc = account->gc;
229 if (!gc)
230 return;
231 gc->proto_data = NULL;
232
233 memset(&params, 0, sizeof(params));
234 strcat(params.nickname_format, "%n@%h%a");
235 params.nickname_parse = silcgaim_nickname_parse;
236 params.ignore_requested_attributes =
237 gaim_account_get_bool(account, "reject-attrs", FALSE);
238
239 /* Allocate SILC client */
240 client = silc_client_alloc(&ops, &params, gc, NULL);
241 if (!client) {
242 gaim_connection_error(gc, _("Out of memory"));
243 return;
244 }
245
246 /* Get username, real name and local hostname for SILC library */
247 if (gaim_account_get_username(account)) {
248 client->username = strdup(gaim_account_get_username(account));
249 } else {
250 client->username = silc_get_username();
251 gaim_account_set_username(account, client->username);
252 }
253 if (gaim_account_get_user_info(account)) {
254 client->realname = strdup(gaim_account_get_user_info(account));
255 } else {
256 client->realname = silc_get_real_name();
257 gaim_account_set_user_info(account, client->realname);
258 }
259 client->hostname = silc_net_localhost();
260
261 gaim_connection_set_display_name(gc, client->username);
262
263 /* Init SILC client */
264 if (!silc_client_init(client)) {
265 gaim_connection_error(gc, ("Cannot initialize SILC protocol"));
266 return;
267 }
268
269 /* Check the ~/.silc dir and create it, and new key pair if necessary. */
270 if (!silcgaim_check_silc_dir(gc)) {
271 gaim_connection_error(gc, ("Cannot find/access ~/.silc directory"));
272 return;
273 }
274
275 /* Progress */
276 gaim_connection_update_progress(gc, _("Connecting to SILC Server"), 1, 5);
277
278 /* Load SILC key pair */
279 if (!silc_load_key_pair(gaim_prefs_get_string("/plugins/prpl/silc/pubkey"),
280 gaim_prefs_get_string("/plugins/prpl/silc/privkey"),
281 "", &client->pkcs, &client->public_key,
282 &client->private_key)) {
283 gaim_connection_error(gc, ("Could not load SILC key pair"));
284 return;
285 }
286
287 sg = silc_calloc(1, sizeof(*sg));
288 if (!sg)
289 return;
290 memset(sg, 0, sizeof(*sg));
291 sg->client = client;
292 sg->gc = gc;
293 sg->account = account;
294 gc->proto_data = sg;
295
296 /* Connect to the SILC server */
297 if (gaim_proxy_connect(account,
298 gaim_account_get_string(account, "server",
299 "silc.silcnet.org"),
300 gaim_account_get_int(account, "port", 706),
301 silcgaim_login_connected, gc)) {
302 gaim_connection_error(gc, ("Unable to create connection"));
303 return;
304 }
305
306 /* Schedule SILC using Glib's event loop */
307 sg->scheduler = g_timeout_add(5, (GSourceFunc)silcgaim_scheduler, sg);
308 }
309
310 static int
311 silcgaim_close_final(gpointer *context)
312 {
313 SilcGaim sg = (SilcGaim)context;
314 silc_client_stop(sg->client);
315 silc_client_free(sg->client);
316 silc_free(sg);
317 return 0;
318 }
319
320 static void
321 silcgaim_close_convos(GaimConversation *convo)
322 {
323 if (convo)
324 gaim_conversation_destroy(convo);
325 }
326
327 static void
328 silcgaim_close(GaimConnection *gc)
329 {
330 SilcGaim sg = gc->proto_data;
331 if (!sg)
332 return;
333
334 /* Close all conversations */
335 gaim_conversation_foreach(silcgaim_close_convos);
336
337 /* Send QUIT */
338 silc_client_command_call(sg->client, sg->conn, NULL,
339 "QUIT", "Leaving", NULL);
340
341 if (sg->conn)
342 silc_client_close_connection(sg->client, sg->conn);
343
344 g_source_remove(sg->scheduler);
345 g_timeout_add(1, (GSourceFunc)silcgaim_close_final, sg);
346 }
347
348
349 /****************************** Protocol Actions *****************************/
350
351 static void
352 silcgaim_attrs_cancel(GaimConnection *gc, GaimRequestFields *fields)
353 {
354 /* Nothing */
355 }
356
357 static void
358 silcgaim_attrs_cb(GaimConnection *gc, GaimRequestFields *fields)
359 {
360 SilcGaim sg = gc->proto_data;
361 SilcClient client = sg->client;
362 SilcClientConnection conn = sg->conn;
363 GaimRequestField *f;
364 char *tmp;
365 SilcUInt32 tmp_len, mask;
366 SilcAttributeObjService service;
367 SilcAttributeObjDevice dev;
368 SilcVCardStruct vcard;
369 const char *val;
370
371 sg = gc->proto_data;
372 if (!sg)
373 return;
374
375 memset(&service, 0, sizeof(service));
376 memset(&dev, 0, sizeof(dev));
377 memset(&vcard, 0, sizeof(vcard));
378
379 silc_client_attribute_del(client, conn,
380 SILC_ATTRIBUTE_USER_INFO, NULL);
381 silc_client_attribute_del(client, conn,
382 SILC_ATTRIBUTE_SERVICE, NULL);
383 silc_client_attribute_del(client, conn,
384 SILC_ATTRIBUTE_STATUS_MOOD, NULL);
385 silc_client_attribute_del(client, conn,
386 SILC_ATTRIBUTE_STATUS_FREETEXT, NULL);
387 silc_client_attribute_del(client, conn,
388 SILC_ATTRIBUTE_STATUS_MESSAGE, NULL);
389 silc_client_attribute_del(client, conn,
390 SILC_ATTRIBUTE_PREFERRED_LANGUAGE, NULL);
391 silc_client_attribute_del(client, conn,
392 SILC_ATTRIBUTE_PREFERRED_CONTACT, NULL);
393 silc_client_attribute_del(client, conn,
394 SILC_ATTRIBUTE_TIMEZONE, NULL);
395 silc_client_attribute_del(client, conn,
396 SILC_ATTRIBUTE_GEOLOCATION, NULL);
397 silc_client_attribute_del(client, conn,
398 SILC_ATTRIBUTE_DEVICE_INFO, NULL);
399
400 /* Set mood */
401 mask = 0;
402 f = gaim_request_fields_get_field(fields, "mood_normal");
403 if (f && gaim_request_field_bool_get_value(f))
404 mask |= SILC_ATTRIBUTE_MOOD_NORMAL;
405 f = gaim_request_fields_get_field(fields, "mood_happy");
406 if (f && gaim_request_field_bool_get_value(f))
407 mask |= SILC_ATTRIBUTE_MOOD_HAPPY;
408 f = gaim_request_fields_get_field(fields, "mood_sad");
409 if (f && gaim_request_field_bool_get_value(f))
410 mask |= SILC_ATTRIBUTE_MOOD_SAD;
411 f = gaim_request_fields_get_field(fields, "mood_angry");
412 if (f && gaim_request_field_bool_get_value(f))
413 mask |= SILC_ATTRIBUTE_MOOD_ANGRY;
414 f = gaim_request_fields_get_field(fields, "mood_jealous");
415 if (f && gaim_request_field_bool_get_value(f))
416 mask |= SILC_ATTRIBUTE_MOOD_JEALOUS;
417 f = gaim_request_fields_get_field(fields, "mood_ashamed");
418 if (f && gaim_request_field_bool_get_value(f))
419 mask |= SILC_ATTRIBUTE_MOOD_ASHAMED;
420 f = gaim_request_fields_get_field(fields, "mood_invincible");
421 if (f && gaim_request_field_bool_get_value(f))
422 mask |= SILC_ATTRIBUTE_MOOD_INVINCIBLE;
423 f = gaim_request_fields_get_field(fields, "mood_inlove");
424 if (f && gaim_request_field_bool_get_value(f))
425 mask |= SILC_ATTRIBUTE_MOOD_INLOVE;
426 f = gaim_request_fields_get_field(fields, "mood_sleepy");
427 if (f && gaim_request_field_bool_get_value(f))
428 mask |= SILC_ATTRIBUTE_MOOD_SLEEPY;
429 f = gaim_request_fields_get_field(fields, "mood_bored");
430 if (f && gaim_request_field_bool_get_value(f))
431 mask |= SILC_ATTRIBUTE_MOOD_BORED;
432 f = gaim_request_fields_get_field(fields, "mood_excited");
433 if (f && gaim_request_field_bool_get_value(f))
434 mask |= SILC_ATTRIBUTE_MOOD_EXCITED;
435 f = gaim_request_fields_get_field(fields, "mood_anxious");
436 if (f && gaim_request_field_bool_get_value(f))
437 mask |= SILC_ATTRIBUTE_MOOD_ANXIOUS;
438 silc_client_attribute_add(client, conn,
439 SILC_ATTRIBUTE_STATUS_MOOD,
440 SILC_32_TO_PTR(mask),
441 sizeof(SilcUInt32));
442
443 /* Set preferred contact */
444 mask = 0;
445 f = gaim_request_fields_get_field(fields, "contact_chat");
446 if (f && gaim_request_field_bool_get_value(f))
447 mask |= SILC_ATTRIBUTE_CONTACT_CHAT;
448 f = gaim_request_fields_get_field(fields, "contact_email");
449 if (f && gaim_request_field_bool_get_value(f))
450 mask |= SILC_ATTRIBUTE_CONTACT_EMAIL;
451 f = gaim_request_fields_get_field(fields, "contact_call");
452 if (f && gaim_request_field_bool_get_value(f))
453 mask |= SILC_ATTRIBUTE_CONTACT_CALL;
454 f = gaim_request_fields_get_field(fields, "contact_sms");
455 if (f && gaim_request_field_bool_get_value(f))
456 mask |= SILC_ATTRIBUTE_CONTACT_SMS;
457 f = gaim_request_fields_get_field(fields, "contact_mms");
458 if (f && gaim_request_field_bool_get_value(f))
459 mask |= SILC_ATTRIBUTE_CONTACT_MMS;
460 f = gaim_request_fields_get_field(fields, "contact_video");
461 if (f && gaim_request_field_bool_get_value(f))
462 mask |= SILC_ATTRIBUTE_CONTACT_VIDEO;
463 if (mask)
464 silc_client_attribute_add(client, conn,
465 SILC_ATTRIBUTE_PREFERRED_CONTACT,
466 SILC_32_TO_PTR(mask),
467 sizeof(SilcUInt32));
468
469 /* Set status text */
470 val = NULL;
471 f = gaim_request_fields_get_field(fields, "status_text");
472 if (f)
473 val = gaim_request_field_string_get_value(f);
474 if (val && *val)
475 silc_client_attribute_add(client, conn,
476 SILC_ATTRIBUTE_STATUS_FREETEXT,
477 (void *)val, strlen(val));
478
479 /* Set vcard */
480 val = NULL;
481 f = gaim_request_fields_get_field(fields, "vcard");
482 if (f)
483 val = gaim_request_field_string_get_value(f);
484 if (val && *val) {
485 gaim_prefs_set_string("/plugins/prpl/silc/vcard", val);
486 gaim_prefs_sync();
487 tmp = silc_file_readfile(val, &tmp_len);
488 if (tmp) {
489 tmp[tmp_len] = 0;
490 if (silc_vcard_decode(tmp, tmp_len, &vcard))
491 silc_client_attribute_add(client, conn,
492 SILC_ATTRIBUTE_USER_INFO,
493 (void *)&vcard,
494 sizeof(vcard));
495 }
496 silc_vcard_free(&vcard);
497 silc_free(tmp);
498 }
499
500 #ifdef HAVE_SYS_UTSNAME_H
501 /* Set device info */
502 f = gaim_request_fields_get_field(fields, "device");
503 if (f && gaim_request_field_bool_get_value(f)) {
504 struct utsname u;
505 if (!uname(&u)) {
506 dev.type = SILC_ATTRIBUTE_DEVICE_COMPUTER;
507 dev.version = u.release;
508 dev.model = u.sysname;
509 silc_client_attribute_add(client, conn,
510 SILC_ATTRIBUTE_DEVICE_INFO,
511 (void *)&dev, sizeof(dev));
512 }
513 }
514 #endif
515
516 /* Set timezone */
517 val = NULL;
518 f = gaim_request_fields_get_field(fields, "timezone");
519 if (f)
520 val = gaim_request_field_string_get_value(f);
521 if (val && *val)
522 silc_client_attribute_add(client, conn,
523 SILC_ATTRIBUTE_TIMEZONE,
524 (void *)val, strlen(val));
525 }
526
527 static void
528 silcgaim_attrs(GaimConnection *gc)
529 {
530 SilcGaim sg = gc->proto_data;
531 SilcClient client = sg->client;
532 SilcClientConnection conn = sg->conn;
533 GaimRequestFields *fields;
534 GaimRequestFieldGroup *g;
535 GaimRequestField *f;
536 SilcHashTable attrs;
537 SilcAttributePayload attr;
538 gboolean mnormal = TRUE, mhappy = FALSE, msad = FALSE,
539 mangry = FALSE, mjealous = FALSE, mashamed = FALSE,
540 minvincible = FALSE, minlove = FALSE, msleepy = FALSE,
541 mbored = FALSE, mexcited = FALSE, manxious = FALSE;
542 gboolean cemail = FALSE, ccall = FALSE, csms = FALSE,
543 cmms = FALSE, cchat = TRUE, cvideo = FALSE;
544 gboolean device = TRUE;
545 char status[1024];
546
547 sg = gc->proto_data;
548 if (!sg)
549 return;
550
551 memset(status, 0, sizeof(status));
552
553 attrs = silc_client_attributes_get(client, conn);
554 if (attrs) {
555 if (silc_hash_table_find(attrs,
556 SILC_32_TO_PTR(SILC_ATTRIBUTE_STATUS_MOOD),
557 NULL, (void *)&attr)) {
558 SilcUInt32 mood = 0;
559 silc_attribute_get_object(attr, &mood, sizeof(mood));
560 mnormal = !mood;
561 mhappy = (mood & SILC_ATTRIBUTE_MOOD_HAPPY);
562 msad = (mood & SILC_ATTRIBUTE_MOOD_SAD);
563 mangry = (mood & SILC_ATTRIBUTE_MOOD_ANGRY);
564 mjealous = (mood & SILC_ATTRIBUTE_MOOD_JEALOUS);
565 mashamed = (mood & SILC_ATTRIBUTE_MOOD_ASHAMED);
566 minvincible = (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE);
567 minlove = (mood & SILC_ATTRIBUTE_MOOD_INLOVE);
568 msleepy = (mood & SILC_ATTRIBUTE_MOOD_SLEEPY);
569 mbored = (mood & SILC_ATTRIBUTE_MOOD_BORED);
570 mexcited = (mood & SILC_ATTRIBUTE_MOOD_EXCITED);
571 manxious = (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS);
572 }
573
574 if (silc_hash_table_find(attrs,
575 SILC_32_TO_PTR(SILC_ATTRIBUTE_PREFERRED_CONTACT),
576 NULL, (void *)&attr)) {
577 SilcUInt32 contact = 0;
578 silc_attribute_get_object(attr, &contact, sizeof(contact));
579 cemail = (contact & SILC_ATTRIBUTE_CONTACT_EMAIL);
580 ccall = (contact & SILC_ATTRIBUTE_CONTACT_CALL);
581 csms = (contact & SILC_ATTRIBUTE_CONTACT_SMS);
582 cmms = (contact & SILC_ATTRIBUTE_CONTACT_MMS);
583 cchat = (contact & SILC_ATTRIBUTE_CONTACT_CHAT);
584 cvideo = (contact & SILC_ATTRIBUTE_CONTACT_VIDEO);
585 }
586
587 if (silc_hash_table_find(attrs,
588 SILC_32_TO_PTR(SILC_ATTRIBUTE_STATUS_FREETEXT),
589 NULL, (void *)&attr))
590 silc_attribute_get_object(attr, &status, sizeof(status));
591
592 if (!silc_hash_table_find(attrs,
593 SILC_32_TO_PTR(SILC_ATTRIBUTE_DEVICE_INFO),
594 NULL, (void *)&attr))
595 device = FALSE;
596 }
597
598 fields = gaim_request_fields_new();
599
600 g = gaim_request_field_group_new(NULL);
601 f = gaim_request_field_label_new("l3", _("Your Current Mood"));
602 gaim_request_field_group_add_field(g, f);
603 f = gaim_request_field_bool_new("mood_normal", _("Normal"), mnormal);
604 gaim_request_field_group_add_field(g, f);
605 f = gaim_request_field_bool_new("mood_happy", _("Happy"), mhappy);
606 gaim_request_field_group_add_field(g, f);
607 f = gaim_request_field_bool_new("mood_sad", _("Sad"), msad);
608 gaim_request_field_group_add_field(g, f);
609 f = gaim_request_field_bool_new("mood_angry", _("Angry"), mangry);
610 gaim_request_field_group_add_field(g, f);
611 f = gaim_request_field_bool_new("mood_jealous", _("Jealous"), mjealous);
612 gaim_request_field_group_add_field(g, f);
613 f = gaim_request_field_bool_new("mood_ashamed", _("Ashamed"), mashamed);
614 gaim_request_field_group_add_field(g, f);
615 f = gaim_request_field_bool_new("mood_invincible", _("Invincible"), minvincible);
616 gaim_request_field_group_add_field(g, f);
617 f = gaim_request_field_bool_new("mood_inlove", _("In Love"), minlove);
618 gaim_request_field_group_add_field(g, f);
619 f = gaim_request_field_bool_new("mood_sleepy", _("Sleepy"), msleepy);
620 gaim_request_field_group_add_field(g, f);
621 f = gaim_request_field_bool_new("mood_bored", _("Bored"), mbored);
622 gaim_request_field_group_add_field(g, f);
623 f = gaim_request_field_bool_new("mood_excited", _("Excited"), mexcited);
624 gaim_request_field_group_add_field(g, f);
625 f = gaim_request_field_bool_new("mood_anxious", _("Anxious"), manxious);
626 gaim_request_field_group_add_field(g, f);
627
628 f = gaim_request_field_label_new("l4", _("\nYour Preferred Contact Methods"));
629 gaim_request_field_group_add_field(g, f);
630 f = gaim_request_field_bool_new("contact_chat", _("Chat"), cchat);
631 gaim_request_field_group_add_field(g, f);
632 f = gaim_request_field_bool_new("contact_email", _("Email"), cemail);
633 gaim_request_field_group_add_field(g, f);
634 f = gaim_request_field_bool_new("contact_call", _("Phone"), ccall);
635 gaim_request_field_group_add_field(g, f);
636 f = gaim_request_field_bool_new("contact_sms", _("SMS"), csms);
637 gaim_request_field_group_add_field(g, f);
638 f = gaim_request_field_bool_new("contact_mms", _("MMS"), cmms);
639 gaim_request_field_group_add_field(g, f);
640 f = gaim_request_field_bool_new("contact_video", _("Video Conferencing"), cvideo);
641 gaim_request_field_group_add_field(g, f);
642 gaim_request_fields_add_group(fields, g);
643
644 g = gaim_request_field_group_new(NULL);
645 f = gaim_request_field_string_new("status_text", _("Your Current Status"),
646 status[0] ? status : NULL, TRUE);
647 gaim_request_field_group_add_field(g, f);
648 gaim_request_fields_add_group(fields, g);
649
650 g = gaim_request_field_group_new(NULL);
651 #if 0
652 f = gaim_request_field_label_new("l2", _("Online Services"));
653 gaim_request_field_group_add_field(g, f);
654 f = gaim_request_field_bool_new("services",
655 _("Let others see what services you are using"),
656 TRUE);
657 gaim_request_field_group_add_field(g, f);
658 #endif
659 #ifdef HAVE_SYS_UTSNAME_H
660 f = gaim_request_field_bool_new("device",
661 _("Let others see what computer you are using"),
662 device);
663 gaim_request_field_group_add_field(g, f);
664 #endif
665 gaim_request_fields_add_group(fields, g);
666
667 g = gaim_request_field_group_new(NULL);
668 f = gaim_request_field_string_new("vcard", _("Your VCard File"),
669 gaim_prefs_get_string("/plugins/prpl/silc/vcard"),
670 FALSE);
671 gaim_request_field_group_add_field(g, f);
672 #ifdef _WIN32
673 f = gaim_request_field_string_new("timezone", _("Timezone"), _tzname[0], FALSE);
674 #else
675 f = gaim_request_field_string_new("timezone", _("Timezone"), tzname[0], FALSE);
676 #endif
677 gaim_request_field_group_add_field(g, f);
678 gaim_request_fields_add_group(fields, g);
679
680
681 gaim_request_fields(NULL, _("User Online Status Attributes"),
682 _("User Online Status Attributes"),
683 _("You can let other users see your online status information "
684 "and your personal information. Please fill the information "
685 "you would like other users to see about yourself."),
686 fields,
687 "OK", G_CALLBACK(silcgaim_attrs_cb),
688 "Cancel", G_CALLBACK(silcgaim_attrs_cancel), gc);
689 }
690
691 static void
692 silcgaim_detach(GaimConnection *gc)
693 {
694 SilcGaim sg;
695
696 if (!gc)
697 return;
698 sg = gc->proto_data;
699 if (!sg)
700 return;
701
702 /* Call DETACH */
703 silc_client_command_call(sg->client, sg->conn, "DETACH");
704 sg->detaching = TRUE;
705 }
706
707 static void
708 silcgaim_view_motd(GaimConnection *gc)
709 {
710 SilcGaim sg;
711
712 if (!gc)
713 return;
714 sg = gc->proto_data;
715 if (!sg)
716 return;
717
718 if (!sg->motd) {
719 gaim_notify_error(
720 gc, _("Message of the Day"), _("No Message of the Day available"),
721 _("There is no Message of the Day associated with this connection"));
722 return;
723 }
724
725 gaim_notify_formatted(gc, "Message of the Day", "Message of the Day", NULL,
726 sg->motd, NULL, NULL);
727 }
728
729 static GList *
730 silcgaim_actions(GaimConnection *gc)
731 {
732 struct proto_actions_menu *pam;
733 GList *list = NULL;
734
735 if (!gaim_account_get_bool(gc->account, "reject-attrs", FALSE)) {
736 pam = g_new0(struct proto_actions_menu, 1);
737 pam->label = _("Online Status");
738 pam->callback = silcgaim_attrs;
739 pam->gc = gc;
740 list = g_list_append(list, pam);
741 }
742
743 pam = g_new0(struct proto_actions_menu, 1);
744 pam->label = _("Detach From Server");
745 pam->callback = silcgaim_detach;
746 pam->gc = gc;
747 list = g_list_append(list, pam);
748
749 pam = g_new0(struct proto_actions_menu, 1);
750 pam->label = _("View Message of the Day");
751 pam->callback = silcgaim_view_motd;
752 pam->gc = gc;
753 list = g_list_append(list, pam);
754
755 return list;
756 }
757
758
759 /******************************* IM Routines *********************************/
760
761 typedef struct {
762 char *nick;
763 unsigned char *message;
764 SilcUInt32 message_len;
765 SilcMessageFlags flags;
766 } *SilcGaimIM;
767
768 static void
769 silcgaim_send_im_resolved(SilcClient client,
770 SilcClientConnection conn,
771 SilcClientEntry *clients,
772 SilcUInt32 clients_count,
773 void *context)
774 {
775 GaimConnection *gc = client->application;
776 SilcGaim sg = gc->proto_data;
777 SilcGaimIM im = context;
778 GaimConversation *convo;
779 char tmp[256], *nickname = NULL;
780 SilcClientEntry client_entry;
781
782 convo = gaim_find_conversation_with_account(im->nick, sg->account);
783 if (!convo)
784 return;
785
786 if (!clients)
787 goto err;
788
789 if (clients_count > 1) {
790 silc_parse_userfqdn(im->nick, &nickname, NULL);
791
792 /* Find the correct one. The im->nick might be a formatted nick
793 so this will find the correct one. */
794 clients = silc_client_get_clients_local(client, conn,
795 nickname, im->nick,
796 &clients_count);
797 if (!clients)
798 goto err;
799 client_entry = clients[0];
800 silc_free(clients);
801 } else {
802 client_entry = clients[0];
803 }
804
805 /* Send the message */
806 silc_client_send_private_message(client, conn, client_entry, im->flags,
807 im->message, im->message_len, TRUE);
808 gaim_conv_im_write(GAIM_CONV_IM(convo), conn->local_entry->nickname,
809 im->message, 0, time(NULL));
810
811 goto out;
812
813 err:
814 g_snprintf(tmp, sizeof(tmp),
815 _("User <I>%s</I> is not present in the network"), im->nick);
816 gaim_conversation_write(convo, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL));
817
818 out:
819 g_free(im->nick);
820 g_free(im->message);
821 silc_free(im);
822 silc_free(nickname);
823 }
824
825 static int
826 silcgaim_send_im(GaimConnection *gc, const char *who, const char *msg,
827 GaimConvImFlags flags)
828 {
829 SilcGaim sg = gc->proto_data;
830 SilcClient client = sg->client;
831 SilcClientConnection conn = sg->conn;
832 SilcClientEntry *clients;
833 SilcUInt32 clients_count, mflags;
834 char *nickname;
835 int ret;
836 gboolean sign = gaim_prefs_get_bool("/plugins/prpl/silc/sign_im");
837
838 if (!who || !msg)
839 return 0;
840
841 /* See if command */
842 if (strlen(msg) > 1 && msg[0] == '/') {
843 if (!silc_client_command_call(client, conn, msg + 1))
844 gaim_notify_error(gc, ("Call Command"), _("Cannot call command"),
845 _("Unknown command"));
846 return 0;
847 }
848
849 if (!silc_parse_userfqdn(who, &nickname, NULL))
850 return 0;
851
852 mflags = SILC_MESSAGE_FLAG_UTF8;
853 if (sign)
854 mflags |= SILC_MESSAGE_FLAG_SIGNED;
855
856 /* Find client entry */
857 clients = silc_client_get_clients_local(client, conn, nickname, who,
858 &clients_count);
859 if (!clients) {
860 /* Resolve unknown user */
861 SilcGaimIM im = silc_calloc(1, sizeof(*im));
862 if (!im)
863 return 0;
864 im->nick = g_strdup(who);
865 im->message = g_strdup(msg);
866 im->message_len = strlen(im->message);
867 im->flags = mflags;
868 silc_client_get_clients(client, conn, nickname, NULL,
869 silcgaim_send_im_resolved, im);
870 silc_free(nickname);
871 return 0;
872 }
873
874 /* Send private message directly */
875 ret = silc_client_send_private_message(client, conn, clients[0],
876 mflags, (char *)msg,
877 strlen(msg), TRUE);
878
879 silc_free(nickname);
880 silc_free(clients);
881 return ret;
882 }
883
884
885 /************************** Plugin Initialization ****************************/
886
887 static GaimPluginPrefFrame *
888 silcgaim_pref_frame(GaimPlugin *plugin)
889 {
890 GaimPluginPrefFrame *frame;
891 GaimPluginPref *ppref;
892
893 frame = gaim_plugin_pref_frame_new();
894
895 ppref = gaim_plugin_pref_new_with_label(_("Instant Messages"));
896 gaim_plugin_pref_frame_add(frame, ppref);
897
898 ppref = gaim_plugin_pref_new_with_name_and_label(
899 "/plugins/prpl/silc/sign_im",
900 _("Digitally sign all IM messages"));
901 gaim_plugin_pref_frame_add(frame, ppref);
902
903 ppref = gaim_plugin_pref_new_with_name_and_label(
904 "/plugins/prpl/silc/verify_im",
905 _("Verify all IM message signatures"));
906 gaim_plugin_pref_frame_add(frame, ppref);
907
908 ppref = gaim_plugin_pref_new_with_label(_("Channel Messages"));
909 gaim_plugin_pref_frame_add(frame, ppref);
910
911 ppref = gaim_plugin_pref_new_with_name_and_label(
912 "/plugins/prpl/silc/sign_chat",
913 _("Digitally sign all channel messages"));
914 gaim_plugin_pref_frame_add(frame, ppref);
915
916 ppref = gaim_plugin_pref_new_with_name_and_label(
917 "/plugins/prpl/silc/verify_chat",
918 _("Verify all channel message signatures"));
919 gaim_plugin_pref_frame_add(frame, ppref);
920
921 ppref = gaim_plugin_pref_new_with_label(_("Default SILC Key Pair"));
922 gaim_plugin_pref_frame_add(frame, ppref);
923
924 ppref = gaim_plugin_pref_new_with_name_and_label(
925 "/plugins/prpl/silc/pubkey",
926 _("SILC Public Key"));
927 gaim_plugin_pref_frame_add(frame, ppref);
928
929 ppref = gaim_plugin_pref_new_with_name_and_label(
930 "/plugins/prpl/silc/privkey",
931 _("SILC Private Key"));
932 gaim_plugin_pref_frame_add(frame, ppref);
933
934 return frame;
935 }
936
937 static GaimPluginUiInfo prefs_info =
938 {
939 silcgaim_pref_frame,
940 };
941
942 static GaimPluginProtocolInfo prpl_info =
943 {
944 GAIM_PRPL_API_VERSION,
945 OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME |
946 OPT_PROTO_PASSWORD_OPTIONAL,
947 NULL,
948 NULL,
949 silcgaim_list_icon,
950 silcgaim_list_emblems,
951 silcgaim_status_text,
952 silcgaim_tooltip_text,
953 silcgaim_away_states,
954 silcgaim_actions,
955 silcgaim_buddy_menu,
956 silcgaim_chat_info,
957 silcgaim_login,
958 silcgaim_close,
959 silcgaim_send_im,
960 NULL,
961 NULL,
962 silcgaim_get_info,
963 silcgaim_set_away,
964 NULL,
965 NULL,
966 NULL,
967 silcgaim_idle_set,
968 NULL,
969 silcgaim_add_buddy,
970 silcgaim_add_buddies,
971 silcgaim_remove_buddy,
972 NULL,
973 NULL,
974 NULL,
975 NULL,
976 NULL,
977 NULL,
978 NULL,
979 silcgaim_chat_join,
980 NULL,
981 silcgaim_chat_invite,
982 silcgaim_chat_leave,
983 NULL,
984 silcgaim_chat_send,
985 silcgaim_keepalive,
986 NULL,
987 NULL,
988 NULL,
989 NULL,
990 NULL,
991 NULL,
992 NULL,
993 NULL,
994 NULL,
995 NULL,
996 NULL,
997 NULL,
998 silcgaim_chat_set_topic,
999 NULL,
1000 silcgaim_roomlist_get_list,
1001 silcgaim_roomlist_cancel,
1002 NULL,
1003 silcgaim_chat_menu
1004 };
1005
1006 static GaimPluginInfo info =
1007 {
1008 GAIM_PLUGIN_API_VERSION, /**< api_version */
1009 GAIM_PLUGIN_PROTOCOL, /**< type */
1010 NULL, /**< ui_requirement */
1011 0, /**< flags */
1012 NULL, /**< dependencies */
1013 GAIM_PRIORITY_DEFAULT, /**< priority */
1014
1015 "prpl-silc", /**< id */
1016 "SILC", /**< name */
1017 "1.0", /**< version */
1018 /** summary */
1019 N_("SILC Protocol Plugin"),
1020 /** description */
1021 N_("Secure Internet Live Conferencing (SILC) Protocol"),
1022 N_("Pekka Riikonen"), /**< author */
1023 N_("http://silcnet.org/"), /**< homepage */
1024
1025 NULL, /**< load */
1026 NULL, /**< unload */
1027 NULL, /**< destroy */
1028
1029 NULL, /**< ui_info */
1030 &prpl_info, /**< extra_info */
1031 &prefs_info /**< prefs_info */
1032 };
1033
1034 static void
1035 init_plugin(GaimPlugin *plugin)
1036 {
1037 GaimAccountOption *option;
1038 char tmp[256];
1039
1040 silc_plugin = plugin;
1041
1042 /* Account options */
1043 option = gaim_account_option_string_new(_("Connect server"),
1044 "server",
1045 "silc.silcnet.org");
1046 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1047 option = gaim_account_option_int_new(_("Port"), "port", 706);
1048 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1049
1050 option = gaim_account_option_bool_new(_("Public key authentication"),
1051 "pubkey-auth", FALSE);
1052 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1053 #if 0 /* XXX Public key auth interface with explicit key pair is
1054 broken in SILC Toolkit */
1055 g_snprintf(tmp, sizeof(tmp), _("%s/public_key.pub"), silcgaim_silcdir());
1056 option = gaim_account_option_string_new(_("Public Key File"),
1057 "public-key", tmp);
1058 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1059 g_snprintf(tmp, sizeof(tmp), _("%s/private_key.prv"), silcgaim_silcdir());
1060 option = gaim_account_option_string_new(_("Private Key File"),
1061 "public-key", tmp);
1062 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1063 #endif
1064
1065 option = gaim_account_option_bool_new(_("Reject watching by other users"),
1066 "reject-watch", FALSE);
1067 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1068 option = gaim_account_option_bool_new(_("Block invites"),
1069 "block-invites", FALSE);
1070 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1071 option = gaim_account_option_bool_new(_("Block IMs without Key Exchange"),
1072 "block-ims", FALSE);
1073 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1074 option = gaim_account_option_bool_new(_("Reject online status attribute requests"),
1075 "reject-attrs", FALSE);
1076 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1077
1078 /* Preferences */
1079 gaim_prefs_add_none("/plugins/prpl/silc");
1080 gaim_prefs_add_bool("/plugins/prpl/silc/sign_im", FALSE);
1081 gaim_prefs_add_bool("/plugins/prpl/silc/verify_im", FALSE);
1082 gaim_prefs_add_bool("/plugins/prpl/silc/sign_chat", FALSE);
1083 gaim_prefs_add_bool("/plugins/prpl/silc/verify_chat", FALSE);
1084 g_snprintf(tmp, sizeof(tmp), _("%s/public_key.pub"), silcgaim_silcdir());
1085 gaim_prefs_add_string("/plugins/prpl/silc/pubkey", tmp);
1086 g_snprintf(tmp, sizeof(tmp), _("%s/private_key.prv"), silcgaim_silcdir());
1087 gaim_prefs_add_string("/plugins/prpl/silc/privkey", tmp);
1088 gaim_prefs_add_string("/plugins/prpl/silc/vcard", "");
1089 }
1090
1091 GAIM_INIT_PLUGIN(silc, init_plugin, info);