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