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

Duplicate the current SILC prpl as silc10 for backwards compatibility with SILC Toolkit 1.0
author Stu Tomlinson <stu@nosnilmot.com>
date Sat, 09 Jun 2007 16:39:00 +0000
parents
children 285bb637a2b7 35b4f1dc4c8d
comparison
equal deleted inserted replaced
17566:016eee704a96 17567:ba1b50f114f6
1 /*
2
3 silcpurple_util.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 "imgstore.h"
24
25 /**************************** Utility Routines *******************************/
26
27 static char str[256], str2[256];
28
29 const char *silcpurple_silcdir(void)
30 {
31 const char *hd = purple_home_dir();
32 memset(str, 0, sizeof(str));
33 g_snprintf(str, sizeof(str) - 1, "%s" G_DIR_SEPARATOR_S ".silc", hd ? hd : "/tmp");
34 return (const char *)str;
35 }
36
37 const char *silcpurple_session_file(const char *account)
38 {
39 memset(str2, 0, sizeof(str2));
40 g_snprintf(str2, sizeof(str2) - 1, "%s" G_DIR_SEPARATOR_S "%s_session",
41 silcpurple_silcdir(), account);
42 return (const char *)str2;
43 }
44
45 gboolean silcpurple_ip_is_private(const char *ip)
46 {
47 if (silc_net_is_ip4(ip)) {
48 if (!strncmp(ip, "10.", 3)) {
49 return TRUE;
50 } else if (!strncmp(ip, "172.", 4) && strlen(ip) > 6) {
51 char tmp[3];
52 int s;
53 memset(tmp, 0, sizeof(tmp));
54 strncpy(tmp, ip + 4, 2);
55 s = atoi(tmp);
56 if (s >= 16 && s <= 31)
57 return TRUE;
58 } else if (!strncmp(ip, "192.168.", 8)) {
59 return TRUE;
60 }
61 }
62
63 return FALSE;
64 }
65
66 /* This checks stats for various SILC files and directories. First it
67 checks if ~/.silc directory exist and is owned by the correct user. If
68 it doesn't exist, it will create the directory. After that it checks if
69 user's Public and Private key files exists and creates them if needed. */
70
71 gboolean silcpurple_check_silc_dir(PurpleConnection *gc)
72 {
73 char filename[256], file_public_key[256], file_private_key[256];
74 char servfilename[256], clientfilename[256], friendsfilename[256];
75 char pkd[256], prd[256];
76 struct stat st;
77 struct passwd *pw;
78 int fd;
79
80 pw = getpwuid(getuid());
81 if (!pw) {
82 purple_debug_error("silc", "silc: %s\n", strerror(errno));
83 return FALSE;
84 }
85
86 g_snprintf(filename, sizeof(filename) - 1, "%s", silcpurple_silcdir());
87 g_snprintf(servfilename, sizeof(servfilename) - 1, "%s" G_DIR_SEPARATOR_S "serverkeys",
88 silcpurple_silcdir());
89 g_snprintf(clientfilename, sizeof(clientfilename) - 1, "%s" G_DIR_SEPARATOR_S "clientkeys",
90 silcpurple_silcdir());
91 g_snprintf(friendsfilename, sizeof(friendsfilename) - 1, "%s" G_DIR_SEPARATOR_S "friends",
92 silcpurple_silcdir());
93
94 /*
95 * Check ~/.silc directory
96 */
97 if ((g_stat(filename, &st)) == -1) {
98 /* If dir doesn't exist */
99 if (errno == ENOENT) {
100 if (pw->pw_uid == geteuid()) {
101 if ((g_mkdir(filename, 0755)) == -1) {
102 purple_debug_error("silc", "Couldn't create '%s' directory\n", filename);
103 return FALSE;
104 }
105 } else {
106 purple_debug_error("silc", "Couldn't create '%s' directory due to a wrong uid!\n",
107 filename);
108 return FALSE;
109 }
110 } else {
111 purple_debug_error("silc", "Couldn't stat '%s' directory, error: %s\n", filename, strerror(errno));
112 return FALSE;
113 }
114 } else {
115 #ifndef _WIN32
116 /* Check the owner of the dir */
117 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
118 purple_debug_error("silc", "You don't seem to own '%s' directory\n",
119 filename);
120 return FALSE;
121 }
122 #endif
123 }
124
125 /*
126 * Check ~./silc/serverkeys directory
127 */
128 if ((g_stat(servfilename, &st)) == -1) {
129 /* If dir doesn't exist */
130 if (errno == ENOENT) {
131 if (pw->pw_uid == geteuid()) {
132 if ((g_mkdir(servfilename, 0755)) == -1) {
133 purple_debug_error("silc", "Couldn't create '%s' directory\n", servfilename);
134 return FALSE;
135 }
136 } else {
137 purple_debug_error("silc", "Couldn't create '%s' directory due to a wrong uid!\n",
138 servfilename);
139 return FALSE;
140 }
141 } else {
142 purple_debug_error("silc", "Couldn't stat '%s' directory, error: %s\n",
143 servfilename, strerror(errno));
144 return FALSE;
145 }
146 }
147
148 /*
149 * Check ~./silc/clientkeys directory
150 */
151 if ((g_stat(clientfilename, &st)) == -1) {
152 /* If dir doesn't exist */
153 if (errno == ENOENT) {
154 if (pw->pw_uid == geteuid()) {
155 if ((g_mkdir(clientfilename, 0755)) == -1) {
156 purple_debug_error("silc", "Couldn't create '%s' directory\n", clientfilename);
157 return FALSE;
158 }
159 } else {
160 purple_debug_error("silc", "Couldn't create '%s' directory due to a wrong uid!\n",
161 clientfilename);
162 return FALSE;
163 }
164 } else {
165 purple_debug_error("silc", "Couldn't stat '%s' directory, error: %s\n",
166 clientfilename, strerror(errno));
167 return FALSE;
168 }
169 }
170
171 /*
172 * Check ~./silc/friends directory
173 */
174 if ((g_stat(friendsfilename, &st)) == -1) {
175 /* If dir doesn't exist */
176 if (errno == ENOENT) {
177 if (pw->pw_uid == geteuid()) {
178 if ((g_mkdir(friendsfilename, 0755)) == -1) {
179 purple_debug_error("silc", "Couldn't create '%s' directory\n", friendsfilename);
180 return FALSE;
181 }
182 } else {
183 purple_debug_error("silc", "Couldn't create '%s' directory due to a wrong uid!\n",
184 friendsfilename);
185 return FALSE;
186 }
187 } else {
188 purple_debug_error("silc", "Couldn't stat '%s' directory, error: %s\n",
189 friendsfilename, strerror(errno));
190 return FALSE;
191 }
192 }
193
194 /*
195 * Check Public and Private keys
196 */
197 g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir());
198 g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir());
199 g_snprintf(file_public_key, sizeof(file_public_key) - 1, "%s",
200 purple_account_get_string(gc->account, "public-key", pkd));
201 g_snprintf(file_private_key, sizeof(file_public_key) - 1, "%s",
202 purple_account_get_string(gc->account, "private-key", prd));
203
204 if ((g_stat(file_public_key, &st)) == -1) {
205 /* If file doesn't exist */
206 if (errno == ENOENT) {
207 purple_connection_update_progress(gc, _("Creating SILC key pair..."), 1, 5);
208 if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS,
209 SILCPURPLE_DEF_PKCS_LEN,
210 file_public_key, file_private_key, NULL,
211 (gc->password == NULL) ? "" : gc->password,
212 NULL, NULL, NULL, FALSE)) {
213 purple_debug_error("silc", "Couldn't create key pair\n");
214 return FALSE;
215 }
216
217 if ((g_stat(file_public_key, &st)) == -1) {
218 purple_debug_error("silc", "Couldn't stat '%s' public key, error: %s\n",
219 file_public_key, strerror(errno));
220 return FALSE;
221 }
222 } else {
223 purple_debug_error("silc", "Couldn't stat '%s' public key, error: %s\n",
224 file_public_key, strerror(errno));
225 return FALSE;
226 }
227 }
228
229 #ifndef _WIN32
230 /* Check the owner of the public key */
231 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
232 purple_debug_error("silc", "You don't seem to own your public key!?\n");
233 return FALSE;
234 }
235 #endif
236
237 if ((fd = g_open(file_private_key, O_RDONLY, 0)) != -1) {
238 if ((fstat(fd, &st)) == -1) {
239 purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n",
240 file_private_key, strerror(errno));
241 close(fd);
242 return FALSE;
243 }
244 } else if ((g_stat(file_private_key, &st)) == -1) {
245 /* If file doesn't exist */
246 if (errno == ENOENT) {
247 purple_connection_update_progress(gc, _("Creating SILC key pair..."), 1, 5);
248 if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS,
249 SILCPURPLE_DEF_PKCS_LEN,
250 file_public_key, file_private_key, NULL,
251 (gc->password == NULL) ? "" : gc->password,
252 NULL, NULL, NULL, FALSE)) {
253 purple_debug_error("silc", "Couldn't create key pair\n");
254 return FALSE;
255 }
256
257 if ((fd = g_open(file_private_key, O_RDONLY, 0)) != -1) {
258 if ((fstat(fd, &st)) == -1) {
259 purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n",
260 file_private_key, strerror(errno));
261 close(fd);
262 return FALSE;
263 }
264 }
265 /* This shouldn't really happen because silc_create_key_pair()
266 * will set the permissions */
267 else if ((g_stat(file_private_key, &st)) == -1) {
268 purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n",
269 file_private_key, strerror(errno));
270 return FALSE;
271 }
272 } else {
273 purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n",
274 file_private_key, strerror(errno));
275 return FALSE;
276 }
277 }
278
279 #ifndef _WIN32
280 /* Check the owner of the private key */
281 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
282 purple_debug_error("silc", "You don't seem to own your private key!?\n");
283 if (fd != -1)
284 close(fd);
285 return FALSE;
286 }
287
288 /* Check the permissions for the private key */
289 if ((st.st_mode & 0777) != 0600) {
290 purple_debug_warning("silc", "Wrong permissions in your private key file `%s'!\n"
291 "Trying to change them ...\n", file_private_key);
292 if ((fd == -1) || (fchmod(fd, S_IRUSR | S_IWUSR)) == -1) {
293 purple_debug_error("silc",
294 "Failed to change permissions for private key file!\n"
295 "Permissions for your private key file must be 0600.\n");
296 if (fd != -1)
297 close(fd);
298 return FALSE;
299 }
300 purple_debug_warning("silc", "Done.\n\n");
301 }
302 #endif
303
304 if (fd != -1)
305 close(fd);
306
307 return TRUE;
308 }
309
310 #ifdef _WIN32
311 struct passwd *getpwuid(uid_t uid) {
312 struct passwd *pwd = calloc(1, sizeof(struct passwd));
313 return pwd;
314 }
315
316 uid_t getuid() {
317 return 0;
318 }
319
320 uid_t geteuid() {
321 return 0;
322 }
323 #endif
324
325 void silcpurple_show_public_key(SilcPurple sg,
326 const char *name, SilcPublicKey public_key,
327 GCallback callback, void *context)
328 {
329 SilcPublicKeyIdentifier ident;
330 SilcPKCS pkcs;
331 char *fingerprint, *babbleprint;
332 unsigned char *pk;
333 SilcUInt32 pk_len, key_len = 0;
334 GString *s;
335 char *buf;
336
337 ident = silc_pkcs_decode_identifier(public_key->identifier);
338 if (!ident)
339 return;
340
341 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
342 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
343 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
344
345 if (silc_pkcs_alloc((unsigned char *)public_key->name, &pkcs)) {
346 key_len = silc_pkcs_public_key_set(pkcs, public_key);
347 silc_pkcs_free(pkcs);
348 }
349
350 s = g_string_new("");
351 if (ident->realname)
352 /* Hint for translators: Please check the tabulator width here and in
353 the next strings (short strings: 2 tabs, longer strings 1 tab,
354 sum: 3 tabs or 24 characters) */
355 g_string_append_printf(s, _("Real Name: \t%s\n"), ident->realname);
356 if (ident->username)
357 g_string_append_printf(s, _("User Name: \t%s\n"), ident->username);
358 if (ident->email)
359 g_string_append_printf(s, _("E-Mail: \t\t%s\n"), ident->email);
360 if (ident->host)
361 g_string_append_printf(s, _("Host Name: \t%s\n"), ident->host);
362 if (ident->org)
363 g_string_append_printf(s, _("Organization: \t%s\n"), ident->org);
364 if (ident->country)
365 g_string_append_printf(s, _("Country: \t%s\n"), ident->country);
366 g_string_append_printf(s, _("Algorithm: \t%s\n"), public_key->name);
367 g_string_append_printf(s, _("Key Length: \t%d bits\n"), (int)key_len);
368 g_string_append_printf(s, "\n");
369 g_string_append_printf(s, _("Public Key Fingerprint:\n%s\n\n"), fingerprint);
370 g_string_append_printf(s, _("Public Key Babbleprint:\n%s"), babbleprint);
371
372 buf = g_string_free(s, FALSE);
373
374 purple_request_action(sg->gc, _("Public Key Information"),
375 _("Public Key Information"),
376 buf, 0, purple_connection_get_account(sg->gc),
377 NULL, NULL, context, 1, _("Close"), callback);
378
379 g_free(buf);
380 silc_free(fingerprint);
381 silc_free(babbleprint);
382 silc_free(pk);
383 silc_pkcs_free_identifier(ident);
384 }
385
386 SilcAttributePayload
387 silcpurple_get_attr(SilcDList attrs, SilcAttribute attribute)
388 {
389 SilcAttributePayload attr = NULL;
390
391 if (!attrs)
392 return NULL;
393
394 silc_dlist_start(attrs);
395 while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END)
396 if (attribute == silc_attribute_get_attribute(attr))
397 break;
398
399 return attr;
400 }
401
402 void silcpurple_get_umode_string(SilcUInt32 mode, char *buf,
403 SilcUInt32 buf_size)
404 {
405 memset(buf, 0, buf_size);
406 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
407 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
408 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
409 "[server operator] " :
410 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
411 "[SILC operator] " : "[unknown mode] ");
412 }
413 if (mode & SILC_UMODE_GONE)
414 strcat(buf, "[away] ");
415 if (mode & SILC_UMODE_INDISPOSED)
416 strcat(buf, "[indisposed] ");
417 if (mode & SILC_UMODE_BUSY)
418 strcat(buf, "[busy] ");
419 if (mode & SILC_UMODE_PAGE)
420 strcat(buf, "[wake me up] ");
421 if (mode & SILC_UMODE_HYPER)
422 strcat(buf, "[hyperactive] ");
423 if (mode & SILC_UMODE_ROBOT)
424 strcat(buf, "[robot] ");
425 if (mode & SILC_UMODE_ANONYMOUS)
426 strcat(buf, "[anonymous] ");
427 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
428 strcat(buf, "[blocks private messages] ");
429 if (mode & SILC_UMODE_DETACHED)
430 strcat(buf, "[detached] ");
431 if (mode & SILC_UMODE_REJECT_WATCHING)
432 strcat(buf, "[rejects watching] ");
433 if (mode & SILC_UMODE_BLOCK_INVITE)
434 strcat(buf, "[blocks invites] ");
435 }
436
437 void silcpurple_get_chmode_string(SilcUInt32 mode, char *buf,
438 SilcUInt32 buf_size)
439 {
440 memset(buf, 0, buf_size);
441 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
442 strcat(buf, "[permanent] ");
443 if (mode & SILC_CHANNEL_MODE_PRIVATE)
444 strcat(buf, "[private] ");
445 if (mode & SILC_CHANNEL_MODE_SECRET)
446 strcat(buf, "[secret] ");
447 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
448 strcat(buf, "[private key] ");
449 if (mode & SILC_CHANNEL_MODE_INVITE)
450 strcat(buf, "[invite only] ");
451 if (mode & SILC_CHANNEL_MODE_TOPIC)
452 strcat(buf, "[topic restricted] ");
453 if (mode & SILC_CHANNEL_MODE_ULIMIT)
454 strcat(buf, "[user count limit] ");
455 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
456 strcat(buf, "[passphrase auth] ");
457 if (mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
458 strcat(buf, "[public key auth] ");
459 if (mode & SILC_CHANNEL_MODE_SILENCE_USERS)
460 strcat(buf, "[users silenced] ");
461 if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS)
462 strcat(buf, "[operators silenced] ");
463 }
464
465 void silcpurple_get_chumode_string(SilcUInt32 mode, char *buf,
466 SilcUInt32 buf_size)
467 {
468 memset(buf, 0, buf_size);
469 if (mode & SILC_CHANNEL_UMODE_CHANFO)
470 strcat(buf, "[founder] ");
471 if (mode & SILC_CHANNEL_UMODE_CHANOP)
472 strcat(buf, "[operator] ");
473 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)
474 strcat(buf, "[blocks messages] ");
475 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS)
476 strcat(buf, "[blocks user messages] ");
477 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS)
478 strcat(buf, "[blocks robot messages] ");
479 if (mode & SILC_CHANNEL_UMODE_QUIET)
480 strcat(buf, "[quieted] ");
481 }
482
483 void
484 silcpurple_parse_attrs(SilcDList attrs, char **moodstr, char **statusstr,
485 char **contactstr, char **langstr, char **devicestr,
486 char **tzstr, char **geostr)
487 {
488 SilcAttributePayload attr;
489 SilcAttributeMood mood = 0;
490 SilcAttributeContact contact;
491 SilcAttributeObjDevice device;
492 SilcAttributeObjGeo geo;
493
494 char tmp[1024];
495 GString *s;
496
497 *moodstr = NULL;
498 *statusstr = NULL;
499 *contactstr = NULL;
500 *langstr = NULL;
501 *devicestr = NULL;
502 *tzstr = NULL;
503 *geostr = NULL;
504
505 if (!attrs)
506 return;
507
508 s = g_string_new("");
509 attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_STATUS_MOOD);
510 if (attr && silc_attribute_get_object(attr, &mood, sizeof(mood))) {
511 if (mood & SILC_ATTRIBUTE_MOOD_HAPPY)
512 g_string_append_printf(s, "[%s] ", _("Happy"));
513 if (mood & SILC_ATTRIBUTE_MOOD_SAD)
514 g_string_append_printf(s, "[%s] ", _("Sad"));
515 if (mood & SILC_ATTRIBUTE_MOOD_ANGRY)
516 g_string_append_printf(s, "[%s] ", _("Angry"));
517 if (mood & SILC_ATTRIBUTE_MOOD_JEALOUS)
518 g_string_append_printf(s, "[%s] ", _("Jealous"));
519 if (mood & SILC_ATTRIBUTE_MOOD_ASHAMED)
520 g_string_append_printf(s, "[%s] ", _("Ashamed"));
521 if (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE)
522 g_string_append_printf(s, "[%s] ", _("Invincible"));
523 if (mood & SILC_ATTRIBUTE_MOOD_INLOVE)
524 g_string_append_printf(s, "[%s] ", _("In Love"));
525 if (mood & SILC_ATTRIBUTE_MOOD_SLEEPY)
526 g_string_append_printf(s, "[%s] ", _("Sleepy"));
527 if (mood & SILC_ATTRIBUTE_MOOD_BORED)
528 g_string_append_printf(s, "[%s] ", _("Bored"));
529 if (mood & SILC_ATTRIBUTE_MOOD_EXCITED)
530 g_string_append_printf(s, "[%s] ", _("Excited"));
531 if (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS)
532 g_string_append_printf(s, "[%s] ", _("Anxious"));
533 }
534 if (strlen(s->str)) {
535 *moodstr = s->str;
536 g_string_free(s, FALSE);
537 } else
538 g_string_free(s, TRUE);
539
540 attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_STATUS_FREETEXT);
541 memset(tmp, 0, sizeof(tmp));
542 if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp)))
543 *statusstr = g_strdup(tmp);
544
545 s = g_string_new("");
546 attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_PREFERRED_CONTACT);
547 if (attr && silc_attribute_get_object(attr, &contact, sizeof(contact))) {
548 if (contact & SILC_ATTRIBUTE_CONTACT_CHAT)
549 g_string_append_printf(s, "[%s] ", _("Chat"));
550 if (contact & SILC_ATTRIBUTE_CONTACT_EMAIL)
551 g_string_append_printf(s, "[%s] ", _("E-Mail"));
552 if (contact & SILC_ATTRIBUTE_CONTACT_CALL)
553 g_string_append_printf(s, "[%s] ", _("Phone"));
554 if (contact & SILC_ATTRIBUTE_CONTACT_PAGE)
555 g_string_append_printf(s, "[%s] ", _("Paging"));
556 if (contact & SILC_ATTRIBUTE_CONTACT_SMS)
557 g_string_append_printf(s, "[%s] ", _("SMS"));
558 if (contact & SILC_ATTRIBUTE_CONTACT_MMS)
559 g_string_append_printf(s, "[%s] ", _("MMS"));
560 if (contact & SILC_ATTRIBUTE_CONTACT_VIDEO)
561 g_string_append_printf(s, "[%s] ", _("Video Conferencing"));
562 }
563 if (strlen(s->str)) {
564 *contactstr = s->str;
565 g_string_free(s, FALSE);
566 } else
567 g_string_free(s, TRUE);
568
569 attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_PREFERRED_LANGUAGE);
570 memset(tmp, 0, sizeof(tmp));
571 if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp)))
572 *langstr = g_strdup(tmp);
573
574 s = g_string_new("");
575 attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_DEVICE_INFO);
576 memset(&device, 0, sizeof(device));
577 if (attr && silc_attribute_get_object(attr, &device, sizeof(device))) {
578 if (device.type == SILC_ATTRIBUTE_DEVICE_COMPUTER)
579 g_string_append_printf(s, "%s: ", _("Computer"));
580 if (device.type == SILC_ATTRIBUTE_DEVICE_MOBILE_PHONE)
581 g_string_append_printf(s, "%s: ", _("Mobile Phone"));
582 if (device.type == SILC_ATTRIBUTE_DEVICE_PDA)
583 g_string_append_printf(s, "%s: ", _("PDA"));
584 if (device.type == SILC_ATTRIBUTE_DEVICE_TERMINAL)
585 g_string_append_printf(s, "%s: ", _("Terminal"));
586 g_string_append_printf(s, "%s %s %s %s",
587 device.manufacturer ? device.manufacturer : "",
588 device.version ? device.version : "",
589 device.model ? device.model : "",
590 device.language ? device.language : "");
591 }
592 if (strlen(s->str)) {
593 *devicestr = s->str;
594 g_string_free(s, FALSE);
595 } else
596 g_string_free(s, TRUE);
597
598 attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_TIMEZONE);
599 memset(tmp, 0, sizeof(tmp));
600 if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp)))
601 *tzstr = g_strdup(tmp);
602
603 attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_GEOLOCATION);
604 memset(&geo, 0, sizeof(geo));
605 if (attr && silc_attribute_get_object(attr, &geo, sizeof(geo)))
606 *geostr = g_strdup_printf("%s %s %s (%s)",
607 geo.longitude ? geo.longitude : "",
608 geo.latitude ? geo.latitude : "",
609 geo.altitude ? geo.altitude : "",
610 geo.accuracy ? geo.accuracy : "");
611 }
612
613 #ifdef HAVE_SILCMIME_H
614 /* Returns MIME type of filetype */
615
616 char *silcpurple_file2mime(const char *filename)
617 {
618 const char *ct;
619
620 ct = strrchr(filename, '.');
621 if (!ct)
622 return NULL;
623 else if (!g_ascii_strcasecmp(".png", ct))
624 return strdup("image/png");
625 else if (!g_ascii_strcasecmp(".jpg", ct))
626 return strdup("image/jpeg");
627 else if (!g_ascii_strcasecmp(".jpeg", ct))
628 return strdup("image/jpeg");
629 else if (!g_ascii_strcasecmp(".gif", ct))
630 return strdup("image/gif");
631 else if (!g_ascii_strcasecmp(".tiff", ct))
632 return strdup("image/tiff");
633
634 return NULL;
635 }
636
637 /* Checks if message has images, and assembles MIME message if it has.
638 If only one image is present, creates simple MIME image message. If
639 there are multiple images and/or text with images multipart MIME
640 message is created. */
641
642 SilcDList silcpurple_image_message(const char *msg, SilcUInt32 *mflags)
643 {
644 SilcMime mime = NULL, p;
645 SilcDList list, parts = NULL;
646 const char *start, *end, *last;
647 GData *attribs;
648 char *type;
649 gboolean images = FALSE;
650
651 last = msg;
652 while (last && *last && purple_markup_find_tag("img", last, &start,
653 &end, &attribs)) {
654 PurpleStoredImage *image = NULL;
655 const char *id;
656
657 /* Check if there is text before image */
658 if (start - last) {
659 char *text, *tmp;
660 p = silc_mime_alloc();
661
662 /* Add content type */
663 silc_mime_add_field(p, "Content-Type",
664 "text/plain; charset=utf-8");
665
666 tmp = g_strndup(last, start - last);
667 text = purple_unescape_html(tmp);
668 g_free(tmp);
669 /* Add text */
670 silc_mime_add_data(p, text, strlen(text));
671 g_free(text);
672
673 if (!parts)
674 parts = silc_dlist_init();
675 silc_dlist_add(parts, p);
676 }
677
678 id = g_datalist_get_data(&attribs, "id");
679 if (id && (image = purple_imgstore_find_by_id(atoi(id)))) {
680 unsigned long imglen = purple_imgstore_get_size(image);
681 gconstpointer img = purple_imgstore_get_data(image);
682
683 p = silc_mime_alloc();
684
685 /* Add content type */
686 type = silcpurple_file2mime(purple_imgstore_get_filename(image));
687 if (!type) {
688 g_datalist_clear(&attribs);
689 last = end + 1;
690 continue;
691 }
692 silc_mime_add_field(p, "Content-Type", type);
693 silc_free(type);
694
695 /* Add content transfer encoding */
696 silc_mime_add_field(p, "Content-Transfer-Encoding", "binary");
697
698 /* Add image data */
699 silc_mime_add_data(p, img, imglen);
700
701 if (!parts)
702 parts = silc_dlist_init();
703 silc_dlist_add(parts, p);
704 images = TRUE;
705 }
706
707 g_datalist_clear(&attribs);
708
709 /* Continue after tag */
710 last = end + 1;
711 }
712
713 /* Check for text after the image(s) */
714 if (images && last && *last) {
715 char *tmp = purple_unescape_html(last);
716 p = silc_mime_alloc();
717
718 /* Add content type */
719 silc_mime_add_field(p, "Content-Type",
720 "text/plain; charset=utf-8");
721
722 /* Add text */
723 silc_mime_add_data(p, tmp, strlen(tmp));
724 g_free(tmp);
725
726 if (!parts)
727 parts = silc_dlist_init();
728 silc_dlist_add(parts, p);
729 }
730
731 /* If there weren't any images, don't return anything. */
732 if (!images) {
733 if (parts)
734 silc_dlist_uninit(parts);
735 return NULL;
736 }
737
738 if (silc_dlist_count(parts) > 1) {
739 /* Multipart MIME message */
740 char b[32];
741 mime = silc_mime_alloc();
742 silc_mime_add_field(mime, "MIME-Version", "1.0");
743 g_snprintf(b, sizeof(b), "b%4X%4X",
744 (unsigned int)time(NULL),
745 silc_dlist_count(parts));
746 silc_mime_set_multipart(mime, "mixed", b);
747 silc_dlist_start(parts);
748 while ((p = silc_dlist_get(parts)) != SILC_LIST_END)
749 silc_mime_add_multipart(mime, p);
750 } else {
751 /* Simple MIME message */
752 silc_dlist_start(parts);
753 mime = silc_dlist_get(parts);
754 silc_mime_add_field(mime, "MIME-Version", "1.0");
755 }
756
757 *mflags &= ~SILC_MESSAGE_FLAG_UTF8;
758 *mflags |= SILC_MESSAGE_FLAG_DATA;
759
760 /* Encode message. Fragment if it is too large */
761 list = silc_mime_encode_partial(mime, 0xfc00);
762
763 silc_dlist_uninit(parts);
764
765 /* Added multiparts gets freed here */
766 silc_mime_free(mime);
767
768 return list;
769 }
770
771 #endif /* HAVE_SILCMIME_H */