presence.2007: fix for OOF note propagation
[siplcs.git] / src / core / sipmsg.c
blob8b2f46850361f671d09d70745b5e967886f13c19
1 /**
2 * @file sipmsg.c
4 * gaim
6 * Copyright (C) 2008 Novell, Inc.
7 * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de>
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; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include <string.h>
25 #include <glib.h>
27 #include "debug.h"
28 #include "mime.h"
30 #include "sipe.h"
31 #include "sipmsg.h"
33 struct sipmsg *sipmsg_parse_msg(const gchar *msg) {
34 const char *tmp = strstr(msg, "\r\n\r\n");
35 char *line;
36 struct sipmsg *smsg;
38 if(!tmp) return NULL;
40 line = g_strndup(msg, tmp - msg);
42 smsg = sipmsg_parse_header(line);
43 smsg->body = g_strdup(tmp + 4);
45 g_free(line);
46 return smsg;
49 struct sipmsg *sipmsg_parse_header(const gchar *header) {
50 struct sipmsg *msg = g_new0(struct sipmsg,1);
51 gchar **lines = g_strsplit(header,"\r\n",0);
52 gchar **parts;
53 gchar *dummy;
54 gchar *dummy2;
55 gchar *tmp;
56 gchar *contentlength;
57 int i=1;
58 if(!lines[0]) {
59 g_strfreev(lines);
60 g_free(msg);
61 return NULL;
63 parts = g_strsplit(lines[0], " ", 3);
64 if(!parts[0] || !parts[1] || !parts[2]) {
65 g_strfreev(parts);
66 g_strfreev(lines);
67 g_free(msg);
68 return NULL;
70 if(strstr(parts[0],"SIP") || strstr(parts[0],"HTTP")) { /* numeric response */
71 msg->method = g_strdup(parts[2]);
72 msg->response = strtol(parts[1],NULL,10);
73 } else { /* request */
74 msg->method = g_strdup(parts[0]);
75 msg->target = g_strdup(parts[1]);
76 msg->response = 0;
78 g_strfreev(parts);
79 for(i=1; lines[i] && strlen(lines[i])>2; i++) {
80 parts = g_strsplit(lines[i], ":", 2);
81 if(!parts[0] || !parts[1]) {
82 g_strfreev(parts);
83 g_strfreev(lines);
84 sipmsg_free(msg);
85 return NULL;
87 dummy = parts[1];
88 dummy2 = 0;
89 while(*dummy==' ' || *dummy=='\t') dummy++;
90 dummy2 = g_strdup(dummy);
91 while(lines[i+1] && (lines[i+1][0]==' ' || lines[i+1][0]=='\t')) {
92 i++;
93 dummy = lines[i];
94 while(*dummy==' ' || *dummy=='\t') dummy++;
95 tmp = g_strdup_printf("%s %s",dummy2, dummy);
96 g_free(dummy2);
97 dummy2 = tmp;
99 sipmsg_add_header_now(msg, parts[0], dummy2);
100 g_free(dummy2);
101 g_strfreev(parts);
103 g_strfreev(lines);
104 contentlength = sipmsg_find_header(msg, "Content-Length");
105 if (contentlength) {
106 msg->bodylen = strtol(contentlength,NULL,10);
107 } else {
108 purple_debug_fatal("sipe", "sipmsg_parse_header(): Content-Length header not found\n");
110 if(msg->response) {
111 g_free(msg->method);
112 tmp = sipmsg_find_header(msg, "CSeq");
113 if(!tmp) {
114 /* SHOULD NOT HAPPEN */
115 msg->method = 0;
116 } else {
117 parts = g_strsplit(tmp, " ", 2);
118 msg->method = g_strdup(parts[1]);
119 g_strfreev(parts);
122 return msg;
125 void sipmsg_print(const struct sipmsg *msg) {
126 GSList *cur;
127 struct siphdrelement *elem;
128 purple_debug(PURPLE_DEBUG_MISC, "sipe", "SIP MSG\n");
129 purple_debug(PURPLE_DEBUG_MISC, "sipe", "response: %d\nmethod: %s\nbodylen: %d\n",msg->response,msg->method,msg->bodylen);
130 if(msg->target) purple_debug(PURPLE_DEBUG_MISC, "sipe", "target: %s\n",msg->target);
131 cur = msg->headers;
132 while(cur) {
133 elem = cur->data;
134 purple_debug(PURPLE_DEBUG_MISC, "sipe", "name: %s value: %s\n",elem->name, elem->value);
135 cur = g_slist_next(cur);
139 char *sipmsg_to_string(const struct sipmsg *msg) {
140 GSList *cur;
141 GString *outstr = g_string_new("");
142 struct siphdrelement *elem;
144 if(msg->response)
145 g_string_append_printf(outstr, "SIP/2.0 %d Unknown\r\n",
146 msg->response);
147 else
148 g_string_append_printf(outstr, "%s %s SIP/2.0\r\n",
149 msg->method, msg->target);
151 cur = msg->headers;
152 while(cur) {
153 elem = cur->data;
154 /*Todo: remove the LFCR in a good way*/
155 /*if(!strcmp(elem->name,"Proxy-Authorization"))
156 g_string_append_printf(outstr, "%s: %s", elem->name,
157 elem->value);
158 else */
159 g_string_append_printf(outstr, "%s: %s\r\n", elem->name,
160 elem->value);
161 cur = g_slist_next(cur);
164 g_string_append_printf(outstr, "\r\n%s", msg->bodylen ? msg->body : "");
166 return g_string_free(outstr, FALSE);
170 * Adds header to current message headers at specified position
172 void sipmsg_add_header_now_pos(struct sipmsg *msg, const gchar *name, const gchar *value, int pos) {
173 struct siphdrelement *element = g_new0(struct siphdrelement,1);
174 element->name = g_strdup(name);
175 element->value = g_strdup(value);
176 msg->headers = g_slist_insert(msg->headers, element,pos);
180 * Adds header to current message headers
182 void sipmsg_add_header_now(struct sipmsg *msg, const gchar *name, const gchar *value) {
183 struct siphdrelement *element = g_new0(struct siphdrelement,1);
184 element->name = g_strdup(name);
185 element->value = g_strdup(value);
186 msg->headers = g_slist_append(msg->headers, element);
190 * Adds header to separate storage for future merge
192 void sipmsg_add_header(struct sipmsg *msg, const gchar *name, const gchar *value) {
193 struct siphdrelement *element = g_new0(struct siphdrelement,1);
194 element->name = g_strdup(name);
195 element->value = g_strdup(value);
196 msg->new_headers = g_slist_append(msg->new_headers, element);
200 * Removes header if it's not in keepers array
202 void sipmsg_strip_headers(struct sipmsg *msg, const gchar *keepers[]) {
203 GSList *entry;
204 struct siphdrelement *elem;
206 entry = msg->headers;
207 while(entry) {
208 int i = 0;
209 gboolean keeper = FALSE;
211 elem = entry->data;
212 while (keepers[i]) {
213 if (!g_strcasecmp(elem->name, keepers[i])) {
214 keeper = TRUE;
215 break;
217 i++;
220 if (!keeper) {
221 GSList *to_delete = entry;
222 purple_debug_info("sipe", "sipmsg_strip_headers: removing %s\n", elem->name);
223 entry = g_slist_next(entry);
224 msg->headers = g_slist_delete_link(msg->headers, to_delete);
225 g_free(elem->name);
226 g_free(elem->value);
227 g_free(elem);
228 } else {
229 entry = g_slist_next(entry);
235 * Merges newly added headers to message
237 void sipmsg_merge_new_headers(struct sipmsg *msg) {
238 while(msg->new_headers) {
239 msg->headers = g_slist_append(msg->headers, msg->new_headers->data);
240 msg->new_headers = g_slist_remove(msg->new_headers, msg->new_headers->data);
244 void sipmsg_free(struct sipmsg *msg) {
245 struct siphdrelement *elem;
246 while(msg->headers) {
247 elem = msg->headers->data;
248 msg->headers = g_slist_remove(msg->headers,elem);
249 g_free(elem->name);
250 g_free(elem->value);
251 g_free(elem);
253 while(msg->new_headers) {
254 elem = msg->new_headers->data;
255 msg->new_headers = g_slist_remove(msg->new_headers,elem);
256 g_free(elem->name);
257 g_free(elem->value);
258 g_free(elem);
260 g_free(msg->signature);
261 g_free(msg->rand);
262 g_free(msg->num);
263 g_free(msg->method);
264 g_free(msg->target);
265 g_free(msg->body);
266 g_free(msg);
269 void sipmsg_remove_header_now(struct sipmsg *msg, const gchar *name) {
270 struct siphdrelement *elem;
271 GSList *tmp = msg->headers;
272 while(tmp) {
273 elem = tmp->data;
274 // OCS2005 can send the same header in either all caps or mixed case
275 if (g_ascii_strcasecmp(elem->name, name)==0) {
276 msg->headers = g_slist_remove(msg->headers, elem);
277 g_free(elem->name);
278 g_free(elem->value);
279 g_free(elem);
280 return;
282 tmp = g_slist_next(tmp);
284 return;
287 gchar *sipmsg_find_header(const struct sipmsg *msg, const gchar *name) {
288 return sipmsg_find_header_instance (msg, name, 0);
291 gchar *sipmsg_find_header_instance(const struct sipmsg *msg, const gchar *name, int which) {
292 GSList *tmp;
293 struct siphdrelement *elem;
294 int i = 0;
295 tmp = msg->headers;
296 while(tmp) {
297 elem = tmp->data;
298 // OCS2005 can send the same header in either all caps or mixed case
299 if (g_ascii_strcasecmp(elem->name,name)==0) {
300 if (i == which) {
301 return elem->value;
303 i++;
305 tmp = g_slist_next(tmp);
307 return NULL;
310 gchar *sipmsg_find_part_of_header(const char *hdr, const char * before, const char * after, const char * def) {
311 const char *tmp;
312 const char *tmp2;
313 gchar *res2;
314 if (!hdr) {
315 return NULL;
318 //printf("partof %s w/ %s before and %s after\n", hdr, before, after);
320 tmp = before == NULL ? hdr : strstr(hdr, before);
321 if (!tmp) {
322 //printf ("not found, returning null\n");
323 return (gchar *)def;
326 if (before != NULL) {
327 tmp += strlen(before);
328 //printf ("tmp now %s\n", tmp);
331 if (after != NULL && (tmp2 = strstr(tmp, after))) {
332 gchar * res = g_strndup(tmp, tmp2 - tmp);
333 //printf("returning %s\n", res);
334 return res;
336 res2 = g_strdup(tmp);
337 //printf("returning %s\n", res2);
338 return res2;
342 * Parse EndPoints header from INVITE request
343 * Returns a list of end points: contact URI plus optional epid.
344 * You must free the values and the list.
346 * Example headers:
347 * EndPoints: "alice alisson" <sip:alice@atlanta.local>, <sip:bob@atlanta.local>;epid=ebca82d94d, <sip:carol@atlanta.local>
348 * EndPoints: "alice, alisson" <sip:alice@atlanta.local>, <sip:bob@atlanta.local>
349 * EndPoints: "alice alisson" <sip:alice@atlanta.local>, "Super, Man" <sip:super@atlanta.local>
351 * @param header (in) EndPoints header contents
353 * @return GSList with struct sipendpoint as elements
355 GSList *sipmsg_parse_endpoints_header(const gchar *header)
357 GSList *list = NULL;
358 gchar **parts = g_strsplit(header, ",", 0);
359 gchar *part;
360 int i;
362 for (i = 0; (part = parts[i]) != NULL; i++) {
363 /* Does the part contain a URI? */
364 gchar *contact = sipmsg_find_part_of_header(part, "<", ">", NULL);
365 if (contact) {
366 struct sipendpoint *end_point = g_new(struct sipendpoint, 1);
367 end_point->contact = contact;
368 end_point->epid = sipmsg_find_part_of_header(part, "epid=", NULL, NULL);
369 list = g_slist_append(list, end_point);
372 g_strfreev(parts);
374 return(list);
378 * sipmsg_find_auth_header will return the particular WWW-Authenticate
379 * header specified by *name.
381 * Use this function when you want to look for a specific authentication
382 * method such as NTLM or Kerberos
385 gchar *sipmsg_find_auth_header(struct sipmsg *msg, const gchar *name) {
386 GSList *tmp;
387 struct siphdrelement *elem;
388 int name_len = strlen(name);
389 tmp = msg->headers;
390 while(tmp) {
391 elem = tmp->data;
392 //purple_debug(PURPLE_DEBUG_MISC, "sipmsg", "Current header: %s\r\n", elem->value);
393 if (elem && elem->name &&
394 (!g_ascii_strcasecmp(elem->name,"WWW-Authenticate")
395 || !g_ascii_strcasecmp(elem->name,"Authentication-Info")) ) {
396 if (!g_strncasecmp((gchar *)elem->value, name, name_len)) {
397 //purple_debug(PURPLE_DEBUG_MISC, "sipmsg", "elem->value: %s\r\n", elem->value);
398 return elem->value;
401 //purple_debug(PURPLE_DEBUG_MISC, "sipmsg", "moving to next header\r\n");
402 tmp = g_slist_next(tmp);
404 purple_debug(PURPLE_DEBUG_MISC, "sipmsg", "Did not found auth header %s\r\n", name);
405 return NULL;
408 gchar *sipmsg_get_x_mms_im_format(gchar *msgr) {
409 gchar *msgr2;
410 gsize msgr_dec64_len;
411 guchar *msgr_dec64;
412 gchar *msgr_utf8;
413 gchar **lines;
414 gchar **parts;
415 gchar *x_mms_im_format;
416 gchar *tmp;
418 if (!msgr) return NULL;
419 msgr2 = g_strdup(msgr);
420 while (strlen(msgr2) % 4 != 0) {
421 gchar *tmp_msgr2 = msgr2;
422 msgr2 = g_strdup_printf("%s=", msgr2);
423 g_free(tmp_msgr2);
425 msgr_dec64 = purple_base64_decode(msgr2, &msgr_dec64_len);
426 msgr_utf8 = g_convert((gchar *) msgr_dec64, msgr_dec64_len, "UTF-8", "UTF-16LE", NULL, NULL, NULL);
427 g_free(msgr_dec64);
428 g_free(msgr2);
429 lines = g_strsplit(msgr_utf8,"\r\n\r\n",0);
430 g_free(msgr_utf8);
431 //@TODO: make extraction like parsing of message headers.
432 parts = g_strsplit(lines[0],"X-MMS-IM-Format:",0);
433 x_mms_im_format = g_strdup(parts[1]);
434 g_strfreev(parts);
435 g_strfreev(lines);
436 tmp = x_mms_im_format;
437 if (x_mms_im_format) {
438 while(*x_mms_im_format==' ' || *x_mms_im_format=='\t') x_mms_im_format++;
440 x_mms_im_format = g_strdup(x_mms_im_format);
441 g_free(tmp);
442 return x_mms_im_format;
445 gchar *sipmsg_get_msgr_string(gchar *x_mms_im_format) {
446 gchar *msgr_orig;
447 gsize msgr_utf16_len;
448 gchar *msgr_utf16;
449 gchar *msgr_enc;
450 gchar *res;
451 int len;
453 if (!x_mms_im_format) return NULL;
454 msgr_orig = g_strdup_printf("X-MMS-IM-Format: %s\r\n\r\n", x_mms_im_format);
455 msgr_utf16 = g_convert(msgr_orig, -1, "UTF-16LE", "UTF-8", NULL, &msgr_utf16_len, NULL);
456 g_free(msgr_orig);
457 msgr_enc = purple_base64_encode((guchar *) msgr_utf16, msgr_utf16_len);
458 g_free(msgr_utf16);
459 len = strlen(msgr_enc);
460 while (msgr_enc[len - 1] == '=') len--;
461 res = g_strndup(msgr_enc, len);
462 g_free(msgr_enc);
463 return res;
466 gchar *sipmsg_apply_x_mms_im_format(const char *x_mms_im_format, gchar *body) {
467 char *pre, *post;
468 gchar *res;
470 if (!x_mms_im_format) {
471 return body ? g_strdup(body) : NULL;
473 msn_parse_format(x_mms_im_format, &pre, &post);
474 res = g_strdup_printf("%s%s%s", pre ? pre : "", body ? body : "", post ? post : "");
475 g_free(pre);
476 g_free(post);
477 return res;
480 /* ms-text-format: text/plain; charset=UTF-8;msgr=WAAtAE0...DIADQAKAA0ACgA;ms-body=SGk= */
481 gchar *get_html_message(const gchar *ms_text_format_in, const gchar *body_in)
483 gchar *tmp_html;
484 gchar *msgr;
485 gchar *res;
486 gchar *ms_text_format = NULL;
487 gchar *body = NULL;
489 if (!strncmp(ms_text_format_in, "multipart/related", 17) ||
490 !strncmp(ms_text_format_in, "multipart/alternative", 21)) {
491 char *doc = g_strdup_printf("Content-Type: %s\r\n\r\n%s", ms_text_format_in, body_in);
492 PurpleMimeDocument *mime;
493 GList* parts;
495 mime = purple_mime_document_parse(doc);
496 parts = purple_mime_document_get_parts(mime);
497 while (parts) {
498 const gchar *content_type = purple_mime_part_get_field(parts->data, "Content-Type");
499 if (content_type) {
500 const gchar *content = purple_mime_part_get_data(parts->data);
501 guint length = purple_mime_part_get_length(parts->data);
503 /* if no other format has stored */
504 if (!ms_text_format && !strncmp(content_type, "text/plain", 10)) {
505 ms_text_format = g_strdup(content_type);
506 body = g_strndup(content, length);
507 /* preferred format */
508 } else if (ms_text_format && !strncmp(ms_text_format, "text/html", 9)) {
509 g_free(ms_text_format);
510 g_free(body);
511 ms_text_format = g_strdup(content_type);
512 body = g_strndup(content, length);
513 break;
516 parts = parts->next;
518 g_free(doc);
519 if (mime)
520 purple_mime_document_free(mime);
521 } else {
522 ms_text_format = g_strdup(ms_text_format_in);
523 body = g_strdup(body_in);
526 if (body) {
527 res = g_strdup(body);
528 } else {
529 res = sipmsg_find_part_of_header(ms_text_format, "ms-body=", NULL, NULL);
530 if (!res) return NULL;
531 tmp_html = res;
532 res = (gchar *) purple_base64_decode(res, NULL);
533 g_free(tmp_html);
536 if (!res) {
537 return NULL;
540 if (ms_text_format && strncmp(ms_text_format, "text/html", 9)) { // NOT html
541 tmp_html = res;
542 res = g_markup_escape_text(res, -1); // as this is not html
543 g_free(tmp_html);
546 msgr = sipmsg_find_part_of_header(ms_text_format, "msgr=", ";", NULL);
547 if (msgr) {
548 gchar *x_mms_im_format = sipmsg_get_x_mms_im_format(msgr);
549 g_free(msgr);
550 tmp_html = res;
551 res = sipmsg_apply_x_mms_im_format(x_mms_im_format, res);
552 g_free(tmp_html);
553 g_free(x_mms_im_format);
556 g_free(ms_text_format);
557 g_free(body);
559 return res;
566 //------------------------------------------------------------------------------------------
567 //TEMP solution to include it here (copy from purple's msn protocol
568 //How to reuse msn's util methods from sipe?
570 // from internal.h for linux compilation
571 #ifndef _WIN32
572 #define MSG_LEN 2048
573 #define BUF_LEN MSG_LEN
574 #endif
575 void
576 msn_parse_format(const char *mime, char **pre_ret, char **post_ret)
578 char *cur;
579 GString *pre = g_string_new(NULL);
580 GString *post = g_string_new(NULL);
581 unsigned int colors[3];
583 if (pre_ret != NULL) *pre_ret = NULL;
584 if (post_ret != NULL) *post_ret = NULL;
586 cur = strstr(mime, "FN=");
588 if (cur && (*(cur = cur + 3) != ';'))
590 pre = g_string_append(pre, "<FONT FACE=\"");
592 while (*cur && *cur != ';')
594 pre = g_string_append_c(pre, *cur);
595 cur++;
598 pre = g_string_append(pre, "\">");
599 post = g_string_prepend(post, "</FONT>");
602 cur = strstr(mime, "EF=");
604 if (cur && (*(cur = cur + 3) != ';'))
606 while (*cur && *cur != ';')
608 pre = g_string_append_c(pre, '<');
609 pre = g_string_append_c(pre, *cur);
610 pre = g_string_append_c(pre, '>');
611 post = g_string_prepend_c(post, '>');
612 post = g_string_prepend_c(post, *cur);
613 post = g_string_prepend_c(post, '/');
614 post = g_string_prepend_c(post, '<');
615 cur++;
619 cur = strstr(mime, "CO=");
621 if (cur && (*(cur = cur + 3) != ';'))
623 int i;
625 i = sscanf(cur, "%02x%02x%02x;", &colors[0], &colors[1], &colors[2]);
627 if (i > 0)
629 char tag[64];
631 if (i == 1)
633 colors[1] = 0;
634 colors[2] = 0;
636 else if (i == 2)
638 unsigned int temp = colors[0];
640 colors[0] = colors[1];
641 colors[1] = temp;
642 colors[2] = 0;
644 else if (i == 3)
646 unsigned int temp = colors[2];
648 colors[2] = colors[0];
649 colors[0] = temp;
652 g_snprintf(tag, sizeof(tag),
653 "<FONT COLOR=\"#%02hhx%02hhx%02hhx\">",
654 colors[0], colors[1], colors[2]);
656 pre = g_string_append(pre, tag);
657 post = g_string_prepend(post, "</FONT>");
661 cur = strstr(mime, "RL=");
663 if (cur && (*(cur = cur + 3) != ';'))
665 if (*cur == '1')
667 /* RTL text was received */
668 pre = g_string_append(pre, "<SPAN style=\"direction:rtl;text-align:right;\">");
669 post = g_string_prepend(post, "</SPAN>");
673 cur = g_strdup(purple_url_decode(pre->str));
674 g_string_free(pre, TRUE);
676 if (pre_ret != NULL)
677 *pre_ret = cur;
678 else
679 g_free(cur);
681 cur = g_strdup(purple_url_decode(post->str));
682 g_string_free(post, TRUE);
684 if (post_ret != NULL)
685 *post_ret = cur;
686 else
687 g_free(cur);
690 static const char *
691 encode_spaces(const char *str)
693 static char buf[BUF_LEN];
694 const char *c;
695 char *d;
697 g_return_val_if_fail(str != NULL, NULL);
699 for (c = str, d = buf; *c != '\0'; c++)
701 if (*c == ' ')
703 *d++ = '%';
704 *d++ = '2';
705 *d++ = '0';
707 else
708 *d++ = *c;
710 *d = '\0';
712 return buf;
715 void
716 msn_import_html(const char *html, char **attributes, char **message)
718 int len, retcount = 0;
719 const char *c;
720 char *msg;
721 char *fontface = NULL;
722 char fonteffect[4];
723 char fontcolor[7];
724 char direction = '0';
726 gboolean has_bold = FALSE;
727 gboolean has_italic = FALSE;
728 gboolean has_underline = FALSE;
729 gboolean has_strikethrough = FALSE;
731 g_return_if_fail(html != NULL);
732 g_return_if_fail(attributes != NULL);
733 g_return_if_fail(message != NULL);
735 len = strlen(html);
736 msg = g_malloc0(len + 1);
738 memset(fontcolor, 0, sizeof(fontcolor));
739 strcat(fontcolor, "0");
740 memset(fonteffect, 0, sizeof(fonteffect));
742 for (c = html; *c != '\0';)
744 if (*c == '<')
746 if (!g_ascii_strncasecmp(c + 1, "br>", 3))
748 msg[retcount++] = '\r';
749 msg[retcount++] = '\n';
750 c += 4;
752 else if (!g_ascii_strncasecmp(c + 1, "i>", 2))
754 if (!has_italic)
756 strcat(fonteffect, "I");
757 has_italic = TRUE;
759 c += 3;
761 else if (!g_ascii_strncasecmp(c + 1, "b>", 2))
763 if (!has_bold)
765 strcat(fonteffect, "B");
766 has_bold = TRUE;
768 c += 3;
770 else if (!g_ascii_strncasecmp(c + 1, "u>", 2))
772 if (!has_underline)
774 strcat(fonteffect, "U");
775 has_underline = TRUE;
777 c += 3;
779 else if (!g_ascii_strncasecmp(c + 1, "s>", 2))
781 if (!has_strikethrough)
783 strcat(fonteffect, "S");
784 has_strikethrough = TRUE;
786 c += 3;
788 else if (!g_ascii_strncasecmp(c + 1, "a href=\"", 8))
790 c += 9;
792 if (!g_ascii_strncasecmp(c, "mailto:", 7))
793 c += 7;
795 while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2))
796 msg[retcount++] = *c++;
798 if (*c != '\0')
799 c += 2;
801 /* ignore descriptive string */
802 while ((*c != '\0') && g_ascii_strncasecmp(c, "</a>", 4))
803 c++;
805 if (*c != '\0')
806 c += 4;
808 else if (!g_ascii_strncasecmp(c + 1, "span", 4))
810 /* Bi-directional text support using CSS properties in span tags */
811 c += 5;
813 while (*c != '\0' && *c != '>')
815 while (*c == ' ')
816 c++;
817 if (!g_ascii_strncasecmp(c, "dir=\"rtl\"", 9))
819 c += 9;
820 direction = '1';
822 else if (!g_ascii_strncasecmp(c, "style=\"", 7))
824 /* Parse inline CSS attributes */
825 char *attributes;
826 int attr_len = 0;
827 c += 7;
828 while (*(c + attr_len) != '\0' && *(c + attr_len) != '"')
829 attr_len++;
830 if (*(c + attr_len) == '"')
832 char *attr_dir;
833 attributes = g_strndup(c, attr_len);
834 attr_dir = purple_markup_get_css_property(attributes, "direction");
835 if (attr_dir && (!g_ascii_strncasecmp(attr_dir, "RTL", 3)))
836 direction = '1';
837 g_free(attr_dir);
838 g_free(attributes);
842 else
844 c++;
847 if (*c == '>')
848 c++;
850 else if (!g_ascii_strncasecmp(c + 1, "font", 4))
852 c += 5;
854 while ((*c != '\0') && !g_ascii_strncasecmp(c, " ", 1))
855 c++;
857 if (!g_ascii_strncasecmp(c, "color=\"#", 7))
859 c += 8;
861 fontcolor[0] = *(c + 4);
862 fontcolor[1] = *(c + 5);
863 fontcolor[2] = *(c + 2);
864 fontcolor[3] = *(c + 3);
865 fontcolor[4] = *c;
866 fontcolor[5] = *(c + 1);
868 c += 8;
870 else if (!g_ascii_strncasecmp(c, "face=\"", 6))
872 const char *end = NULL;
873 const char *comma = NULL;
874 unsigned int namelen = 0;
876 c += 6;
877 end = strchr(c, '\"');
878 comma = strchr(c, ',');
880 if (comma == NULL || comma > end)
881 namelen = (unsigned int)(end - c);
882 else
883 namelen = (unsigned int)(comma - c);
885 fontface = g_strndup(c, namelen);
886 c = end + 2;
888 else
890 /* Drop all unrecognized/misparsed font tags */
891 while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2))
892 c++;
894 if (*c != '\0')
895 c += 2;
898 else
900 while ((*c != '\0') && (*c != '>'))
901 c++;
902 if (*c != '\0')
903 c++;
906 else if (*c == '&')
908 if (!g_ascii_strncasecmp(c, "&lt;", 4))
910 msg[retcount++] = '<';
911 c += 4;
913 else if (!g_ascii_strncasecmp(c, "&gt;", 4))
915 msg[retcount++] = '>';
916 c += 4;
918 else if (!g_ascii_strncasecmp(c, "&nbsp;", 6))
920 msg[retcount++] = ' ';
921 c += 6;
923 else if (!g_ascii_strncasecmp(c, "&quot;", 6))
925 msg[retcount++] = '"';
926 c += 6;
928 else if (!g_ascii_strncasecmp(c, "&amp;", 5))
930 msg[retcount++] = '&';
931 c += 5;
933 else if (!g_ascii_strncasecmp(c, "&apos;", 6))
935 msg[retcount++] = '\'';
936 c += 6;
938 else
939 msg[retcount++] = *c++;
941 else
942 msg[retcount++] = *c++;
945 if (fontface == NULL)
946 fontface = g_strdup("MS Sans Serif");
948 *attributes = g_strdup_printf("FN=%s; EF=%s; CO=%s; PF=0; RL=%c",
949 encode_spaces(fontface),
950 fonteffect, fontcolor, direction);
951 *message = msg;
953 g_free(fontface);
955 // End of TEMP
958 Local Variables:
959 mode: c
960 c-file-style: "bsd"
961 indent-tabs-mode: t
962 tab-width: 8
963 End: