Mercurial > libpst
annotate src/lspst.c @ 60:97b7706bdda2
Work around bogus 7c.b5 blocks in some messages that have been read.
They appear to have attachments, but of some unknown format.
Before the message was read, it did not have any attachments.
Use autoscan to cleanup our autoconf system.
Use autoconf to detect when we need to use our XGetopt files
and other header files.
More fields, including BCC.
Fix missing LE32_CPU byte swapping for FILETIME types.
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Sat, 16 Feb 2008 12:26:35 -0800 |
parents | 7d5c637aaafb |
children | 3cb02cb1e6cd |
rev | line source |
---|---|
16 | 1 /*** |
2 * lspst.c | |
3 * Part of the LibPST project | |
4 * Author: Joe Nahmias <joe@nahmias.net> | |
5 * Based on readpst.c by by David Smith <dave.s@earthcorp.com> | |
6 * | |
7 */ | |
8 | |
48 | 9 #include "define.h" |
10 | |
16 | 11 #include <stdio.h> |
12 #include <stdlib.h> | |
13 #include <time.h> | |
14 #include <string.h> | |
15 #include <ctype.h> | |
16 #include <errno.h> | |
50 | 17 #include <unistd.h> |
16 | 18 |
19 #include "libpst.h" | |
20 #include "timeconv.h" | |
43 | 21 |
16 | 22 struct file_ll { |
43 | 23 char *dname; |
24 int32_t stored_count; | |
25 int32_t email_count; | |
26 int32_t skip_count; | |
27 int32_t type; | |
16 | 28 }; |
43 | 29 |
30 | |
16 | 31 void canonicalize_filename(char *fname); |
32 void debug_print(char *fmt, ...); | |
50 | 33 int usage(char *prog_name); |
34 int version(); | |
43 | 35 |
36 // global settings | |
37 pst_file pstfile; | |
38 | |
16 | 39 |
43 | 40 void create_enter_dir(struct file_ll* f, pst_item *item) |
41 { | |
42 f->email_count = 0; | |
43 f->skip_count = 0; | |
44 f->type = item->type; | |
45 f->stored_count = (item->folder) ? item->folder->email_count : 0; | |
46 f->dname = (char*) xmalloc(strlen(item->file_as)+1); | |
47 strcpy(f->dname, item->file_as); | |
48 } | |
16 | 49 |
50 | |
43 | 51 void close_enter_dir(struct file_ll *f) |
52 { | |
53 free(f->dname); | |
54 } | |
16 | 55 |
56 | |
43 | 57 void process(pst_item *outeritem, pst_desc_ll *d_ptr) |
58 { | |
59 struct file_ll ff; | |
60 pst_item *item = NULL; | |
61 | |
62 DEBUG_ENT("process"); | |
63 memset(&ff, 0, sizeof(ff)); | |
64 create_enter_dir(&ff, outeritem); | |
16 | 65 |
43 | 66 while (d_ptr) { |
67 DEBUG_MAIN(("main: New item record, d_ptr = %p.\n", d_ptr)); | |
68 if (!d_ptr->desc) { | |
69 DEBUG_WARN(("main: ERROR ?? item's desc record is NULL\n")); | |
70 ff.skip_count++; | |
71 } | |
72 else { | |
73 DEBUG_MAIN(("main: Desc Email ID %x [d_ptr->id = %x]\n", d_ptr->desc->id, d_ptr->id)); | |
16 | 74 |
46 | 75 item = pst_parse_item(&pstfile, d_ptr); |
43 | 76 DEBUG_MAIN(("main: About to process item @ %p.\n", item)); |
77 if (item) { | |
78 if (item->message_store) { | |
79 // there should only be one message_store, and we have already done it | |
80 DIE(("main: A second message_store has been found. Sorry, this must be an error.\n")); | |
81 } | |
16 | 82 |
43 | 83 if (item->folder && d_ptr->child) { |
84 // if this is a folder, we want to recurse into it | |
85 printf("Folder \"%s\"\n", item->file_as); | |
86 process(item, d_ptr->child); | |
16 | 87 |
43 | 88 } else if (item->contact && (item->type == PST_TYPE_CONTACT)) { |
89 // Process Contact item | |
90 if (ff.type != PST_TYPE_CONTACT) { | |
91 DEBUG_MAIN(("main: I have a contact, but the folder isn't a contacts folder. Processing anyway\n")); | |
92 } | |
93 printf("Contact"); | |
50 | 94 if (item->contact->fullname) |
43 | 95 printf("\t%s", pst_rfc2426_escape(item->contact->fullname)); |
96 printf("\n"); | |
16 | 97 |
43 | 98 } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT)) { |
99 // Process Email item | |
100 if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_REPORT)) { | |
101 DEBUG_MAIN(("main: I have an email, but the folder isn't an email folder. Processing anyway\n")); | |
102 } | |
103 printf("Email"); | |
50 | 104 if (item->email->outlook_sender_name) |
43 | 105 printf("\tFrom: %s", item->email->outlook_sender_name); |
50 | 106 if (item->email->subject && item->email->subject->subj) |
43 | 107 printf("\tSubject: %s", item->email->subject->subj); |
108 printf("\n"); | |
16 | 109 |
43 | 110 } else if (item->journal && (item->type == PST_TYPE_JOURNAL)) { |
111 // Process Journal item | |
112 if (ff.type != PST_TYPE_JOURNAL) { | |
113 DEBUG_MAIN(("main: I have a journal entry, but folder isn't specified as a journal type. Processing...\n")); | |
114 } | |
50 | 115 if (item->email && item->email->subject && item->email->subject->subj) |
116 printf("Journal\t%s\n", pst_rfc2426_escape(item->email->subject->subj)); | |
16 | 117 |
43 | 118 } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) { |
119 // Process Calendar Appointment item | |
120 DEBUG_MAIN(("main: Processing Appointment Entry\n")); | |
121 if (ff.type != PST_TYPE_APPOINTMENT) { | |
122 DEBUG_MAIN(("main: I have an appointment, but folder isn't specified as an appointment type. Processing...\n")); | |
123 } | |
124 printf("Appointment"); | |
50 | 125 if (item->email && item->email->subject) |
43 | 126 printf("\tSUMMARY: %s", pst_rfc2426_escape(item->email->subject->subj)); |
50 | 127 if (item->appointment->start) |
128 printf("\tSTART: %s", pst_rfc2445_datetime_format(item->appointment->start)); | |
129 if (item->appointment->end) | |
130 printf("\tEND: %s", pst_rfc2445_datetime_format(item->appointment->end)); | |
131 printf("\tALL DAY: %s", (item->appointment->all_day==1 ? "Yes" : "No")); | |
43 | 132 printf("\n"); |
16 | 133 |
43 | 134 } else { |
135 ff.skip_count++; | |
136 DEBUG_MAIN(("main: Unknown item type. %i. Ascii1=\"%s\"\n", | |
137 item->type, item->ascii_type)); | |
138 } | |
46 | 139 pst_freeItem(item); |
43 | 140 } else { |
141 ff.skip_count++; | |
142 DEBUG_MAIN(("main: A NULL item was seen\n")); | |
143 } | |
144 d_ptr = d_ptr->next; | |
145 } | |
146 } | |
147 close_enter_dir(&ff); | |
52 | 148 DEBUG_RET(); |
43 | 149 } |
16 | 150 |
43 | 151 |
50 | 152 int usage(char *prog_name) { |
153 DEBUG_ENT("usage"); | |
154 version(); | |
155 printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name); | |
156 printf("OPTIONS:\n"); | |
157 printf("\t-d <filename> \t- Debug to file. This is a binary log. Use readlog to print it\n"); | |
158 printf("\t-h\t- Help. This screen\n"); | |
159 printf("\t-V\t- Version. Display program version\n"); | |
160 DEBUG_RET(); | |
161 return 0; | |
162 } | |
163 | |
164 | |
165 int version() { | |
166 DEBUG_ENT("version"); | |
167 printf("lspst / LibPST v%s\n", VERSION); | |
168 #if BYTE_ORDER == BIG_ENDIAN | |
169 printf("Big Endian implementation being used.\n"); | |
170 #elif BYTE_ORDER == LITTLE_ENDIAN | |
171 printf("Little Endian implementation being used.\n"); | |
172 #else | |
173 # error "Byte order not supported by this library" | |
174 #endif | |
175 #ifdef __GNUC__ | |
176 printf("GCC %d.%d : %s %s\n", __GNUC__, __GNUC_MINOR__, __DATE__, __TIME__); | |
177 #endif | |
178 DEBUG_RET(); | |
179 return 0; | |
180 } | |
181 | |
182 | |
43 | 183 int main(int argc, char** argv) { |
184 pst_item *item = NULL; | |
185 pst_desc_ll *d_ptr; | |
186 char *temp = NULL; //temporary char pointer | |
50 | 187 int c; |
43 | 188 char *d_log = NULL; |
16 | 189 |
50 | 190 while ((c = getopt(argc, argv, "d:hV"))!= -1) { |
191 switch (c) { | |
192 case 'd': | |
193 d_log = optarg; | |
194 break; | |
195 case 'h': | |
196 usage(argv[0]); | |
197 exit(0); | |
198 break; | |
199 case 'V': | |
200 version(); | |
201 exit(0); | |
202 break; | |
203 default: | |
204 usage(argv[0]); | |
205 exit(1); | |
206 break; | |
207 } | |
208 } | |
43 | 209 |
48 | 210 #ifdef DEBUG_ALL |
211 // force a log file | |
212 if (!d_log) d_log = "lspst.log"; | |
213 #endif // defined DEBUG_ALL | |
43 | 214 DEBUG_INIT(d_log); |
215 DEBUG_REGISTER_CLOSE(); | |
216 DEBUG_ENT("main"); | |
217 | |
50 | 218 if (argc <= optind) { |
219 usage(argv[0]); | |
220 exit(2); | |
221 } | |
222 | |
43 | 223 // Open PST file |
59
7d5c637aaafb
General cleanup and code fixes.
Carl Byington <carl@five-ten-sg.com>
parents:
52
diff
changeset
|
224 if (pst_open(&pstfile, argv[optind])) DIE(("Error opening File\n")); |
16 | 225 |
43 | 226 // Load PST index |
227 if (pst_load_index(&pstfile)) DIE(("Index Error\n")); | |
228 | |
229 pst_load_extended_attributes(&pstfile); | |
16 | 230 |
43 | 231 d_ptr = pstfile.d_head; // first record is main record |
46 | 232 item = pst_parse_item(&pstfile, d_ptr); |
43 | 233 if (!item || !item->message_store) { |
234 DEBUG_RET(); | |
235 DIE(("main: Could not get root record\n")); | |
236 } | |
16 | 237 |
43 | 238 // default the file_as to the same as the main filename if it doesn't exist |
239 if (!item->file_as) { | |
240 if (!(temp = strrchr(argv[1], '/'))) | |
241 if (!(temp = strrchr(argv[1], '\\'))) | |
242 temp = argv[1]; | |
243 else | |
244 temp++; // get past the "\\" | |
245 else | |
246 temp++; // get past the "/" | |
247 item->file_as = (char*)xmalloc(strlen(temp)+1); | |
248 strcpy(item->file_as, temp); | |
249 } | |
250 fprintf(stderr, "item->file_as = '%s'.\n", item->file_as); | |
16 | 251 |
43 | 252 d_ptr = pst_getTopOfFolders(&pstfile, item); |
253 if (!d_ptr) DIE(("Top of folders record not found. Cannot continue\n")); | |
254 DEBUG_MAIN(("d_ptr(TOF) = %p.\n", d_ptr)); | |
16 | 255 |
43 | 256 process(item, d_ptr->child); // do the childred of TOPF |
46 | 257 pst_freeItem(item); |
43 | 258 pst_close(&pstfile); |
16 | 259 |
43 | 260 DEBUG_RET(); |
261 return 0; | |
16 | 262 } |
43 | 263 |
264 | |
265 // This function will make sure that a filename is in cannonical form. That | |
16 | 266 // is, it will replace any slashes, backslashes, or colons with underscores. |
267 void canonicalize_filename(char *fname) { | |
43 | 268 DEBUG_ENT("canonicalize_filename"); |
269 if (fname == NULL) { | |
270 DEBUG_RET(); | |
271 return; | |
272 } | |
50 | 273 while (fname = strpbrk(fname, "/\\:")) |
43 | 274 *fname = '_'; |
275 DEBUG_RET(); | |
16 | 276 } |
43 | 277 |
278 | |
16 | 279 void debug_print(char *fmt, ...) { |
43 | 280 // shamlessly stolen from minprintf() in K&R pg. 156 |
281 va_list ap; | |
282 char *p, *sval; | |
283 void *pval; | |
284 int ival; | |
285 double dval; | |
286 FILE *fp = stderr; | |
16 | 287 |
43 | 288 va_start(ap, fmt); |
289 for(p = fmt; *p; p++) { | |
290 if (*p != '%') { | |
291 fputc(*p, fp); | |
292 continue; | |
293 } | |
294 switch (tolower(*++p)) { | |
295 case 'd': case 'i': | |
296 ival = va_arg(ap, int); | |
297 fprintf(fp, "%d", ival); | |
298 break; | |
299 case 'f': | |
300 dval = va_arg(ap, double); | |
301 fprintf(fp, "%f", dval); | |
302 break; | |
303 case 's': | |
304 for (sval = va_arg(ap, char *); *sval; ++sval) | |
305 fputc(*sval, fp); | |
306 break; | |
307 case 'p': | |
308 pval = va_arg(ap, void *); | |
309 fprintf(fp, "%p", pval); | |
310 break; | |
311 case 'x': | |
312 ival = va_arg(ap, int); | |
313 fprintf(fp, "%#010x", ival); | |
314 break; | |
315 default: | |
316 fputc(*p, fp); | |
317 break; | |
318 } | |
319 } | |
320 va_end(ap); | |
16 | 321 } |
322 | |
323 |