comparison src/pst2ldif.cpp @ 104:39ba19372732

many fixes in pst2ldif by Robert Harris
author Carl Byington <carl@five-ten-sg.com>
date Thu, 09 Oct 2008 12:04:40 -0700
parents b7f456946c5b
children 4703d622e95b
comparison
equal deleted inserted replaced
103:0af0bbe166e1 104:39ba19372732
10 10
11 using namespace std; 11 using namespace std;
12 12
13 // needed for std c++ collections 13 // needed for std c++ collections
14 #include <set> 14 #include <set>
15 #include <vector>
16 #include <string>
15 17
16 extern "C" { 18 extern "C" {
17 #include "define.h" 19 #include "define.h"
18 #include "libstrfunc.h" 20 #include "libstrfunc.h"
19 #include "libpst.h" 21 #include "libpst.h"
25 } 27 }
26 28
27 int32_t usage(); 29 int32_t usage();
28 int32_t version(); 30 int32_t version();
29 char *check_filename(char *fname); 31 char *check_filename(char *fname);
30 char *dn_escape(const char *str); 32 void print_ldif_single(const char *attr, const char *value);
31 void print_ldif(const char *dn, const char *value); 33 void print_ldif_address(const char *attr, int nvalues, char *value, ...);
32 void print_ldif_single(const char *dn, const char *value); 34 void print_ldif_dn(const char *attr, const char *value, const char *base);
33 void print_ldif_multi(const char *dn, const char *value); 35 void print_ldif_multi(const char *dn, const char *value);
34 void print_ldif_two(const char *dn, const char *value1, const char *value2); 36 void print_ldif_two(const char *attr, const char *value1, const char *value2);
37 void print_escaped_dn(const char *value);
35 void build_cn(char *cn, size_t len, int nvalues, char *value, ...); 38 void build_cn(char *cn, size_t len, int nvalues, char *value, ...);
36 39
37 char *prog_name; 40 char *prog_name;
38 pst_file pstfile; 41 pst_file pstfile;
39 char *ldap_base = NULL; // 'o=some.domain.tld, c=US' 42 bool old_schema = false;
40 char *ldap_class = NULL; // 'newPerson' 43 char *ldap_base = NULL; // 'o=some.domain.tld,c=US'
41 char *ldap_org = NULL; // 'some.domain.tld', computed from ldap_base 44 int ldif_extra_line_count = 0;
42 iconv_t cd = 0; // Character set conversion descriptor 45 iconv_t cd = 0; // Character set conversion descriptor
46 vector<string> ldap_class; // 'newPerson' or 'inetOrgPerson'
47 vector<string> ldif_extra_line; // 'o: myorg'
43 48
44 49
45 //////////////////////////////////////////////// 50 ////////////////////////////////////////////////
46 // define our ordering 51 // define our ordering
47 struct ltstr { 52 struct ltstr {
121 process(d_ptr->child); 126 process(d_ptr->child);
122 127
123 } else if (item->contact && (item->type == PST_TYPE_CONTACT)) { 128 } else if (item->contact && (item->type == PST_TYPE_CONTACT)) {
124 // deal with a contact 129 // deal with a contact
125 char cn[1000]; 130 char cn[1000];
131
126 build_cn(cn, sizeof(cn), 4, 132 build_cn(cn, sizeof(cn), 4,
127 item->contact->display_name_prefix, 133 item->contact->display_name_prefix,
128 item->contact->first_name, 134 item->contact->first_name,
129 item->contact->surname, 135 item->contact->surname,
130 item->contact->suffix); 136 item->contact->suffix);
131 if (cn[0] != 0) { 137 if (cn[0] != 0) {
132 // have a valid cn 138 // have a valid cn
133 const char *ucn = unique_string(cn); 139 const char *ucn = unique_string(cn);
134 char dn[strlen(ucn) + strlen(ldap_base) + 6]; 140
135 141 print_ldif_dn("dn", ucn, ldap_base);
136 sprintf(dn, "cn=%s, %s", ucn, ldap_base);
137 print_ldif_single("dn", dn);
138 print_ldif_single("cn", ucn); 142 print_ldif_single("cn", ucn);
139 if (item->contact->first_name) { 143 if (item->contact->first_name) {
140 print_ldif_two("givenName", 144 print_ldif_two("givenName",
141 item->contact->display_name_prefix, 145 item->contact->display_name_prefix,
142 item->contact->first_name); 146 item->contact->first_name);
150 print_ldif_single("sn", item->contact->company_name); 154 print_ldif_single("sn", item->contact->company_name);
151 } 155 }
152 else 156 else
153 print_ldif_single("sn", ucn); // use cn as sn if we cannot find something better 157 print_ldif_single("sn", ucn); // use cn as sn if we cannot find something better
154 158
155 if (item->contact->job_title) 159 if (old_schema) {
156 print_ldif_single("personalTitle", item->contact->job_title); 160 if (item->contact->job_title)
157 if (item->contact->company_name) 161 print_ldif_single("personalTitle", item->contact->job_title);
158 print_ldif_single("company", item->contact->company_name); 162 if (item->contact->company_name)
163 print_ldif_single("company", item->contact->company_name);
164 else {
165 // new schema
166 if (item->contact->job_title)
167 print_ldif_single("title", item->contact->job_title);
168 if (item->contact->company_name)
169 print_ldif_single("o", item->contact->company_name);
170 }
171 }
159 if (item->contact->address1 && *item->contact->address1) 172 if (item->contact->address1 && *item->contact->address1)
160 print_ldif_single("mail", item->contact->address1); 173 print_ldif_single("mail", item->contact->address1);
161 if (item->contact->address2 && *item->contact->address2) 174 if (item->contact->address2 && *item->contact->address2)
162 print_ldif_single("mail", item->contact->address2); 175 print_ldif_single("mail", item->contact->address2);
163 if (item->contact->address3 && *item->contact->address3) 176 if (item->contact->address3 && *item->contact->address3)
166 print_ldif_single("mail", item->contact->address1a); 179 print_ldif_single("mail", item->contact->address1a);
167 if (item->contact->address2a && *item->contact->address2a) 180 if (item->contact->address2a && *item->contact->address2a)
168 print_ldif_single("mail", item->contact->address2a); 181 print_ldif_single("mail", item->contact->address2a);
169 if (item->contact->address3a && *item->contact->address3a) 182 if (item->contact->address3a && *item->contact->address3a)
170 print_ldif_single("mail", item->contact->address3a); 183 print_ldif_single("mail", item->contact->address3a);
171 if (item->contact->business_address) { 184
172 if (item->contact->business_po_box) 185 if (old_schema) {
173 print_ldif_single("postalAddress", item->contact->business_po_box); 186 if (item->contact->business_address) {
174 if (item->contact->business_street) 187 if (item->contact->business_po_box)
175 print_ldif_multi("postalAddress", item->contact->business_street); 188 print_ldif_single("postalAddress", item->contact->business_po_box);
176 if (item->contact->business_city) 189 if (item->contact->business_street)
177 print_ldif_single("l", item->contact->business_city); 190 print_ldif_multi("postalAddress", item->contact->business_street);
178 if (item->contact->business_state) 191 if (item->contact->business_city)
179 print_ldif_single("st", item->contact->business_state); 192 print_ldif_single("l", item->contact->business_city);
180 if (item->contact->business_postal_code) 193 if (item->contact->business_state)
181 print_ldif_single("postalCode", item->contact->business_postal_code); 194 print_ldif_single("st", item->contact->business_state);
195 if (item->contact->business_postal_code)
196 print_ldif_single("postalCode", item->contact->business_postal_code);
197 }
198 else if (item->contact->home_address) {
199 if (item->contact->home_po_box)
200 print_ldif_single("postalAddress", item->contact->home_po_box);
201 if (item->contact->home_street)
202 print_ldif_multi("postalAddress", item->contact->home_street);
203 if (item->contact->home_city)
204 print_ldif_single("l", item->contact->home_city);
205 if (item->contact->home_state)
206 print_ldif_single("st", item->contact->home_state);
207 if (item->contact->home_postal_code)
208 print_ldif_single("postalCode", item->contact->home_postal_code);
209 }
210 else if (item->contact->other_address) {
211 if (item->contact->other_po_box)
212 print_ldif_single("postalAddress", item->contact->other_po_box);
213 if (item->contact->other_street)
214 print_ldif_multi("postalAddress", item->contact->other_street);
215 if (item->contact->other_city)
216 print_ldif_single("l", item->contact->other_city);
217 if (item->contact->other_state)
218 print_ldif_single("st", item->contact->other_state);
219 if (item->contact->other_postal_code)
220 print_ldif_single("postalCode", item->contact->other_postal_code);
221 }
182 } 222 }
183 else if (item->contact->home_address) { 223 else {
184 if (item->contact->home_po_box) 224 // new schema, with proper RFC4517 postal addresses
185 print_ldif_single("postalAddress", item->contact->home_po_box); 225 if (item->contact->business_address) {
186 if (item->contact->home_street) 226 print_ldif_address("postalAddress", 6,
187 print_ldif_multi("postalAddress", item->contact->home_street); 227 item->contact->business_po_box,
188 if (item->contact->home_city) 228 item->contact->business_street,
189 print_ldif_single("l", item->contact->home_city); 229 item->contact->business_city,
190 if (item->contact->home_state) 230 item->contact->business_state,
191 print_ldif_single("st", item->contact->home_state); 231 item->contact->business_postal_code,
192 if (item->contact->home_postal_code) 232 item->contact->business_country);
193 print_ldif_single("postalCode", item->contact->home_postal_code); 233 if (item->contact->business_city)
234 print_ldif_single("l", item->contact->business_city);
235 if (item->contact->business_state)
236 print_ldif_single("st", item->contact->business_state);
237 if (item->contact->business_postal_code)
238 print_ldif_single("postalCode", item->contact->business_postal_code);
239 }
240 else if (item->contact->home_address) {
241 if (item->contact->home_city)
242 print_ldif_single("l", item->contact->home_city);
243 if (item->contact->home_state)
244 print_ldif_single("st", item->contact->home_state);
245 if (item->contact->home_postal_code)
246 print_ldif_single("postalCode", item->contact->home_postal_code);
247 }
248 else if (item->contact->other_address) {
249 print_ldif_address("postalAddress", 6,
250 item->contact->other_po_box,
251 item->contact->other_street,
252 item->contact->other_city,
253 item->contact->other_state,
254 item->contact->other_postal_code,
255 item->contact->other_country);
256 if (item->contact->other_city)
257 print_ldif_single("l", item->contact->other_city);
258 if (item->contact->other_state)
259 print_ldif_single("st", item->contact->other_state);
260 if (item->contact->other_postal_code)
261 print_ldif_single("postalCode", item->contact->other_postal_code);
262 }
263 if (item->contact->home_address) {
264 print_ldif_address("homePostalAddress", 6,
265 item->contact->home_po_box,
266 item->contact->home_street,
267 item->contact->home_city,
268 item->contact->home_state,
269 item->contact->home_postal_code,
270 item->contact->home_country);
271 }
194 } 272 }
195 else if (item->contact->other_address) { 273
196 if (item->contact->other_po_box)
197 print_ldif_single("postalAddress", item->contact->other_po_box);
198 if (item->contact->other_street)
199 print_ldif_multi("postalAddress", item->contact->other_street);
200 if (item->contact->other_city)
201 print_ldif_single("l", item->contact->other_city);
202 if (item->contact->other_state)
203 print_ldif_single("st", item->contact->other_state);
204 if (item->contact->other_postal_code)
205 print_ldif_single("postalCode", item->contact->other_postal_code);
206 }
207 if (item->contact->business_fax) 274 if (item->contact->business_fax)
208 print_ldif_single("facsimileTelephoneNumber", item->contact->business_fax); 275 print_ldif_single("facsimileTelephoneNumber", item->contact->business_fax);
209 else if (item->contact->home_fax) 276 else if (item->contact->home_fax)
210 print_ldif_single("facsimileTelephoneNumber", item->contact->home_fax); 277 print_ldif_single("facsimileTelephoneNumber", item->contact->home_fax);
211 278
219 else if (item->contact->mobile_phone) 286 else if (item->contact->mobile_phone)
220 print_ldif_single("mobile", item->contact->mobile_phone); 287 print_ldif_single("mobile", item->contact->mobile_phone);
221 else if (item->contact->other_phone) 288 else if (item->contact->other_phone)
222 print_ldif_single("mobile", item->contact->other_phone); 289 print_ldif_single("mobile", item->contact->other_phone);
223 290
291 if (!old_schema) {
292 if (item->contact->business_homepage)
293 print_ldif_single("labeledURI", item->contact->business_homepage);
294 if (item->contact->personal_homepage)
295 print_ldif_single("labeledURI", item->contact->personal_homepage);
296 }
224 297
225 if (item->comment) 298 if (item->comment)
226 print_ldif_single("description", item->comment); 299 print_ldif_single("description", item->comment);
227 300
228 print_ldif("objectClass", ldap_class); 301 for (int i=0; i<ldap_class.size(); i++)
229 putchar('\n'); 302 print_ldif_single("objectClass", ldap_class[i].c_str());
303 printf("\n");
230 } 304 }
231 } 305 }
232 else { 306 else {
233 DEBUG_INFO(("item is not a contact\n")); 307 DEBUG_INFO(("item is not a contact\n"));
234 } 308 }
238 d_ptr = d_ptr->next; 312 d_ptr = d_ptr->next;
239 } 313 }
240 } 314 }
241 315
242 316
243 void print_ldif(const char *dn, const char *value) 317 // Prints an attribute together with its 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), 318 // If the value isn't a "SAFE STRING" (as defined in RFC2849),
251 // then it is output as a BASE-64 encoded value 319 // then it is output as a BASE-64 encoded value
252 void print_ldif_single(const char *dn, const char *value) 320 void print_ldif_single(const char *attr, const char *value)
253 { 321 {
254 size_t len; 322 size_t len;
255 bool is_safe_string = true; 323 bool is_safe_string = true;
256 bool needs_code_conversion = false; 324 bool needs_code_conversion = false;
257 bool space_flag = false; 325 bool space_flag = false;
259 // Strip leading spaces 327 // Strip leading spaces
260 while (*value == ' ') value++; 328 while (*value == ' ') value++;
261 len = strlen(value) + 1; 329 len = strlen(value) + 1;
262 char buffer[len]; 330 char buffer[len];
263 char *p = buffer; 331 char *p = buffer;
332
264 // See if "value" is a "SAFE STRING" 333 // See if "value" is a "SAFE STRING"
265
266 // First check characters that are safe but not safe as initial characters 334 // First check characters that are safe but not safe as initial characters
267 if (*value == ':' || *value == '<') 335 if (*value == ':' || *value == '<')
268 is_safe_string = false; 336 is_safe_string = false;
269 for (;;) { 337 for (;;) {
270 char ch = *value++; 338 char ch = *value++;
289 *p++ = ch; 357 *p++ = ch;
290 } 358 }
291 } 359 }
292 *p = 0; 360 *p = 0;
293 if (is_safe_string) { 361 if (is_safe_string) {
294 printf("%s: %s\n", dn, buffer); 362 printf("%s: %s\n", attr, buffer);
295 return; 363 return;
296 } 364 }
297 365
298 if (needs_code_conversion && cd != 0) { 366 if (needs_code_conversion && cd != 0) {
299 size_t inlen = p - buffer; 367 size_t inlen = p - buffer;
312 else 380 else
313 p = base64_encode(buffer, strlen(buffer)); 381 p = base64_encode(buffer, strlen(buffer));
314 } 382 }
315 else 383 else
316 p = base64_encode(buffer, strlen(buffer)); 384 p = base64_encode(buffer, strlen(buffer));
317 printf("%s:: %s\n", dn, p); 385 printf("%s:: %s\n", attr, p);
318 free(p); 386 free(p);
319 } 387 }
320 388
321 389
322 void print_ldif_multi(const char *dn, const char *value) 390 // Combines values representing address lines into an address,i
323 { 391 // lines separated with "$" as per PostalAddress syntax in RFC4517
324 const char *n; 392 void print_ldif_address(const char *attr, int nvalues, char *value, ...)
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 { 393 {
360 bool space_flag = false; 394 bool space_flag = false;
361 int i = 0; 395 bool newline_flag = false;
396 char *address = NULL; // Buffer where address is built up
397 int len = 0; // Length of buffer
398 int i = 0; // Index of next character position in buffer
362 va_list ap; 399 va_list ap;
363 400
364 va_start(ap, value); 401 va_start(ap, value);
365 402
366 while (!value) { 403 while (!value) {
367 nvalues--; 404 nvalues--;
368 if (nvalues == 0) { 405 if (nvalues == 0) { // Nothing at all to do!
369 va_end(ap); 406 va_end(ap);
370 return; 407 return;
371 } 408 }
372 value = va_arg(ap, char *); 409 value = va_arg(ap, char *);
373 } 410 }
381 if (nvalues == 0) break; 418 if (nvalues == 0) break;
382 value = va_arg(ap, char *); 419 value = va_arg(ap, char *);
383 } while (!value); 420 } while (!value);
384 if (!value) break; 421 if (!value) break;
385 space_flag = true; 422 space_flag = true;
423 newline_flag = true;
424 }
425 else if (ch == '\r')
426 continue;
427 else if (ch == '\n') {
428 newline_flag = true;
429 continue;
430 }
431 else if (ch == ' ') {
432 space_flag = true;
433 continue;
434 }
435 else {
436 if (i > (len-5)) {
437 len += 256;
438 address = (char *)realloc(address, len);
439 }
440 if (newline_flag) {
441 address[i++] = '$';
442 newline_flag = false;
443 space_flag = false;
444 }
445 else if (space_flag) {
446 address[i++] = ' ';
447 space_flag = false;
448 }
449 if (ch == '$' || ch == '\\') address[i++] = '\\';
450 address[i++] = ch;
451 }
452 }
453 va_end(ap);
454 if (i == 0) return; // Nothing to do
455 address[i] = 0;
456 print_ldif_single(attr, address);
457 free(address);
458 }
459
460
461 void print_ldif_multi(const char *dn, const char *value)
462 {
463 const char *n;
464 while ((n = strchr(value, '\n'))) {
465 print_ldif_single(dn, value);
466 value = n + 1;
467 }
468 print_ldif_single(dn, value);
469 }
470
471
472 void print_ldif_two(const char *attr, const char *value1, const char *value2)
473 {
474 size_t len1, len2;
475 if (value1 && *value1)
476 len1 = strlen(value1);
477 else {
478 print_ldif_single(attr, value2);
479 return;
480 }
481
482 if (value2 && *value2)
483 len2 = strlen(value2);
484 else {
485 print_ldif_single(attr, value1);
486 return;
487 }
488
489 char value[len1 + len2 + 2];
490 memcpy(value, value1, len1);
491 value[len1] = ' ';
492 memcpy(value + len1 + 1, value2, len2 + 1);
493 print_ldif_single(attr, value);
494 }
495
496
497 void build_cn(char *cn, size_t len, int nvalues, char *value, ...)
498 {
499 bool space_flag = false;
500 int i = 0;
501 va_list ap;
502
503 va_start(ap, value);
504
505 while (!value) {
506 nvalues--;
507 if (nvalues == 0) {
508 cn[0] = 0; // Just a terminating NUL
509 va_end(ap);
510 return;
511 }
512 value = va_arg(ap, char *);
513 }
514 for (;;) {
515 char ch = *value++;
516
517 if (ch == 0 || ch == '\n') {
518 do {
519 value = NULL;
520 nvalues--;
521 if (nvalues == 0) break;
522 value = va_arg(ap, char *);
523 } while (!value);
524 if (!value) break;
525 space_flag = true;
386 } 526 }
387 else if (ch == '\r') 527 else if (ch == '\r')
388 continue; 528 continue;
389 else if (ch == ' ') { 529 else if (ch == ' ') {
390 space_flag = true; 530 space_flag = true;
408 548
409 549
410 int main(int argc, char** argv) { 550 int main(int argc, char** argv) {
411 pst_desc_ll *d_ptr; 551 pst_desc_ll *d_ptr;
412 char *fname = NULL; 552 char *fname = NULL;
413 char *temp = NULL; //temporary char pointer
414 int c; 553 int c;
415 char *d_log = NULL; 554 char *d_log = NULL;
416 prog_name = argv[0]; 555 prog_name = argv[0];
417 pst_item *item = NULL; 556 pst_item *item = NULL;
418 557
419 while ((c = getopt(argc, argv, "b:c:C:d:Vh"))!= -1) { 558 while ((c = getopt(argc, argv, "b:c:C:d:l:oVh"))!= -1) {
420 switch (c) { 559 switch (c) {
421 case 'b': 560 case 'b':
422 ldap_base = optarg; 561 ldap_base = optarg;
423 temp = strchr(ldap_base, ',');
424 if (temp) {
425 *temp = '\0';
426 ldap_org = strdup(ldap_base+2); // assume first 2 chars are o=
427 *temp = ',';
428 }
429 break; 562 break;
430 case 'c': 563 case 'c':
431 ldap_class = optarg; 564 ldap_class.push_back(string(optarg));
432 break; 565 break;
433 case 'C': 566 case 'C':
434 cd = iconv_open("UTF-8", optarg); 567 cd = iconv_open("UTF-8", optarg);
435 if (cd == (iconv_t)(-1)) { 568 if (cd == (iconv_t)(-1)) {
436 fprintf(stderr, "I don't know character set \"%s\"!\n\n", optarg); 569 fprintf(stderr, "I don't know character set \"%s\"!\n\n", optarg);
443 break; 576 break;
444 case 'h': 577 case 'h':
445 usage(); 578 usage();
446 exit(0); 579 exit(0);
447 break; 580 break;
581 case 'l':
582 ldif_extra_line.push_back(string(optarg));
583 break;
584 case 'o':
585 old_schema = true;
586 break;
448 case 'V': 587 case 'V':
449 version(); 588 version();
450 exit(0); 589 exit(0);
451 break; 590 break;
452 default: 591 default:
454 exit(1); 593 exit(1);
455 break; 594 break;
456 } 595 }
457 } 596 }
458 597
459 if ((argc > optind) && (ldap_base) && (ldap_class) && (ldap_org)) { 598 if ((argc > optind) && (ldap_base)) {
460 fname = argv[optind]; 599 fname = argv[optind];
461 } else { 600 } else {
462 usage(); 601 usage();
463 exit(2); 602 exit(2);
464 } 603 }
488 DIE(("Top of folders record not found. Cannot continue\n")); 627 DIE(("Top of folders record not found. Cannot continue\n"));
489 } 628 }
490 629
491 pst_freeItem(item); 630 pst_freeItem(item);
492 631
493 // write the ldap header 632 if (old_schema && (strlen(ldap_base) > 2)) {
494 printf("dn: %s\n", ldap_base); 633 char *ldap_org = strdup(ldap_base+2); // assume first 2 chars are o=
495 printf("o: %s\n", ldap_org); 634 char *temp = strchr(ldap_org, ',');
496 printf("objectClass: organization\n\n"); 635 if (temp) {
497 printf("dn: cn=root, %s\n", ldap_base); 636 *temp = '\0';
498 printf("cn: root\n"); 637 // write the ldap header
499 printf("objectClass: %s\n\n", ldap_class); 638 printf("dn: %s\n", ldap_base);
639 printf("o: %s\n", ldap_org);
640 printf("objectClass: organization\n\n");
641 printf("dn: cn=root, %s\n", ldap_base);
642 printf("cn: root\n");
643 for (int i=0; i<ldap_class.size(); i++)
644 print_ldif_single("objectClass", ldap_class[i].c_str());
645 printf("\n");
646 }
647 }
500 648
501 process(d_ptr->child); // do the children of TOPF 649 process(d_ptr->child); // do the children of TOPF
502 pst_close(&pstfile); 650 pst_close(&pstfile);
503 DEBUG_RET(); 651 DEBUG_RET();
504 free_strings(all_strings); 652 free_strings(all_strings);
653 if (cd) iconv_close(cd);
654
505 return 0; 655 return 0;
506 } 656 }
507 657
508 658
509 int usage() { 659 int usage() {
510 version(); 660 version();
511 printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name); 661 printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name);
512 printf("OPTIONS:\n"); 662 printf("OPTIONS:\n");
663 printf("\t-V\t- Version. Display program version\n");
664 printf("\t-C charset\t- assumed character set of non-ASCII characters\n");
665 printf("\t-b ldapbase\t- set the LDAP base value\n");
666 printf("\t-c class\t- set the class of the LDAP objects (may contain more than one)\n");
667 printf("\t-d <filename>\t- Debug to file. This is a binary log. Use readpstlog to print it\n");
513 printf("\t-h\t- Help. This screen\n"); 668 printf("\t-h\t- Help. This screen\n");
514 printf("\t-V\t- Version. Display program version\n"); 669 printf("\t-l line\t- extra line to insert in the LDIF file for each contact\n");
515 printf("\t-b ldapbase\t- set the LDAP base value\n"); 670 printf("\t-o\t- use old schema, default is new schema\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");
518 return 0; 671 return 0;
519 } 672 }
520 673
521 674
522 int version() { 675 int version() {
545 *t = '_'; //replace them with an underscore 698 *t = '_'; //replace them with an underscore
546 } 699 }
547 return fname; 700 return fname;
548 } 701 }
549 702
550 #if 0 703
551 // This function escapes Distinguished Names (as per RFC4514) 704 // This function escapes Distinguished Names (as per RFC4514)
552 char *dn_escape(const char *str) { 705 void print_ldif_dn(const char *attr, const char *value, const char *base)
553 static char* buf = NULL; 706 {
554 const char *a; 707 printf("dn: cn=");
555 char *ret, *b; 708 // remove leading spaces (RFC says escape them)
556 if (str == NULL) 709 while (*value == ' ')
557 ret = NULL; 710 value++;
558 else { 711
559 // Calculate maximum space needed (if every character must be escaped) 712 print_escaped_dn(value);
560 int x = 2 * strlen(str) + 1; // don't forget room for the NUL 713 if (base && base[0]) {
561 buf = (char*) realloc(buf, x); 714 printf(",");
562 a = str; 715 print_escaped_dn(base);
563 b = buf; 716 }
564 717 printf("\n");
565 // remove leading spaces (RFC says escape them) 718 return;
566 while (*a == ' ') 719 }
567 a++; 720
568 721
569 // escape initial '#' 722 void print_escaped_dn(const char *value)
570 if (*a == '#') 723 {
571 *b++ = '\\'; 724 char ch;
572 725 bool needs_code_conversion = false;
573 while (*a != '\0') { 726 char *utf8_buffer = NULL;
574 switch(*a) { 727
575 case '\\': 728 // First do a quick scan to see if any code conversion is required
576 case '"' : 729 if (cd) {
577 case '+' : 730 const char *p = value;
578 case ';' : 731 while (*p) {
579 case '<' : 732 if (*p++ & 0x80) {
580 case '>' : 733 needs_code_conversion = true;
581 *(b++)='\\';
582 *b=*a;
583 break; 734 break;
584 case '\r': // skip cr 735 }
585 b--; 736 }
586 break; 737 }
587 default: 738
588 *b=*a; 739 if (needs_code_conversion) {
589 } 740 size_t inlen = strlen(value);
590 b++; 741 size_t utf8_len = 2 * inlen + 1;
591 a++; 742 char *p = (char *)value;
592 } 743 char *utf8_p = utf8_buffer;
593 *b = '\0'; // NUL-terminate the string (buf) 744
594 ret = buf; 745 utf8_buffer = (char *)malloc(utf8_len);
595 } 746 utf8_p = utf8_buffer;
596 return ret; 747 iconv(cd, NULL, NULL, NULL, NULL);
597 } 748 if (iconv(cd, &p, &inlen, &utf8_p, &utf8_len) >= 0) {
598 #endif 749 *utf8_p = 0;
750 value = utf8_buffer;
751 }
752 }
753
754 // escape initial '#' and space
755 if (*value == '#' || *value == ' ')
756 putchar('\\');
757
758 while ((ch = *value++) != 0) {
759 if (((ch & 0x80) != 0) || (ch <= 0x1F))
760 // Print as escaped hex digits
761 printf("\\%2.2X", ch & 0xFF);
762 else switch (ch) {
763 case '\\':
764 case '"' :
765 case '+' :
766 case ';' :
767 case '<' :
768 case '>' :
769 putchar('\\');
770 // Fall through
771 default:
772 putchar(ch);
773 }
774 }
775 if (utf8_buffer) free((void *)utf8_buffer);
776 return;
777 }