Start the Big Split...
[siplcs.git] / src / sipmsg.c
blob620226ba4ea854b34530aec0a05e8ec05ca8da48
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 #ifndef _WIN32
25 #include <sys/socket.h>
26 #include <sys/ioctl.h>
27 #include <sys/types.h>
28 #include <netinet/in.h>
29 #include <net/if.h>
30 #else /* _WIN32 */
31 #ifdef _DLL
32 #define _WS2TCPIP_H_
33 #define _WINSOCK2API_
34 #define _LIBC_INTERNAL_
35 #endif /* _DLL */
37 #include "internal.h"
38 #endif /* _WIN32 */
40 #include <string.h>
42 #include "accountopt.h"
43 #include "blist.h"
44 #include "conversation.h"
45 #include "debug.h"
46 #include "notify.h"
47 #include "prpl.h"
48 #include "plugin.h"
49 #include "util.h"
50 #include "version.h"
52 #include "sipe.h"
53 #include "sipmsg.h"
55 struct sipmsg *sipmsg_parse_msg(const gchar *msg) {
56 const char *tmp = strstr(msg, "\r\n\r\n");
57 char *line;
58 struct sipmsg *smsg;
60 if(!tmp) return NULL;
62 line = g_strndup(msg, tmp - msg);
64 smsg = sipmsg_parse_header(line);
65 smsg->body = g_strdup(tmp + 4);
67 g_free(line);
68 return smsg;
71 struct sipmsg *sipmsg_parse_header(const gchar *header) {
72 struct sipmsg *msg = g_new0(struct sipmsg,1);
73 gchar **lines = g_strsplit(header,"\r\n",0);
74 gchar **parts;
75 gchar *dummy;
76 gchar *dummy2;
77 gchar *tmp;
78 gchar *contentlength;
79 int i=1;
80 if(!lines[0]) return NULL;
81 parts = g_strsplit(lines[0], " ", 3);
82 if(!parts[0] || !parts[1] || !parts[2]) {
83 g_strfreev(parts);
84 g_strfreev(lines);
85 g_free(msg);
86 return NULL;
88 if(strstr(parts[0],"SIP")) { /* numeric response */
89 msg->method = g_strdup(parts[2]);
90 msg->response = strtol(parts[1],NULL,10);
91 } else { /* request */
92 msg->method = g_strdup(parts[0]);
93 msg->target = g_strdup(parts[1]);
94 msg->response = 0;
96 g_strfreev(parts);
97 for(i=1; lines[i] && strlen(lines[i])>2; i++) {
98 parts = g_strsplit(lines[i], ":", 2);
99 if(!parts[0] || !parts[1]) {
100 g_strfreev(parts);
101 g_strfreev(lines);
102 sipmsg_free(msg);
103 return NULL;
105 dummy = parts[1];
106 dummy2 = 0;
107 while(*dummy==' ' || *dummy=='\t') dummy++;
108 dummy2 = g_strdup(dummy);
109 while(lines[i+1] && (lines[i+1][0]==' ' || lines[i+1][0]=='\t')) {
110 i++;
111 dummy = lines[i];
112 while(*dummy==' ' || *dummy=='\t') dummy++;
113 tmp = g_strdup_printf("%s %s",dummy2, dummy);
114 g_free(dummy2);
115 dummy2 = tmp;
117 sipmsg_add_header_now(msg, parts[0], dummy2);
118 g_free(dummy2);
119 g_strfreev(parts);
121 g_strfreev(lines);
122 contentlength = sipmsg_find_header(msg, "Content-Length");
123 if (contentlength) {
124 msg->bodylen = strtol(contentlength,NULL,10);
125 } else {
126 purple_debug_fatal("sipe", "sipmsg_parse_header(): Content-Length header not found\n");
128 if(msg->response) {
129 g_free(msg->method);
130 tmp = sipmsg_find_header(msg, "CSeq");
131 if(!tmp) {
132 /* SHOULD NOT HAPPEN */
133 msg->method = 0;
134 } else {
135 parts = g_strsplit(tmp, " ", 2);
136 msg->method = g_strdup(parts[1]);
137 g_strfreev(parts);
140 return msg;
143 void sipmsg_print(const struct sipmsg *msg) {
144 GSList *cur;
145 struct siphdrelement *elem;
146 purple_debug(PURPLE_DEBUG_MISC, "sipe", "SIP MSG\n");
147 purple_debug(PURPLE_DEBUG_MISC, "sipe", "response: %d\nmethod: %s\nbodylen: %d\n",msg->response,msg->method,msg->bodylen);
148 if(msg->target) purple_debug(PURPLE_DEBUG_MISC, "sipe", "target: %s\n",msg->target);
149 cur = msg->headers;
150 while(cur) {
151 elem = cur->data;
152 purple_debug(PURPLE_DEBUG_MISC, "sipe", "name: %s value: %s\n",elem->name, elem->value);
153 cur = g_slist_next(cur);
157 char *sipmsg_to_string(const struct sipmsg *msg) {
158 GSList *cur;
159 GString *outstr = g_string_new("");
160 struct siphdrelement *elem;
162 if(msg->response)
163 g_string_append_printf(outstr, "SIP/2.0 %d Unknown\r\n",
164 msg->response);
165 else
166 g_string_append_printf(outstr, "%s %s SIP/2.0\r\n",
167 msg->method, msg->target);
169 cur = msg->headers;
170 while(cur) {
171 elem = cur->data;
172 /*Todo: remove the LFCR in a good way*/
173 /*if(!strcmp(elem->name,"Proxy-Authorization"))
174 g_string_append_printf(outstr, "%s: %s", elem->name,
175 elem->value);
176 else */
177 g_string_append_printf(outstr, "%s: %s\r\n", elem->name,
178 elem->value);
179 cur = g_slist_next(cur);
182 g_string_append_printf(outstr, "\r\n%s", msg->bodylen ? msg->body : "");
184 return g_string_free(outstr, FALSE);
188 * Adds header to current message headers at specified position
190 void sipmsg_add_header_now_pos(struct sipmsg *msg, const gchar *name, const gchar *value, int pos) {
191 struct siphdrelement *element = g_new0(struct siphdrelement,1);
192 element->name = g_strdup(name);
193 element->value = g_strdup(value);
194 msg->headers = g_slist_insert(msg->headers, element,pos);
198 * Adds header to current message headers
200 void sipmsg_add_header_now(struct sipmsg *msg, const gchar *name, const gchar *value) {
201 struct siphdrelement *element = g_new0(struct siphdrelement,1);
202 element->name = g_strdup(name);
203 element->value = g_strdup(value);
204 msg->headers = g_slist_append(msg->headers, element);
208 * Adds header to separate storage for future merge
210 void sipmsg_add_header(struct sipmsg *msg, const gchar *name, const gchar *value) {
211 struct siphdrelement *element = g_new0(struct siphdrelement,1);
212 element->name = g_strdup(name);
213 element->value = g_strdup(value);
214 msg->new_headers = g_slist_append(msg->new_headers, element);
218 * Removes header if it's not in keepers array
220 void sipmsg_strip_headers(struct sipmsg *msg, const gchar *keepers[]) {
221 GSList *entry;
222 struct siphdrelement *elem;
224 entry = msg->headers;
225 while(entry) {
226 int i = 0;
227 gboolean keeper = FALSE;
229 elem = entry->data;
230 while (keepers[i]) {
231 if (!g_strcasecmp(elem->name, keepers[i])) {
232 keeper = TRUE;
233 break;
235 i++;
238 if (!keeper) {
239 GSList *to_delete = entry;
240 purple_debug_info("sipe", "sipmsg_strip_headers: removing %s\n", elem->name);
241 entry = g_slist_next(entry);
242 msg->headers = g_slist_delete_link(msg->headers, to_delete);
243 g_free(elem->name);
244 g_free(elem->value);
245 g_free(elem);
246 } else {
247 entry = g_slist_next(entry);
253 * Merges newly added headers to message
255 void sipmsg_merge_new_headers(struct sipmsg *msg) {
256 while(msg->new_headers) {
257 msg->headers = g_slist_append(msg->headers, msg->new_headers->data);
258 msg->new_headers = g_slist_remove(msg->new_headers, msg->new_headers->data);
262 void sipmsg_free(struct sipmsg *msg) {
263 struct siphdrelement *elem;
264 while(msg->headers) {
265 elem = msg->headers->data;
266 msg->headers = g_slist_remove(msg->headers,elem);
267 g_free(elem->name);
268 g_free(elem->value);
269 g_free(elem);
271 while(msg->new_headers) {
272 elem = msg->new_headers->data;
273 msg->new_headers = g_slist_remove(msg->new_headers,elem);
274 g_free(elem->name);
275 g_free(elem->value);
276 g_free(elem);
278 g_free(msg->signature);
279 g_free(msg->rand);
280 g_free(msg->num);
281 g_free(msg->method);
282 g_free(msg->target);
283 g_free(msg->body);
284 g_free(msg);
287 void sipmsg_remove_header_now(struct sipmsg *msg, const gchar *name) {
288 struct siphdrelement *elem;
289 GSList *tmp = msg->headers;
290 while(tmp) {
291 elem = tmp->data;
292 // OCS2005 can send the same header in either all caps or mixed case
293 if (g_ascii_strcasecmp(elem->name, name)==0) {
294 msg->headers = g_slist_remove(msg->headers, elem);
295 g_free(elem->name);
296 g_free(elem->value);
297 g_free(elem);
298 return;
300 tmp = g_slist_next(tmp);
302 return;
305 gchar *sipmsg_find_header(const struct sipmsg *msg, const gchar *name) {
306 return sipmsg_find_header_instance (msg, name, 0);
309 gchar *sipmsg_find_header_instance(const struct sipmsg *msg, const gchar *name, int which) {
310 GSList *tmp;
311 struct siphdrelement *elem;
312 int i = 0;
313 tmp = msg->headers;
314 while(tmp) {
315 elem = tmp->data;
316 // OCS2005 can send the same header in either all caps or mixed case
317 if (g_ascii_strcasecmp(elem->name,name)==0) {
318 if (i == which) {
319 return elem->value;
321 i++;
323 tmp = g_slist_next(tmp);
325 return NULL;
328 gchar *sipmsg_find_part_of_header(const char *hdr, const char * before, const char * after, const char * def) {
329 const char *tmp;
330 const char *tmp2;
331 gchar *res2;
332 if (!hdr) {
333 return NULL;
336 //printf("partof %s w/ %s before and %s after\n", hdr, before, after);
338 tmp = before == NULL ? hdr : strstr(hdr, before);
339 if (!tmp) {
340 //printf ("not found, returning null\n");
341 return (gchar *)def;
344 if (before != NULL) {
345 tmp += strlen(before);
346 //printf ("tmp now %s\n", tmp);
349 if (after != NULL && (tmp2 = strstr(tmp, after))) {
350 gchar * res = g_strndup(tmp, tmp2 - tmp);
351 //printf("returning %s\n", res);
352 return res;
354 res2 = g_strdup(tmp);
355 //printf("returning %s\n", res2);
356 return res2;
360 * Parse EndPoints header from INVITE request
361 * Returns a list of end points: contact URI plus optional epid.
362 * You must free the values and the list.
364 * Example headers:
365 * EndPoints: "alice alisson" <sip:alice@atlanta.local>, <sip:bob@atlanta.local>;epid=ebca82d94d, <sip:carol@atlanta.local>
366 * EndPoints: "alice, alisson" <sip:alice@atlanta.local>, <sip:bob@atlanta.local>
367 * EndPoints: "alice alisson" <sip:alice@atlanta.local>, "Super, Man" <sip:super@atlanta.local>
369 * @param header (in) EndPoints header contents
371 * @return GSList with struct sipendpoint as elements
373 GSList *sipmsg_parse_endpoints_header(const gchar *header)
375 GSList *list = NULL;
376 gchar **parts = g_strsplit(header, ",", 0);
377 gchar *part;
378 int i;
380 for (i = 0; (part = parts[i]) != NULL; i++) {
381 /* Does the part contain a URI? */
382 gchar *contact = sipmsg_find_part_of_header(part, "<", ">", NULL);
383 if (contact) {
384 struct sipendpoint *end_point = g_new(struct sipendpoint, 1);
385 end_point->contact = contact;
386 end_point->epid = sipmsg_find_part_of_header(part, "epid=", NULL, NULL);
387 list = g_slist_append(list, end_point);
390 g_strfreev(parts);
392 return(list);
396 * sipmsg_find_auth_header will return the particular WWW-Authenticate
397 * header specified by *name.
399 * Use this function when you want to look for a specific authentication
400 * method such as NTLM or Kerberos
403 gchar *sipmsg_find_auth_header(struct sipmsg *msg, const gchar *name) {
404 GSList *tmp;
405 struct siphdrelement *elem;
406 int name_len = strlen(name);
407 tmp = msg->headers;
408 while(tmp) {
409 elem = tmp->data;
410 //purple_debug(PURPLE_DEBUG_MISC, "sipmsg", "Current header: %s\r\n", elem->value);
411 if (elem && elem->name &&
412 (!g_ascii_strcasecmp(elem->name,"WWW-Authenticate")
413 || !g_ascii_strcasecmp(elem->name,"Authentication-Info")) ) {
414 if (!g_strncasecmp((gchar *)elem->value, name, name_len)) {
415 //purple_debug(PURPLE_DEBUG_MISC, "sipmsg", "elem->value: %s\r\n", elem->value);
416 return elem->value;
419 //purple_debug(PURPLE_DEBUG_MISC, "sipmsg", "moving to next header\r\n");
420 tmp = g_slist_next(tmp);
422 purple_debug(PURPLE_DEBUG_MISC, "sipmsg", "Did not found auth header %s\r\n", name);
423 return NULL;
426 gchar *sipmsg_get_x_mms_im_format(gchar *msgr) {
427 gchar *msgr2;
428 gsize msgr_dec64_len;
429 guchar *msgr_dec64;
430 gchar *msgr_utf8;
431 gchar **lines;
432 gchar **parts;
433 gchar *x_mms_im_format;
434 gchar *tmp;
436 if (!msgr) return NULL;
437 msgr2 = g_strdup(msgr);
438 while (strlen(msgr2) % 4 != 0) {
439 gchar *tmp_msgr2 = msgr2;
440 msgr2 = g_strdup_printf("%s=", msgr2);
441 g_free(tmp_msgr2);
443 msgr_dec64 = purple_base64_decode(msgr2, &msgr_dec64_len);
444 msgr_utf8 = g_convert((gchar *) msgr_dec64, msgr_dec64_len, "UTF-8", "UTF-16LE", NULL, NULL, NULL);
445 g_free(msgr_dec64);
446 g_free(msgr2);
447 lines = g_strsplit(msgr_utf8,"\r\n\r\n",0);
448 g_free(msgr_utf8);
449 //@TODO: make extraction like parsing of message headers.
450 parts = g_strsplit(lines[0],"X-MMS-IM-Format:",0);
451 x_mms_im_format = g_strdup(parts[1]);
452 g_strfreev(parts);
453 g_strfreev(lines);
454 tmp = x_mms_im_format;
455 if (x_mms_im_format) {
456 while(*x_mms_im_format==' ' || *x_mms_im_format=='\t') x_mms_im_format++;
458 x_mms_im_format = g_strdup(x_mms_im_format);
459 g_free(tmp);
460 return x_mms_im_format;
463 gchar *sipmsg_get_msgr_string(gchar *x_mms_im_format) {
464 gchar *msgr_orig;
465 gsize msgr_utf16_len;
466 gchar *msgr_utf16;
467 gchar *msgr_enc;
468 gchar *res;
469 int len;
471 if (!x_mms_im_format) return NULL;
472 msgr_orig = g_strdup_printf("X-MMS-IM-Format: %s\r\n\r\n", x_mms_im_format);
473 msgr_utf16 = g_convert(msgr_orig, -1, "UTF-16LE", "UTF-8", NULL, &msgr_utf16_len, NULL);
474 g_free(msgr_orig);
475 msgr_enc = purple_base64_encode((guchar *) msgr_utf16, msgr_utf16_len);
476 g_free(msgr_utf16);
477 len = strlen(msgr_enc);
478 while (msgr_enc[len - 1] == '=') len--;
479 res = g_strndup(msgr_enc, len);
480 g_free(msgr_enc);
481 return res;
484 gchar *sipmsg_apply_x_mms_im_format(const char *x_mms_im_format, gchar *body) {
485 char *pre, *post;
486 gchar *res;
488 if (!x_mms_im_format) {
489 return body ? g_strdup(body) : NULL;
491 msn_parse_format(x_mms_im_format, &pre, &post);
492 res = g_strdup_printf("%s%s%s", pre ? pre : "", body ? body : "", post ? post : "");
493 g_free(pre);
494 g_free(post);
495 return res;
498 //ms-text-format: text/plain; charset=UTF-8;msgr=WAAtAE0...DIADQAKAA0ACgA;ms-body=SGk=
499 gchar *get_html_message(const gchar *ms_text_format, const gchar *body)
501 gchar *tmp_html;
502 gchar *msgr;
503 gchar *res;
505 if (body) {
506 res = g_strdup(body);
507 } else {
508 res = sipmsg_find_part_of_header(ms_text_format, "ms-body=", NULL, NULL);
509 if (!res) return NULL;
510 tmp_html = res;
511 res = (gchar *) purple_base64_decode(res, NULL);
512 g_free(tmp_html);
515 if (!res) {
516 return NULL;
519 if (strncmp(ms_text_format, "text/html", 9)) { // NOT html
520 tmp_html = res;
521 res = g_markup_escape_text(res, -1); // as this is not html
522 g_free(tmp_html);
525 msgr = sipmsg_find_part_of_header(ms_text_format, "msgr=", ";", NULL);
526 if (msgr) {
527 gchar *x_mms_im_format = sipmsg_get_x_mms_im_format(msgr);
528 g_free(msgr);
529 tmp_html = res;
530 res = sipmsg_apply_x_mms_im_format(x_mms_im_format, res);
531 g_free(tmp_html);
532 g_free(x_mms_im_format);
535 return res;
542 //------------------------------------------------------------------------------------------
543 //TEMP solution to include it here (copy from purple's msn protocol
544 //How to reuse msn's util methods from sipe?
546 // from internal.h for linux compilation
547 #ifndef _WIN32
548 #define MSG_LEN 2048
549 #define BUF_LEN MSG_LEN
550 #endif
551 void
552 msn_parse_format(const char *mime, char **pre_ret, char **post_ret)
554 char *cur;
555 GString *pre = g_string_new(NULL);
556 GString *post = g_string_new(NULL);
557 unsigned int colors[3];
559 if (pre_ret != NULL) *pre_ret = NULL;
560 if (post_ret != NULL) *post_ret = NULL;
562 cur = strstr(mime, "FN=");
564 if (cur && (*(cur = cur + 3) != ';'))
566 pre = g_string_append(pre, "<FONT FACE=\"");
568 while (*cur && *cur != ';')
570 pre = g_string_append_c(pre, *cur);
571 cur++;
574 pre = g_string_append(pre, "\">");
575 post = g_string_prepend(post, "</FONT>");
578 cur = strstr(mime, "EF=");
580 if (cur && (*(cur = cur + 3) != ';'))
582 while (*cur && *cur != ';')
584 pre = g_string_append_c(pre, '<');
585 pre = g_string_append_c(pre, *cur);
586 pre = g_string_append_c(pre, '>');
587 post = g_string_prepend_c(post, '>');
588 post = g_string_prepend_c(post, *cur);
589 post = g_string_prepend_c(post, '/');
590 post = g_string_prepend_c(post, '<');
591 cur++;
595 cur = strstr(mime, "CO=");
597 if (cur && (*(cur = cur + 3) != ';'))
599 int i;
601 i = sscanf(cur, "%02x%02x%02x;", &colors[0], &colors[1], &colors[2]);
603 if (i > 0)
605 char tag[64];
607 if (i == 1)
609 colors[1] = 0;
610 colors[2] = 0;
612 else if (i == 2)
614 unsigned int temp = colors[0];
616 colors[0] = colors[1];
617 colors[1] = temp;
618 colors[2] = 0;
620 else if (i == 3)
622 unsigned int temp = colors[2];
624 colors[2] = colors[0];
625 colors[0] = temp;
628 g_snprintf(tag, sizeof(tag),
629 "<FONT COLOR=\"#%02hhx%02hhx%02hhx\">",
630 colors[0], colors[1], colors[2]);
632 pre = g_string_append(pre, tag);
633 post = g_string_prepend(post, "</FONT>");
637 cur = strstr(mime, "RL=");
639 if (cur && (*(cur = cur + 3) != ';'))
641 if (*cur == '1')
643 /* RTL text was received */
644 pre = g_string_append(pre, "<SPAN style=\"direction:rtl;text-align:right;\">");
645 post = g_string_prepend(post, "</SPAN>");
649 cur = g_strdup(purple_url_decode(pre->str));
650 g_string_free(pre, TRUE);
652 if (pre_ret != NULL)
653 *pre_ret = cur;
654 else
655 g_free(cur);
657 cur = g_strdup(purple_url_decode(post->str));
658 g_string_free(post, TRUE);
660 if (post_ret != NULL)
661 *post_ret = cur;
662 else
663 g_free(cur);
666 static const char *
667 encode_spaces(const char *str)
669 static char buf[BUF_LEN];
670 const char *c;
671 char *d;
673 g_return_val_if_fail(str != NULL, NULL);
675 for (c = str, d = buf; *c != '\0'; c++)
677 if (*c == ' ')
679 *d++ = '%';
680 *d++ = '2';
681 *d++ = '0';
683 else
684 *d++ = *c;
686 *d = '\0';
688 return buf;
691 void
692 msn_import_html(const char *html, char **attributes, char **message)
694 int len, retcount = 0;
695 const char *c;
696 char *msg;
697 char *fontface = NULL;
698 char fonteffect[4];
699 char fontcolor[7];
700 char direction = '0';
702 gboolean has_bold = FALSE;
703 gboolean has_italic = FALSE;
704 gboolean has_underline = FALSE;
705 gboolean has_strikethrough = FALSE;
707 g_return_if_fail(html != NULL);
708 g_return_if_fail(attributes != NULL);
709 g_return_if_fail(message != NULL);
711 len = strlen(html);
712 msg = g_malloc0(len + 1);
714 memset(fontcolor, 0, sizeof(fontcolor));
715 strcat(fontcolor, "0");
716 memset(fonteffect, 0, sizeof(fonteffect));
718 for (c = html; *c != '\0';)
720 if (*c == '<')
722 if (!g_ascii_strncasecmp(c + 1, "br>", 3))
724 msg[retcount++] = '\r';
725 msg[retcount++] = '\n';
726 c += 4;
728 else if (!g_ascii_strncasecmp(c + 1, "i>", 2))
730 if (!has_italic)
732 strcat(fonteffect, "I");
733 has_italic = TRUE;
735 c += 3;
737 else if (!g_ascii_strncasecmp(c + 1, "b>", 2))
739 if (!has_bold)
741 strcat(fonteffect, "B");
742 has_bold = TRUE;
744 c += 3;
746 else if (!g_ascii_strncasecmp(c + 1, "u>", 2))
748 if (!has_underline)
750 strcat(fonteffect, "U");
751 has_underline = TRUE;
753 c += 3;
755 else if (!g_ascii_strncasecmp(c + 1, "s>", 2))
757 if (!has_strikethrough)
759 strcat(fonteffect, "S");
760 has_strikethrough = TRUE;
762 c += 3;
764 else if (!g_ascii_strncasecmp(c + 1, "a href=\"", 8))
766 c += 9;
768 if (!g_ascii_strncasecmp(c, "mailto:", 7))
769 c += 7;
771 while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2))
772 msg[retcount++] = *c++;
774 if (*c != '\0')
775 c += 2;
777 /* ignore descriptive string */
778 while ((*c != '\0') && g_ascii_strncasecmp(c, "</a>", 4))
779 c++;
781 if (*c != '\0')
782 c += 4;
784 else if (!g_ascii_strncasecmp(c + 1, "span", 4))
786 /* Bi-directional text support using CSS properties in span tags */
787 c += 5;
789 while (*c != '\0' && *c != '>')
791 while (*c == ' ')
792 c++;
793 if (!g_ascii_strncasecmp(c, "dir=\"rtl\"", 9))
795 c += 9;
796 direction = '1';
798 else if (!g_ascii_strncasecmp(c, "style=\"", 7))
800 /* Parse inline CSS attributes */
801 char *attributes;
802 int attr_len = 0;
803 c += 7;
804 while (*(c + attr_len) != '\0' && *(c + attr_len) != '"')
805 attr_len++;
806 if (*(c + attr_len) == '"')
808 char *attr_dir;
809 attributes = g_strndup(c, attr_len);
810 attr_dir = purple_markup_get_css_property(attributes, "direction");
811 if (attr_dir && (!g_ascii_strncasecmp(attr_dir, "RTL", 3)))
812 direction = '1';
813 g_free(attr_dir);
814 g_free(attributes);
818 else
820 c++;
823 if (*c == '>')
824 c++;
826 else if (!g_ascii_strncasecmp(c + 1, "font", 4))
828 c += 5;
830 while ((*c != '\0') && !g_ascii_strncasecmp(c, " ", 1))
831 c++;
833 if (!g_ascii_strncasecmp(c, "color=\"#", 7))
835 c += 8;
837 fontcolor[0] = *(c + 4);
838 fontcolor[1] = *(c + 5);
839 fontcolor[2] = *(c + 2);
840 fontcolor[3] = *(c + 3);
841 fontcolor[4] = *c;
842 fontcolor[5] = *(c + 1);
844 c += 8;
846 else if (!g_ascii_strncasecmp(c, "face=\"", 6))
848 const char *end = NULL;
849 const char *comma = NULL;
850 unsigned int namelen = 0;
852 c += 6;
853 end = strchr(c, '\"');
854 comma = strchr(c, ',');
856 if (comma == NULL || comma > end)
857 namelen = (unsigned int)(end - c);
858 else
859 namelen = (unsigned int)(comma - c);
861 fontface = g_strndup(c, namelen);
862 c = end + 2;
864 else
866 /* Drop all unrecognized/misparsed font tags */
867 while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2))
868 c++;
870 if (*c != '\0')
871 c += 2;
874 else
876 while ((*c != '\0') && (*c != '>'))
877 c++;
878 if (*c != '\0')
879 c++;
882 else if (*c == '&')
884 if (!g_ascii_strncasecmp(c, "&lt;", 4))
886 msg[retcount++] = '<';
887 c += 4;
889 else if (!g_ascii_strncasecmp(c, "&gt;", 4))
891 msg[retcount++] = '>';
892 c += 4;
894 else if (!g_ascii_strncasecmp(c, "&nbsp;", 6))
896 msg[retcount++] = ' ';
897 c += 6;
899 else if (!g_ascii_strncasecmp(c, "&quot;", 6))
901 msg[retcount++] = '"';
902 c += 6;
904 else if (!g_ascii_strncasecmp(c, "&amp;", 5))
906 msg[retcount++] = '&';
907 c += 5;
909 else if (!g_ascii_strncasecmp(c, "&apos;", 6))
911 msg[retcount++] = '\'';
912 c += 6;
914 else
915 msg[retcount++] = *c++;
917 else
918 msg[retcount++] = *c++;
921 if (fontface == NULL)
922 fontface = g_strdup("MS Sans Serif");
924 *attributes = g_strdup_printf("FN=%s; EF=%s; CO=%s; PF=0; RL=%c",
925 encode_spaces(fontface),
926 fonteffect, fontcolor, direction);
927 *message = msg;
929 g_free(fontface);
931 // End of TEMP
934 Local Variables:
935 mode: c
936 c-file-style: "bsd"
937 indent-tabs-mode: t
938 tab-width: 8
939 End: