Mercurial > libpst
comparison src/pst2ldif.cpp @ 99:b7f456946c5b
add configure option --enable-dii=no to remove dependency on libgd.
many fixes in pst2ldif by Robert Harris.
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Sun, 28 Sep 2008 17:08:52 -0700 |
parents | 56fa05fd5271 |
children | 39ba19372732 |
comparison
equal
deleted
inserted
replaced
98:e12db0edd80a | 99:b7f456946c5b |
---|---|
18 #include "libstrfunc.h" | 18 #include "libstrfunc.h" |
19 #include "libpst.h" | 19 #include "libpst.h" |
20 #include "common.h" | 20 #include "common.h" |
21 #include "timeconv.h" | 21 #include "timeconv.h" |
22 #include "lzfu.h" | 22 #include "lzfu.h" |
23 } | 23 #include "stdarg.h" |
24 | 24 #include "iconv.h" |
25 int32_t usage(); | 25 } |
26 int32_t version(); | 26 |
27 char *my_stristr(char *haystack, char *needle); | 27 int32_t usage(); |
28 int32_t version(); | |
28 char *check_filename(char *fname); | 29 char *check_filename(char *fname); |
29 const char *single(char *str); | 30 char *dn_escape(const char *str); |
30 const char *folded(char *str); | 31 void print_ldif(const char *dn, const char *value); |
31 void multi(const char *fmt, char *str); | 32 void print_ldif_single(const char *dn, const char *value); |
32 char *rfc2426_escape(char *str); | 33 void print_ldif_multi(const char *dn, const char *value); |
33 int32_t chr_count(char *str, char x); | 34 void print_ldif_two(const char *dn, const char *value1, const char *value2); |
35 void build_cn(char *cn, size_t len, int nvalues, char *value, ...); | |
34 | 36 |
35 char *prog_name; | 37 char *prog_name; |
36 pst_file pstfile; | 38 pst_file pstfile; |
37 char *ldap_base = NULL; // 'o=some.domain.tld, c=US' | 39 char *ldap_base = NULL; // 'o=some.domain.tld, c=US' |
38 char *ldap_class = NULL; // 'newPerson' | 40 char *ldap_class = NULL; // 'newPerson' |
39 char *ldap_org = NULL; // 'o=some.domain.tld', computed from ldap_base | 41 char *ldap_org = NULL; // 'some.domain.tld', computed from ldap_base |
42 iconv_t cd = 0; // Character set conversion descriptor | |
40 | 43 |
41 | 44 |
42 //////////////////////////////////////////////// | 45 //////////////////////////////////////////////// |
43 // define our ordering | 46 // define our ordering |
44 struct ltstr { | 47 struct ltstr { |
74 if (i != s.end()) return *i; | 77 if (i != s.end()) return *i; |
75 char *x = strdup(name); | 78 char *x = strdup(name); |
76 s.insert(x); | 79 s.insert(x); |
77 return x; | 80 return x; |
78 } | 81 } |
82 | |
79 | 83 |
80 //////////////////////////////////////////////// | 84 //////////////////////////////////////////////// |
81 // register a global string | 85 // register a global string |
82 // | 86 // |
83 static const char* register_string(const char *name); | 87 static const char* register_string(const char *name); |
101 if (i == all_strings.end()) return register_string(n); | 105 if (i == all_strings.end()) return register_string(n); |
102 } | 106 } |
103 } | 107 } |
104 | 108 |
105 | 109 |
106 //////////////////////////////////////////////// | |
107 // remove leading and trailing blanks | |
108 // | |
109 static char *trim(char *name); | |
110 static char *trim(char *name) { | |
111 char *p; | |
112 while (*name == ' ') name++; | |
113 p = name + strlen(name) - 1; | |
114 while ((p >= name) && (*p == ' ')) *p-- = '\0'; | |
115 return name; | |
116 } | |
117 | |
118 | |
119 static void process(pst_desc_ll *d_ptr); | 110 static void process(pst_desc_ll *d_ptr); |
120 static void process(pst_desc_ll *d_ptr) { | 111 static void process(pst_desc_ll *d_ptr) { |
121 pst_item *item = NULL; | 112 pst_item *item = NULL; |
122 while (d_ptr) { | 113 while (d_ptr) { |
123 if (d_ptr->desc) { | 114 if (d_ptr->desc) { |
130 process(d_ptr->child); | 121 process(d_ptr->child); |
131 | 122 |
132 } else if (item->contact && (item->type == PST_TYPE_CONTACT)) { | 123 } else if (item->contact && (item->type == PST_TYPE_CONTACT)) { |
133 // deal with a contact | 124 // deal with a contact |
134 char cn[1000]; | 125 char cn[1000]; |
135 snprintf(cn, sizeof(cn), "%s %s %s %s", | 126 build_cn(cn, sizeof(cn), 4, |
136 single(item->contact->display_name_prefix), | 127 item->contact->display_name_prefix, |
137 single(item->contact->first_name), | 128 item->contact->first_name, |
138 single(item->contact->surname), | 129 item->contact->surname, |
139 single(item->contact->suffix)); | 130 item->contact->suffix); |
140 if (strcmp(cn, " ")) { | 131 if (cn[0] != 0) { |
141 // have a valid cn | 132 // have a valid cn |
142 const char *ucn = unique_string(folded(trim(cn))); | 133 const char *ucn = unique_string(cn); |
143 printf("dn: cn=%s, %s\n", ucn, ldap_base); | 134 char dn[strlen(ucn) + strlen(ldap_base) + 6]; |
144 printf("cn: %s\n", ucn); | 135 |
136 sprintf(dn, "cn=%s, %s", ucn, ldap_base); | |
137 print_ldif_single("dn", dn); | |
138 print_ldif_single("cn", ucn); | |
145 if (item->contact->first_name) { | 139 if (item->contact->first_name) { |
146 snprintf(cn, sizeof(cn), "%s %s", | 140 print_ldif_two("givenName", |
147 single(item->contact->display_name_prefix), | 141 item->contact->display_name_prefix, |
148 single(item->contact->first_name)); | 142 item->contact->first_name); |
149 printf("givenName: %s\n", trim(cn)); | |
150 } | 143 } |
151 if (item->contact->surname) { | 144 if (item->contact->surname) { |
152 snprintf(cn, sizeof(cn), "%s %s", | 145 print_ldif_two("sn", |
153 single(item->contact->surname), | 146 item->contact->surname, |
154 single(item->contact->suffix)); | 147 item->contact->suffix); |
155 printf("sn: %s\n", trim(cn)); | |
156 } | 148 } |
157 else if (item->contact->company_name) { | 149 else if (item->contact->company_name) { |
158 printf("sn: %s\n", single(item->contact->company_name)); | 150 print_ldif_single("sn", item->contact->company_name); |
159 } | 151 } |
160 else | 152 else |
161 printf("sn: %s\n", ucn); // use cn as sn if we cannot find something better | 153 print_ldif_single("sn", ucn); // use cn as sn if we cannot find something better |
162 | 154 |
163 if (item->contact->job_title) | 155 if (item->contact->job_title) |
164 printf("personalTitle: %s\n", single(item->contact->job_title)); | 156 print_ldif_single("personalTitle", item->contact->job_title); |
165 if (item->contact->company_name) | 157 if (item->contact->company_name) |
166 printf("company: %s\n", single(item->contact->company_name)); | 158 print_ldif_single("company", item->contact->company_name); |
167 if (item->contact->address1 && *item->contact->address1) | 159 if (item->contact->address1 && *item->contact->address1) |
168 printf("mail: %s\n", single(item->contact->address1)); | 160 print_ldif_single("mail", item->contact->address1); |
169 if (item->contact->address2 && *item->contact->address2) | 161 if (item->contact->address2 && *item->contact->address2) |
170 printf("mail: %s\n", single(item->contact->address2)); | 162 print_ldif_single("mail", item->contact->address2); |
171 if (item->contact->address3 && *item->contact->address3) | 163 if (item->contact->address3 && *item->contact->address3) |
172 printf("mail: %s\n", single(item->contact->address3)); | 164 print_ldif_single("mail", item->contact->address3); |
173 if (item->contact->address1a && *item->contact->address1a) | 165 if (item->contact->address1a && *item->contact->address1a) |
174 printf("mail: %s\n", single(item->contact->address1a)); | 166 print_ldif_single("mail", item->contact->address1a); |
175 if (item->contact->address2a && *item->contact->address2a) | 167 if (item->contact->address2a && *item->contact->address2a) |
176 printf("mail: %s\n", single(item->contact->address2a)); | 168 print_ldif_single("mail", item->contact->address2a); |
177 if (item->contact->address3a && *item->contact->address3a) | 169 if (item->contact->address3a && *item->contact->address3a) |
178 printf("mail: %s\n", single(item->contact->address3a)); | 170 print_ldif_single("mail", item->contact->address3a); |
179 if (item->contact->business_address) { | 171 if (item->contact->business_address) { |
180 if (item->contact->business_po_box) | 172 if (item->contact->business_po_box) |
181 printf("postalAddress: %s\n", single(item->contact->business_po_box)); | 173 print_ldif_single("postalAddress", item->contact->business_po_box); |
182 if (item->contact->business_street) | 174 if (item->contact->business_street) |
183 multi("postalAddress: %s\n", item->contact->business_street); | 175 print_ldif_multi("postalAddress", item->contact->business_street); |
184 if (item->contact->business_city) | 176 if (item->contact->business_city) |
185 printf("l: %s\n", single(item->contact->business_city)); | 177 print_ldif_single("l", item->contact->business_city); |
186 if (item->contact->business_state) | 178 if (item->contact->business_state) |
187 printf("st: %s\n", single(item->contact->business_state)); | 179 print_ldif_single("st", item->contact->business_state); |
188 if (item->contact->business_postal_code) | 180 if (item->contact->business_postal_code) |
189 printf("postalCode: %s\n", single(item->contact->business_postal_code)); | 181 print_ldif_single("postalCode", item->contact->business_postal_code); |
190 } | 182 } |
191 else if (item->contact->home_address) { | 183 else if (item->contact->home_address) { |
192 if (item->contact->home_po_box) | 184 if (item->contact->home_po_box) |
193 printf("postalAddress: %s\n", single(item->contact->home_po_box)); | 185 print_ldif_single("postalAddress", item->contact->home_po_box); |
194 if (item->contact->home_street) | 186 if (item->contact->home_street) |
195 multi("postalAddress: %s\n", item->contact->home_street); | 187 print_ldif_multi("postalAddress", item->contact->home_street); |
196 if (item->contact->home_city) | 188 if (item->contact->home_city) |
197 printf("l: %s\n", single(item->contact->home_city)); | 189 print_ldif_single("l", item->contact->home_city); |
198 if (item->contact->home_state) | 190 if (item->contact->home_state) |
199 printf("st: %s\n", single(item->contact->home_state)); | 191 print_ldif_single("st", item->contact->home_state); |
200 if (item->contact->home_postal_code) | 192 if (item->contact->home_postal_code) |
201 printf("postalCode: %s\n", single(item->contact->home_postal_code)); | 193 print_ldif_single("postalCode", item->contact->home_postal_code); |
202 } | 194 } |
203 else if (item->contact->other_address) { | 195 else if (item->contact->other_address) { |
204 if (item->contact->other_po_box) | 196 if (item->contact->other_po_box) |
205 printf("postalAddress: %s\n", single(item->contact->other_po_box)); | 197 print_ldif_single("postalAddress", item->contact->other_po_box); |
206 if (item->contact->other_street) | 198 if (item->contact->other_street) |
207 multi("postalAddress: %s\n", item->contact->other_street); | 199 print_ldif_multi("postalAddress", item->contact->other_street); |
208 if (item->contact->other_city) | 200 if (item->contact->other_city) |
209 printf("l: %s\n", single(item->contact->other_city)); | 201 print_ldif_single("l", item->contact->other_city); |
210 if (item->contact->other_state) | 202 if (item->contact->other_state) |
211 printf("st: %s\n", single(item->contact->other_state)); | 203 print_ldif_single("st", item->contact->other_state); |
212 if (item->contact->other_postal_code) | 204 if (item->contact->other_postal_code) |
213 printf("postalCode: %s\n", single(item->contact->other_postal_code)); | 205 print_ldif_single("postalCode", item->contact->other_postal_code); |
214 } | 206 } |
215 if (item->contact->business_fax) | 207 if (item->contact->business_fax) |
216 printf("facsimileTelephoneNumber: %s\n", single(item->contact->business_fax)); | 208 print_ldif_single("facsimileTelephoneNumber", item->contact->business_fax); |
217 else if (item->contact->home_fax) | 209 else if (item->contact->home_fax) |
218 printf("facsimileTelephoneNumber: %s\n", single(item->contact->home_fax)); | 210 print_ldif_single("facsimileTelephoneNumber", item->contact->home_fax); |
219 | 211 |
220 if (item->contact->business_phone) | 212 if (item->contact->business_phone) |
221 printf("telephoneNumber: %s\n", single(item->contact->business_phone)); | 213 print_ldif_single("telephoneNumber", item->contact->business_phone); |
222 if (item->contact->home_phone) | 214 if (item->contact->home_phone) |
223 printf("homePhone: %s\n", single(item->contact->home_phone)); | 215 print_ldif_single("homePhone", item->contact->home_phone); |
224 | 216 |
225 if (item->contact->car_phone) | 217 if (item->contact->car_phone) |
226 printf("mobile: %s\n", single(item->contact->car_phone)); | 218 print_ldif_single("mobile", item->contact->car_phone); |
227 else if (item->contact->mobile_phone) | 219 else if (item->contact->mobile_phone) |
228 printf("mobile: %s\n", single(item->contact->mobile_phone)); | 220 print_ldif_single("mobile", item->contact->mobile_phone); |
229 else if (item->contact->other_phone) | 221 else if (item->contact->other_phone) |
230 printf("mobile: %s\n", single(item->contact->other_phone)); | 222 print_ldif_single("mobile", item->contact->other_phone); |
231 | 223 |
232 | 224 |
233 if (item->comment) | 225 if (item->comment) |
234 printf("description: %s\n", single(item->comment)); | 226 print_ldif_single("description", item->comment); |
235 | 227 |
236 printf("objectClass: %s\n\n", ldap_class); | 228 print_ldif("objectClass", ldap_class); |
229 putchar('\n'); | |
237 } | 230 } |
238 } | 231 } |
239 else { | 232 else { |
240 DEBUG_INFO(("item is not a contact\n")); | 233 DEBUG_INFO(("item is not a contact\n")); |
241 } | 234 } |
245 d_ptr = d_ptr->next; | 238 d_ptr = d_ptr->next; |
246 } | 239 } |
247 } | 240 } |
248 | 241 |
249 | 242 |
243 void print_ldif(const char *dn, const char *value) | |
244 { | |
245 printf("%s: %s\n", dn, value); | |
246 } | |
247 | |
248 | |
249 // Prints a Distinguished Name together with its value. | |
250 // If the value isn't a "SAFE STRING" (as defined in RFC2849), | |
251 // then it is output as a BASE-64 encoded value | |
252 void print_ldif_single(const char *dn, const char *value) | |
253 { | |
254 size_t len; | |
255 bool is_safe_string = true; | |
256 bool needs_code_conversion = false; | |
257 bool space_flag = false; | |
258 | |
259 // Strip leading spaces | |
260 while (*value == ' ') value++; | |
261 len = strlen(value) + 1; | |
262 char buffer[len]; | |
263 char *p = buffer; | |
264 // See if "value" is a "SAFE STRING" | |
265 | |
266 // First check characters that are safe but not safe as initial characters | |
267 if (*value == ':' || *value == '<') | |
268 is_safe_string = false; | |
269 for (;;) { | |
270 char ch = *value++; | |
271 | |
272 if (ch == 0 || ch == '\n') | |
273 break; | |
274 else if (ch == '\r') | |
275 continue; | |
276 else if (ch == ' ') { | |
277 space_flag = true; | |
278 continue; | |
279 } | |
280 else { | |
281 if ((ch & 0x80) == 0x80) { | |
282 needs_code_conversion = true; | |
283 is_safe_string = false; | |
284 } | |
285 if (space_flag) { | |
286 *p++ = ' '; | |
287 space_flag = false; | |
288 } | |
289 *p++ = ch; | |
290 } | |
291 } | |
292 *p = 0; | |
293 if (is_safe_string) { | |
294 printf("%s: %s\n", dn, buffer); | |
295 return; | |
296 } | |
297 | |
298 if (needs_code_conversion && cd != 0) { | |
299 size_t inlen = p - buffer; | |
300 size_t utf8_len = 2 * inlen + 1; | |
301 char utf8_buffer[utf8_len]; | |
302 char *utf8_p = utf8_buffer; | |
303 | |
304 iconv(cd, NULL, NULL, NULL, NULL); | |
305 p = buffer; | |
306 int ret = iconv(cd, &p, &inlen, &utf8_p, &utf8_len); | |
307 | |
308 if (ret >= 0) { | |
309 *utf8_p = 0; | |
310 p = base64_encode(utf8_buffer, utf8_p - utf8_buffer); | |
311 } | |
312 else | |
313 p = base64_encode(buffer, strlen(buffer)); | |
314 } | |
315 else | |
316 p = base64_encode(buffer, strlen(buffer)); | |
317 printf("%s:: %s\n", dn, p); | |
318 free(p); | |
319 } | |
320 | |
321 | |
322 void print_ldif_multi(const char *dn, const char *value) | |
323 { | |
324 const char *n; | |
325 while ((n = strchr(value, '\n'))) { | |
326 print_ldif_single(dn, value); | |
327 value = n + 1; | |
328 } | |
329 print_ldif_single(dn, value); | |
330 } | |
331 | |
332 | |
333 void print_ldif_two(const char *dn, const char *value1, const char *value2) | |
334 { | |
335 size_t len1, len2; | |
336 if (value1 && *value1) | |
337 len1 = strlen(value1); | |
338 else { | |
339 print_ldif_single(dn, value2); | |
340 return; | |
341 } | |
342 | |
343 if (value2 && *value2) | |
344 len2 = strlen(value2); | |
345 else { | |
346 print_ldif_single(dn, value1); | |
347 return; | |
348 } | |
349 | |
350 char value[len1 + len2 + 2]; | |
351 memcpy(value, value1, len1); | |
352 value[len1] = ' '; | |
353 memcpy(value + len1 + 1, value2, len2 + 1); | |
354 print_ldif_single(dn, value); | |
355 } | |
356 | |
357 | |
358 void build_cn(char *cn, size_t len, int nvalues, char *value, ...) | |
359 { | |
360 bool space_flag = false; | |
361 int i = 0; | |
362 va_list ap; | |
363 | |
364 va_start(ap, value); | |
365 | |
366 while (!value) { | |
367 nvalues--; | |
368 if (nvalues == 0) { | |
369 va_end(ap); | |
370 return; | |
371 } | |
372 value = va_arg(ap, char *); | |
373 } | |
374 for (;;) { | |
375 char ch = *value++; | |
376 | |
377 if (ch == 0 || ch == '\n') { | |
378 do { | |
379 value = NULL; | |
380 nvalues--; | |
381 if (nvalues == 0) break; | |
382 value = va_arg(ap, char *); | |
383 } while (!value); | |
384 if (!value) break; | |
385 space_flag = true; | |
386 } | |
387 else if (ch == '\r') | |
388 continue; | |
389 else if (ch == ' ') { | |
390 space_flag = true; | |
391 continue; | |
392 } | |
393 else { | |
394 if (space_flag) { | |
395 if (i > 0) { | |
396 if (i < (len - 2)) cn[i++] = ' '; | |
397 else break; | |
398 } | |
399 space_flag = false; | |
400 } | |
401 if (i < (len - 1)) cn[i++] = ch; | |
402 else break; | |
403 } | |
404 } | |
405 cn[i] = 0; | |
406 va_end(ap); | |
407 } | |
408 | |
409 | |
250 int main(int argc, char** argv) { | 410 int main(int argc, char** argv) { |
251 pst_desc_ll *d_ptr; | 411 pst_desc_ll *d_ptr; |
252 char *fname = NULL; | 412 char *fname = NULL; |
253 char *temp = NULL; //temporary char pointer | 413 char *temp = NULL; //temporary char pointer |
254 char c; | 414 int c; |
255 char *d_log = NULL; | 415 char *d_log = NULL; |
256 prog_name = argv[0]; | 416 prog_name = argv[0]; |
257 pst_item *item = NULL; | 417 pst_item *item = NULL; |
258 | 418 |
259 while ((c = getopt(argc, argv, "b:c:d:Vh"))!= -1) { | 419 while ((c = getopt(argc, argv, "b:c:C:d:Vh"))!= -1) { |
260 switch (c) { | 420 switch (c) { |
261 case 'b': | 421 case 'b': |
262 ldap_base = optarg; | 422 ldap_base = optarg; |
263 temp = strchr(ldap_base, ','); | 423 temp = strchr(ldap_base, ','); |
264 if (temp) { | 424 if (temp) { |
267 *temp = ','; | 427 *temp = ','; |
268 } | 428 } |
269 break; | 429 break; |
270 case 'c': | 430 case 'c': |
271 ldap_class = optarg; | 431 ldap_class = optarg; |
432 break; | |
433 case 'C': | |
434 cd = iconv_open("UTF-8", optarg); | |
435 if (cd == (iconv_t)(-1)) { | |
436 fprintf(stderr, "I don't know character set \"%s\"!\n\n", optarg); | |
437 fprintf(stderr, "Type: \"iconv --list\" to get list of known character sets\n"); | |
438 return 1; | |
439 } | |
272 break; | 440 break; |
273 case 'd': | 441 case 'd': |
274 d_log = optarg; | 442 d_log = optarg; |
275 break; | 443 break; |
276 case 'h': | 444 case 'h': |
342 version(); | 510 version(); |
343 printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name); | 511 printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name); |
344 printf("OPTIONS:\n"); | 512 printf("OPTIONS:\n"); |
345 printf("\t-h\t- Help. This screen\n"); | 513 printf("\t-h\t- Help. This screen\n"); |
346 printf("\t-V\t- Version. Display program version\n"); | 514 printf("\t-V\t- Version. Display program version\n"); |
347 printf("\t-b ldapbase\t- set the ldap base value\n"); | 515 printf("\t-b ldapbase\t- set the LDAP base value\n"); |
348 printf("\t-c class \t- set the class of the ldap objects\n"); | 516 printf("\t-c class \t- set the class of the LDAP objects\n"); |
517 printf("\t-C charset \t- assumed character set of non-ASCII characters\n"); | |
349 return 0; | 518 return 0; |
350 } | 519 } |
351 | 520 |
352 | 521 |
353 int version() { | 522 int version() { |
364 #endif | 533 #endif |
365 return 0; | 534 return 0; |
366 } | 535 } |
367 | 536 |
368 | 537 |
369 // my_stristr varies from strstr in that its searches are case-insensitive | |
370 char * my_stristr(char *haystack, char *needle) { | |
371 char *x=haystack, *y=needle, *z = NULL; | |
372 if (haystack == NULL || needle == NULL) | |
373 return NULL; | |
374 while (*y != '\0' && *x != '\0') { | |
375 if (tolower(*y) == tolower(*x)) { | |
376 // move y on one | |
377 y++; | |
378 if (z == NULL) { | |
379 z = x; // store first position in haystack where a match is made | |
380 } | |
381 } else { | |
382 y = needle; // reset y to the beginning of the needle | |
383 z = NULL; // reset the haystack storage point | |
384 } | |
385 x++; // advance the search in the haystack | |
386 } | |
387 return z; | |
388 } | |
389 | |
390 | |
391 char *check_filename(char *fname) { | 538 char *check_filename(char *fname) { |
392 char *t = fname; | 539 char *t = fname; |
393 if (t == NULL) { | 540 if (t == NULL) { |
394 return fname; | 541 return fname; |
395 } | 542 } |
398 *t = '_'; //replace them with an underscore | 545 *t = '_'; //replace them with an underscore |
399 } | 546 } |
400 return fname; | 547 return fname; |
401 } | 548 } |
402 | 549 |
403 | 550 #if 0 |
404 const char *single(char *str) { | 551 // This function escapes Distinguished Names (as per RFC4514) |
405 if (!str) return ""; | 552 char *dn_escape(const char *str) { |
406 char *ret = rfc2426_escape(str); | 553 static char* buf = NULL; |
407 char *n = strchr(ret, '\n'); | 554 const char *a; |
408 if (n) *n = '\0'; | 555 char *ret, *b; |
556 if (str == NULL) | |
557 ret = NULL; | |
558 else { | |
559 // Calculate maximum space needed (if every character must be escaped) | |
560 int x = 2 * strlen(str) + 1; // don't forget room for the NUL | |
561 buf = (char*) realloc(buf, x); | |
562 a = str; | |
563 b = buf; | |
564 | |
565 // remove leading spaces (RFC says escape them) | |
566 while (*a == ' ') | |
567 a++; | |
568 | |
569 // escape initial '#' | |
570 if (*a == '#') | |
571 *b++ = '\\'; | |
572 | |
573 while (*a != '\0') { | |
574 switch(*a) { | |
575 case '\\': | |
576 case '"' : | |
577 case '+' : | |
578 case ';' : | |
579 case '<' : | |
580 case '>' : | |
581 *(b++)='\\'; | |
582 *b=*a; | |
583 break; | |
584 case '\r': // skip cr | |
585 b--; | |
586 break; | |
587 default: | |
588 *b=*a; | |
589 } | |
590 b++; | |
591 a++; | |
592 } | |
593 *b = '\0'; // NUL-terminate the string (buf) | |
594 ret = buf; | |
595 } | |
409 return ret; | 596 return ret; |
410 } | 597 } |
411 | 598 #endif |
412 | |
413 const char *folded(char *str) { | |
414 if (!str) return ""; | |
415 char *ret = rfc2426_escape(str); | |
416 char *n = ret; | |
417 while ((n = strchr(n, '\n'))) { | |
418 *n = ' '; | |
419 } | |
420 n = ret; | |
421 while ((n = strchr(n, ','))) { | |
422 *n = ' '; | |
423 } | |
424 return ret; | |
425 } | |
426 | |
427 | |
428 void multi(const char *fmt, char *str) { | |
429 if (!str) return; | |
430 char *ret = rfc2426_escape(str); | |
431 char *n = ret; | |
432 while ((n = strchr(ret, '\n'))) { | |
433 *n = '\0'; | |
434 printf(fmt, ret); | |
435 ret = n+1; | |
436 } | |
437 if (*ret) printf(fmt, ret); | |
438 } | |
439 | |
440 | |
441 char *rfc2426_escape(char *str) { | |
442 static char* buf = NULL; | |
443 char *ret, *a, *b; | |
444 int x = 0, y, z; | |
445 if (str == NULL) | |
446 ret = str; | |
447 else { | |
448 | |
449 // calculate space required to escape all the following characters | |
450 y = chr_count(str, '\\') | |
451 + chr_count(str, ';'); | |
452 z = chr_count(str, '\r'); | |
453 if (y == 0 && z == 0) | |
454 // there isn't any extra space required | |
455 ret = str; | |
456 else { | |
457 x = strlen(str) + y - z + 1; // don't forget room for the NUL | |
458 buf = (char*) realloc(buf, x); | |
459 a = str; | |
460 b = buf; | |
461 while (*a != '\0') { | |
462 switch(*a) { | |
463 case '\\': | |
464 case ';' : | |
465 *(b++)='\\'; | |
466 *b=*a; | |
467 break; | |
468 case '\r': // skip cr | |
469 b--; | |
470 break; | |
471 default: | |
472 *b=*a; | |
473 } | |
474 b++; | |
475 a++; | |
476 } | |
477 *b = '\0'; // NUL-terminate the string (buf) | |
478 ret = buf; | |
479 } | |
480 } | |
481 return ret; | |
482 } | |
483 | |
484 | |
485 int chr_count(char *str, char x) { | |
486 int r = 0; | |
487 while (*str != '\0') { | |
488 if (*str == x) | |
489 r++; | |
490 str++; | |
491 } | |
492 return r; | |
493 } | |
494 |