libpurple/protocols/gg/lib/message.c

branch
release-2.x.y
changeset 35617
c9069e0e3c36
parent 31683
5fce84b95b78
child 35627
fd11790cc4d6
equal deleted inserted replaced
35602:ba59da68fb79 35617:c9069e0e3c36
162 uin_t gg_message_get_recipient(gg_message_t *gm) 162 uin_t gg_message_get_recipient(gg_message_t *gm)
163 { 163 {
164 GG_MESSAGE_CHECK(gm, (uin_t) -1); 164 GG_MESSAGE_CHECK(gm, (uin_t) -1);
165 165
166 if ((gm->recipients == NULL) || (gm->recipient_count < 1)) { 166 if ((gm->recipients == NULL) || (gm->recipient_count < 1)) {
167 // errno = XXX; 167 /* errno = XXX; */
168 return (uin_t) -1; 168 return (uin_t) -1;
169 } 169 }
170 170
171 return gm->recipients[0]; 171 return gm->recipients[0];
172 } 172 }
290 if (gm->html == NULL && gm->text != NULL && gm->auto_convert) { 290 if (gm->html == NULL && gm->text != NULL && gm->auto_convert) {
291 size_t len; 291 size_t len;
292 292
293 free(gm->html_converted); 293 free(gm->html_converted);
294 294
295 len = gg_message_text_to_html(NULL, gm->text, gm->attributes, gm->attributes_length); 295 len = gg_message_text_to_html(NULL, gm->text, GG_ENCODING_UTF8, gm->attributes, gm->attributes_length);
296 296
297 gm->html_converted = malloc(len + 1); 297 gm->html_converted = malloc(len + 1);
298 298
299 if (gm->html_converted == NULL) 299 if (gm->html_converted == NULL)
300 return NULL; 300 return NULL;
301 301
302 gg_message_text_to_html(gm->html_converted, gm->text, gm->attributes, gm->attributes_length); 302 gg_message_text_to_html(gm->html_converted, gm->text, GG_ENCODING_UTF8, gm->attributes, gm->attributes_length);
303 303
304 return gm->html_converted; 304 return gm->html_converted;
305 } 305 }
306 306
307 return gm->html; 307 return gm->html;
310 int gg_message_set_attributes(gg_message_t *gm, const char *attributes, size_t length) 310 int gg_message_set_attributes(gg_message_t *gm, const char *attributes, size_t length)
311 { 311 {
312 GG_MESSAGE_CHECK(gm, -1); 312 GG_MESSAGE_CHECK(gm, -1);
313 313
314 if (length > 0xfffd) { 314 if (length > 0xfffd) {
315 // errno = XXX; 315 /* errno = XXX; */
316 return -1; 316 return -1;
317 } 317 }
318 318
319 if ((attributes == NULL) || (length == 0)) { 319 if ((attributes == NULL) || (length == 0)) {
320 free(gm->attributes); 320 free(gm->attributes);
359 * \param dst Wskaźnik na bufor roboczy 359 * \param dst Wskaźnik na bufor roboczy
360 * \param pos Wskaźnik na aktualne położenie w buforze roboczym 360 * \param pos Wskaźnik na aktualne położenie w buforze roboczym
361 * \param src Dodawany tekst 361 * \param src Dodawany tekst
362 * \param len Długość dodawanego tekstu 362 * \param len Długość dodawanego tekstu
363 */ 363 */
364 static void gg_append(char *dst, size_t *pos, const void *src, int len) 364 static void gg_append(char *dst, size_t *pos, const void *src, size_t len)
365 { 365 {
366 if (dst != NULL) 366 if (dst != NULL)
367 memcpy(&dst[*pos], src, len); 367 memcpy(&dst[*pos], src, len);
368 368
369 *pos += len; 369 *pos += len;
371 371
372 /** 372 /**
373 * \internal Zamienia tekst z formatowaniem Gadu-Gadu na HTML. 373 * \internal Zamienia tekst z formatowaniem Gadu-Gadu na HTML.
374 * 374 *
375 * \param dst Bufor wynikowy (może być \c NULL) 375 * \param dst Bufor wynikowy (może być \c NULL)
376 * \param src Tekst źródłowy w UTF-8 376 * \param src Tekst źródłowy
377 * \param encoding Kodowanie tekstu źródłowego oraz wynikowego
377 * \param format Atrybuty tekstu źródłowego 378 * \param format Atrybuty tekstu źródłowego
378 * \param format_len Długość bloku atrybutów tekstu źródłowego 379 * \param format_len Długość bloku atrybutów tekstu źródłowego
379 * 380 *
380 * \note Wynikowy tekst nie jest idealnym kodem HTML, ponieważ ma jak 381 * \note Wynikowy tekst nie jest idealnym kodem HTML, ponieważ ma jak
381 * dokładniej odzwierciedlać to, co wygenerowałby oryginalny klient. 382 * dokładniej odzwierciedlać to, co wygenerowałby oryginalny klient.
382 * 383 *
383 * \note Dokleja \c \\0 na końcu bufora wynikowego. 384 * \note Dokleja \c \\0 na końcu bufora wynikowego.
384 * 385 *
385 * \return Długość tekstu wynikowego bez \c \\0 (nawet jeśli \c dst to \c NULL). 386 * \return Długość tekstu wynikowego bez \c \\0 (nawet jeśli \c dst to \c NULL).
386 */ 387 */
387 size_t gg_message_text_to_html(char *dst, const char *src, const char *format, size_t format_len) 388 size_t gg_message_text_to_html(char *dst, const char *src, gg_encoding_t encoding, const unsigned char *format, size_t format_len)
388 { 389 {
389 const char span_fmt[] = "<span style=\"color:#%02x%02x%02x; font-family:'MS Shell Dlg 2'; font-size:9pt; \">"; 390 const char span_fmt[] = "<span style=\"color:#%02x%02x%02x; font-family:'MS Shell Dlg 2'; font-size:9pt; \">";
390 const int span_len = 75; 391 const size_t span_len = 75;
391 const char img_fmt[] = "<img name=\"%02x%02x%02x%02x%02x%02x%02x%02x\">"; 392 const char img_fmt[] = "<img name=\"%02x%02x%02x%02x%02x%02x%02x%02x\">";
392 const int img_len = 29; 393 const size_t img_len = 29;
393 int char_pos = 0; 394 size_t char_pos = 0;
394 int format_idx = 0;
395 unsigned char old_attr = 0; 395 unsigned char old_attr = 0;
396 const unsigned char *color = (const unsigned char*) "\x00\x00\x00"; 396 const unsigned char default_color[] = {'\x00', '\x00', '\x00'};
397 int i; 397 const unsigned char *old_color = NULL;
398 size_t len; 398 int in_span = 0;
399 const unsigned char *format_ = (const unsigned char*) format; 399 unsigned int i;
400 400 size_t len = 0;
401 len = 0;
402
403 /* Nie mamy atrybutów dla pierwsze znaku, a tekst nie jest pusty, więc
404 * tak czy inaczej trzeba otworzyć <span>. */
405
406 if (src[0] != 0 && (format_idx + 3 > format_len || (format_[format_idx] | (format_[format_idx + 1] << 8)) != 0)) {
407 if (dst != NULL)
408 sprintf(&dst[len], span_fmt, 0, 0, 0);
409
410 len += span_len;
411 }
412 401
413 /* Pętla przechodzi też przez kończące \0, żeby móc dokleić obrazek 402 /* Pętla przechodzi też przez kończące \0, żeby móc dokleić obrazek
414 * na końcu tekstu. */ 403 * na końcu tekstu. */
415 404
416 for (i = 0; ; i++) { 405 for (i = 0; ; i++) {
417 /* Analizuj atrybuty tak długo jak dotyczą aktualnego znaku. */ 406 int in_char = 0;
407 size_t format_idx = 0;
408
409 /* Sprawdź, czy bajt jest kontynuacją znaku UTF-8. */
410 if (encoding == GG_ENCODING_UTF8 && (src[i] & 0xc0) == 0x80)
411 in_char = 1;
412
413 /* GG_FONT_IMAGE powinno dotyczyć tylko jednego znaku, więc czyścimy stary atrybut */
414
415 if (!in_char && (old_attr & GG_FONT_IMAGE) != 0)
416 old_attr &= ~GG_FONT_IMAGE;
417
418 /* Analizuj wszystkie atrybuty dotyczące aktualnego znaku. */
418 for (;;) { 419 for (;;) {
419 unsigned char attr; 420 unsigned char attr;
420 int attr_pos; 421 size_t attr_pos;
422
423 /* Nie wstawiamy niczego wewnątrz wielobajtowego znaku UTF-8. */
424 if (in_char)
425 break;
421 426
422 if (format_idx + 3 > format_len) 427 if (format_idx + 3 > format_len)
423 break; 428 break;
424 429
425 attr_pos = format_[format_idx] | (format_[format_idx + 1] << 8); 430 attr_pos = format[format_idx] | (format[format_idx + 1] << 8);
426 431 attr = format[format_idx + 2];
427 if (attr_pos != char_pos)
428 break;
429
430 attr = format_[format_idx + 2];
431 432
432 /* Nie doklejaj atrybutów na końcu, co najwyżej obrazki. */ 433 /* Nie doklejaj atrybutów na końcu, co najwyżej obrazki. */
433 434
434 if (src[i] == 0) 435 if (src[i] == 0)
435 attr &= ~(GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR); 436 attr &= ~(GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR);
436 437
437 format_idx += 3; 438 format_idx += 3;
438 439
439 if ((attr & (GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR)) != 0 || (attr == 0 && old_attr != 0)) { 440 if (attr_pos != char_pos) {
440 if (char_pos != 0) { 441 if ((attr & GG_FONT_COLOR) != 0)
441 if ((old_attr & GG_FONT_UNDERLINE) != 0) 442 format_idx += 3;
442 gg_append(dst, &len, "</u>", 4); 443 if ((attr & GG_FONT_IMAGE) != 0)
443 444 format_idx += 10;
444 if ((old_attr & GG_FONT_ITALIC) != 0) 445
445 gg_append(dst, &len, "</i>", 4); 446 continue;
446 447 }
447 if ((old_attr & GG_FONT_BOLD) != 0) 448
448 gg_append(dst, &len, "</b>", 4); 449 if ((old_attr & GG_FONT_UNDERLINE) != 0)
449 450 gg_append(dst, &len, "</u>", 4);
450 if (src[i] != 0) 451
451 gg_append(dst, &len, "</span>", 7); 452 if ((old_attr & GG_FONT_ITALIC) != 0)
452 } 453 gg_append(dst, &len, "</i>", 4);
454
455 if ((old_attr & GG_FONT_BOLD) != 0)
456 gg_append(dst, &len, "</b>", 4);
457
458 if ((attr & (GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR)) != 0) {
459 const unsigned char *color;
453 460
454 if (((attr & GG_FONT_COLOR) != 0) && (format_idx + 3 <= format_len)) { 461 if (((attr & GG_FONT_COLOR) != 0) && (format_idx + 3 <= format_len)) {
455 color = &format_[format_idx]; 462 color = &format[format_idx];
456 format_idx += 3; 463 format_idx += 3;
457 } else { 464 } else {
458 color = (unsigned char*) "\x00\x00\x00"; 465 color = default_color;
459 } 466 }
460 467
461 if (src[i] != 0) { 468 if (old_color == NULL || memcmp(color, old_color, 3) != 0) {
462 if (dst != NULL) 469 if (in_span) {
463 sprintf(&dst[len], span_fmt, color[0], color[1], color[2]); 470 gg_append(dst, &len, "</span>", 7);
464 len += span_len; 471 in_span = 0;
472 }
473
474 if (src[i] != 0) {
475 if (dst != NULL)
476 sprintf(&dst[len], span_fmt, color[0], color[1], color[2]);
477
478 len += span_len;
479 in_span = 1;
480 old_color = color;
481 }
465 } 482 }
466 } else if (char_pos == 0 && src[0] != 0) {
467 if (dst != NULL)
468 sprintf(&dst[len], span_fmt, 0, 0, 0);
469 len += span_len;
470 } 483 }
471 484
472 if ((attr & GG_FONT_BOLD) != 0) 485 if ((attr & GG_FONT_BOLD) != 0)
473 gg_append(dst, &len, "<b>", 3); 486 gg_append(dst, &len, "<b>", 3);
474 487
479 gg_append(dst, &len, "<u>", 3); 492 gg_append(dst, &len, "<u>", 3);
480 493
481 if (((attr & GG_FONT_IMAGE) != 0) && (format_idx + 10 <= format_len)) { 494 if (((attr & GG_FONT_IMAGE) != 0) && (format_idx + 10 <= format_len)) {
482 if (dst != NULL) { 495 if (dst != NULL) {
483 sprintf(&dst[len], img_fmt, 496 sprintf(&dst[len], img_fmt,
484 format_[format_idx + 9], 497 format[format_idx + 9],
485 format_[format_idx + 8], 498 format[format_idx + 8],
486 format_[format_idx + 7], 499 format[format_idx + 7],
487 format_[format_idx + 6], 500 format[format_idx + 6],
488 format_[format_idx + 5], 501 format[format_idx + 5],
489 format_[format_idx + 4], 502 format[format_idx + 4],
490 format_[format_idx + 3], 503 format[format_idx + 3],
491 format_[format_idx + 2]); 504 format[format_idx + 2]);
492 } 505 }
493 506
494 len += img_len; 507 len += img_len;
495 format_idx += 10; 508 format_idx += 10;
496 } 509 }
497 510
498 old_attr = attr; 511 old_attr = attr;
512 }
513
514 if (src[i] == 0)
515 break;
516
517 /* Znaki oznaczone jako GG_FONT_IMAGE nie są częścią wiadomości. */
518
519 if ((old_attr & GG_FONT_IMAGE) != 0) {
520 if (!in_char)
521 char_pos++;
522
523 continue;
524 }
525
526 /* Jesteśmy na początku tekstu i choć nie było atrybutów dla pierwszego
527 * znaku, ponieważ tekst nie jest pusty, trzeba otworzyć <span>. */
528
529 if (!in_span) {
530 if (dst != NULL)
531 sprintf(&dst[len], span_fmt, default_color[0], default_color[1], default_color[2]);
532
533 len += span_len;
534 in_span = 1;
535 old_color = default_color;
499 } 536 }
500 537
501 /* Doklej znak zachowując htmlowe escapowanie. */ 538 /* Doklej znak zachowując htmlowe escapowanie. */
502 539
503 switch (src[i]) { 540 switch (src[i]) {
518 break; 555 break;
519 case '\n': 556 case '\n':
520 gg_append(dst, &len, "<br>", 4); 557 gg_append(dst, &len, "<br>", 4);
521 break; 558 break;
522 case '\r': 559 case '\r':
523 case 0:
524 break; 560 break;
525 default: 561 default:
526 if (dst != NULL) 562 if (dst != NULL)
527 dst[len] = src[i]; 563 dst[len] = src[i];
528 len++; 564 len++;
529 } 565 }
530 566
531 /* Sprawdź, czy bajt nie jest kontynuacją znaku unikodowego. */ 567 if (!in_char)
532
533 if ((src[i] & 0xc0) != 0xc0)
534 char_pos++; 568 char_pos++;
535
536 if (src[i] == 0)
537 break;
538 } 569 }
539 570
540 /* Zamknij tagi. */ 571 /* Zamknij tagi. */
541 572
542 if ((old_attr & GG_FONT_UNDERLINE) != 0) 573 if ((old_attr & GG_FONT_UNDERLINE) != 0)
546 gg_append(dst, &len, "</i>", 4); 577 gg_append(dst, &len, "</i>", 4);
547 578
548 if ((old_attr & GG_FONT_BOLD) != 0) 579 if ((old_attr & GG_FONT_BOLD) != 0)
549 gg_append(dst, &len, "</b>", 4); 580 gg_append(dst, &len, "</b>", 4);
550 581
551 if (src[0] != 0) 582 if (in_span)
552 gg_append(dst, &len, "</span>", 7); 583 gg_append(dst, &len, "</span>", 7);
553 584
554 if (dst != NULL) 585 if (dst != NULL)
555 dst[len] = 0; 586 dst[len] = 0;
556 587
557 return len; 588 return len;
558 } 589 }
559 590
560 /** 591 /**
592 * \internal Dokleja nowe atrybuty formatowania, jeśli konieczne, oraz inkrementuje pozycję znaku w tekście.
593 *
594 * \param pos Wskaźnik na zmienną przechowującą pozycję znaku w tekście
595 * \param attr_flag Aktualna flaga atrybutu formatowania
596 * \param old_attr_flag Wskaźnik na poprzednią flagę atrybutu formatowania
597 * \param color Wskaźnik na tablicę z aktualnym kolorem RGB (jeśli \p attr_flag nie zawiera flagi \c GG_FONT_COLOR, ignorowane)
598 * \param old_color Wskaźnik na tablicę z poprzednim kolorem RGB
599 * \param imgs_size Rozmiar atrybutów formatowania obrazków znajdujących się obecnie w tablicy atrybutów formatowania, w bajtach
600 * \param format Wskaźnik na wskaźnik do tablicy atrybutów formatowania
601 * \param format_len Wskaźnik na zmienną zawierającą długość tablicy atrybutów formatowania, w bajtach (może być \c NULL)
602 */
603 static void gg_after_append_formatted_char(uint16_t *pos, unsigned char attr_flag, unsigned char *old_attr_flag, const unsigned char *color, unsigned char *old_color, size_t imgs_size, unsigned char **format, size_t *format_len)
604 {
605 const size_t color_size = 3;
606 int has_color = 0;
607
608 if ((attr_flag & GG_FONT_COLOR) != 0)
609 has_color = 1;
610
611 if (*old_attr_flag != attr_flag || (has_color && memcmp(old_color, color, color_size) != 0)) {
612 size_t attr_size = sizeof(*pos) + sizeof(attr_flag) + (has_color ? color_size : 0);
613
614 if (*format != NULL) {
615 /* Staramy się naśladować oryginalnego klienta i atrybuty obrazków trzymamy na końcu */
616
617 *format -= imgs_size;
618 memmove(*format + attr_size, *format, imgs_size);
619
620 **format = (unsigned char) (*pos & (uint16_t) 0x00ffU);
621 *format += 1;
622 **format = (unsigned char) ((*pos & (uint16_t) 0xff00U) >> 8);
623 *format += 1;
624
625 **format = attr_flag;
626 *format += 1;
627
628 if (has_color) {
629 memcpy(*format, color, color_size);
630 *format += color_size;
631 }
632
633 *format += imgs_size;
634 }
635
636 if (format_len != NULL)
637 *format_len += attr_size;
638
639 *old_attr_flag = attr_flag;
640 if (has_color)
641 memcpy(old_color, color, color_size);
642 }
643
644 *pos += 1;
645 }
646
647 /**
561 * \internal Zamienia tekst w formacie HTML na czysty tekst. 648 * \internal Zamienia tekst w formacie HTML na czysty tekst.
562 * 649 *
563 * \param dst Bufor wynikowy (może być \c NULL) 650 * \param dst Bufor wynikowy (może być \c NULL)
651 * \param format Bufor wynikowy z atrybutami formatowania (może być \c NULL)
652 * \param format_len Wskaźnik na zmienną, do której zostanie zapisana potrzebna wielkość bufora wynikowego z atrybutami formatowania, w bajtach (może być \c NULL)
564 * \param html Tekst źródłowy 653 * \param html Tekst źródłowy
654 * \param encoding Kodowanie tekstu źródłowego oraz wynikowego
565 * 655 *
566 * \note Dokleja \c \\0 na końcu bufora wynikowego. 656 * \note Dokleja \c \\0 na końcu bufora wynikowego.
567 * 657 *
568 * \note Funkcja służy do zachowania kompatybilności przy przesyłaniu 658 * \return Długość bufora wynikowego bez \c \\0 (nawet jeśli \c dst to \c NULL).
569 * wiadomości HTML do klientów, które tego formatu nie obsługują. Z tego
570 * powodu funkcja nie zachowuje formatowania, a jedynie usuwa tagi i
571 * zamienia podstawowe encje na ich odpowiedniki ASCII.
572 *
573 * \return Długość tekstu wynikowego bez \c \\0 (nawet jeśli \c dst to \c NULL).
574 */ 659 */
575 size_t gg_message_html_to_text(char *dst, const char *html) 660 size_t gg_message_html_to_text(char *dst, unsigned char *format, size_t *format_len, const char *html, gg_encoding_t encoding)
576 { 661 {
577 const char *src, *entity, *tag; 662 const char *src, *entity = NULL, *tag = NULL;
578 int in_tag, in_entity; 663 int in_tag = 0, in_entity = 0, in_bold = 0, in_italic = 0, in_underline = 0;
579 size_t len; 664 unsigned char color[3] = { 0 }, old_color[3] = { 0 };
580 665 unsigned char attr_flag = 0, old_attr_flag = 0;
581 len = 0; 666 uint16_t pos = 0;
582 in_tag = 0; 667 size_t len = 0, imgs_size = 0;
583 tag = NULL; 668
584 in_entity = 0; 669 if (format_len != NULL)
585 entity = NULL; 670 *format_len = 0;
586 671
587 for (src = html; *src != 0; src++) { 672 for (src = html; *src != 0; src++) {
588 if (in_entity && !(isalnum(*src) || *src == '#' || *src == ';')) { 673 if (in_entity && !(isalnum(*src) || *src == '#' || *src == ';')) {
674 int first = 1;
675 size_t i, append_len = src - entity;
676
677 gg_append(dst, &len, entity, append_len);
678 for (i = 0; i < append_len; i++) {
679 if (encoding != GG_ENCODING_UTF8 || (entity[i] & 0xc0) != 0x80) {
680 if (first) {
681 gg_after_append_formatted_char(&pos, attr_flag, &old_attr_flag, color, old_color, imgs_size, &format, format_len);
682 first = 0;
683 } else {
684 pos++;
685 }
686 }
687 }
688
589 in_entity = 0; 689 in_entity = 0;
590 gg_append(dst, &len, entity, src - entity);
591 } 690 }
592 691
593 if (*src == '<') { 692 if (*src == '<') {
594 tag = src; 693 tag = src;
595 in_tag = 1; 694 in_tag = 1;
599 if (in_tag && (*src == '>')) { 698 if (in_tag && (*src == '>')) {
600 if (strncmp(tag, "<br", 3) == 0) { 699 if (strncmp(tag, "<br", 3) == 0) {
601 if (dst != NULL) 700 if (dst != NULL)
602 dst[len] = '\n'; 701 dst[len] = '\n';
603 len++; 702 len++;
703
704 gg_after_append_formatted_char(&pos, attr_flag, &old_attr_flag, color, old_color, imgs_size, &format, format_len);
705 } else if (strncmp(tag, "<img name=\"", 11) == 0 || strncmp(tag, "<img name=\'", 11) == 0) {
706 tag += 11;
707
708 /* 17 bo jeszcze cudzysłów musi być zamknięty */
709 if (tag + 17 <= src) {
710 int i, ok = 1;
711
712 for (i = 0; i < 16; i++) {
713 if ((tag[i] < '0' || tag[i] > '9') && (tolower(tag[i]) < 'a' || tolower(tag[i]) > 'f')) {
714 ok = 0;
715 break;
716 }
717 }
718
719 if (ok) {
720 unsigned char img_attr[13];
721
722 if (format != NULL) {
723 char buf[3] = { 0 };
724
725 img_attr[0] = (unsigned char) (pos & (uint16_t) 0x00ffU);
726 img_attr[1] = (unsigned char) ((pos & (uint16_t) 0xff00U) >> 8);
727 img_attr[2] = GG_FONT_IMAGE;
728 img_attr[3] = '\x09';
729 img_attr[4] = '\x01';
730 for (i = 0; i < 16; i += 2) {
731 buf[0] = tag[i];
732 buf[1] = tag[i + 1];
733 /* buf[2] to '\0' */
734 img_attr[12 - i / 2] = (unsigned char) strtoul(buf, NULL, 16);
735 }
736
737 memcpy(format, img_attr, sizeof(img_attr));
738 format += sizeof(img_attr);
739 }
740
741 if (format_len != NULL)
742 *format_len += sizeof(img_attr);
743 imgs_size += sizeof(img_attr);
744
745 if (dst != NULL) {
746 if (encoding == GG_ENCODING_UTF8)
747 dst[len++] = '\xc2';
748 dst[len++] = '\xa0';
749 } else {
750 len += 2;
751 }
752
753 /* Nie używamy tutaj gg_after_append_formatted_char(). Po pierwsze to praktycznie niczego
754 * by nie zmieniło, a po drugie nie wszystkim klientom mogłaby się spodobać redefinicja
755 * atrybutów formatowania dla jednego znaku (bo np. najpierw byśmy zdefiniowali bolda od
756 * znaku 10, a potem by się okazało, że znak 10 to obrazek).
757 */
758
759 pos++;
760
761 /* Resetujemy atrybuty, aby je w razie czego redefiniować od następnego znaku, co by sobie
762 * nikt przypadkiem nie pomyślał, że GG_FONT_IMAGE dotyczy więcej, niż jednego znaku.
763 * Tak samo robi oryginalny klient.
764 */
765
766 old_attr_flag = -1;
767 }
768 }
769 } else if (strncmp(tag, "<b>", 3) == 0) {
770 in_bold++;
771 attr_flag |= GG_FONT_BOLD;
772 } else if (strncmp(tag, "</b>", 4) == 0) {
773 if (in_bold > 0) {
774 in_bold--;
775 if (in_bold == 0)
776 attr_flag &= ~GG_FONT_BOLD;
777 }
778 } else if (strncmp(tag, "<i>", 3) == 0) {
779 in_italic++;
780 attr_flag |= GG_FONT_ITALIC;
781 } else if (strncmp(tag, "</i>", 4) == 0) {
782 if (in_italic > 0) {
783 in_italic--;
784 if (in_italic == 0)
785 attr_flag &= ~GG_FONT_ITALIC;
786 }
787 } else if (strncmp(tag, "<u>", 3) == 0) {
788 in_underline++;
789 attr_flag |= GG_FONT_UNDERLINE;
790 } else if (strncmp(tag, "</u>", 4) == 0) {
791 if (in_underline > 0) {
792 in_underline--;
793 if (in_underline == 0)
794 attr_flag &= ~GG_FONT_UNDERLINE;
795 }
796 } else if (strncmp(tag, "<span ", 6) == 0) {
797 for (tag += 6; tag < src - 8; tag++) {
798 if (*tag == '\"' || *tag == '\'' || *tag == ' ') {
799 if (strncmp(tag + 1, "color:#", 7) == 0) {
800 int i, ok = 1;
801 char buf[3] = { 0 };
802
803 tag += 8;
804 if (tag + 6 > src)
805 break;
806
807 for (i = 0; i < 6; i++) {
808 if ((tag[i] < '0' || tag[i] > '9') && (tolower(tag[i]) < 'a' || tolower(tag[i]) > 'f')) {
809 ok = 0;
810 break;
811 }
812 }
813
814 if (!ok)
815 break;
816
817 for (i = 0; i < 6; i += 2) {
818 buf[0] = tag[i];
819 buf[1] = tag[i + 1];
820 /* buf[2] to '\0' */
821 color[i / 2] = (unsigned char) strtoul(buf, NULL, 16);
822 }
823
824 attr_flag |= GG_FONT_COLOR;
825 }
826 }
827 }
828 } else if (strncmp(tag, "</span", 6) == 0) {
829 /* Można by trzymać kolory na stosie i tutaj przywracać poprzedni, ale to raczej zbędne */
830
831 attr_flag &= ~GG_FONT_COLOR;
604 } 832 }
833
834 tag = NULL;
605 in_tag = 0; 835 in_tag = 0;
606 continue; 836 continue;
607 } 837 }
608 838
609 if (in_tag) 839 if (in_tag)
615 continue; 845 continue;
616 } 846 }
617 847
618 if (in_entity && *src == ';') { 848 if (in_entity && *src == ';') {
619 in_entity = 0; 849 in_entity = 0;
850
620 if (dst != NULL) { 851 if (dst != NULL) {
621 if (strncmp(entity, "&lt;", 4) == 0) 852 if (strncmp(entity, "&lt;", 4) == 0)
622 dst[len++] = '<'; 853 dst[len++] = '<';
623 else if (strncmp(entity, "&gt;", 4) == 0) 854 else if (strncmp(entity, "&gt;", 4) == 0)
624 dst[len++] = '>'; 855 dst[len++] = '>';
627 else if (strncmp(entity, "&apos;", 6) == 0) 858 else if (strncmp(entity, "&apos;", 6) == 0)
628 dst[len++] = '\''; 859 dst[len++] = '\'';
629 else if (strncmp(entity, "&amp;", 5) == 0) 860 else if (strncmp(entity, "&amp;", 5) == 0)
630 dst[len++] = '&'; 861 dst[len++] = '&';
631 else if (strncmp(entity, "&nbsp;", 6) == 0) { 862 else if (strncmp(entity, "&nbsp;", 6) == 0) {
632 dst[len++] = 0xc2; 863 if (encoding == GG_ENCODING_UTF8)
633 dst[len++] = 0xa0; 864 dst[len++] = '\xc2';
865 dst[len++] = '\xa0';
634 } else 866 } else
635 dst[len++] = '?'; 867 dst[len++] = '?';
636 } else { 868 } else {
637 if (strncmp(entity, "&nbsp;", 6) == 0) 869 if (strncmp(entity, "&nbsp;", 6) == 0)
638 len += 2; 870 len += 2;
639 else 871 else
640 len++; 872 len++;
641 } 873 }
642 874
875 gg_after_append_formatted_char(&pos, attr_flag, &old_attr_flag, color, old_color, imgs_size, &format, format_len);
876
643 continue; 877 continue;
644 } 878 }
645 879
646 if (in_entity && !(isalnum(*src) || *src == '#')) 880 if (in_entity && !(isalnum(*src) || *src == '#'))
647 in_entity = 0; 881 in_entity = 0;
649 if (in_entity) 883 if (in_entity)
650 continue; 884 continue;
651 885
652 if (dst != NULL) 886 if (dst != NULL)
653 dst[len] = *src; 887 dst[len] = *src;
654
655 len++; 888 len++;
889
890 if (encoding != GG_ENCODING_UTF8 || (*src & 0xc0) != 0x80)
891 gg_after_append_formatted_char(&pos, attr_flag, &old_attr_flag, color, old_color, imgs_size, &format, format_len);
656 } 892 }
657 893
658 if (dst != NULL) 894 if (dst != NULL)
659 dst[len] = 0; 895 dst[len] = '\0';
660 896
661 return len; 897 return len;
662 } 898 }
663 899
900 static size_t gg_message_html_to_text_110_buff(char *dst, const char *html)
901 {
902 return gg_message_html_to_text(dst, NULL, NULL, html, GG_ENCODING_UTF8);
903 }
904
905 static size_t gg_message_text_to_html_110_buff(char *dst, const char *text,
906 ssize_t text_len)
907 {
908 size_t i, dst_len;
909
910 if (text_len == -1)
911 text_len = strlen(text);
912 dst_len = 0;
913
914 gg_append(dst, &dst_len, "<span>", 6);
915
916 for (i = 0; i < (size_t)text_len; i++)
917 {
918 char c = text[i];
919 if (c == '<')
920 gg_append(dst, &dst_len, "&lt;", 4);
921 else if (c == '>')
922 gg_append(dst, &dst_len, "&gt;", 4);
923 else if (c == '&')
924 gg_append(dst, &dst_len, "&amp;", 5);
925 else if (c == '"')
926 gg_append(dst, &dst_len, "&quot;", 6);
927 else if (c == '\'')
928 gg_append(dst, &dst_len, "&apos;", 6);
929 else if (c == '\n')
930 gg_append(dst, &dst_len, "<br>", 4);
931 else if (c == '\r')
932 continue;
933 else if (c == '\xc2' && text[i + 1] == '\xa0') {
934 gg_append(dst, &dst_len, "&nbsp;", 6);
935 i++;
936 } else {
937 if (dst)
938 dst[dst_len] = c;
939 dst_len++;
940 }
941 }
942
943 gg_append(dst, &dst_len, "</span>", 7);
944
945 if (dst)
946 dst[dst_len] = '\0';
947
948 return dst_len;
949 }
950
951 char *gg_message_html_to_text_110(const char *html)
952 {
953 size_t dst_len;
954 char *dst;
955
956 dst_len = gg_message_html_to_text_110_buff(NULL, html) + 1;
957 dst = malloc(dst_len);
958 if (!dst)
959 return NULL;
960 gg_message_html_to_text_110_buff(dst, html);
961
962 return dst;
963 }
964
965 char *gg_message_text_to_html_110(const char *text, ssize_t text_len)
966 {
967 size_t dst_len;
968 char *dst;
969
970 dst_len = gg_message_text_to_html_110_buff(NULL, text, text_len) + 1;
971 dst = malloc(dst_len);
972 if (!dst)
973 return NULL;
974 gg_message_text_to_html_110_buff(dst, text, text_len);
975
976 return dst;
977 }
978

mercurial