'LibPst'
lspst.c
Go to the documentation of this file.
1 /***
2  * lspst.c
3  * Part of the LibPST project
4  * Author: Joe Nahmias <joe@nahmias.net>
5  * Based on readpst.c by David Smith <dave.s@earthcorp.com>
6  *
7  */
8 
9 #include "define.h"
10 
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 };
18 
19 struct options {
21  char *date_format;
22 };
23 
24 void canonicalize_filename(char *fname);
25 void debug_print(char *fmt, ...);
26 void usage(char *prog_name);
27 void version();
28 
29 // global settings
31 
32 
33 void create_enter_dir(struct file_ll* f, pst_item *item)
34 {
35  pst_convert_utf8(item, &item->file_as);
36  f->item_count = 0;
37  f->skip_count = 0;
38  f->type = item->type;
39  f->stored_count = (item->folder) ? item->folder->item_count : 0;
40  f->dname = strdup(item->file_as.str);
41 }
42 
43 
44 void close_enter_dir(struct file_ll *f)
45 {
46  free(f->dname);
47 }
48 
49 void process(pst_item *outeritem, pst_desc_tree *d_ptr, struct options o)
50 {
51  struct file_ll ff;
52  pst_item *item = NULL;
53  char *result = NULL;
54  size_t resultlen = 0;
55  size_t dateresultlen;
56 
57  DEBUG_ENT("process");
58  memset(&ff, 0, sizeof(ff));
59  create_enter_dir(&ff, outeritem);
60 
61  while (d_ptr) {
62  if (!d_ptr->desc) {
63  DEBUG_WARN(("ERROR item's desc record is NULL\n"));
64  ff.skip_count++;
65  }
66  else {
67  DEBUG_INFO(("Desc Email ID %"PRIx64" [d_ptr->d_id = %"PRIx64"]\n", d_ptr->desc->i_id, d_ptr->d_id));
68 
69  item = pst_parse_item(&pstfile, d_ptr, NULL);
70  DEBUG_INFO(("About to process item @ %p.\n", item));
71  if (item) {
72  if (item->message_store) {
73  // there should only be one message_store, and we have already done it
74  DIE(("A second message_store has been found. Sorry, this must be an error.\n"));
75  }
76 
77  if (item->folder && d_ptr->child) {
78  // if this is a folder, we want to recurse into it
79  pst_convert_utf8(item, &item->file_as);
80  printf("Folder \"%s\"\n", item->file_as.str);
81  process(item, d_ptr->child, o);
82 
83  } else if (item->contact && (item->type == PST_TYPE_CONTACT)) {
84  if (!ff.type) ff.type = item->type;
85  // Process Contact item
86  if (ff.type != PST_TYPE_CONTACT) {
87  DEBUG_INFO(("I have a contact, but the folder isn't a contacts folder. Processing anyway\n"));
88  }
89  printf("Contact");
90  if (item->contact->fullname.str)
91  printf("\t%s", pst_rfc2426_escape(item->contact->fullname.str, &result, &resultlen));
92  printf("\n");
93 
94  } else if (item->email && ((item->type == PST_TYPE_NOTE) || (item->type == PST_TYPE_SCHEDULE) || (item->type == PST_TYPE_REPORT))) {
95  if (!ff.type) ff.type = item->type;
96  // Process Email item
97  if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_SCHEDULE) && (ff.type != PST_TYPE_REPORT)) {
98  DEBUG_INFO(("I have an email, but the folder isn't an email folder. Processing anyway\n"));
99  }
100  printf("Email");
101  if (o.long_format == 1) {
102  if (item->email->arrival_date) {
103  char time_buffer[MAXDATEFMTLEN];
104  dateresultlen = pst_fileTimeToString(item->email->arrival_date, o.date_format, time_buffer);
105  if (dateresultlen < 1)
106  DIE(("Date format error in -f option.\n"));
107  printf("\tDate: %s", time_buffer);
108  }
109  else
110  printf("\t");
111  }
112  if (item->email->outlook_sender_name.str)
113  printf("\tFrom: %s", item->email->outlook_sender_name.str);
114  else
115  printf("\t");
116  if (o.long_format == 1) {
117  if (item->email->outlook_recipient_name.str)
118  printf("\tTo: %s", item->email->outlook_recipient_name.str);
119  else
120  printf("\t");
121  if (item->email->cc_address.str)
122  printf("\tCC: %s", item->email->cc_address.str);
123  else
124  printf("\t");
125  if (item->email->bcc_address.str)
126  printf("\tBCC: %s", item->email->bcc_address.str);
127  else
128  printf("\t");
129  }
130  if (item->subject.str)
131  printf("\tSubject: %s", item->subject.str);
132  else
133  printf("\t");
134  printf("\n");
135 
136  } else if (item->journal && (item->type == PST_TYPE_JOURNAL)) {
137  if (!ff.type) ff.type = item->type;
138  // Process Journal item
139  if (ff.type != PST_TYPE_JOURNAL) {
140  DEBUG_INFO(("I have a journal entry, but folder isn't specified as a journal type. Processing...\n"));
141  }
142  if (item->subject.str)
143  printf("Journal\t%s\n", pst_rfc2426_escape(item->subject.str, &result, &resultlen));
144 
145  } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) {
146  char time_buffer[30];
147  if (!ff.type) ff.type = item->type;
148  // Process Calendar Appointment item
149  DEBUG_INFO(("Processing Appointment Entry\n"));
150  if (ff.type != PST_TYPE_APPOINTMENT) {
151  DEBUG_INFO(("I have an appointment, but folder isn't specified as an appointment type. Processing...\n"));
152  }
153  printf("Appointment");
154  if (item->subject.str)
155  printf("\tSUMMARY: %s", pst_rfc2426_escape(item->subject.str, &result, &resultlen));
156  if (item->appointment->start)
157  printf("\tSTART: %s", pst_rfc2445_datetime_format(item->appointment->start, sizeof(time_buffer), time_buffer));
158  if (item->appointment->end)
159  printf("\tEND: %s", pst_rfc2445_datetime_format(item->appointment->end, sizeof(time_buffer), time_buffer));
160  printf("\tALL DAY: %s", (item->appointment->all_day==1 ? "Yes" : "No"));
161  printf("\n");
162 
163  } else {
164  ff.skip_count++;
165  DEBUG_INFO(("Unknown item type. %i. Ascii1=\"%s\"\n",
166  item->type, item->ascii_type));
167  }
168  pst_freeItem(item);
169  } else {
170  ff.skip_count++;
171  DEBUG_INFO(("A NULL item was seen\n"));
172  }
173  }
174  d_ptr = d_ptr->next;
175  }
176  close_enter_dir(&ff);
177  if (result) free(result);
178  DEBUG_RET();
179 }
180 
181 
182 void usage(char *prog_name) {
183  DEBUG_ENT("usage");
184  version();
185  printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name);
186  printf("OPTIONS:\n");
187  printf("\t-d <filename> \t- Debug to file. This is a binary log. Use readlog to print it\n");
188  printf("\t-l\t- Print the date, CC and BCC fields of emails too (by default only the From and Subject)\n");
189  printf("\t-f <date_format> \t- Select the date format in ctime format (by default \"%%F %%T\")\n");
190  printf("\t-h\t- Help. This screen\n");
191  printf("\t-V\t- Version. Display program version\n");
192  DEBUG_RET();
193 }
194 
195 
196 void version() {
197  DEBUG_ENT("version");
198  printf("lspst / LibPST v%s\n", VERSION);
199 #if BYTE_ORDER == BIG_ENDIAN
200  printf("Big Endian implementation being used.\n");
201 #elif BYTE_ORDER == LITTLE_ENDIAN
202  printf("Little Endian implementation being used.\n");
203 #else
204 # error "Byte order not supported by this library"
205 #endif
206  DEBUG_RET();
207 }
208 
209 
210 int main(int argc, char* const* argv) {
211  pst_item *item = NULL;
212  pst_desc_tree *d_ptr;
213  char *temp = NULL; //temporary char pointer
214  int c;
215  char *d_log = NULL;
216  struct options o;
217  o.long_format = 0;
218  char *defaultfmtdate = "%F %T";
219  o.date_format = defaultfmtdate;
220 
221  while ((c = getopt(argc, argv, "d:f:lhV"))!= -1) {
222  switch (c) {
223  case 'd':
224  d_log = optarg;
225  break;
226  case 'f':
227  o.date_format = optarg;
228  break;
229  case 'l':
230  o.long_format = 1;
231  break;
232  case 'h':
233  usage(argv[0]);
234  exit(0);
235  break;
236  case 'V':
237  version();
238  exit(0);
239  break;
240  default:
241  usage(argv[0]);
242  exit(1);
243  break;
244  }
245  }
246 
247  #ifdef DEBUG_ALL
248  // force a log file
249  if (!d_log) d_log = "lspst.log";
250  #endif // defined DEBUG_ALL
251  DEBUG_INIT(d_log, NULL);
252  DEBUG_ENT("main");
253 
254  if (argc <= optind) {
255  usage(argv[0]);
256  exit(2);
257  }
258 
259  // Open PST file
260  if (pst_open(&pstfile, argv[optind], NULL)) DIE(("Error opening File\n"));
261 
262  // Load PST index
263  if (pst_load_index(&pstfile)) DIE(("Index Error\n"));
264 
266 
267  d_ptr = pstfile.d_head; // first record is main record
268  item = pst_parse_item(&pstfile, d_ptr, NULL);
269  if (!item || !item->message_store) {
270  DEBUG_RET();
271  DIE(("Could not get root record\n"));
272  }
273 
274  // default the file_as to the same as the main filename if it doesn't exist
275  if (!item->file_as.str) {
276  if (!(temp = strrchr(argv[1], '/')))
277  if (!(temp = strrchr(argv[1], '\\')))
278  temp = argv[1];
279  else
280  temp++; // get past the "\\"
281  else
282  temp++; // get past the "/"
283  item->file_as.str = strdup(temp);
284  item->file_as.is_utf8 = 1;
285  }
286 
287  d_ptr = pst_getTopOfFolders(&pstfile, item);
288  if (!d_ptr) DIE(("Top of folders record not found. Cannot continue\n"));
289 
290  process(item, d_ptr->child, o); // do the childred of TOPF
291  pst_freeItem(item);
292  pst_close(&pstfile);
293 
294  DEBUG_RET();
295  return 0;
296 }
297 
298 
299 // This function will make sure that a filename is in canonical form. That
300 // is, it will replace any slashes, backslashes, or colons with underscores.
301 void canonicalize_filename(char *fname) {
302  DEBUG_ENT("canonicalize_filename");
303  if (fname == NULL) {
304  DEBUG_RET();
305  return;
306  }
307  while ((fname = strpbrk(fname, "/\\:")))
308  *fname = '_';
309  DEBUG_RET();
310 }
311 
312 
#define MAXDATEFMTLEN
Definition: define.h:259
Definition: lspst.c:19
#define DEBUG_WARN(x)
Definition: define.h:165
#define DIE(x)
Definition: define.h:160
void process(pst_item *outeritem, pst_desc_tree *d_ptr, struct options o)
Definition: lspst.c:49
#define VERSION
Definition: config.h:503
void create_enter_dir(struct file_ll *f, pst_item *item)
Definition: lspst.c:33
int main(int argc, char *const *argv)
Definition: lspst.c:210
void canonicalize_filename(char *fname)
Definition: lspst.c:301
int long_format
Definition: lspst.c:20
void pst_freeItem(pst_item *item)
Free the item returned by pst_parse_item().
Definition: libpst.c:3381
int pst_load_extended_attributes(pst_file *pf)
Try to load the extended attributes from the pst file.
Definition: libpst.c:698
char * pst_rfc2426_escape(char *str, char **buf, size_t *buflen)
Add any necessary escape characters for rfc2426 vcard format.
Definition: libpst.c:4293
int pst_close(pst_file *pf)
Close a pst file.
Definition: libpst.c:410
uint64_t d_id
Definition: libpst.h:127
#define PST_TYPE_SCHEDULE
Definition: libpst.h:32
#define DEBUG_INFO(x)
Definition: define.h:166
This contains the common mapi elements, and pointers to structures for each major mapi item type...
Definition: libpst.h:780
const char * prog_name
Definition: pst2dii.cpp:37
#define DEBUG_ENT(x)
Definition: define.h:171
int getopt(int argc, char *const *argv, char *optstring)
Definition: XGetopt.c:139
int32_t skip_count
Definition: lspst.c:15
#define DEBUG_RET()
Definition: define.h:176
#define PST_TYPE_REPORT
Definition: libpst.h:39
pst_string file_as
mapi element 0x3001 PR_DISPLAY_NAME
Definition: libpst.h:827
uint64_t i_id
Definition: libpst.h:110
struct pst_desc_tree * next
Definition: libpst.h:133
int32_t stored_count
Definition: lspst.c:13
pst_desc_tree * pst_getTopOfFolders(pst_file *pf, const pst_item *root)
Get the top of folders descriptor tree.
Definition: libpst.c:544
struct pst_desc_tree * child
Definition: libpst.h:135
int pst_open(pst_file *pf, const char *name, const char *charset)
Open a pst file.
Definition: libpst.c:315
int32_t type
Definition: lspst.c:16
pst_index_ll * desc
Definition: libpst.h:129
pst_item_message_store * message_store
message store mapi elements
Definition: libpst.h:794
int type
derived from mapi elements 0x001a PR_MESSAGE_CLASS or 0x3613 PR_CONTAINER_CLASS
Definition: libpst.h:811
int32_t item_count
Definition: lspst.c:14
size_t pst_fileTimeToString(const FILETIME *filetime, const char *date_format, char *result)
Convert a FILETIME to string in date_format format.
Definition: timeconv.c:11
int is_utf8
Definition: libpst.h:147
#define PST_TYPE_NOTE
Definition: libpst.h:31
pst_item * pst_parse_item(pst_file *pf, pst_desc_tree *d_ptr, pst_id2_tree *m_head)
Process a high level object from the pst file.
Definition: libpst.c:1249
void close_enter_dir(struct file_ll *f)
Definition: lspst.c:44
void debug_print(char *fmt,...)
char * pst_rfc2445_datetime_format(const FILETIME *ft, int buflen, char *result)
Convert a FILETIME into rfc2445 date/time format 19531015T231000Z.
Definition: libpst.c:4369
int optind
Definition: XGetopt.c:137
pst_desc_tree * d_head
the head and tail of the top level of the descriptor tree
Definition: libpst.h:907
Definition: lspst.c:11
#define PST_TYPE_JOURNAL
Definition: libpst.h:35
#define PST_TYPE_APPOINTMENT
Definition: libpst.h:33
#define PST_TYPE_CONTACT
Definition: libpst.h:34
char * date_format
Definition: lspst.c:21
#define DEBUG_INIT(fname, mutex)
Definition: define.h:182
void version()
Definition: lspst.c:196
pst_file pstfile
Definition: lspst.c:30
char * dname
Definition: lspst.c:12
int pst_load_index(pst_file *pf)
Load the index entries from the pst file.
Definition: libpst.c:652
void usage(char *prog_name)
Definition: lspst.c:182
pst_item_folder * folder
folder mapi elements
Definition: libpst.h:788
char * str
Definition: libpst.h:148
char * optarg
Definition: XGetopt.c:136
int32_t item_count
mapi element 0x3602 PR_CONTENT_COUNT
Definition: libpst.h:345
void pst_convert_utf8(pst_item *item, pst_string *str)
Convert str to utf8 if possible; null strings are converted into empty strings.
Definition: libpst.c:4546