libpst

view src/lspst.c @ 348:c006b76da81d

document new -8 switch
author Carl Byington <carl@five-ten-sg.com>
date Mon, 09 Mar 2015 11:49:11 -0700
parents 898118c3675e
children d1f930be4711
line source
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 */
9 #include "define.h"
11 struct file_ll {
12 char *dname;
13 int32_t stored_count;
14 int32_t item_count;
15 int32_t skip_count;
16 int32_t type;
17 };
20 void canonicalize_filename(char *fname);
21 void debug_print(char *fmt, ...);
22 void usage(char *prog_name);
23 void version();
25 // global settings
26 pst_file pstfile;
29 void create_enter_dir(struct file_ll* f, pst_item *item)
30 {
31 pst_convert_utf8(item, &item->file_as);
32 f->item_count = 0;
33 f->skip_count = 0;
34 f->type = item->type;
35 f->stored_count = (item->folder) ? item->folder->item_count : 0;
36 f->dname = strdup(item->file_as.str);
37 }
40 void close_enter_dir(struct file_ll *f)
41 {
42 free(f->dname);
43 }
46 void process(pst_item *outeritem, pst_desc_tree *d_ptr)
47 {
48 struct file_ll ff;
49 pst_item *item = NULL;
50 char *result = NULL;
51 size_t resultlen = 0;
53 DEBUG_ENT("process");
54 memset(&ff, 0, sizeof(ff));
55 create_enter_dir(&ff, outeritem);
57 while (d_ptr) {
58 if (!d_ptr->desc) {
59 DEBUG_WARN(("ERROR item's desc record is NULL\n"));
60 ff.skip_count++;
61 }
62 else {
63 DEBUG_INFO(("Desc Email ID %"PRIx64" [d_ptr->d_id = %"PRIx64"]\n", d_ptr->desc->i_id, d_ptr->d_id));
65 item = pst_parse_item(&pstfile, d_ptr, NULL);
66 DEBUG_INFO(("About to process item @ %p.\n", item));
67 if (item) {
68 if (item->message_store) {
69 // there should only be one message_store, and we have already done it
70 DIE(("A second message_store has been found. Sorry, this must be an error.\n"));
71 }
73 if (item->folder && d_ptr->child) {
74 // if this is a folder, we want to recurse into it
75 pst_convert_utf8(item, &item->file_as);
76 printf("Folder \"%s\"\n", item->file_as.str);
77 process(item, d_ptr->child);
79 } else if (item->contact && (item->type == PST_TYPE_CONTACT)) {
80 if (!ff.type) ff.type = item->type;
81 // Process Contact item
82 if (ff.type != PST_TYPE_CONTACT) {
83 DEBUG_INFO(("I have a contact, but the folder isn't a contacts folder. Processing anyway\n"));
84 }
85 printf("Contact");
86 if (item->contact->fullname.str)
87 printf("\t%s", pst_rfc2426_escape(item->contact->fullname.str, &result, &resultlen));
88 printf("\n");
90 } else if (item->email && ((item->type == PST_TYPE_NOTE) || (item->type == PST_TYPE_SCHEDULE) || (item->type == PST_TYPE_REPORT))) {
91 if (!ff.type) ff.type = item->type;
92 // Process Email item
93 if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_SCHEDULE) && (ff.type != PST_TYPE_REPORT)) {
94 DEBUG_INFO(("I have an email, but the folder isn't an email folder. Processing anyway\n"));
95 }
96 printf("Email");
97 if (item->email->outlook_sender_name.str)
98 printf("\tFrom: %s", item->email->outlook_sender_name.str);
99 if (item->subject.str)
100 printf("\tSubject: %s", item->subject.str);
101 printf("\n");
103 } else if (item->journal && (item->type == PST_TYPE_JOURNAL)) {
104 if (!ff.type) ff.type = item->type;
105 // Process Journal item
106 if (ff.type != PST_TYPE_JOURNAL) {
107 DEBUG_INFO(("I have a journal entry, but folder isn't specified as a journal type. Processing...\n"));
108 }
109 if (item->subject.str)
110 printf("Journal\t%s\n", pst_rfc2426_escape(item->subject.str, &result, &resultlen));
112 } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) {
113 char time_buffer[30];
114 if (!ff.type) ff.type = item->type;
115 // Process Calendar Appointment item
116 DEBUG_INFO(("Processing Appointment Entry\n"));
117 if (ff.type != PST_TYPE_APPOINTMENT) {
118 DEBUG_INFO(("I have an appointment, but folder isn't specified as an appointment type. Processing...\n"));
119 }
120 printf("Appointment");
121 if (item->subject.str)
122 printf("\tSUMMARY: %s", pst_rfc2426_escape(item->subject.str, &result, &resultlen));
123 if (item->appointment->start)
124 printf("\tSTART: %s", pst_rfc2445_datetime_format(item->appointment->start, sizeof(time_buffer), time_buffer));
125 if (item->appointment->end)
126 printf("\tEND: %s", pst_rfc2445_datetime_format(item->appointment->end, sizeof(time_buffer), time_buffer));
127 printf("\tALL DAY: %s", (item->appointment->all_day==1 ? "Yes" : "No"));
128 printf("\n");
130 } else {
131 ff.skip_count++;
132 DEBUG_INFO(("Unknown item type. %i. Ascii1=\"%s\"\n",
133 item->type, item->ascii_type));
134 }
135 pst_freeItem(item);
136 } else {
137 ff.skip_count++;
138 DEBUG_INFO(("A NULL item was seen\n"));
139 }
140 d_ptr = d_ptr->next;
141 }
142 }
143 close_enter_dir(&ff);
144 if (result) free(result);
145 DEBUG_RET();
146 }
149 void usage(char *prog_name) {
150 DEBUG_ENT("usage");
151 version();
152 printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name);
153 printf("OPTIONS:\n");
154 printf("\t-d <filename> \t- Debug to file. This is a binary log. Use readlog to print it\n");
155 printf("\t-h\t- Help. This screen\n");
156 printf("\t-V\t- Version. Display program version\n");
157 DEBUG_RET();
158 }
161 void version() {
162 DEBUG_ENT("version");
163 printf("lspst / LibPST v%s\n", VERSION);
164 #if BYTE_ORDER == BIG_ENDIAN
165 printf("Big Endian implementation being used.\n");
166 #elif BYTE_ORDER == LITTLE_ENDIAN
167 printf("Little Endian implementation being used.\n");
168 #else
169 # error "Byte order not supported by this library"
170 #endif
171 DEBUG_RET();
172 }
175 int main(int argc, char* const* argv) {
176 pst_item *item = NULL;
177 pst_desc_tree *d_ptr;
178 char *temp = NULL; //temporary char pointer
179 int c;
180 char *d_log = NULL;
182 while ((c = getopt(argc, argv, "d:hV"))!= -1) {
183 switch (c) {
184 case 'd':
185 d_log = optarg;
186 break;
187 case 'h':
188 usage(argv[0]);
189 exit(0);
190 break;
191 case 'V':
192 version();
193 exit(0);
194 break;
195 default:
196 usage(argv[0]);
197 exit(1);
198 break;
199 }
200 }
202 #ifdef DEBUG_ALL
203 // force a log file
204 if (!d_log) d_log = "lspst.log";
205 #endif // defined DEBUG_ALL
206 DEBUG_INIT(d_log, NULL);
207 DEBUG_ENT("main");
209 if (argc <= optind) {
210 usage(argv[0]);
211 exit(2);
212 }
214 // Open PST file
215 if (pst_open(&pstfile, argv[optind], NULL)) DIE(("Error opening File\n"));
217 // Load PST index
218 if (pst_load_index(&pstfile)) DIE(("Index Error\n"));
220 pst_load_extended_attributes(&pstfile);
222 d_ptr = pstfile.d_head; // first record is main record
223 item = pst_parse_item(&pstfile, d_ptr, NULL);
224 if (!item || !item->message_store) {
225 DEBUG_RET();
226 DIE(("Could not get root record\n"));
227 }
229 // default the file_as to the same as the main filename if it doesn't exist
230 if (!item->file_as.str) {
231 if (!(temp = strrchr(argv[1], '/')))
232 if (!(temp = strrchr(argv[1], '\\')))
233 temp = argv[1];
234 else
235 temp++; // get past the "\\"
236 else
237 temp++; // get past the "/"
238 item->file_as.str = strdup(temp);
239 item->file_as.is_utf8 = 1;
240 }
242 d_ptr = pst_getTopOfFolders(&pstfile, item);
243 if (!d_ptr) DIE(("Top of folders record not found. Cannot continue\n"));
245 process(item, d_ptr->child); // do the childred of TOPF
246 pst_freeItem(item);
247 pst_close(&pstfile);
249 DEBUG_RET();
250 return 0;
251 }
254 // This function will make sure that a filename is in cannonical form. That
255 // is, it will replace any slashes, backslashes, or colons with underscores.
256 void canonicalize_filename(char *fname) {
257 DEBUG_ENT("canonicalize_filename");
258 if (fname == NULL) {
259 DEBUG_RET();
260 return;
261 }
262 while ((fname = strpbrk(fname, "/\\:")))
263 *fname = '_';
264 DEBUG_RET();
265 }