423cb1d1fe70bed7172c3b09723a2e8fb59bf722
[tridge/openchange.git] / branches / plugfest / utils / openchange-tools.c
1 /*
2    Convenient functions for openchange tools
3
4    OpenChange Project
5
6    Copyright (C) Julien Kerihuel 2007
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "libmapi/libmapi.h"
23 #include "openchange-tools.h"
24
25 static void popt_openchange_version_callback(poptContext con,
26                                              enum poptCallbackReason reason,
27                                              const struct poptOption *opt,
28                                              const char *arg,
29                                              const void *data)
30 {
31         switch (opt->val) {
32         case 'V':
33                 printf("Version %s\n", OPENCHANGE_VERSION_STRING);
34                 exit (0);
35         }
36 }
37
38 struct poptOption popt_openchange_version[] = {
39         { NULL, '\0', POPT_ARG_CALLBACK, (void *)popt_openchange_version_callback, '\0', NULL, NULL },
40         { "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version ", NULL },
41         POPT_TABLEEND
42 };
43
44
45 /*
46  * Retrieve the property value for a given SRow and property tag.  
47  *
48  * If the property type is a string: fetch PT_UNICODE then PT_STRING8
49  * in case the desired property is not available in first choice.
50  *
51  * Fetch property normally for any others properties
52  */
53 _PUBLIC_ void *octool_get_propval(struct SRow *aRow, uint32_t proptag)
54 {
55         const char      *str;
56
57         if (((proptag & 0xFFFF) == PT_STRING8) ||
58             ((proptag & 0xFFFF) == PT_UNICODE)) {
59                 proptag = (proptag & 0xFFFF0000) | PT_UNICODE;
60                 str = (const char *) find_SPropValue_data(aRow, proptag);
61                 if (str) return (void *)str;
62
63                 proptag = (proptag & 0xFFFF0000) | PT_STRING8;
64                 str = (const char *) find_SPropValue_data(aRow, proptag);
65                 return (void *)str;
66         } 
67
68         return (void *)find_SPropValue_data(aRow, proptag);
69 }
70
71
72 /*
73  * Read a stream and store it in a DATA_BLOB
74  */
75 _PUBLIC_ enum MAPISTATUS octool_get_stream(TALLOC_CTX *mem_ctx,
76                                          mapi_object_t *obj_stream, 
77                                          DATA_BLOB *body)
78 {
79         enum MAPISTATUS retval;
80         uint16_t        read_size;
81         uint8_t         buf[0x1000];
82
83         body->length = 0;
84         body->data = talloc_zero(mem_ctx, uint8_t);
85
86         do {
87                 retval = ReadStream(obj_stream, buf, 0x1000, &read_size);
88                 MAPI_RETVAL_IF(retval, GetLastError(), body->data);
89                 if (read_size) {
90                         body->data = talloc_realloc(mem_ctx, body->data, uint8_t,
91                                                     body->length + read_size);
92                         memcpy(&(body->data[body->length]), buf, read_size);
93                         body->length += read_size;
94                 }
95         } while (read_size);
96
97         errno = 0;
98         return MAPI_E_SUCCESS;
99 }
100
101
102 /*
103  * Fetch the body given PR_MSG_EDITOR_FORMAT property value
104  */
105 _PUBLIC_ enum MAPISTATUS octool_get_body(TALLOC_CTX *mem_ctx,
106                                        mapi_object_t *obj_message,
107                                        struct SRow *aRow,
108                                        DATA_BLOB *body)
109 {
110         enum MAPISTATUS                 retval;
111         const struct SBinary_short      *bin;
112         mapi_object_t                   obj_stream;
113         char                            *data;
114         uint8_t                         format;
115
116         /* Sanity checks */
117         MAPI_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
118
119         /* initialize body DATA_BLOB */
120         body->data = NULL;
121         body->length = 0;
122
123         retval = GetBestBody(obj_message, &format);
124         MAPI_RETVAL_IF(retval, retval, NULL);
125
126         switch (format) {
127         case olEditorText:
128                 data = octool_get_propval(aRow, PR_BODY_UNICODE);
129                 if (data) {
130                         body->data = talloc_memdup(mem_ctx, data, strlen(data));
131                         body->length = strlen(data);
132                 } else {
133                         mapi_object_init(&obj_stream);
134                         retval = OpenStream(obj_message, PR_BODY_UNICODE, 0, &obj_stream);
135                         MAPI_RETVAL_IF(retval, GetLastError(), NULL);
136                         
137                         retval = octool_get_stream(mem_ctx, &obj_stream, body);
138                         MAPI_RETVAL_IF(retval, GetLastError(), NULL);
139                         
140                         mapi_object_release(&obj_stream);
141                 }
142                 break;
143         case olEditorHTML:
144                 bin = (const struct SBinary_short *) octool_get_propval(aRow, PR_HTML);
145                 if (bin) {
146                         body->data = talloc_memdup(mem_ctx, bin->lpb, bin->cb);
147                         body->length = bin->cb;
148                 } else {
149                         mapi_object_init(&obj_stream);
150                         retval = OpenStream(obj_message, PR_HTML, 0, &obj_stream);
151                         MAPI_RETVAL_IF(retval, GetLastError(), NULL);
152
153                         retval = octool_get_stream(mem_ctx, &obj_stream, body);
154                         MAPI_RETVAL_IF(retval, GetLastError(), NULL);
155
156                         mapi_object_release(&obj_stream);
157                 }                       
158                 break;
159         case olEditorRTF:
160                 mapi_object_init(&obj_stream);
161
162                 retval = OpenStream(obj_message, PR_RTF_COMPRESSED, 0, &obj_stream);
163                 MAPI_RETVAL_IF(retval, GetLastError(), NULL);
164
165                 retval = WrapCompressedRTFStream(&obj_stream, body);
166                 MAPI_RETVAL_IF(retval, GetLastError(), NULL);
167
168                 mapi_object_release(&obj_stream);
169                 break;
170         default:
171                 DEBUG(0, ("Undefined Body\n"));
172                 break;
173         }
174
175         return MAPI_E_SUCCESS;
176 }
177
178
179 /*
180  * Optimized dump message routine (use GetProps rather than GetPropsAll)
181  */
182 _PUBLIC_ enum MAPISTATUS octool_message(TALLOC_CTX *mem_ctx,
183                                         mapi_object_t *obj_message)
184 {
185         enum MAPISTATUS                 retval;
186         struct SPropTagArray            *SPropTagArray;
187         struct SPropValue               *lpProps;
188         struct SRow                     aRow;
189         uint32_t                        count;
190         ssize_t                         len;
191         /* common email fields */
192         const char                      *msgid;
193         const char                      *from, *to, *cc, *bcc;
194         const char                      *subject;
195         DATA_BLOB                       body;
196         const uint8_t                   *has_attach;
197         const uint32_t                  *cp;
198         const char                      *codepage;
199
200         /* Build the array of properties we want to fetch */
201         SPropTagArray = set_SPropTagArray(mem_ctx, 0x13,
202                                           PR_INTERNET_MESSAGE_ID,
203                                           PR_INTERNET_MESSAGE_ID_UNICODE,
204                                           PR_CONVERSATION_TOPIC,
205                                           PR_CONVERSATION_TOPIC_UNICODE,
206                                           PR_MSG_EDITOR_FORMAT,
207                                           PR_BODY,
208                                           PR_BODY_UNICODE,
209                                           PR_HTML,
210                                           PR_RTF_COMPRESSED,
211                                           PR_SENT_REPRESENTING_NAME,
212                                           PR_SENT_REPRESENTING_NAME_UNICODE,
213                                           PR_DISPLAY_TO,
214                                           PR_DISPLAY_TO_UNICODE,
215                                           PR_DISPLAY_CC,
216                                           PR_DISPLAY_CC_UNICODE,
217                                           PR_DISPLAY_BCC,
218                                           PR_DISPLAY_BCC_UNICODE,
219                                           PR_HASATTACH,
220                                           PR_MESSAGE_CODEPAGE);
221         lpProps = talloc_zero(mem_ctx, struct SPropValue);
222         retval = GetProps(obj_message, SPropTagArray, &lpProps, &count);
223         MAPIFreeBuffer(SPropTagArray);
224         MAPI_RETVAL_IF(retval, retval, NULL);
225
226         /* Build a SRow structure */
227         aRow.ulAdrEntryPad = 0;
228         aRow.cValues = count;
229         aRow.lpProps = lpProps;
230
231         msgid = (const char *) octool_get_propval(&aRow, PR_INTERNET_MESSAGE_ID);
232         subject = (const char *) octool_get_propval(&aRow, PR_CONVERSATION_TOPIC);
233
234         retval = octool_get_body(mem_ctx, obj_message, &aRow, &body);
235
236         if (retval != MAPI_E_SUCCESS) {
237                 printf("Invalid Message: %s\n", msgid ? msgid : "");
238                 MAPI_RETVAL_IF(retval, GetLastError(), NULL);
239         }
240         
241         from = (const char *) octool_get_propval(&aRow, PR_SENT_REPRESENTING_NAME);
242         to = (const char *) octool_get_propval(&aRow, PR_DISPLAY_TO_UNICODE);
243         cc = (const char *) octool_get_propval(&aRow, PR_DISPLAY_CC_UNICODE);
244         bcc = (const char *) octool_get_propval(&aRow, PR_DISPLAY_BCC_UNICODE);
245
246         has_attach = (const uint8_t *) octool_get_propval(&aRow, PR_HASATTACH);
247         cp = (const uint32_t *) octool_get_propval(&aRow, PR_MESSAGE_CODEPAGE);
248         switch (cp ? *cp : 0) {
249         case CP_USASCII:
250                 codepage = "CP_USASCII";
251                 break;
252         case CP_UNICODE:
253                 codepage = "CP_UNICODE";
254                 break;
255         case CP_JAUTODETECT:
256                 codepage = "CP_JAUTODETECT";
257                 break;
258         case CP_KAUTODETECT:
259                 codepage = "CP_KAUTODETECT";
260                 break;
261         case CP_ISO2022JPESC:
262                 codepage = "CP_ISO2022JPESC";
263                 break;
264         case CP_ISO2022JPSIO:
265                 codepage = "CP_ISO2022JPSIO";
266                 break;
267         default:
268                 codepage = "";
269                 break;
270         }
271
272         printf("+-------------------------------------+\n");
273         printf("message id: %s\n", msgid ? msgid : "");
274         printf("subject: %s\n", subject ? subject : "");
275         printf("From: %s\n", from ? from : "");
276         printf("To:  %s\n", to ? to : "");
277         printf("Cc:  %s\n", cc ? cc : "");
278         printf("Bcc: %s\n", bcc ? bcc : "");
279         if (has_attach) {
280                 printf("Attachment: %s\n", *has_attach ? "True" : "False");
281         }
282         printf("Codepage: %s\n", codepage);
283         printf("Body:\n");
284         fflush(0);
285         if (body.length) {
286                 len = write(1, body.data, body.length);
287                 len = write(1, "\n", 1);
288                 fflush(0);
289                 talloc_free(body.data);
290         } 
291         return MAPI_E_SUCCESS;
292 }
293
294
295 /*
296  * OpenChange MAPI programs initialization routine
297  */
298 _PUBLIC_ struct mapi_session *octool_init_mapi(struct mapi_context *mapi_ctx,
299                                                const char *opt_profname,
300                                                const char *opt_password,
301                                                uint32_t provider)
302 {
303         enum MAPISTATUS         retval;
304         char                    *profname = NULL;
305         struct mapi_session     *session = NULL;
306         TALLOC_CTX              *mem_ctx = NULL;
307
308         mem_ctx = talloc_named(NULL, 0, "octool_init_mapi");
309         if (opt_profname) {
310                 profname = talloc_strdup(mem_ctx, (char *)opt_profname);
311         } else {
312                 retval = GetDefaultProfile(mapi_ctx, &profname);
313                 if (retval != MAPI_E_SUCCESS) {
314                         mapi_errstr("GetDefaultProfile", GetLastError());
315                         talloc_free(mem_ctx);
316                         return NULL;
317                 }
318         }
319
320         if (!provider) {
321                 retval = MapiLogonEx(mapi_ctx, &session, profname, opt_password);
322         } else {
323                 retval = MapiLogonProvider(mapi_ctx, &session, profname, opt_password, provider);
324         }
325         MAPIFreeBuffer((char *)profname);
326
327         if (retval != MAPI_E_SUCCESS) {
328                 mapi_errstr("MapiLogonEx", GetLastError());
329                 talloc_free(mem_ctx);
330                 return NULL;
331         }
332
333         talloc_free(mem_ctx);
334         return session;
335 }