|
a/src/utils/mimeparse.cpp |
|
b/src/utils/mimeparse.cpp |
|
... |
|
... |
472 |
// This is not supposed to be used for MIME parameter values, but it
|
472 |
// This is not supposed to be used for MIME parameter values, but it
|
473 |
// happens.
|
473 |
// happens.
|
474 |
// Bugs:
|
474 |
// Bugs:
|
475 |
// - We should turn off decoding while inside quoted strings
|
475 |
// - We should turn off decoding while inside quoted strings
|
476 |
//
|
476 |
//
|
477 |
typedef enum {rfc2047base, rfc2047ready, rfc2047open_eq,
|
477 |
typedef enum {rfc2047ready, rfc2047open_eq,
|
478 |
rfc2047charset, rfc2047encoding,
|
478 |
rfc2047charset, rfc2047encoding,
|
479 |
rfc2047value, rfc2047close_q} Rfc2047States;
|
479 |
rfc2047value, rfc2047close_q} Rfc2047States;
|
480 |
|
480 |
|
481 |
bool rfc2047_decode(const std::string& in, std::string &out)
|
481 |
bool rfc2047_decode(const std::string& in, std::string &out)
|
482 |
{
|
482 |
{
|
|
... |
|
... |
488 |
out.clear();
|
488 |
out.clear();
|
489 |
|
489 |
|
490 |
for (string::size_type ii = 0; ii < in.length(); ii++) {
|
490 |
for (string::size_type ii = 0; ii < in.length(); ii++) {
|
491 |
char ch = in[ii];
|
491 |
char ch = in[ii];
|
492 |
switch (state) {
|
492 |
switch (state) {
|
493 |
case rfc2047base:
|
|
|
494 |
{
|
|
|
495 |
value += ch;
|
|
|
496 |
switch (ch) {
|
|
|
497 |
// Linear whitespace
|
|
|
498 |
case ' ': case ' ': state = rfc2047ready; break;
|
|
|
499 |
default: break;
|
|
|
500 |
}
|
|
|
501 |
}
|
|
|
502 |
break;
|
|
|
503 |
case rfc2047ready:
|
493 |
case rfc2047ready:
|
504 |
{
|
494 |
{
|
|
|
495 |
DPRINT((stderr, "STATE: ready, ch %c\n", ch));
|
505 |
switch (ch) {
|
496 |
switch (ch) {
|
506 |
// Whitespace: stay ready
|
497 |
// Whitespace: stay ready
|
507 |
case ' ': case ' ': value += ch;break;
|
498 |
case ' ': case ' ': value += ch;break;
|
508 |
// '=' -> forward to next state
|
499 |
// '=' -> forward to next state
|
509 |
case '=': state = rfc2047open_eq; break;
|
500 |
case '=': state = rfc2047open_eq; break;
|
|
|
501 |
DPRINT((stderr, "STATE: open_eq\n"));
|
510 |
// Other: go back to sleep
|
502 |
// Other: go back to sleep
|
511 |
default: value += ch; state = rfc2047base;
|
503 |
default: value += ch; state = rfc2047ready;
|
512 |
}
|
504 |
}
|
513 |
}
|
505 |
}
|
514 |
break;
|
506 |
break;
|
515 |
case rfc2047open_eq:
|
507 |
case rfc2047open_eq:
|
516 |
{
|
508 |
{
|
|
|
509 |
DPRINT((stderr, "STATE: open_eq, ch %c\n", ch));
|
517 |
switch (ch) {
|
510 |
switch (ch) {
|
518 |
case '?':
|
511 |
case '?':
|
519 |
{
|
512 |
{
|
520 |
// Transcode current (unencoded part) value:
|
513 |
// Transcode current (unencoded part) value:
|
521 |
// we sometimes find 8-bit chars in
|
514 |
// we sometimes find 8-bit chars in
|
|
... |
|
... |
526 |
value.clear();
|
519 |
value.clear();
|
527 |
}
|
520 |
}
|
528 |
state = rfc2047charset;
|
521 |
state = rfc2047charset;
|
529 |
}
|
522 |
}
|
530 |
break;
|
523 |
break;
|
531 |
default: state = rfc2047base; out += '='; out += ch;break;
|
524 |
default: state = rfc2047ready; out += '='; out += ch;break;
|
532 |
}
|
525 |
}
|
533 |
}
|
526 |
}
|
534 |
break;
|
527 |
break;
|
535 |
case rfc2047charset:
|
528 |
case rfc2047charset:
|
536 |
{
|
529 |
{
|
|
|
530 |
DPRINT((stderr, "STATE: charset, ch %c\n", ch));
|
537 |
switch (ch) {
|
531 |
switch (ch) {
|
538 |
case '?': state = rfc2047encoding; break;
|
532 |
case '?': state = rfc2047encoding; break;
|
539 |
default: charset += ch; break;
|
533 |
default: charset += ch; break;
|
540 |
}
|
534 |
}
|
541 |
}
|
535 |
}
|
542 |
break;
|
536 |
break;
|
543 |
case rfc2047encoding:
|
537 |
case rfc2047encoding:
|
544 |
{
|
538 |
{
|
|
|
539 |
DPRINT((stderr, "STATE: encoding, ch %c\n", ch));
|
545 |
switch (ch) {
|
540 |
switch (ch) {
|
546 |
case '?': state = rfc2047value; break;
|
541 |
case '?': state = rfc2047value; break;
|
547 |
default: encoding += ch; break;
|
542 |
default: encoding += ch; break;
|
548 |
}
|
543 |
}
|
549 |
}
|
544 |
}
|
550 |
break;
|
545 |
break;
|
551 |
case rfc2047value:
|
546 |
case rfc2047value:
|
552 |
{
|
547 |
{
|
|
|
548 |
DPRINT((stderr, "STATE: value, ch %c\n", ch));
|
553 |
switch (ch) {
|
549 |
switch (ch) {
|
554 |
case '?': state = rfc2047close_q; break;
|
550 |
case '?': state = rfc2047close_q; break;
|
555 |
default: value += ch;break;
|
551 |
default: value += ch;break;
|
556 |
}
|
552 |
}
|
557 |
}
|
553 |
}
|
558 |
break;
|
554 |
break;
|
559 |
case rfc2047close_q:
|
555 |
case rfc2047close_q:
|
560 |
{
|
556 |
{
|
|
|
557 |
DPRINT((stderr, "STATE: close_q, ch %c\n", ch));
|
561 |
switch (ch) {
|
558 |
switch (ch) {
|
562 |
case '=':
|
559 |
case '=':
|
563 |
{
|
560 |
{
|
|
|
561 |
DPRINT((stderr, "End of encoded area. Charset %s, Encoding %s\n", charset.c_str(), encoding.c_str()));
|
564 |
string utf8;
|
562 |
string utf8;
|
565 |
state = rfc2047base;
|
563 |
state = rfc2047ready;
|
566 |
if (!rfc2047_decodeParsed(charset, encoding, value,
|
564 |
if (!rfc2047_decodeParsed(charset, encoding, value,
|
567 |
utf8)) {
|
565 |
utf8)) {
|
568 |
return false;
|
566 |
return false;
|
569 |
}
|
567 |
}
|
570 |
out += utf8;
|
568 |
out += utf8;
|
|
... |
|
... |
576 |
default: state = rfc2047value; value += '?';value += ch;break;
|
574 |
default: state = rfc2047value; value += '?';value += ch;break;
|
577 |
}
|
575 |
}
|
578 |
}
|
576 |
}
|
579 |
break;
|
577 |
break;
|
580 |
default: // ??
|
578 |
default: // ??
|
|
|
579 |
DPRINT((stderr, "STATE: default ?? ch %c\n", ch));
|
581 |
return false;
|
580 |
return false;
|
582 |
}
|
581 |
}
|
583 |
}
|
582 |
}
|
584 |
|
583 |
|
585 |
if (value.length() > 0) {
|
584 |
if (value.length() > 0) {
|
586 |
transcode(value, utf8, "ISO-8859-1", "UTF-8");
|
585 |
transcode(value, utf8, "ISO-8859-1", "UTF-8");
|
587 |
out += utf8;
|
586 |
out += utf8;
|
588 |
value.clear();
|
587 |
value.clear();
|
589 |
}
|
588 |
}
|
590 |
if (state != rfc2047base)
|
589 |
if (state != rfc2047ready)
|
591 |
return false;
|
590 |
return false;
|
592 |
return true;
|
591 |
return true;
|
593 |
}
|
592 |
}
|
594 |
|
593 |
|
595 |
#define DEBUGDATE 0
|
594 |
#define DEBUGDATE 0
|