Created SILC GIT repository.
[silc.git] / apps / irssi / src / silc / core / silc-queries.c
1 /*
2
3   silc-queries.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2002 - 2008 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 "module.h"
21 #include "signals.h"
22 #include "misc.h"
23 #include "silc-queries.h"
24 #include "settings.h"
25 #include "levels.h"
26 #include "modules.h"
27 #include "commands.h"
28 #include "misc.h"
29
30 #include "fe-common/core/printtext.h"
31 #include "fe-common/core/fe-channels.h"
32 #include "fe-common/core/keyboard.h"
33 #include "fe-common/silc/module-formats.h"
34
35 static void silc_query_attributes_print_final(bool success, void *context);
36 static void silc_query_attributes_accept(const char *line, void *context);
37
38 QUERY_REC *silc_query_create(const char *server_tag,
39                              const char *nick, int automatic)
40 {
41   QUERY_REC *rec;
42
43   g_return_val_if_fail(nick != NULL, NULL);
44
45   rec = g_new0(QUERY_REC, 1);
46   rec->chat_type = SILC_PROTOCOL;
47   rec->name = g_strdup(nick);
48   rec->server_tag = g_strdup(server_tag);
49   query_init(rec, automatic);
50   return rec;
51 }
52
53 void silc_queries_init(void)
54 {
55 }
56
57 void silc_queries_deinit(void)
58 {
59 }
60
61 /* ATTR command */
62
63 void command_attr(const char *data, SILC_SERVER_REC *server,
64                   WI_ITEM_REC *item)
65 {
66   char *tmp;
67   unsigned char **argv;
68   SilcUInt32 argc;
69   SilcUInt32 *argv_lens, *argv_types;
70   const char *sv;
71   bool allowed;
72
73   /* Now parse all arguments */
74   tmp = g_strconcat("ATTR", " ", data, NULL);
75   silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 3);
76   g_free(tmp);
77
78   if (argc == 1) {
79     /* Show all attributes */
80     printformat_module("fe-common/silc", server, NULL,
81                        MSGLEVEL_CRAP, SILCTXT_ATTR_HEADER);
82
83     allowed = settings_get_bool("attr_allow");
84     printformat_module("fe-common/silc", server, NULL,
85                        MSGLEVEL_CRAP, SILCTXT_ATTR_ALLOW,
86                        allowed ? "Yes" : "No");
87
88     sv = settings_get_str("attr_vcard");
89     if (sv && *sv)
90       printformat_module("fe-common/silc", server, NULL,
91                          MSGLEVEL_CRAP, SILCTXT_ATTR_VCARD_FILE, sv);
92
93     sv = settings_get_str("attr_services");
94     if (sv && *sv)
95       printformat_module("fe-common/silc", server, NULL,
96                          MSGLEVEL_CRAP, SILCTXT_ATTR_SERVICES, sv);
97
98     sv = settings_get_str("attr_status_mood");
99     if (sv && *sv)
100       printformat_module("fe-common/silc", server, NULL,
101                          MSGLEVEL_CRAP, SILCTXT_ATTR_STATUS_MOOD, sv);
102
103     sv = settings_get_str("attr_status_text");
104     if (sv && *sv)
105       printformat_module("fe-common/silc", server, NULL,
106                          MSGLEVEL_CRAP, SILCTXT_ATTR_STATUS_TEXT, sv);
107
108     sv = settings_get_str("attr_status_message");
109     if (sv && *sv)
110       printformat_module("fe-common/silc", server, NULL,
111                          MSGLEVEL_CRAP, SILCTXT_ATTR_STATUS_MESSAGE_FILE,
112                          sv);
113
114     sv = settings_get_str("attr_preferred_language");
115     if (sv && *sv)
116       printformat_module("fe-common/silc", server, NULL,
117                          MSGLEVEL_CRAP, SILCTXT_ATTR_PREFERRED_LANGUAGE,
118                          sv);
119
120     sv = settings_get_str("attr_preferred_contact");
121     if (sv && *sv)
122       printformat_module("fe-common/silc", server, NULL,
123                          MSGLEVEL_CRAP, SILCTXT_ATTR_PREFERRED_CONTACT,
124                          sv);
125
126     sv = settings_get_str("attr_geolocation");
127     if (sv && *sv)
128       printformat_module("fe-common/silc", server, NULL,
129                          MSGLEVEL_CRAP, SILCTXT_ATTR_GEOLOCATION,
130                          sv);
131
132     sv = settings_get_str("attr_device_info");
133     if (sv && *sv)
134       printformat_module("fe-common/silc", server, NULL,
135                          MSGLEVEL_CRAP, SILCTXT_ATTR_DEVICE_INFO,
136                          sv);
137
138     sv = settings_get_str("attr_public_keys");
139     if (sv && *sv)
140       printformat_module("fe-common/silc", server, NULL,
141                          MSGLEVEL_CRAP, SILCTXT_ATTR_PUBLIC_KEYS,
142                          sv);
143
144     allowed = settings_get_bool("attr_timezone");
145     printformat_module("fe-common/silc", server, NULL,
146                        MSGLEVEL_CRAP, SILCTXT_ATTR_TIMEZONE_ALLOW,
147                        allowed ? "Yes" : "No");
148
149     printformat_module("fe-common/silc", server, NULL,
150                        MSGLEVEL_CRAP, SILCTXT_ATTR_FOOTER);
151     return;
152   }
153
154   if (argc < 3)
155     cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
156
157   if (!strcasecmp(argv[1], "-del")) {
158     /* Delete attribute */
159     if (!strcasecmp(argv[2], "vcard")) {
160       silc_client_attribute_del(silc_client, server->conn,
161                                 SILC_ATTRIBUTE_USER_INFO, NULL);
162       settings_set_str("attr_vcard", "");
163     } else if (!strcasecmp(argv[2], "services")) {
164       silc_client_attribute_del(silc_client, server->conn,
165                                 SILC_ATTRIBUTE_SERVICE, NULL);
166       settings_set_str("attr_services", argv[2]);
167     } else if (!strcasecmp(argv[2], "status_mood")) {
168       silc_client_attribute_del(silc_client, server->conn,
169                                 SILC_ATTRIBUTE_STATUS_MOOD, NULL);
170       settings_set_str("attr_status_mood", "");
171     } else if (!strcasecmp(argv[2], "status_text")) {
172       silc_client_attribute_del(silc_client, server->conn,
173                                 SILC_ATTRIBUTE_STATUS_FREETEXT, NULL);
174       settings_set_str("attr_status_text", "");
175     } else if (!strcasecmp(argv[2], "status_message")) {
176       silc_client_attribute_del(silc_client, server->conn,
177                                 SILC_ATTRIBUTE_STATUS_MESSAGE, NULL);
178       settings_set_str("attr_status_message", "");
179     } else if (!strcasecmp(argv[2], "preferred_language")) {
180       silc_client_attribute_del(silc_client, server->conn,
181                                 SILC_ATTRIBUTE_PREFERRED_LANGUAGE, NULL);
182       settings_set_str("attr_preferred_language", "");
183     } else if (!strcasecmp(argv[2], "preferred_contact")) {
184       silc_client_attribute_del(silc_client, server->conn,
185                                 SILC_ATTRIBUTE_PREFERRED_CONTACT, NULL);
186       settings_set_str("attr_preferred_contact", "");
187     } else if (!strcasecmp(argv[2], "timezone")) {
188       return;
189     } else if (!strcasecmp(argv[2], "geolocation")) {
190       silc_client_attribute_del(silc_client, server->conn,
191                                 SILC_ATTRIBUTE_GEOLOCATION, NULL);
192       settings_set_str("attr_geolocation", "");
193     } else if (!strcasecmp(argv[2], "device_info")) {
194       silc_client_attribute_del(silc_client, server->conn,
195                                 SILC_ATTRIBUTE_DEVICE_INFO, NULL);
196       settings_set_str("attr_device_info", "");
197     } else if (!strcasecmp(argv[2], "public_keys")) {
198       silc_client_attribute_del(silc_client, server->conn,
199                                 SILC_ATTRIBUTE_USER_PUBLIC_KEY, NULL);
200       settings_set_str("attr_public_keys", "");
201     } else {
202       cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
203     }
204     return;
205   }
206
207   /* Add new attribute */
208   if (!strcasecmp(argv[1], "allow")) {
209     allowed = !strcasecmp(argv[2], "ON") || !strcasecmp(argv[2], "YES");
210     settings_set_bool("attr_allow", allowed);
211   } else if (!strcasecmp(argv[1], "vcard")) {
212     settings_set_str("attr_vcard", argv[2]);
213   } else if (!strcasecmp(argv[1], "services")) {
214     settings_set_str("attr_services", argv[2]);
215   } else if (!strcasecmp(argv[1], "status_mood")) {
216     settings_set_str("attr_status_mood", argv[2]);
217   } else if (!strcasecmp(argv[1], "status_text")) {
218     settings_set_str("attr_status_text", argv[2]);
219   } else if (!strcasecmp(argv[1], "status_message")) {
220     settings_set_str("attr_status_message", argv[2]);
221   } else if (!strcasecmp(argv[1], "preferred_language")) {
222     settings_set_str("attr_preferred_language", argv[2]);
223   } else if (!strcasecmp(argv[1], "preferred_contact")) {
224     settings_set_str("attr_preferred_contact", argv[2]);
225   } else if (!strcasecmp(argv[1], "timezone")) {
226     allowed = !strcasecmp(argv[2], "ON") || !strcasecmp(argv[2], "YES");
227     settings_set_bool("attr_timezone", allowed);
228   } else if (!strcasecmp(argv[1], "geolocation")) {
229     settings_set_str("attr_geolocation", argv[2]);
230   } else if (!strcasecmp(argv[1], "device_info")) {
231     settings_set_str("attr_device_info", argv[2]);
232   } else if (!strcasecmp(argv[1], "public_keys")) {
233     settings_set_str("attr_public_keys", argv[2]);
234   } else {
235     cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
236   }
237
238   silc_query_attributes_default(silc_client, server->conn);
239 }
240
241 /* Put default attributes to client library */
242
243 void silc_query_attributes_default(SilcClient client,
244                                    SilcClientConnection conn)
245 {
246   char *tmp, **list, **entry;
247   const char *sv;
248   SilcUInt32 tmp_len, mask;
249   SilcAttributeObjService service;
250   SilcMime mime;
251   SilcAttributeObjGeo geo;
252   SilcAttributeObjDevice dev;
253   SilcAttributeObjPk pk;
254   SilcVCardStruct vcard;
255   bool allowed;
256
257   memset(&service, 0, sizeof(service));
258   memset(&geo, 0, sizeof(geo));
259   memset(&dev, 0, sizeof(dev));
260   memset(&pk, 0, sizeof(pk));
261   memset(&vcard, 0, sizeof(vcard));
262
263   allowed = settings_get_bool("attr_allow");
264   if (!allowed) {
265     silc_client_attribute_del(silc_client, conn,
266                               SILC_ATTRIBUTE_USER_INFO, NULL);
267     silc_client_attribute_del(silc_client, conn,
268                               SILC_ATTRIBUTE_SERVICE, NULL);
269     silc_client_attribute_del(silc_client, conn,
270                               SILC_ATTRIBUTE_STATUS_MOOD, NULL);
271     silc_client_attribute_del(silc_client, conn,
272                               SILC_ATTRIBUTE_STATUS_FREETEXT, NULL);
273     silc_client_attribute_del(silc_client, conn,
274                               SILC_ATTRIBUTE_STATUS_MESSAGE, NULL);
275     silc_client_attribute_del(silc_client, conn,
276                               SILC_ATTRIBUTE_PREFERRED_LANGUAGE, NULL);
277     silc_client_attribute_del(silc_client, conn,
278                               SILC_ATTRIBUTE_PREFERRED_CONTACT, NULL);
279     silc_client_attribute_del(silc_client, conn,
280                               SILC_ATTRIBUTE_TIMEZONE, NULL);
281     silc_client_attribute_del(silc_client, conn,
282                               SILC_ATTRIBUTE_GEOLOCATION, NULL);
283     silc_client_attribute_del(silc_client, conn,
284                               SILC_ATTRIBUTE_DEVICE_INFO, NULL);
285     silc_client_attribute_del(silc_client, conn,
286                               SILC_ATTRIBUTE_USER_PUBLIC_KEY, NULL);
287     return;
288   }
289
290   sv = settings_get_str("attr_vcard");
291   if (sv && *sv) {
292     /* Put USER_INFO */
293     silc_client_attribute_del(silc_client, conn,
294                               SILC_ATTRIBUTE_USER_INFO, NULL);
295     tmp = silc_file_readfile(sv, &tmp_len, NULL);
296     if (tmp) {
297       tmp[tmp_len] = 0;
298       if (silc_vcard_decode(tmp, tmp_len, &vcard))
299         silc_client_attribute_add(silc_client, conn,
300                                   SILC_ATTRIBUTE_USER_INFO, (void *)&vcard,
301                                   sizeof(vcard));
302     }
303     silc_vcard_free(&vcard);
304     silc_free(tmp);
305   }
306
307   sv = settings_get_str("attr_services");
308   if (sv && *sv) {
309     /* Put SERVICE */
310     silc_client_attribute_del(silc_client, conn,
311                               SILC_ATTRIBUTE_SERVICE, NULL);
312     list = g_strsplit(sv, " ", -1);
313     for (entry = list; *entry != NULL; entry++) {
314       if (!strchr(*entry, ':'))
315         continue;
316       tmp = strchr(*entry, ':') + 1;
317       if (!tmp || !(*tmp))
318         continue;
319       memset(&service, 0, sizeof(service));
320       service.port = atoi(tmp);
321       *strchr(*entry, ':') = '\0';
322       silc_strncat(service.address, sizeof(service.address), *entry,
323                    strlen(*entry));
324       service.status = TRUE;
325       service.idle = 0;
326       silc_client_attribute_add(silc_client, conn,
327                                 SILC_ATTRIBUTE_SERVICE, &service,
328                                 sizeof(service));
329     }
330     g_strfreev(list);
331   }
332
333   sv = settings_get_str("attr_status_mood");
334   if (sv && *sv) {
335     /* Put STATUS_MOOD */
336     silc_client_attribute_del(silc_client, conn,
337                               SILC_ATTRIBUTE_STATUS_MOOD, NULL);
338     mask = 0;
339     list = g_strsplit(sv, " ", -1);
340     for (entry = list; *entry != NULL; entry++) {
341       if (!strcasecmp(*entry, "NORMAL"))
342         mask |= SILC_ATTRIBUTE_MOOD_NORMAL;
343       if (!strcasecmp(*entry, "HAPPY"))
344         mask |= SILC_ATTRIBUTE_MOOD_HAPPY;
345       if (!strcasecmp(*entry, "SAD"))
346         mask |= SILC_ATTRIBUTE_MOOD_SAD;
347       if (!strcasecmp(*entry, "ANGRY"))
348         mask |= SILC_ATTRIBUTE_MOOD_ANGRY;
349       if (!strcasecmp(*entry, "JEALOUS"))
350         mask |= SILC_ATTRIBUTE_MOOD_JEALOUS;
351       if (!strcasecmp(*entry, "ASHAMED"))
352         mask |= SILC_ATTRIBUTE_MOOD_ASHAMED;
353       if (!strcasecmp(*entry, "INVINCIBLE"))
354         mask |= SILC_ATTRIBUTE_MOOD_INVINCIBLE;
355       if (!strcasecmp(*entry, "INLOVE"))
356         mask |= SILC_ATTRIBUTE_MOOD_INLOVE;
357       if (!strcasecmp(*entry, "SLEEPY"))
358         mask |= SILC_ATTRIBUTE_MOOD_SLEEPY;
359       if (!strcasecmp(*entry, "BORED"))
360         mask |= SILC_ATTRIBUTE_MOOD_BORED;
361       if (!strcasecmp(*entry, "EXCITED"))
362         mask |= SILC_ATTRIBUTE_MOOD_EXCITED;
363       if (!strcasecmp(*entry, "ANXIOUS"))
364         mask |= SILC_ATTRIBUTE_MOOD_ANXIOUS;
365     }
366     silc_client_attribute_add(silc_client, conn,
367                               SILC_ATTRIBUTE_STATUS_MOOD,
368                               SILC_32_TO_PTR(mask),
369                               sizeof(SilcUInt32));
370     g_strfreev(list);
371   }
372
373   sv = settings_get_str("attr_status_text");
374   if (sv && *sv) {
375     /* Put STATUS_TEXT */
376     silc_client_attribute_del(silc_client, conn,
377                               SILC_ATTRIBUTE_STATUS_FREETEXT, NULL);
378     silc_client_attribute_add(silc_client, conn,
379                               SILC_ATTRIBUTE_STATUS_FREETEXT, (void *)sv,
380                               strlen(sv));
381   }
382
383   sv = settings_get_str("attr_status_message");
384   if (sv && *sv) {
385     /* Put STATUS_MESSAGE */
386     silc_client_attribute_del(silc_client, conn,
387                               SILC_ATTRIBUTE_STATUS_MESSAGE, NULL);
388     tmp = silc_file_readfile(sv, &tmp_len, NULL);
389     if (tmp) {
390       mime = silc_mime_decode(NULL, tmp, tmp_len);
391       if (mime)
392         silc_client_attribute_add(silc_client, conn,
393                                   SILC_ATTRIBUTE_STATUS_MESSAGE, mime,
394                                   sizeof(*mime));
395     }
396     silc_free(tmp);
397   }
398
399   sv = settings_get_str("attr_preferred_language");
400   if (sv && *sv) {
401     /* Put PREFERRED_LANGUAGE */
402     silc_client_attribute_del(silc_client, conn,
403                               SILC_ATTRIBUTE_PREFERRED_LANGUAGE, NULL);
404     list = g_strsplit(sv, " ", -1);
405     for (entry = list; *entry != NULL; entry++) {
406       silc_client_attribute_add(silc_client, conn,
407                                 SILC_ATTRIBUTE_PREFERRED_LANGUAGE, *entry,
408                                 strlen(*entry));
409     }
410     g_strfreev(list);
411   }
412
413   sv = settings_get_str("attr_preferred_contact");
414   if (sv && *sv) {
415     /* Put PREFERRED_CONTACT */
416     silc_client_attribute_del(silc_client, conn,
417                               SILC_ATTRIBUTE_PREFERRED_CONTACT, NULL);
418     mask = 0;
419     list = g_strsplit(sv, " ", -1);
420     for (entry = list; *entry != NULL; entry++) {
421       if (!strcasecmp(*entry, "NONE"))
422         mask = 0;
423       if (!strcasecmp(*entry, "EMAIL"))
424         mask |= SILC_ATTRIBUTE_CONTACT_EMAIL;
425       if (!strcasecmp(*entry, "CALL"))
426         mask |= SILC_ATTRIBUTE_CONTACT_CALL;
427       if (!strcasecmp(*entry, "PAGE"))
428         mask |= SILC_ATTRIBUTE_CONTACT_PAGE;
429       if (!strcasecmp(*entry, "SMS"))
430         mask |= SILC_ATTRIBUTE_CONTACT_SMS;
431       if (!strcasecmp(*entry, "MMS"))
432         mask |= SILC_ATTRIBUTE_CONTACT_MMS;
433       if (!strcasecmp(*entry, "CHAT"))
434         mask |= SILC_ATTRIBUTE_CONTACT_CHAT;
435       if (!strcasecmp(*entry, "VIDEO"))
436         mask |= SILC_ATTRIBUTE_CONTACT_VIDEO;
437     }
438     silc_client_attribute_add(silc_client, conn,
439                               SILC_ATTRIBUTE_PREFERRED_CONTACT,
440                               SILC_32_TO_PTR(mask),
441                               sizeof(SilcUInt32));
442     g_strfreev(list);
443   }
444
445   /* Put TIMEZONE */
446   allowed = settings_get_bool("attr_timezone");
447   silc_client_attribute_del(silc_client, conn,
448                             SILC_ATTRIBUTE_TIMEZONE, NULL);
449   if (allowed)
450     silc_client_attribute_add(silc_client, conn,
451                               SILC_ATTRIBUTE_TIMEZONE, "foo", 3);
452
453   sv = settings_get_str("attr_geolocation");
454   if (sv && *sv) {
455     /* Put GEOLOCATION */
456     silc_client_attribute_del(silc_client, conn,
457                               SILC_ATTRIBUTE_GEOLOCATION, NULL);
458     list = g_strsplit(sv, ":", -1);
459     for (entry = list; *entry != NULL; entry++) {
460       if (!geo.longitude) {
461         geo.longitude = *entry;
462         continue;
463       }
464       if (!geo.latitude) {
465         geo.latitude = *entry;
466         continue;
467       }
468       if (!geo.altitude) {
469         geo.altitude = *entry;
470         continue;
471       }
472       if (!geo.accuracy) {
473         geo.accuracy = *entry;
474         continue;
475       }
476     }
477     silc_client_attribute_add(silc_client, conn,
478                               SILC_ATTRIBUTE_GEOLOCATION, &geo,
479                               sizeof(geo));
480     g_strfreev(list);
481   }
482
483   sv = settings_get_str("attr_device_info");
484   if (sv && *sv) {
485     /* Put DEVICE_INFO */
486     silc_client_attribute_del(silc_client, conn,
487                               SILC_ATTRIBUTE_DEVICE_INFO, NULL);
488     allowed = FALSE;
489     list = g_strsplit(sv, ":", -1);
490     for (entry = list; *entry != NULL; entry++) {
491       if (!allowed) {
492         allowed = TRUE;
493         if (!strcasecmp(*entry, "COMPUTER"))
494           dev.type = SILC_ATTRIBUTE_DEVICE_COMPUTER;
495         if (!strcasecmp(*entry, "MOBILE_PHONE"))
496           dev.type = SILC_ATTRIBUTE_DEVICE_MOBILE_PHONE;
497         if (!strcasecmp(sv, "PDA"))
498           dev.type = SILC_ATTRIBUTE_DEVICE_PDA;
499         if (!strcasecmp(sv, "TERMINAL"))
500           dev.type = SILC_ATTRIBUTE_DEVICE_TERMINAL;
501         continue;
502       }
503       if (!dev.manufacturer) {
504         dev.manufacturer = *entry;
505         continue;
506       }
507       if (!dev.version) {
508         dev.version = *entry;
509         continue;
510       }
511       if (!dev.model) {
512         dev.model = *entry;
513         continue;
514       }
515       if (!dev.language) {
516         dev.language = *entry;
517         continue;
518       }
519     }
520     silc_client_attribute_add(silc_client, conn,
521                               SILC_ATTRIBUTE_DEVICE_INFO, &dev,
522                               sizeof(dev));
523     g_strfreev(list);
524   }
525
526   sv = settings_get_str("attr_public_keys");
527   if (sv && *sv) {
528     /* Put USER_PUBLIC_KEY */
529     silc_client_attribute_del(silc_client, conn,
530                               SILC_ATTRIBUTE_USER_PUBLIC_KEY, NULL);
531     list = g_strsplit(sv, " ", -1);
532     for (entry = list; *entry != NULL; entry++) {
533       if (!strncasecmp(*entry, "silc-rsa:", 8)) {
534         tmp = silc_file_readfile((*entry) + 8, &tmp_len, NULL);
535         if (tmp) {
536           tmp[tmp_len] = 0;
537           pk.type = "silc-rsa";
538           pk.data = tmp;
539           pk.data_len = tmp_len;
540           silc_client_attribute_add(silc_client, conn,
541                                     SILC_ATTRIBUTE_USER_PUBLIC_KEY, &pk,
542                                     sizeof(pk));
543         }
544         silc_free(tmp);
545       } else {
546         silc_say_error("Unsupported public key type '%s'", *entry);
547       }
548     }
549     g_strfreev(list);
550   }
551 }
552
553 typedef struct {
554   SilcClient client;
555   SILC_SERVER_REC *server;
556   char *name;
557   SilcAttributeObjPk userpk;
558   SilcPublicKey public_key;
559   SilcVCardStruct vcard;
560   SilcMime message;
561   SilcMime extension;
562   bool nopk;
563 } *AttrVerify;
564
565 static void silc_query_attributes_verify(SilcBool success, void *context)
566 {
567   *(SilcBool *)context = success;
568 }
569
570 void silc_query_attributes_print(SILC_SERVER_REC *server,
571                                  SilcClient client,
572                                  SilcClientConnection conn,
573                                  SilcDList attrs,
574                                  SilcClientEntry client_entry)
575 {
576   SilcAttributePayload attr;
577   SilcAttribute attribute;
578   char tmp[512];
579   SilcAttributeObjPk serverpk, usersign, serversign;
580   AttrVerify verify;
581
582   printformat_module("fe-common/silc", server, NULL,
583                      MSGLEVEL_CRAP, SILCTXT_ATTR_HEADER);
584
585   memset(&serverpk, 0, sizeof(serverpk));
586   memset(&usersign, 0, sizeof(usersign));
587   memset(&serversign, 0, sizeof(serversign));
588
589   verify = silc_calloc(1, sizeof(*verify));
590   if (!verify)
591     return;
592   verify->client = client;
593   verify->server = server;
594   verify->name = strdup(client_entry->nickname);
595
596   silc_dlist_start(attrs);
597   while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
598     attribute = silc_attribute_get_attribute(attr);
599     memset(tmp, 0, sizeof(tmp));
600
601     switch (attribute) {
602
603     case SILC_ATTRIBUTE_USER_INFO:
604       {
605         if (!silc_attribute_get_object(attr, (void *)&verify->vcard,
606                                        sizeof(verify->vcard)))
607           continue;
608         printformat_module("fe-common/silc", server, NULL,
609                            MSGLEVEL_CRAP, SILCTXT_ATTR_VCARD_FILE,
610                            "present");
611       }
612       break;
613
614     case SILC_ATTRIBUTE_SERVICE:
615       {
616         SilcAttributeObjService service;
617         memset(&service, 0, sizeof(service));
618         if (!silc_attribute_get_object(attr, (void *)&service,
619                                        sizeof(service)))
620           continue;
621         snprintf(tmp, sizeof(tmp) - 1, "%s:%d (logged %s) idle %d seconds",
622                  service.address, (unsigned int)service.port,
623                  service.status ? "in" : "out",
624                  (unsigned int)service.idle);
625         printformat_module("fe-common/silc", server, NULL,
626                            MSGLEVEL_CRAP, SILCTXT_ATTR_SERVICES, tmp);
627       }
628       break;
629
630     case SILC_ATTRIBUTE_STATUS_MOOD:
631       {
632         SilcUInt32 mask;
633         if (!silc_attribute_get_object(attr, (void *)&mask, sizeof(mask)))
634           continue;
635         if (!mask)
636           silc_strncat(tmp, sizeof(tmp), "NORMAL ", strlen(" NORMAL"));
637         if (mask & SILC_ATTRIBUTE_MOOD_HAPPY)
638           silc_strncat(tmp, sizeof(tmp), "HAPPY ", strlen(" HAPPY"));
639         if (mask & SILC_ATTRIBUTE_MOOD_SAD)
640           silc_strncat(tmp, sizeof(tmp), "SAD ", strlen(" SAD"));
641         if (mask & SILC_ATTRIBUTE_MOOD_ANGRY)
642           silc_strncat(tmp, sizeof(tmp), "ANGRY ", strlen(" ANGRY"));
643         if (mask & SILC_ATTRIBUTE_MOOD_JEALOUS)
644           silc_strncat(tmp, sizeof(tmp), "JEALOUS ", strlen(" JEALOUS"));
645         if (mask & SILC_ATTRIBUTE_MOOD_ASHAMED)
646           silc_strncat(tmp, sizeof(tmp), "ASHAMED ", strlen(" ASHAMED"));
647         if (mask & SILC_ATTRIBUTE_MOOD_INVINCIBLE)
648           silc_strncat(tmp, sizeof(tmp), "INVINCIBLE ", strlen(" INVINCIBLE"));
649         if (mask & SILC_ATTRIBUTE_MOOD_INLOVE)
650           silc_strncat(tmp, sizeof(tmp), "INLOVE ", strlen(" INLOVE"));
651         if (mask & SILC_ATTRIBUTE_MOOD_SLEEPY)
652           silc_strncat(tmp, sizeof(tmp), "SLEEPY ", strlen(" SLEEPY"));
653         if (mask & SILC_ATTRIBUTE_MOOD_BORED)
654           silc_strncat(tmp, sizeof(tmp), "BORED ", strlen(" BORED"));
655         if (mask & SILC_ATTRIBUTE_MOOD_EXCITED)
656           silc_strncat(tmp, sizeof(tmp), "EXCITED ", strlen(" EXCITED"));
657         if (mask & SILC_ATTRIBUTE_MOOD_ANXIOUS)
658           silc_strncat(tmp, sizeof(tmp), "ANXIOUS ", strlen(" ANXIOUS"));
659         printformat_module("fe-common/silc", server, NULL,
660                            MSGLEVEL_CRAP, SILCTXT_ATTR_STATUS_MOOD, tmp);
661       }
662       break;
663
664     case SILC_ATTRIBUTE_STATUS_FREETEXT:
665       {
666         if (!silc_attribute_get_object(attr, (void *)&tmp, sizeof(tmp) - 1))
667           continue;
668         printformat_module("fe-common/silc", server, NULL,
669                            MSGLEVEL_CRAP, SILCTXT_ATTR_STATUS_TEXT, tmp);
670       }
671       break;
672
673     case SILC_ATTRIBUTE_STATUS_MESSAGE:
674       {
675         verify->message = silc_mime_alloc();
676         if (!verify->message)
677           continue;
678         if (!silc_attribute_get_object(attr, (void *)verify->message,
679                                        sizeof(*verify->message)))
680           continue;
681         printformat_module("fe-common/silc", server, NULL,
682                            MSGLEVEL_CRAP, SILCTXT_ATTR_STATUS_MESSAGE,
683                            "present");
684       }
685       break;
686
687     case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
688       {
689         if (!silc_attribute_get_object(attr, (void *)&tmp, sizeof(tmp) - 1))
690           continue;
691         printformat_module("fe-common/silc", server, NULL,
692                            MSGLEVEL_CRAP, SILCTXT_ATTR_PREFERRED_LANGUAGE,
693                            tmp);
694       }
695       break;
696
697     case SILC_ATTRIBUTE_PREFERRED_CONTACT:
698       {
699         SilcUInt32 mask;
700         if (!silc_attribute_get_object(attr, (void *)&mask, sizeof(mask)))
701           continue;
702         if (!mask)
703           silc_strncat(tmp, sizeof(tmp), "NONE ", strlen(" NONE"));
704         if (mask & SILC_ATTRIBUTE_CONTACT_CHAT)
705           silc_strncat(tmp, sizeof(tmp), "CHAT ", strlen(" CHAT"));
706         if (mask & SILC_ATTRIBUTE_CONTACT_EMAIL)
707           silc_strncat(tmp, sizeof(tmp), "EMAIL ", strlen(" EMAIL"));
708         if (mask & SILC_ATTRIBUTE_CONTACT_CALL)
709           silc_strncat(tmp, sizeof(tmp), "CALL ", strlen(" CALL"));
710         if (mask & SILC_ATTRIBUTE_CONTACT_PAGE)
711           silc_strncat(tmp, sizeof(tmp), "PAGE ", strlen(" PAGE"));
712         if (mask & SILC_ATTRIBUTE_CONTACT_SMS)
713           silc_strncat(tmp, sizeof(tmp), "SMS ", strlen(" SMS"));
714         if (mask & SILC_ATTRIBUTE_CONTACT_MMS)
715           silc_strncat(tmp, sizeof(tmp), "MMS ", strlen(" MMS"));
716         if (mask & SILC_ATTRIBUTE_CONTACT_VIDEO)
717           silc_strncat(tmp, sizeof(tmp), "VIDEO ", strlen(" VIDEO"));
718         printformat_module("fe-common/silc", server, NULL,
719                            MSGLEVEL_CRAP, SILCTXT_ATTR_PREFERRED_CONTACT, tmp);
720       }
721       break;
722
723     case SILC_ATTRIBUTE_TIMEZONE:
724       {
725         if (!silc_attribute_get_object(attr, (void *)&tmp, sizeof(tmp) - 1))
726           continue;
727         printformat_module("fe-common/silc", server, NULL,
728                            MSGLEVEL_CRAP, SILCTXT_ATTR_TIMEZONE, tmp);
729       }
730       break;
731
732     case SILC_ATTRIBUTE_EXTENSION:
733       {
734         verify->extension = silc_mime_alloc();
735         if (!verify->extension)
736           continue;
737         if (!silc_attribute_get_object(attr, (void *)verify->extension,
738                                        sizeof(*verify->extension)))
739           continue;
740         printformat_module("fe-common/silc", server, NULL,
741                            MSGLEVEL_CRAP, SILCTXT_ATTR_EXTENSION,
742                            "present");
743       }
744       break;
745
746     case SILC_ATTRIBUTE_GEOLOCATION:
747       {
748         SilcAttributeObjGeo geo;
749         memset(&geo, 0, sizeof(geo));
750         if (!silc_attribute_get_object(attr, (void *)&geo, sizeof(geo)))
751           continue;
752         snprintf(tmp, sizeof(tmp) - 1, "%s:%s:%s:%s",
753                  geo.longitude ? geo.longitude : "",
754                  geo.latitude ? geo.latitude : "",
755                  geo.altitude ? geo.altitude : "",
756                  geo.accuracy ? geo.accuracy : "");
757         printformat_module("fe-common/silc", server, NULL,
758                            MSGLEVEL_CRAP, SILCTXT_ATTR_GEOLOCATION, tmp);
759       }
760       break;
761
762     case SILC_ATTRIBUTE_DEVICE_INFO:
763       {
764         SilcAttributeObjDevice dev;
765         memset(&dev, 0, sizeof(dev));
766         if (!silc_attribute_get_object(attr, (void *)&dev, sizeof(dev)))
767           continue;
768         snprintf(tmp, sizeof(tmp) - 1, "%s:%s:%s:%s:%s",
769                  (dev.type == SILC_ATTRIBUTE_DEVICE_COMPUTER ? "COMPUTER" :
770                   dev.type == SILC_ATTRIBUTE_DEVICE_PDA ? "PDA" :
771                   dev.type == SILC_ATTRIBUTE_DEVICE_MOBILE_PHONE ?
772                   "MOBILE PHONE" :
773                   dev.type == SILC_ATTRIBUTE_DEVICE_TERMINAL ? "TERMINAL" :
774                   ""),
775                  dev.manufacturer ? dev.manufacturer : "",
776                  dev.version ? dev.version : "",
777                  dev.model ? dev.model: "",
778                  dev.language ? dev.language : "");
779         printformat_module("fe-common/silc", server, NULL,
780                            MSGLEVEL_CRAP, SILCTXT_ATTR_DEVICE_INFO, tmp);
781       }
782       break;
783
784     case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
785       {
786         if (verify->userpk.type)
787           continue;
788         if (!silc_attribute_get_object(attr, (void *)&verify->userpk,
789                                        sizeof(verify->userpk)))
790           continue;
791       }
792       break;
793
794     case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
795       {
796         if (serverpk.type)
797           continue;
798         if (!silc_attribute_get_object(attr, (void *)&serverpk,
799                                        sizeof(serverpk)))
800           continue;
801       }
802       break;
803
804     case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
805       {
806         if (usersign.data)
807           continue;
808         if (!silc_attribute_get_object(attr, (void *)&usersign,
809                                        sizeof(usersign)))
810           continue;
811       }
812       break;
813
814     case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
815       {
816         if (serversign.data)
817           continue;
818         if (!silc_attribute_get_object(attr, (void *)&serversign,
819                                        sizeof(serversign)))
820           continue;
821       }
822       break;
823
824     default:
825       break;
826     }
827   }
828
829   /* Handle the signature verifications and public key verifying here */
830
831   if (verify->userpk.data) {
832     SilcPKCSType type = 0;
833
834     if (!strcmp(verify->userpk.type, "silc-rsa"))
835       type = SILC_PKCS_SILC;
836     else if (!strcmp(verify->userpk.type, "ssh-rsa"))
837       type = SILC_PKCS_SSH2;
838     else if (!strcmp(verify->userpk.type, "x509v3-sign-rsa"))
839       type = SILC_PKCS_X509V3;
840     else if (!strcmp(verify->userpk.type, "pgp-sign-rsa"))
841       type = SILC_PKCS_OPENPGP;
842
843     silc_pkcs_public_key_alloc(type, verify->userpk.data,
844                                verify->userpk.data_len,
845                                &verify->public_key);
846   }
847
848   if (usersign.data) {
849     /* Verify the signature now */
850     unsigned char *verifyd;
851     SilcUInt32 verify_len;
852     SilcBool verified = FALSE;
853
854     if (verify->public_key) {
855       verifyd = silc_attribute_get_verify_data(attrs, FALSE, &verify_len);
856       if (verifyd)
857         silc_pkcs_verify_async(verify->public_key, usersign.data,
858                                usersign.data_len, verifyd, verify_len,
859                                TRUE, sha1hash,
860                                silc_query_attributes_verify, &verified);
861
862       if (verified) {
863         printformat_module("fe-common/silc", server, NULL,
864                            MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_VERIFIED);
865       } else {
866         printformat_module("fe-common/silc", server, NULL,
867                            MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_FAILED);
868       }
869
870       silc_free(verifyd);
871     } else {
872       printformat_module("fe-common/silc", server, NULL,
873                          MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_FAILED);
874     }
875   } else {
876     printformat_module("fe-common/silc", server, NULL,
877                        MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_NOT_PRESENT);
878   }
879
880   if (serversign.data) {
881     /* Verify the signature now */
882     SilcPublicKey public_key;
883     SilcPKCSType type = 0;
884     unsigned char *verifyd;
885     SilcUInt32 verify_len;
886     SilcBool verified = FALSE;
887
888     if (!strcmp(serverpk.type, "silc-rsa"))
889       type = SILC_PKCS_SILC;
890     else if (!strcmp(serverpk.type, "ssh-rsa"))
891       type = SILC_PKCS_SSH2;
892     else if (!strcmp(serverpk.type, "x509v3-sign-rsa"))
893       type = SILC_PKCS_X509V3;
894     else if (!strcmp(serverpk.type, "pgp-sign-rsa"))
895       type = SILC_PKCS_OPENPGP;
896
897     if (silc_pkcs_public_key_alloc(type, serverpk.data,
898                                    serverpk.data_len,
899                                    &public_key)) {
900       verifyd = silc_attribute_get_verify_data(attrs, TRUE, &verify_len);
901       if (verifyd)
902         silc_pkcs_verify_async(public_key, serversign.data,
903                                serversign.data_len, verifyd,
904                                verify_len, TRUE, sha1hash,
905                                silc_query_attributes_verify, &verified);
906       if (verified) {
907         printformat_module("fe-common/silc", server, NULL,
908                            MSGLEVEL_CRAP, SILCTXT_ATTR_SERVER_SIGN_VERIFIED);
909       } else {
910         printformat_module("fe-common/silc", server, NULL,
911                            MSGLEVEL_CRAP, SILCTXT_ATTR_SERVER_SIGN_FAILED);
912       }
913
914       silc_pkcs_public_key_free(public_key);
915       silc_free(verifyd);
916     } else {
917       printformat_module("fe-common/silc", server, NULL,
918                          MSGLEVEL_CRAP, SILCTXT_ATTR_SERVER_SIGN_FAILED);
919     }
920   }
921
922   if (verify->public_key) {
923     silc_verify_public_key(client, conn, SILC_CONN_CLIENT,
924                            verify->public_key,
925                            silc_query_attributes_print_final, verify);
926   } else {
927     verify->nopk = TRUE;
928     silc_query_attributes_print_final(FALSE, verify);
929   }
930 }
931
932 static void silc_query_attributes_print_final(bool success, void *context)
933 {
934   AttrVerify verify = context;
935   SILC_SERVER_REC *server = verify->server;
936   char *format = NULL;
937   unsigned char filename[256], *fingerprint = NULL, *tmp;
938   struct stat st;
939   int i;
940
941   if (!verify->nopk) {
942     if (success) {
943       printformat_module("fe-common/silc", NULL, NULL,
944                          MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, "user",
945                          verify->name);
946     } else {
947       printformat_module("fe-common/silc", NULL, NULL,
948                          MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED, "user",
949                          verify->name);
950     }
951   }
952
953   printformat_module("fe-common/silc", server, NULL,
954                      MSGLEVEL_CRAP, SILCTXT_ATTR_FOOTER);
955
956   /* Replace all whitespaces with `_'. */
957   fingerprint = silc_hash_fingerprint(sha1hash,
958                                       verify->userpk.data,
959                                       verify->userpk.data_len);
960   for (i = 0; i < strlen(fingerprint); i++)
961     if (fingerprint[i] == ' ')
962       fingerprint[i] = '_';
963
964   /* Filename for dir */
965   tmp = fingerprint + strlen(fingerprint) - 9;
966   snprintf(filename, sizeof(filename) - 1, "%s/friends/%s",
967            get_irssi_dir(), tmp);
968   silc_free(fingerprint);
969
970   if ((stat(filename, &st)) == -1) {
971     /* Ask to accept save requested attributes */
972     format = format_get_text("fe-common/silc", NULL, NULL, NULL,
973                              SILCTXT_ATTR_SAVE);
974     keyboard_entry_redirect((SIGNAL_FUNC)silc_query_attributes_accept,
975                             format, 0, verify);
976   } else {
977     /* Save new data to existing directory */
978     silc_query_attributes_accept("Y", verify);
979   }
980
981   g_free(format);
982 }
983
984 static void silc_query_attributes_accept(const char *line, void *context)
985 {
986   AttrVerify verify = context;
987   SILC_SERVER_REC *server = verify->server;
988   struct stat st;
989   struct passwd *pw;
990   unsigned char filename[256], filename2[256], *fingerprint = NULL, *tmp;
991   SilcUInt32 len;
992   int i;
993
994   if (line[0] == 'Y' || line[0] == 'y') {
995     /* Save the attributes */
996     memset(filename, 0, sizeof(filename));
997     memset(filename2, 0, sizeof(filename2));
998
999     pw = getpwuid(getuid());
1000     if (!pw)
1001       goto out;
1002
1003     /* Replace all whitespaces with `_'. */
1004     fingerprint = silc_hash_fingerprint(sha1hash,
1005                                         verify->userpk.data,
1006                                         verify->userpk.data_len);
1007     for (i = 0; i < strlen(fingerprint); i++)
1008       if (fingerprint[i] == ' ')
1009         fingerprint[i] = '_';
1010
1011     /* Filename for dir */
1012     tmp = fingerprint + strlen(fingerprint) - 9;
1013     snprintf(filename, sizeof(filename) - 1, "%s/friends/%s",
1014              get_irssi_dir(), tmp);
1015
1016     /* Create dir if it doesn't exist */
1017     if ((stat(filename, &st)) == -1) {
1018       /* If dir doesn't exist */
1019       if (errno == ENOENT) {
1020         if (pw->pw_uid == geteuid()) {
1021           if ((mkdir(filename, 0755)) == -1) {
1022             silc_say_error("Couldn't create `%s' directory",
1023                            filename);
1024             goto out;
1025           }
1026         } else {
1027           silc_say_error("Couldn't create `%s' directory due to a "
1028                          "wrong uid!", filename);
1029           goto out;
1030         }
1031       } else {
1032         silc_say_error("%s", strerror(errno));
1033         goto out;
1034       }
1035     }
1036
1037     /* Save the stuff to the directory */
1038
1039     /* Save VCard */
1040     snprintf(filename2, sizeof(filename2) - 1, "%s/vcard", filename);
1041     if (verify->vcard.full_name) {
1042       tmp = silc_vcard_encode(&verify->vcard, &len);
1043       silc_file_writefile(filename2, tmp, len);
1044       silc_free(tmp);
1045     }
1046
1047     /* Save public key */
1048     if (verify->public_key) {
1049       memset(filename2, 0, sizeof(filename2));
1050       snprintf(filename2, sizeof(filename2) - 1, "%s/clientkey_%s.pub",
1051                filename, fingerprint);
1052       silc_pkcs_save_public_key(filename2, verify->public_key,
1053                                 SILC_PKCS_FILE_BASE64);
1054     }
1055
1056     /* Save extension data */
1057     if (verify->extension) {
1058       memset(filename2, 0, sizeof(filename2));
1059       snprintf(filename2, sizeof(filename2) - 1, "%s/extension.mime",
1060                filename);
1061       tmp = silc_mime_encode(verify->extension, &len);
1062       if (tmp)
1063         silc_file_writefile(filename2, tmp, len);
1064     }
1065
1066     /* Save MIME message data */
1067     if (verify->message) {
1068       memset(filename2, 0, sizeof(filename2));
1069       snprintf(filename2, sizeof(filename2) - 1, "%s/status_message.mime",
1070                filename);
1071       tmp = silc_mime_encode(verify->message, &len);
1072       if (tmp)
1073         silc_file_writefile(filename2, tmp, len);
1074     }
1075
1076     printformat_module("fe-common/silc", server, NULL,
1077                        MSGLEVEL_CRAP, SILCTXT_ATTR_SAVED, filename);
1078   }
1079
1080  out:
1081   silc_free(fingerprint);
1082   silc_free(verify->name);
1083   silc_vcard_free(&verify->vcard);
1084   silc_free(verify);
1085 }