00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "vformat.h"
00024 #include "clog.h"
00025
00026
00027
00028
00029
00030 #include <string.h>
00031 #include <stdio.h>
00032 #include <ctype.h>
00033 #include <stdlib.h>
00034 #include <iconv.h>
00035
00036
00037 #define TRACE_INTERNAL 1
00038 #define TRACE_ENTRY 1
00039 #define TRACE_EXIT 1
00040 #define TRACE_ERROR 0
00041
00042 static size_t base64_encode_step(const unsigned char *in, size_t len, gboolean break_lines, unsigned char *out, int *state, int *save);
00043 static size_t base64_decode_step(const unsigned char *in, size_t len, unsigned char *out, int *state, unsigned int *save);
00044 static size_t base64_decode_simple (char *data, size_t len);
00045 static char *base64_encode_simple (const char *data, size_t len);
00046
00047 static size_t quoted_decode_simple (char *data, size_t len);
00048 static char *quoted_encode_simple (const unsigned char *string, int len);
00049
00050
00051
00052
00053
00054
00055
00056 static int _helper_is_base64(const char *check_string)
00057 {
00058 if(!g_ascii_strcasecmp ((char *) check_string, "BASE64") ||
00059 !g_ascii_strcasecmp ((char *) check_string, "b") )
00060 return (1);
00061 return (0);
00062 }
00063
00064 time_t b_vformat_time_to_unix(const char *inptime)
00065 {
00066 char *date = NULL;
00067 char *time = NULL;
00068 char *ftime = NULL;
00069 if ((ftime = g_strrstr(inptime, "T"))) {
00070
00071 date = g_strndup(inptime, ftime - inptime);
00072 if (ftime[3] == ':')
00073 time = g_strndup(ftime + 1, 8);
00074 else
00075 time = g_strndup(ftime + 1, 6);
00076 } else {
00077 date = g_strdup(inptime);
00078 }
00079
00080 struct tm btime;
00081 memset(&btime, 0, sizeof(struct tm));
00082 btime.tm_isdst = -1;
00083
00084 if (strlen(date) == 10) {
00085 btime.tm_year = date[0] * 1000 + date[1] * 100 + date[2] * 10 + date[3] - '0' * 1111 - 1900;
00086 btime.tm_mon = date[5] * 10 + date[6] - '0' * 11 - 1;
00087 btime.tm_mday = date[8] * 10 + date[9] - '0' * 11;
00088 } else {
00089 btime.tm_year = date[0] * 1000 + date[1] * 100 + date[2] * 10 + date[3] - '0' * 1111- 1900;
00090 btime.tm_mon = date[4] * 10 + date[5] - '0' * 11 - 1;
00091 btime.tm_mday = date[6] * 10 + date[7] - '0' * 11;
00092 }
00093
00094 if (time && strlen(time) == 8) {
00095
00096 btime.tm_hour = time[0] * 10 + time[1] - '0' * 11;
00097 btime.tm_min = time[3] * 10 + time[4] - '0' * 11;
00098 btime.tm_sec = time[6] * 10 + time[7] - '0' * 11;
00099 } else if (time && strlen(time) == 6) {
00100 btime.tm_hour = time[0] * 10 + time[1] - '0' * 11;
00101 btime.tm_min = time[2] * 10 + time[3] - '0' * 11;
00102 btime.tm_sec = time[4] * 10 + time[5] - '0' * 11;
00103 }
00104
00105 time_t utime = mktime(&btime);
00106 return utime;
00107 }
00108
00109 static char *_fold_lines (char *buf)
00110 {
00111 GString *str = g_string_new ("");
00112 GString *line = g_string_new ("");
00113 char *p = buf;
00114 char *next, *next2, *q;
00115 gboolean newline = TRUE;
00116 gboolean quotedprintable = FALSE;
00117
00118
00119
00120
00121
00122
00123
00124 while (*p) {
00125
00126
00127 if (newline) {
00128 for (q=p; *q != '\n' && *q != '\0'; q++)
00129 line = g_string_append_unichar (line, g_utf8_get_char (q));
00130
00131 if (strstr(line->str, "ENCODING=QUOTED-PRINTABLE"))
00132 quotedprintable = TRUE;
00133
00134 g_string_free(line, TRUE);
00135 line = g_string_new ("");
00136
00137 newline = FALSE;
00138 }
00139
00140
00141 if ((quotedprintable && *p == '=') || *p == '\r' || *p == '\n') {
00142 next = g_utf8_next_char (p);
00143 if (*next == '\n' || *next == '\r') {
00144 next2 = g_utf8_next_char (next);
00145 if (*next2 == '\n' || *next2 == '\r' || *next2 == ' ' || *next2 == '\t') {
00146 p = g_utf8_next_char (next2);
00147 }
00148 else if(quotedprintable) {
00149 p = g_utf8_next_char (next);
00150 }
00151 else {
00152 str = g_string_append (str, CRLF);
00153 p = g_utf8_next_char (next);
00154 newline = TRUE;
00155 quotedprintable = FALSE;
00156 }
00157 }
00158 else if (*p == '=') {
00159 str = g_string_append_unichar (str, g_utf8_get_char (p));
00160 p = g_utf8_next_char (p);
00161 }
00162 else if (*next == ' ' || *next == '\t') {
00163 p = g_utf8_next_char (next);
00164 }
00165 else {
00166 str = g_string_append (str, CRLF);
00167 p = g_utf8_next_char (p);
00168 newline = TRUE;
00169 quotedprintable = FALSE;
00170 }
00171 }
00172 else {
00173 str = g_string_append_unichar (str, g_utf8_get_char (p));
00174 p = g_utf8_next_char (p);
00175 }
00176 }
00177
00178 g_free (buf);
00179 g_string_free(line, TRUE);
00180
00181 return g_string_free (str, FALSE);
00182 }
00183
00184
00185 static void _skip_to_next_line (char **p)
00186 {
00187 char *lp;
00188 lp = *p;
00189
00190 while (*lp != '\r' && *lp != '\0')
00191 lp = g_utf8_next_char (lp);
00192
00193 if (*lp == '\r') {
00194 lp = g_utf8_next_char (lp);
00195 lp = g_utf8_next_char (lp);
00196 }
00197
00198 *p = lp;
00199 }
00200
00201
00202
00203 static void _skip_until (char **p, char *s)
00204 {
00205 char *lp;
00206
00207 lp = *p;
00208
00209 while (*lp != '\r' && *lp != '\0') {
00210 gboolean s_matches = FALSE;
00211 char *ls;
00212 for (ls = s; *ls; ls = g_utf8_next_char (ls)) {
00213 if (g_utf8_get_char (ls) == g_utf8_get_char (lp)) {
00214 s_matches = TRUE;
00215 break;
00216 }
00217 }
00218
00219 if (s_matches)
00220 break;
00221 lp++;
00222 }
00223
00224 *p = lp;
00225 }
00226
00227 static void _read_attribute_value_add (b_VFormatAttribute *attr, GString *str, GString *charset)
00228 {
00229
00230 if (str->len == 0) {
00231 b_vformat_attribute_add_value(attr, str->str);
00232 return;
00233 }
00234
00235 char *inbuf, *outbuf, *p;
00236 size_t inbytesleft, outbytesleft;
00237
00238 inbuf = str->str;
00239 p = outbuf = malloc(str->len*2);
00240 inbytesleft = str->len;
00241 outbytesleft = str->len*2;
00242
00243 iconv_t cd;
00244
00245
00246 if (charset) {
00247
00248 cd = iconv_open("UTF-8", charset->str);
00249 #ifdef SOLARIS
00250 if (iconv(cd, (const char**)&inbuf, &inbytesleft, &p, &outbytesleft) != (size_t)(-1)) {
00251 #else
00252 if (iconv(cd, &inbuf, &inbytesleft, &p, &outbytesleft) != (size_t)(-1)) {
00253 #endif
00254 *p = 0;
00255 b_vformat_attribute_add_value(attr, outbuf);
00256
00257 } else {
00258
00259
00260 b_vformat_attribute_add_value(attr, str->str);
00261
00262 }
00263
00264 iconv_close(cd);
00265
00266 } else {
00267
00268
00269 if (g_utf8_validate (inbuf, -1, NULL)) {
00270
00271 b_vformat_attribute_add_value (attr, str->str);
00272
00273 } else {
00274
00275
00276 cd = iconv_open("UTF-8", "ISO-8859-1");
00277 #ifdef SOLARIS
00278 if (iconv(cd, (const char**)&inbuf, &inbytesleft, &p, &outbytesleft) != (size_t)(-1)) {
00279 #else
00280 if (iconv(cd, &inbuf, &inbytesleft, &p, &outbytesleft) != (size_t)(-1)) {
00281 #endif
00282 *p = 0;
00283 b_vformat_attribute_add_value (attr, outbuf);
00284
00285 } else {
00286
00287 b_vformat_attribute_add_value (attr, str->str);
00288
00289 }
00290
00291 iconv_close(cd);
00292
00293 }
00294
00295 }
00296
00297 free(outbuf);
00298
00299 }
00300
00301 static void _read_attribute_value (b_VFormatAttribute *attr, char **p, int format_encoding, GString *charset)
00302 {
00303 char *lp = *p;
00304 GString *str;
00305
00306
00307 str = g_string_new ("");
00308 while (*lp != '\r' && *lp != '\0') {
00309 if (*lp == '=' && format_encoding == VF_ENCODING_QP) {
00310 char a, b, x1=0, x2=0;
00311
00312 if ((a = *(++lp)) == '\0') break;
00313 if ((b = *(++lp)) == '\0') break;
00314
00315 if (isalnum(a)) {
00316 if (isalnum(b)) {
00317
00318
00319
00320 x1=a;
00321 x2=b;
00322 }
00323 else if (b == '=') {
00324
00325
00326
00327
00328
00329 char *tmplp = lp;
00330 if (*(++tmplp) == '\r' && *(++tmplp) == '\n' && isalnum(*(++tmplp))) {
00331 x1 = a;
00332 x2 = *tmplp;
00333 lp = tmplp;
00334 }
00335 }
00336 else {
00337
00338
00339 str = g_string_append_c(str, a);
00340 str = g_string_append_c(str, b);
00341 }
00342 }
00343 else if (a == '=') {
00344 char *tmplp = lp;
00345 char c, d, e;
00346 c = *(++tmplp);
00347 d = *(++tmplp);
00348 e = *(++tmplp);
00349 if (b == '\r' && c == '\n' && isalnum(d) && isalnum(e)) {
00350 x1 = d;
00351 x2 = e;
00352 lp = tmplp;
00353 }
00354 else {
00355
00356
00357 str = g_string_append_c(str, a);
00358 str = g_string_append_c(str, b);
00359 }
00360 }
00361 else {
00362
00363
00364 str = g_string_append_c(str, a);
00365 str = g_string_append_c(str, b);
00366 }
00367 if (x1 && x2) {
00368 char c;
00369
00370 a = tolower (x1);
00371 b = tolower (x2);
00372
00373 c = (((a>='a'?a-'a'+10:a-'0')&0x0f) << 4)
00374 | ((b>='a'?b-'a'+10:b-'0')&0x0f);
00375
00376 str = g_string_append_c (str, c);
00377 }
00378 lp++;
00379 x1 = x2 = 0;
00380 }
00381 else if (format_encoding == VF_ENCODING_BASE64) {
00382 if((*lp != ' ') && (*lp != '\t') )
00383 str = g_string_append_unichar (str, g_utf8_get_char (lp));
00384 lp = g_utf8_next_char(lp);
00385 }
00386 else if (*lp == '\\') {
00387
00388
00389 lp = g_utf8_next_char(lp);
00390 if (*lp == '\0') {
00391 str = g_string_append_c (str, '\\');
00392 break;
00393 }
00394 switch (*lp) {
00395 case 'n': str = g_string_append_c (str, '\n'); break;
00396 case 'r': str = g_string_append_c (str, '\r'); break;
00397 case ';': str = g_string_append_c (str, ';'); break;
00398 case ',':
00399 if (!g_ascii_strcasecmp (attr->name, "CATEGORIES")) {
00400
00401
00402 _read_attribute_value_add (attr, str, charset);
00403 g_string_assign (str, "");
00404 } else
00405 str = g_string_append_c (str, ',');
00406 break;
00407 case '\\': str = g_string_append_c (str, '\\'); break;
00408 case '"': str = g_string_append_c (str, '"'); break;
00409
00410 case 't': str = g_string_append_c (str, '\t'); break;
00411 default:
00412 BarryLogf(TRACE_INTERNAL, "invalid escape, passing it through. escaped char was %u", (unsigned int)*lp);
00413 str = g_string_append_c (str, '\\');
00414 str = g_string_append_unichar (str, g_utf8_get_char(lp));
00415 break;
00416 }
00417 lp = g_utf8_next_char(lp);
00418 }
00419 else if ((*lp == ';') ||
00420 (*lp == ',' && !g_ascii_strcasecmp (attr->name, "CATEGORIES"))) {
00421 _read_attribute_value_add (attr, str, charset);
00422 g_string_assign (str, "");
00423 lp = g_utf8_next_char(lp);
00424 }
00425 else {
00426 str = g_string_append_unichar (str, g_utf8_get_char (lp));
00427 lp = g_utf8_next_char(lp);
00428 }
00429 }
00430 if (str) {
00431 _read_attribute_value_add (attr, str, charset);
00432 g_string_free (str, TRUE);
00433 }
00434
00435 if (*lp == '\r') {
00436 lp = g_utf8_next_char (lp);
00437 lp = g_utf8_next_char (lp);
00438 }
00439
00440 *p = lp;
00441 }
00442
00443 static void _read_attribute_params(b_VFormatAttribute *attr, char **p, int *format_encoding, GString **charset)
00444 {
00445 char *lp = *p;
00446 GString *str;
00447 b_VFormatParam *param = NULL;
00448 gboolean in_quote = FALSE;
00449 str = g_string_new ("");
00450
00451 while (*lp != '\0') {
00452 if (*lp == '"') {
00453 in_quote = !in_quote;
00454 lp = g_utf8_next_char (lp);
00455 }
00456 else if (in_quote || g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_' || *lp == '/' || *lp == '.' || *lp == ' ') {
00457 str = g_string_append_unichar (str, g_utf8_get_char (lp));
00458 lp = g_utf8_next_char (lp);
00459 }
00460
00461
00462
00463
00464
00465
00466 else if (*lp == '=') {
00467 if (str->len > 0) {
00468 param = b_vformat_attribute_param_new (str->str);
00469 g_string_assign (str, "");
00470 lp = g_utf8_next_char (lp);
00471 }
00472 else {
00473 _skip_until (&lp, ":;");
00474 if (*lp == '\r') {
00475 lp = g_utf8_next_char (lp);
00476 lp = g_utf8_next_char (lp);
00477 break;
00478 }
00479 else if (*lp == ';')
00480 lp = g_utf8_next_char (lp);
00481 }
00482 }
00483 else if (*lp == ';' || *lp == ':' || *lp == ',') {
00484 gboolean colon = (*lp == ':');
00485 gboolean comma = (*lp == ',');
00486
00487 if (param) {
00488 if (str->len > 0) {
00489 b_vformat_attribute_param_add_value (param, str->str);
00490 g_string_assign (str, "");
00491 if (!colon)
00492 lp = g_utf8_next_char (lp);
00493 }
00494 else {
00495
00496
00497
00498
00499
00500
00501
00502
00503 if (!param->values) {
00504 b_vformat_attribute_param_free (param);
00505 param = NULL;
00506 if (!colon)
00507 lp = g_utf8_next_char (lp);
00508 }
00509 }
00510
00511 if (param
00512 && !g_ascii_strcasecmp (param->name, "encoding")) {
00513 if (!g_ascii_strcasecmp (param->values->data, "quoted-printable")) {
00514 *format_encoding = VF_ENCODING_QP;
00515 b_vformat_attribute_param_free (param);
00516 param = NULL;
00517 } else if ( _helper_is_base64(param->values->data)) {
00518 *format_encoding = VF_ENCODING_BASE64;
00519
00520
00521 }
00522 } else if (param && !g_ascii_strcasecmp(param->name, "charset")) {
00523 *charset = g_string_new(param->values->data);
00524 b_vformat_attribute_param_free (param);
00525 param = NULL;
00526 }
00527 }
00528 else {
00529 if (str->len > 0) {
00530 char *param_name;
00531 if (!g_ascii_strcasecmp (str->str,
00532 "quoted-printable")) {
00533 param_name = "ENCODING";
00534 *format_encoding = VF_ENCODING_QP;
00535 }
00536
00537
00538 else if (!g_ascii_strcasecmp (str->str,
00539 "base64")) {
00540 param_name = "ENCODING";
00541 g_string_assign (str, "b");
00542 *format_encoding = VF_ENCODING_BASE64;
00543 }
00544 else {
00545 param_name = "TYPE";
00546 }
00547
00548 if (param_name) {
00549 param = b_vformat_attribute_param_new (param_name);
00550 b_vformat_attribute_param_add_value (param, str->str);
00551 }
00552 g_string_assign (str, "");
00553 if (!colon)
00554 lp = g_utf8_next_char (lp);
00555 }
00556 else {
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569 if (!colon)
00570 lp = g_utf8_next_char (lp);
00571 }
00572 }
00573 if (param && !comma) {
00574 b_vformat_attribute_add_param (attr, param);
00575 param = NULL;
00576 }
00577 if (colon)
00578 break;
00579 }
00580 else {
00581 BarryLogf(TRACE_INTERNAL, "invalid character found in parameter spec: \"%i\" String so far: %s", lp[0], str->str);
00582 g_string_assign (str, "");
00583 _skip_until (&lp, ":;");
00584 }
00585 }
00586
00587 if (str)
00588 g_string_free (str, TRUE);
00589
00590 *p = lp;
00591 }
00592
00593
00594
00595 static b_VFormatAttribute *_read_attribute (char **p)
00596 {
00597 char *attr_group = NULL;
00598 char *attr_name = NULL;
00599 b_VFormatAttribute *attr = NULL;
00600 GString *str, *charset = NULL;
00601 char *lp = *p;
00602
00603 gboolean is_qp = FALSE;
00604
00605
00606 str = g_string_new ("");
00607 while (*lp != '\r' && *lp != '\0') {
00608 if (*lp == ':' || *lp == ';') {
00609 if (str->len != 0) {
00610
00611 attr_name = g_string_free (str, FALSE);
00612 break;
00613 }
00614 else {
00615
00616
00617
00618
00619
00620
00621
00622 g_string_free (str, TRUE);
00623 *p = lp;
00624 _skip_to_next_line(p);
00625 goto lose;
00626 }
00627 }
00628 else if (*lp == '.') {
00629 if (attr_group) {
00630 BarryLogf(TRACE_INTERNAL, "extra `.' in attribute specification. ignoring extra group `%s'", str->str);
00631 g_string_free (str, TRUE);
00632 str = g_string_new ("");
00633 }
00634 if (str->len != 0) {
00635 attr_group = g_string_free (str, FALSE);
00636 str = g_string_new ("");
00637 }
00638 }
00639 else if (g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_' || *lp == '/') {
00640 str = g_string_append_unichar (str, g_utf8_get_char (lp));
00641 }
00642 else {
00643 BarryLogf(TRACE_INTERNAL, "invalid character found in attribute group/name: \"%i\" String so far: %s", lp[0], str->str);
00644 g_string_free (str, TRUE);
00645 *p = lp;
00646 _skip_to_next_line(p);
00647 goto lose;
00648 }
00649
00650 lp = g_utf8_next_char(lp);
00651 }
00652
00653 if (!attr_name) {
00654 _skip_to_next_line (p);
00655 goto lose;
00656 }
00657
00658 attr = b_vformat_attribute_new (attr_group, attr_name);
00659 g_free (attr_group);
00660 g_free (attr_name);
00661
00662 if (*lp == ';') {
00663
00664 lp = g_utf8_next_char(lp);
00665 _read_attribute_params (attr, &lp, &is_qp, &charset);
00666 }
00667 if (*lp == ':') {
00668
00669 lp = g_utf8_next_char(lp);
00670 _read_attribute_value (attr, &lp, is_qp, charset);
00671 }
00672
00673 if (charset) g_string_free(charset, TRUE);
00674 *p = lp;
00675
00676 if (!attr->values)
00677 goto lose;
00678
00679 return attr;
00680 lose:
00681 if (attr)
00682 b_vformat_attribute_free (attr);
00683 return NULL;
00684 }
00685
00686 static void open_block(char **block, const char *block_name)
00687 {
00688 char *start = *block ? *block : "";
00689 char *result = NULL;
00690
00691 result = g_strconcat(start, "/", block_name, NULL);
00692 if( *block )
00693 g_free(*block);
00694 *block = result;
00695 }
00696
00697 static void close_block(char **block, const char *block_name)
00698 {
00699 int name_len = strlen(block_name);
00700 int block_len = *block ? strlen(*block) : 0;
00701 char *cmp_start = NULL;
00702
00703 if( block_len < name_len + 1 )
00704 return;
00705
00706 cmp_start = *block + (block_len - name_len - 1);
00707 if( cmp_start[0] == '/' &&
00708 g_ascii_strcasecmp(cmp_start+1, block_name) == 0 )
00709 {
00710
00711
00712
00713
00714 *cmp_start = '\0';
00715 }
00716 }
00717
00718
00719
00720
00721
00722 static void _parse(b_VFormat *evc, const char *str)
00723 {
00724 char *buf = g_strdup (str);
00725 char *p, *end;
00726 b_VFormatAttribute *attr;
00727
00728
00729 if (!g_utf8_validate (buf, -1, (const char **)&end)) {
00730
00731 BarryLogf(TRACE_INTERNAL, "invalid utf8 passed to b_VFormat. Limping along.");
00732 *end = '\0';
00733 }
00734
00735 buf = _fold_lines (buf);
00736
00737 p = buf;
00738
00739 attr = _read_attribute (&p);
00740 if (!attr)
00741 attr = _read_attribute (&p);
00742
00743 if (!attr || attr->group || g_ascii_strcasecmp (attr->name, "begin")) {
00744 BarryLogf(TRACE_INTERNAL, "vformat began without a BEGIN\n");
00745 }
00746 if (attr && !g_ascii_strcasecmp (attr->name, "begin"))
00747 b_vformat_attribute_free (attr);
00748 else if (attr)
00749 b_vformat_add_attribute (evc, attr);
00750
00751 char *block = NULL;
00752 while (*p) {
00753 b_VFormatAttribute *next_attr = _read_attribute (&p);
00754
00755 if (next_attr) {
00756 if( g_ascii_strcasecmp(next_attr->name, "begin") == 0 ) {
00757
00758 char *value = b_vformat_attribute_get_value(next_attr);
00759 open_block(&block, value);
00760
00761 g_free(value);
00762 }
00763 else if( g_ascii_strcasecmp(next_attr->name, "end") == 0 ) {
00764
00765 char *value = b_vformat_attribute_get_value(next_attr);
00766 close_block(&block, value);
00767
00768 g_free(value);
00769 }
00770
00771
00772 next_attr->block = g_strdup(block);
00773
00774
00775 b_vformat_add_attribute (evc, next_attr);
00776 attr = next_attr;
00777 }
00778 }
00779
00780 if (!attr || attr->group || g_ascii_strcasecmp (attr->name, "end")) {
00781 BarryLogf(TRACE_INTERNAL, "vformat ended without END");
00782 }
00783
00784 g_free (buf);
00785 g_free (block);
00786 }
00787
00788 char *b_vformat_escape_string (const char *s, b_VFormatType type)
00789 {
00790 GString *str;
00791 const char *p;
00792
00793 str = g_string_new ("");
00794
00795
00796 for (p = s; p && *p; p++) {
00797 switch (*p) {
00798 case '\n':
00799 str = g_string_append (str, "\\n");
00800 break;
00801 case '\r':
00802 if (*(p+1) == '\n')
00803 p++;
00804 str = g_string_append (str, "\\n");
00805 break;
00806 case ';':
00807 str = g_string_append (str, "\\;");
00808 break;
00809 case ',':
00810 if (type == VFORMAT_CARD_30 || type == VFORMAT_EVENT_20 || type == VFORMAT_TODO_20)
00811 str = g_string_append (str, "\\,");
00812 else
00813 str = g_string_append_c (str, *p);
00814 break;
00815 case '\\':
00816
00817
00818
00819
00820
00821 if (*p != '\0' && type == VFORMAT_CARD_21) {
00822 BarryLogf(TRACE_INTERNAL, "[%s]We won't escape backslashes", __func__);
00823 str = g_string_append_c(str, *p);
00824 }
00825 else {
00826 BarryLogf(TRACE_INTERNAL, "[%s] escape backslashes!!", __func__);
00827 str = g_string_append (str, "\\\\");
00828 }
00829 break;
00830 default:
00831 str = g_string_append_c (str, *p);
00832 break;
00833 }
00834 }
00835
00836 return g_string_free (str, FALSE);
00837 }
00838
00839 char*
00840 b_vformat_unescape_string (const char *s)
00841 {
00842 GString *str;
00843 const char *p;
00844
00845 g_return_val_if_fail (s != NULL, NULL);
00846
00847 str = g_string_new ("");
00848
00849
00850 for (p = s; *p; p++) {
00851 if (*p == '\\') {
00852 p++;
00853 if (*p == '\0') {
00854 str = g_string_append_c (str, '\\');
00855 break;
00856 }
00857 switch (*p) {
00858 case 'n': str = g_string_append_c (str, '\n'); break;
00859 case 'r': str = g_string_append_c (str, '\r'); break;
00860 case ';': str = g_string_append_c (str, ';'); break;
00861 case ',': str = g_string_append_c (str, ','); break;
00862 case '\\': str = g_string_append_c (str, '\\'); break;
00863 case '"': str = g_string_append_c (str, '"'); break;
00864
00865 case 't': str = g_string_append_c (str, '\t'); break;
00866 default:
00867 BarryLogf(TRACE_INTERNAL, "invalid escape, passing it through. escaped char was %u", (unsigned int)*p);
00868 str = g_string_append_c (str, '\\');
00869 str = g_string_append_unichar (str, g_utf8_get_char(p));
00870 break;
00871 }
00872 }
00873 }
00874
00875 return g_string_free (str, FALSE);
00876 }
00877
00878 void
00879 b_vformat_construct (b_VFormat *evc, const char *str)
00880 {
00881 g_return_if_fail (str != NULL);
00882
00883 if (*str)
00884 _parse (evc, str);
00885 }
00886
00887 void b_vformat_free(b_VFormat *format)
00888 {
00889 g_list_foreach (format->attributes, (GFunc)b_vformat_attribute_free, NULL);
00890 g_list_free (format->attributes);
00891 g_free(format);
00892 }
00893
00894 b_VFormat *b_vformat_new_from_string (const char *str)
00895 {
00896 g_return_val_if_fail (str != NULL, NULL);
00897 b_VFormat *evc = g_malloc0(sizeof(b_VFormat));
00898
00899 b_vformat_construct (evc, str);
00900
00901 return evc;
00902 }
00903
00904 b_VFormat *b_vformat_new(void)
00905 {
00906 return b_vformat_new_from_string ("");
00907 }
00908
00909 static int _block_match(b_VFormatAttribute *attr, const char *block)
00910 {
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920 int attr_len = attr->block ? strlen(attr->block) : 0;
00921 int block_len = block ? strlen(block) : 0;
00922
00923 if( block == NULL )
00924 return 1;
00925
00926 if( attr_len < block_len )
00927 return 0;
00928
00929 if( attr_len == 0 && block_len == 0 )
00930 return 1;
00931
00932 if( attr->block == NULL )
00933 return 0;
00934
00935 return g_ascii_strcasecmp(&attr->block[attr_len - block_len], block) == 0;
00936 }
00937
00938 b_VFormatAttribute *b_vformat_find_attribute(b_VFormat *vcard, const char *name, int nth, const char *block)
00939 {
00940 GList *attributes = b_vformat_get_attributes(vcard);
00941 GList *a = NULL;
00942 int i = 0;
00943 for (a = attributes; a; a = a->next) {
00944 b_VFormatAttribute *attr = a->data;
00945 if (!g_ascii_strcasecmp(b_vformat_attribute_get_name(attr), name)) {
00946 if( block == NULL || _block_match(attr, block) ) {
00947 if( i == nth )
00948 return attr;
00949 i++;
00950 }
00951 }
00952 }
00953 return NULL;
00954 }
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976 char *b_vformat_to_string (b_VFormat *evc, b_VFormatType type)
00977 {
00978 BarryLogf(TRACE_ENTRY, "%s(%p, %i)", __func__, evc, type);
00979 GList *l;
00980 GList *v;
00981
00982 GString *str = g_string_new ("");
00983
00984 switch (type) {
00985 case VFORMAT_CARD_21:
00986 str = g_string_append (str, "BEGIN:VCARD\r\nVERSION:2.1\r\n");
00987 break;
00988 case VFORMAT_CARD_30:
00989 str = g_string_append (str, "BEGIN:VCARD\r\nVERSION:3.0\r\n");
00990 break;
00991 case VFORMAT_TODO_10:
00992 case VFORMAT_EVENT_10:
00993 str = g_string_append (str, "BEGIN:VCALENDAR\r\nVERSION:1.0\r\n");
00994 break;
00995 case VFORMAT_TODO_20:
00996 case VFORMAT_EVENT_20:
00997 case VFORMAT_JOURNAL:
00998 str = g_string_append (str, "BEGIN:VCALENDAR\r\nVERSION:2.0\r\n");
00999 break;
01000 case VFORMAT_NOTE:
01001 str = g_string_append (str, "BEGIN:VNOTE\r\nVERSION:1.1\r\n");
01002 break;
01003 }
01004
01005 for (l = evc->attributes; l; l = l->next) {
01006 GList *p;
01007 b_VFormatAttribute *attr = l->data;
01008 GString *attr_str;
01009 int l;
01010 int format_encoding = VF_ENCODING_RAW;
01011
01012 attr_str = g_string_new ("");
01013
01014
01015
01016
01017
01018
01019 if (attr->group) {
01020 attr_str = g_string_append (attr_str, attr->group);
01021 attr_str = g_string_append_c (attr_str, '.');
01022 }
01023 attr_str = g_string_append (attr_str, attr->name);
01024
01025 for (p = attr->params; p; p = p->next) {
01026 b_VFormatParam *param = p->data;
01027
01028
01029
01030 if( type == VFORMAT_CARD_30 || type == VFORMAT_TODO_20
01031 || type == VFORMAT_EVENT_20 || type == VFORMAT_JOURNAL) {
01032
01033
01034
01035
01036
01037 if (!g_ascii_strcasecmp (param->name, "CHARSET"))
01038 continue;
01039 attr_str = g_string_append_c (attr_str, ';');
01040 attr_str = g_string_append (attr_str, param->name);
01041 if (param->values) {
01042 attr_str = g_string_append_c (attr_str, '=');
01043 }
01044 for (v = param->values; v; v = v->next) {
01045 if (_helper_is_base64((const char *) v->data)) {
01046 format_encoding = VF_ENCODING_BASE64;
01047
01048 v->data=g_strdup("B");
01049 }
01050
01051
01052
01053
01054 if (!g_ascii_strcasecmp (param->name, "ENCODING") && !g_ascii_strcasecmp ((char *) v->data, "QUOTED-PRINTABLE")) {
01055 BarryLogf(TRACE_ERROR, "%s false encoding QUOTED-PRINTABLE is not allowed", __func__);
01056 format_encoding = VF_ENCODING_QP;
01057 }
01058 attr_str = g_string_append (attr_str, v->data);
01059
01060 if (v->next)
01061 attr_str = g_string_append_c (attr_str, ',');
01062 }
01063 }
01064 else {
01065 attr_str = g_string_append_c (attr_str, ';');
01066
01067
01068
01069
01070
01071 gboolean must_have_type = FALSE;
01072 if (!g_ascii_strcasecmp (attr->name, "PHOTO") || !g_ascii_strcasecmp (attr->name, "LOGO") || !g_ascii_strcasecmp (attr->name, "SOUND") )
01073 must_have_type = TRUE;
01074 if ( must_have_type || g_ascii_strcasecmp (param->name, "TYPE") )
01075 attr_str = g_string_append (attr_str, param->name);
01076 if ( param->values && (must_have_type || g_ascii_strcasecmp (param->name, "TYPE")) )
01077 attr_str = g_string_append_c (attr_str, '=');
01078 for (v = param->values; v; v = v->next) {
01079
01080 if (!g_ascii_strcasecmp (param->name, "ENCODING") && !g_ascii_strcasecmp ((char *) v->data, "QUOTED-PRINTABLE"))
01081 format_encoding = VF_ENCODING_QP;
01082
01083 if (_helper_is_base64((const char *) v->data)) {
01084 format_encoding = VF_ENCODING_BASE64;
01085 v->data=g_strdup("BASE64");
01086 }
01087 attr_str = g_string_append (attr_str, v->data);
01088 if (v->next)
01089 attr_str = g_string_append_c (attr_str, ',');
01090 }
01091 }
01092 }
01093
01094 attr_str = g_string_append_c (attr_str, ':');
01095
01096 for (v = attr->values; v; v = v->next) {
01097 char *value = v->data;
01098 char *escaped_value = NULL;
01099
01100 if (!g_ascii_strcasecmp (attr->name, "RRULE") &&
01101 strstr (value, "BYDAY") == v->data) {
01102 attr_str = g_string_append (attr_str, value);
01103 } else {
01104 escaped_value = b_vformat_escape_string (value, type);
01105 attr_str = g_string_append (attr_str, escaped_value);
01106 }
01107
01108 if (v->next) {
01109
01110
01111
01112
01113 if (!g_ascii_strcasecmp (attr->name, "CATEGORIES"))
01114 attr_str = g_string_append_c (attr_str, ',');
01115 else
01116 attr_str = g_string_append_c (attr_str, ';');
01117 }
01118
01119 g_free (escaped_value);
01120 }
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163 l = 0;
01164 do {
01165 if (g_utf8_strlen(attr_str->str, attr_str->len) - l > 75) {
01166 l += 75;
01167
01168
01169 if (format_encoding == VF_ENCODING_QP) {
01170 if (g_utf8_get_char(g_utf8_offset_to_pointer(attr_str->str, l-1)) == '=') l--;
01171 else if (g_utf8_get_char(g_utf8_offset_to_pointer(attr_str->str, l-2)) == '=') l -= 2;
01172 }
01173
01174 char *p = g_utf8_offset_to_pointer(attr_str->str, l);
01175
01176 if (format_encoding == VF_ENCODING_QP)
01177 attr_str = g_string_insert_len (attr_str, p - attr_str->str, "=" CRLF "", sizeof ("=" CRLF "") - 1);
01178 else
01179 attr_str = g_string_insert_len (attr_str, p - attr_str->str, CRLF " ", sizeof (CRLF " ") - 1);
01180 }
01181 else
01182 break;
01183 } while (l < g_utf8_strlen(attr_str->str, attr_str->len));
01184
01185 attr_str = g_string_append (attr_str, CRLF);
01186
01187
01188
01189
01190
01191
01192 if( format_encoding == VF_ENCODING_BASE64
01193 && (type == VFORMAT_CARD_21))
01194 attr_str = g_string_append (attr_str, CRLF);
01195
01196 str = g_string_append (str, attr_str->str);
01197 g_string_free (attr_str, TRUE);
01198 }
01199
01200 switch (type) {
01201 case VFORMAT_CARD_21:
01202 str = g_string_append (str, "END:VCARD\r\n");
01203 break;
01204 case VFORMAT_CARD_30:
01205 str = g_string_append (str, "END:VCARD\r\n");
01206 break;
01207 case VFORMAT_TODO_10:
01208 case VFORMAT_EVENT_10:
01209 str = g_string_append (str, "END:VCALENDAR\r\n");
01210 break;
01211 case VFORMAT_TODO_20:
01212 case VFORMAT_EVENT_20:
01213 case VFORMAT_JOURNAL:
01214 str = g_string_append (str, "END:VCALENDAR\r\n");
01215 break;
01216 case VFORMAT_NOTE:
01217 str = g_string_append (str, "END:VNOTE\r\n");
01218 break;
01219 }
01220
01221 BarryLogf(TRACE_EXIT, "%s", __func__);
01222 return g_string_free (str, FALSE);
01223 }
01224
01225 void b_vformat_dump_structure (b_VFormat *evc)
01226 {
01227 GList *a;
01228 GList *v;
01229 int i;
01230
01231 printf ("b_VFormat\n");
01232 for (a = evc->attributes; a; a = a->next) {
01233 GList *p;
01234 b_VFormatAttribute *attr = a->data;
01235 printf ("+-- %s\n", attr->name);
01236 if (attr->params) {
01237 printf (" +- params=\n");
01238
01239 for (p = attr->params, i = 0; p; p = p->next, i++) {
01240 b_VFormatParam *param = p->data;
01241 printf (" | [%d] = %s", i,param->name);
01242 printf ("(");
01243 for (v = param->values; v; v = v->next) {
01244 char *value = b_vformat_escape_string ((char*)v->data, VFORMAT_CARD_21);
01245 printf ("%s", value);
01246 if (v->next)
01247 printf (",");
01248 g_free (value);
01249 }
01250
01251 printf (")\n");
01252 }
01253 }
01254 printf (" +- values=\n");
01255 for (v = attr->values, i = 0; v; v = v->next, i++) {
01256 printf (" [%d] = `%s'\n", i, (char*)v->data);
01257 }
01258 }
01259 }
01260
01261 b_VFormatAttribute *b_vformat_attribute_new (const char *attr_group, const char *attr_name)
01262 {
01263 b_VFormatAttribute *attr;
01264
01265 attr = g_new0 (b_VFormatAttribute, 1);
01266
01267 attr->group = g_strdup (attr_group);
01268 attr->name = g_strdup (attr_name);
01269
01270 return attr;
01271 }
01272
01273 void
01274 b_vformat_attribute_free (b_VFormatAttribute *attr)
01275 {
01276 g_return_if_fail (attr != NULL);
01277
01278 g_free (attr->block);
01279 g_free (attr->group);
01280 g_free (attr->name);
01281
01282 b_vformat_attribute_remove_values (attr);
01283
01284 b_vformat_attribute_remove_params (attr);
01285
01286 g_free (attr);
01287 }
01288
01289 b_VFormatAttribute*
01290 b_vformat_attribute_copy (b_VFormatAttribute *attr)
01291 {
01292 b_VFormatAttribute *a;
01293 GList *p;
01294
01295 g_return_val_if_fail (attr != NULL, NULL);
01296
01297 a = b_vformat_attribute_new (b_vformat_attribute_get_group (attr),
01298 b_vformat_attribute_get_name (attr));
01299
01300 for (p = attr->values; p; p = p->next)
01301 b_vformat_attribute_add_value (a, p->data);
01302
01303 for (p = attr->params; p; p = p->next)
01304 b_vformat_attribute_add_param (a, b_vformat_attribute_param_copy (p->data));
01305
01306 return a;
01307 }
01308
01309 void
01310 b_vformat_remove_attributes (b_VFormat *evc, const char *attr_group, const char *attr_name)
01311 {
01312 GList *attr;
01313
01314 g_return_if_fail (attr_name != NULL);
01315
01316 attr = evc->attributes;
01317 while (attr) {
01318 GList *next_attr;
01319 b_VFormatAttribute *a = attr->data;
01320
01321 next_attr = attr->next;
01322
01323 if (((!attr_group && !a->group) ||
01324 (attr_group && !g_ascii_strcasecmp (attr_group, a->group))) &&
01325 ((!attr_name && !a->name) || !g_ascii_strcasecmp (attr_name, a->name))) {
01326
01327
01328 evc->attributes = g_list_remove_link (evc->attributes, attr);
01329
01330 b_vformat_attribute_free (a);
01331 }
01332
01333 attr = next_attr;
01334 }
01335 }
01336
01337 void
01338 b_vformat_remove_attribute (b_VFormat *evc, b_VFormatAttribute *attr)
01339 {
01340 g_return_if_fail (attr != NULL);
01341
01342 evc->attributes = g_list_remove (evc->attributes, attr);
01343 b_vformat_attribute_free (attr);
01344 }
01345
01346 void
01347 b_vformat_add_attribute (b_VFormat *evc, b_VFormatAttribute *attr)
01348 {
01349 g_return_if_fail (attr != NULL);
01350
01351 evc->attributes = g_list_append (evc->attributes, attr);
01352 }
01353
01354 void
01355 b_vformat_add_attribute_with_value (b_VFormat *b_VFormat,
01356 b_VFormatAttribute *attr, const char *value)
01357 {
01358 g_return_if_fail (attr != NULL);
01359
01360 b_vformat_attribute_add_value (attr, value);
01361
01362 b_vformat_add_attribute (b_VFormat, attr);
01363 }
01364
01365 void
01366 b_vformat_add_attribute_with_values (b_VFormat *b_VFormat, b_VFormatAttribute *attr, ...)
01367 {
01368 va_list ap;
01369 char *v;
01370
01371 g_return_if_fail (attr != NULL);
01372
01373 va_start (ap, attr);
01374
01375 while ((v = va_arg (ap, char*))) {
01376 b_vformat_attribute_add_value (attr, v);
01377 }
01378
01379 va_end (ap);
01380
01381 b_vformat_add_attribute (b_VFormat, attr);
01382 }
01383
01384 void
01385 b_vformat_attribute_add_value (b_VFormatAttribute *attr, const char *value)
01386 {
01387 g_return_if_fail (attr != NULL);
01388
01389 attr->values = g_list_append (attr->values, g_strdup (value));
01390 }
01391
01392 void
01393 b_vformat_attribute_add_value_decoded (b_VFormatAttribute *attr, const char *value, int len)
01394 {
01395 g_return_if_fail (attr != NULL);
01396
01397 switch (attr->encoding) {
01398 case VF_ENCODING_RAW:
01399 BarryLogf(TRACE_INTERNAL, "can't add_value_decoded with an attribute using RAW encoding. you must set the ENCODING parameter first");
01400 break;
01401 case VF_ENCODING_BASE64: {
01402 char *b64_data = base64_encode_simple (value, len);
01403 GString *decoded = g_string_new_len (value, len);
01404
01405
01406 b_vformat_attribute_get_values_decoded (attr);
01407
01408 attr->values = g_list_append (attr->values, b64_data);
01409 attr->decoded_values = g_list_append (attr->decoded_values, decoded);
01410 break;
01411 }
01412 case VF_ENCODING_QP: {
01413 char *qp_data = quoted_encode_simple ((unsigned char*)value, len);
01414 GString *decoded = g_string_new (value);
01415
01416
01417 b_vformat_attribute_get_values_decoded (attr);
01418
01419 attr->values = g_list_append (attr->values, qp_data);
01420 attr->decoded_values = g_list_append (attr->decoded_values, decoded);
01421 break;
01422 }
01423 case VF_ENCODING_8BIT: {
01424 char *data = g_strdup(value);
01425 GString *decoded = g_string_new (value);
01426
01427
01428 b_vformat_attribute_get_values_decoded (attr);
01429
01430 attr->values = g_list_append (attr->values, data);
01431 attr->decoded_values = g_list_append (attr->decoded_values, decoded);
01432 break;
01433 }
01434 }
01435 }
01436
01437 void
01438 b_vformat_attribute_add_values (b_VFormatAttribute *attr, ...)
01439 {
01440 va_list ap;
01441 char *v;
01442
01443 g_return_if_fail (attr != NULL);
01444
01445 va_start (ap, attr);
01446
01447 while ((v = va_arg (ap, char*))) {
01448 b_vformat_attribute_add_value (attr, v);
01449 }
01450
01451 va_end (ap);
01452 }
01453
01454 static void
01455 free_gstring (GString *str)
01456 {
01457 g_string_free (str, TRUE);
01458 }
01459
01460 void
01461 b_vformat_attribute_remove_values (b_VFormatAttribute *attr)
01462 {
01463 g_return_if_fail (attr != NULL);
01464
01465 g_list_foreach (attr->values, (GFunc)g_free, NULL);
01466 g_list_free (attr->values);
01467 attr->values = NULL;
01468
01469 g_list_foreach (attr->decoded_values, (GFunc)free_gstring, NULL);
01470 g_list_free (attr->decoded_values);
01471 attr->decoded_values = NULL;
01472 }
01473
01474 void
01475 b_vformat_attribute_remove_params (b_VFormatAttribute *attr)
01476 {
01477 g_return_if_fail (attr != NULL);
01478
01479 g_list_foreach (attr->params, (GFunc)b_vformat_attribute_param_free, NULL);
01480 g_list_free (attr->params);
01481 attr->params = NULL;
01482
01483
01484 attr->encoding_set = FALSE;
01485 attr->encoding = VF_ENCODING_RAW;
01486 }
01487
01488 b_VFormatParam*
01489 b_vformat_attribute_param_new (const char *name)
01490 {
01491 b_VFormatParam *param = g_new0 (b_VFormatParam, 1);
01492 param->name = g_strdup (name);
01493
01494 return param;
01495 }
01496
01497 void
01498 b_vformat_attribute_param_free (b_VFormatParam *param)
01499 {
01500 g_return_if_fail (param != NULL);
01501
01502 g_free (param->name);
01503
01504 b_vformat_attribute_param_remove_values (param);
01505
01506 g_free (param);
01507 }
01508
01509 b_VFormatParam*
01510 b_vformat_attribute_param_copy (b_VFormatParam *param)
01511 {
01512 b_VFormatParam *p;
01513 GList *l;
01514
01515 g_return_val_if_fail (param != NULL, NULL);
01516
01517 p = b_vformat_attribute_param_new (b_vformat_attribute_param_get_name (param));
01518
01519 for (l = param->values; l; l = l->next) {
01520 b_vformat_attribute_param_add_value (p, l->data);
01521 }
01522
01523 return p;
01524 }
01525
01526 void
01527 b_vformat_attribute_add_param (b_VFormatAttribute *attr,
01528 b_VFormatParam *param)
01529 {
01530 g_return_if_fail (attr != NULL);
01531 g_return_if_fail (param != NULL);
01532
01533 attr->params = g_list_append (attr->params, param);
01534
01535
01536
01537 if (!g_ascii_strcasecmp (param->name, "ENCODING")) {
01538 if (attr->encoding_set) {
01539 BarryLogf(TRACE_INTERNAL, "ENCODING specified twice");
01540 return;
01541 }
01542
01543 if (param->values && param->values->data) {
01544 if (_helper_is_base64((const char*)param->values->data))
01545 attr->encoding = VF_ENCODING_BASE64;
01546 else if (!g_ascii_strcasecmp ((char*)param->values->data, "QUOTED-PRINTABLE"))
01547 attr->encoding = VF_ENCODING_QP;
01548 else if (!g_ascii_strcasecmp ((char *)param->values->data, "8BIT"))
01549 attr->encoding = VF_ENCODING_8BIT;
01550 else {
01551 BarryLogf(TRACE_INTERNAL, "Unknown value `%s' for ENCODING parameter. values will be treated as raw", (char*)param->values->data);
01552 }
01553
01554 attr->encoding_set = TRUE;
01555 }
01556 else {
01557 BarryLogf(TRACE_INTERNAL, "ENCODING parameter added with no value");
01558 }
01559 }
01560 }
01561
01562 b_VFormatParam *b_vformat_attribute_find_param(b_VFormatAttribute *attr, const char *name, int level)
01563 {
01564 g_return_val_if_fail (attr != NULL, NULL);
01565 GList *p = NULL;
01566 for (p = attr->params; p; p = p->next) {
01567 b_VFormatParam *param = p->data;
01568 if (!g_ascii_strcasecmp (param->name, name)) {
01569 if( level == 0 )
01570 return param;
01571 else
01572 level--;
01573 }
01574 }
01575 return NULL;
01576 }
01577
01578 void
01579 b_vformat_attribute_set_value (b_VFormatAttribute *attr,
01580 int nth, const char *value)
01581 {
01582 GList *param = g_list_nth(attr->values, nth);
01583 g_free(param->data);
01584 param->data = g_strdup(value);
01585 }
01586
01587 void
01588 b_vformat_attribute_param_add_value (b_VFormatParam *param,
01589 const char *value)
01590 {
01591 g_return_if_fail (param != NULL);
01592
01593 param->values = g_list_append (param->values, g_strdup (value));
01594 }
01595
01596 void
01597 b_vformat_attribute_param_add_values (b_VFormatParam *param,
01598 ...)
01599 {
01600 va_list ap;
01601 char *v;
01602
01603 g_return_if_fail (param != NULL);
01604
01605 va_start (ap, param);
01606
01607 while ((v = va_arg (ap, char*))) {
01608 b_vformat_attribute_param_add_value (param, v);
01609 }
01610
01611 va_end (ap);
01612 }
01613
01614 void
01615 b_vformat_attribute_add_param_with_value (b_VFormatAttribute *attr, const char *name, const char *value)
01616 {
01617 g_return_if_fail (attr != NULL);
01618 g_return_if_fail (name != NULL);
01619
01620 if (!value)
01621 return;
01622
01623 b_VFormatParam *param = b_vformat_attribute_param_new(name);
01624
01625 b_vformat_attribute_param_add_value (param, value);
01626
01627 b_vformat_attribute_add_param (attr, param);
01628 }
01629
01630 void
01631 b_vformat_attribute_add_param_with_values (b_VFormatAttribute *attr,
01632 b_VFormatParam *param, ...)
01633 {
01634 va_list ap;
01635 char *v;
01636
01637 g_return_if_fail (attr != NULL);
01638 g_return_if_fail (param != NULL);
01639
01640 va_start (ap, param);
01641
01642 while ((v = va_arg (ap, char*))) {
01643 b_vformat_attribute_param_add_value (param, v);
01644 }
01645
01646 va_end (ap);
01647
01648 b_vformat_attribute_add_param (attr, param);
01649 }
01650
01651 void
01652 b_vformat_attribute_param_remove_values (b_VFormatParam *param)
01653 {
01654 g_return_if_fail (param != NULL);
01655
01656 g_list_foreach (param->values, (GFunc)g_free, NULL);
01657 g_list_free (param->values);
01658 param->values = NULL;
01659 }
01660
01661 GList*
01662 b_vformat_get_attributes (b_VFormat *format)
01663 {
01664 return format->attributes;
01665 }
01666
01667 const char*
01668 b_vformat_attribute_get_group (b_VFormatAttribute *attr)
01669 {
01670 g_return_val_if_fail (attr != NULL, NULL);
01671
01672 return attr->group;
01673 }
01674
01675 const char*
01676 b_vformat_attribute_get_name (b_VFormatAttribute *attr)
01677 {
01678 g_return_val_if_fail (attr != NULL, NULL);
01679
01680 return attr->name;
01681 }
01682
01683 const char*
01684 b_vformat_attribute_get_block (b_VFormatAttribute *attr)
01685 {
01686 g_return_val_if_fail (attr != NULL, NULL);
01687
01688 return attr->block;
01689 }
01690
01691 GList*
01692 b_vformat_attribute_get_values (b_VFormatAttribute *attr)
01693 {
01694 g_return_val_if_fail (attr != NULL, NULL);
01695
01696 return attr->values;
01697 }
01698
01699 GList*
01700 b_vformat_attribute_get_values_decoded (b_VFormatAttribute *attr)
01701 {
01702 g_return_val_if_fail (attr != NULL, NULL);
01703
01704 if (!attr->decoded_values) {
01705 GList *l;
01706 switch (attr->encoding) {
01707 case VF_ENCODING_RAW:
01708 case VF_ENCODING_8BIT:
01709 for (l = attr->values; l; l = l->next)
01710 attr->decoded_values = g_list_append (attr->decoded_values, g_string_new ((char*)l->data));
01711 break;
01712 case VF_ENCODING_BASE64:
01713 for (l = attr->values; l; l = l->next) {
01714 char *decoded = g_strdup ((char*)l->data);
01715 int len = base64_decode_simple (decoded, strlen (decoded));
01716 attr->decoded_values = g_list_append (attr->decoded_values, g_string_new_len (decoded, len));
01717 g_free (decoded);
01718 }
01719 break;
01720 case VF_ENCODING_QP:
01721 for (l = attr->values; l; l = l->next) {
01722 if (!(l->data))
01723 continue;
01724 char *decoded = g_strdup ((char*)l->data);
01725 int len = quoted_decode_simple (decoded, strlen (decoded));
01726 attr->decoded_values = g_list_append (attr->decoded_values, g_string_new_len (decoded, len));
01727 g_free (decoded);
01728 }
01729 break;
01730 }
01731 }
01732
01733 return attr->decoded_values;
01734 }
01735
01736 gboolean
01737 b_vformat_attribute_is_single_valued (b_VFormatAttribute *attr)
01738 {
01739 g_return_val_if_fail (attr != NULL, FALSE);
01740
01741 if (attr->values == NULL
01742 || attr->values->next != NULL)
01743 return FALSE;
01744
01745 return TRUE;
01746 }
01747
01748 char*
01749 b_vformat_attribute_get_value (b_VFormatAttribute *attr)
01750 {
01751 GList *values;
01752
01753 g_return_val_if_fail (attr != NULL, NULL);
01754
01755 values = b_vformat_attribute_get_values (attr);
01756
01757 if (!b_vformat_attribute_is_single_valued (attr))
01758 BarryLogf(TRACE_INTERNAL, "b_vformat_attribute_get_value called on multivalued attribute");
01759
01760 return values ? g_strdup ((char*)values->data) : NULL;
01761 }
01762
01763 GString*
01764 b_vformat_attribute_get_value_decoded (b_VFormatAttribute *attr)
01765 {
01766 GList *values;
01767 GString *str = NULL;
01768
01769 g_return_val_if_fail (attr != NULL, NULL);
01770
01771 values = b_vformat_attribute_get_values_decoded (attr);
01772
01773 if (!b_vformat_attribute_is_single_valued (attr))
01774 BarryLogf(TRACE_INTERNAL, "b_vformat_attribute_get_value_decoded called on multivalued attribute");
01775
01776 if (values)
01777 str = values->data;
01778
01779 return str ? g_string_new_len (str->str, str->len) : NULL;
01780 }
01781
01782 const char *b_vformat_attribute_get_nth_value(b_VFormatAttribute *attr, int nth)
01783 {
01784 GList *values = b_vformat_attribute_get_values_decoded(attr);
01785 if (!values)
01786 return NULL;
01787 GString *retstr = (GString *)g_list_nth_data(values, nth);
01788 if (!retstr)
01789 return NULL;
01790
01791 if (!g_utf8_validate(retstr->str, -1, NULL)) {
01792 values = b_vformat_attribute_get_values(attr);
01793 if (!values)
01794 return NULL;
01795 return g_list_nth_data(values, nth);
01796 }
01797
01798 return retstr->str;
01799 }
01800
01801 gboolean
01802 b_vformat_attribute_has_type (b_VFormatAttribute *attr, const char *typestr)
01803 {
01804 GList *params;
01805 GList *p;
01806
01807 g_return_val_if_fail (attr != NULL, FALSE);
01808 g_return_val_if_fail (typestr != NULL, FALSE);
01809
01810 params = b_vformat_attribute_get_params (attr);
01811
01812 for (p = params; p; p = p->next) {
01813 b_VFormatParam *param = p->data;
01814
01815 if (!strcasecmp (b_vformat_attribute_param_get_name (param), "TYPE")) {
01816 GList *values = b_vformat_attribute_param_get_values (param);
01817 GList *v;
01818
01819 for (v = values; v; v = v->next) {
01820 if (!strcasecmp ((char*)v->data, typestr))
01821 return TRUE;
01822 }
01823 }
01824 }
01825
01826 return FALSE;
01827 }
01828
01829
01830 gboolean b_vformat_attribute_has_param(b_VFormatAttribute *attr, const char *name)
01831 {
01832 g_return_val_if_fail (attr != NULL, FALSE);
01833 g_return_val_if_fail (name != NULL, FALSE);
01834
01835 GList *params = b_vformat_attribute_get_params(attr);
01836 GList *p;
01837 for (p = params; p; p = p->next) {
01838 b_VFormatParam *param = p->data;
01839 if (!strcasecmp(name, b_vformat_attribute_param_get_name(param)))
01840 return TRUE;
01841 }
01842 return FALSE;
01843 }
01844
01845 GList*
01846 b_vformat_attribute_get_params (b_VFormatAttribute *attr)
01847 {
01848 g_return_val_if_fail (attr != NULL, NULL);
01849
01850 return attr->params;
01851 }
01852
01853 const char*
01854 b_vformat_attribute_param_get_name (b_VFormatParam *param)
01855 {
01856 g_return_val_if_fail (param != NULL, NULL);
01857
01858 return param->name;
01859 }
01860
01861 GList*
01862 b_vformat_attribute_param_get_values (b_VFormatParam *param)
01863 {
01864 g_return_val_if_fail (param != NULL, NULL);
01865
01866 return param->values;
01867 }
01868
01869 const char *b_vformat_attribute_param_get_nth_value(b_VFormatParam *param, int nth)
01870 {
01871 const char *ret = NULL;
01872 GList *values = b_vformat_attribute_param_get_values(param);
01873 if (!values)
01874 return NULL;
01875 ret = g_list_nth_data(values, nth);
01876 return ret;
01877 }
01878
01879 static const char *base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
01880
01881
01882
01883 static void base64_init(char *rank)
01884 {
01885 int i;
01886
01887 memset(rank, 0xff, sizeof(rank));
01888 for (i=0;i<64;i++) {
01889 rank[(unsigned int)base64_alphabet[i]] = i;
01890 }
01891 rank['='] = 0;
01892 }
01893
01894
01895
01896 static size_t base64_encode_close(const unsigned char *in, size_t inlen, gboolean break_lines, unsigned char *out, int *state, int *save)
01897 {
01898 int c1, c2;
01899 unsigned char *outptr = out;
01900
01901 if (inlen>0)
01902 outptr += base64_encode_step(in, inlen, break_lines, outptr, state, save);
01903
01904 c1 = ((unsigned char *)save)[1];
01905 c2 = ((unsigned char *)save)[2];
01906
01907 switch (((char *)save)[0]) {
01908 case 2:
01909 outptr[2] = base64_alphabet[ ( (c2 &0x0f) << 2 ) ];
01910 g_assert(outptr[2] != 0);
01911 goto skip;
01912 case 1:
01913 outptr[2] = '=';
01914 skip:
01915 outptr[0] = base64_alphabet[ c1 >> 2 ];
01916 outptr[1] = base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 )];
01917 outptr[3] = '=';
01918 outptr += 4;
01919 break;
01920 }
01921 if (break_lines)
01922 *outptr++ = '\n';
01923
01924 *save = 0;
01925 *state = 0;
01926
01927 return outptr-out;
01928 }
01929
01930
01931
01932
01933
01934
01935 static size_t base64_encode_step(const unsigned char *in, size_t len, gboolean break_lines, unsigned char *out, int *state, int *save)
01936 {
01937 register const unsigned char *inptr;
01938 register unsigned char *outptr;
01939
01940 if (len<=0)
01941 return 0;
01942
01943 inptr = in;
01944 outptr = out;
01945
01946 if (len + ((char *)save)[0] > 2) {
01947 const unsigned char *inend = in+len-2;
01948 register int c1, c2, c3;
01949 register int already;
01950
01951 already = *state;
01952
01953 switch (((char *)save)[0]) {
01954 case 1: c1 = ((unsigned char *)save)[1]; goto skip1;
01955 case 2: c1 = ((unsigned char *)save)[1];
01956 c2 = ((unsigned char *)save)[2]; goto skip2;
01957 }
01958
01959
01960 while (inptr < inend) {
01961 c1 = *inptr++;
01962 skip1:
01963 c2 = *inptr++;
01964 skip2:
01965 c3 = *inptr++;
01966 *outptr++ = base64_alphabet[ c1 >> 2 ];
01967 *outptr++ = base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 ) ];
01968 *outptr++ = base64_alphabet[ ( (c2 &0x0f) << 2 ) | (c3 >> 6) ];
01969 *outptr++ = base64_alphabet[ c3 & 0x3f ];
01970
01971 if (break_lines && (++already)>=19) {
01972 *outptr++='\n';
01973 already = 0;
01974 }
01975 }
01976
01977 ((char *)save)[0] = 0;
01978 len = 2-(inptr-inend);
01979 *state = already;
01980 }
01981
01982 if (len>0) {
01983 register char *saveout;
01984
01985
01986 saveout = & (((char *)save)[1]) + ((char *)save)[0];
01987
01988
01989 switch(len) {
01990 case 2: *saveout++ = *inptr++;
01991 case 1: *saveout++ = *inptr++;
01992 }
01993 ((char *)save)[0]+=len;
01994 }
01995
01996 return outptr-out;
01997 }
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007
02008
02009
02010 static size_t base64_decode_step(const unsigned char *in, size_t len, unsigned char *out, int *state, unsigned int *save)
02011 {
02012 unsigned char base64_rank[256];
02013 base64_init((char*)base64_rank);
02014
02015 register const unsigned char *inptr;
02016 register unsigned char *outptr;
02017 const unsigned char *inend;
02018 unsigned char c;
02019 register unsigned int v;
02020 int i;
02021
02022 inend = in+len;
02023 outptr = out;
02024
02025
02026 v=*save;
02027 i=*state;
02028 inptr = in;
02029 while (inptr<inend) {
02030 c = base64_rank[*inptr++];
02031 if (c != 0xff) {
02032 v = (v<<6) | c;
02033 i++;
02034 if (i==4) {
02035 *outptr++ = v>>16;
02036 *outptr++ = v>>8;
02037 *outptr++ = v;
02038 i=0;
02039 }
02040 }
02041 }
02042
02043 *save = v;
02044 *state = i;
02045
02046
02047
02048 i=2;
02049 while (inptr>in && i) {
02050 inptr--;
02051 if (base64_rank[*inptr] != 0xff) {
02052 if (*inptr == '=' && outptr>out)
02053 outptr--;
02054 i--;
02055 }
02056 }
02057
02058
02059 return outptr-out;
02060 }
02061
02062 static char *base64_encode_simple (const char *data, size_t len)
02063 {
02064 unsigned char *out;
02065 int state = 0, outlen;
02066 unsigned int save = 0;
02067
02068 g_return_val_if_fail (data != NULL, NULL);
02069
02070 out = g_malloc (len * 4 / 3 + 5);
02071 outlen = base64_encode_close ((unsigned char *)data, len, FALSE,
02072 out, &state, (int*)&save);
02073 out[outlen] = '\0';
02074 return (char *)out;
02075 }
02076
02077 static size_t base64_decode_simple (char *data, size_t len)
02078 {
02079 int state = 0;
02080 unsigned int save = 0;
02081
02082 g_return_val_if_fail (data != NULL, 0);
02083
02084 return base64_decode_step ((unsigned char *)data, len,
02085 (unsigned char *)data, &state, &save);
02086 }
02087
02088 static char *quoted_encode_simple(const unsigned char *string, int len)
02089 {
02090 GString *tmp = g_string_new("");
02091
02092 int i = 0;
02093 while(string[i] != 0) {
02094 if (string[i] > 127 || string[i] == 13 || string[i] == 10 || string[i] == '=') {
02095 g_string_append_printf(tmp, "=%02X", string[i]);
02096 } else {
02097 g_string_append_c(tmp, string[i]);
02098 }
02099 i++;
02100 }
02101
02102 char *ret = tmp->str;
02103 g_string_free(tmp, FALSE);
02104 return ret;
02105 }
02106
02107
02108 static size_t quoted_decode_simple (char *data, size_t len)
02109 {
02110 g_return_val_if_fail (data != NULL, 0);
02111
02112 GString *string = g_string_new(data);
02113 if (!string)
02114 return 0;
02115
02116 char hex[5];
02117 hex[4] = 0;
02118
02119 while (1) {
02120
02121 int i = strcspn(string->str, "=");
02122 if (i >= strlen(string->str))
02123 break;
02124
02125 strcpy(hex, "0x");
02126 strncat(hex, &string->str[i + 1], 2);
02127 char rep = ((int)(strtod(hex, NULL)));
02128 g_string_erase(string, i, 2);
02129 g_string_insert_c(string, i, rep);
02130 }
02131
02132 memset(data, 0, strlen(data));
02133 strcpy(data, string->str);
02134 g_string_free(string, 1);
02135
02136 return strlen(data);
02137 }