1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_shell.hxx"
30 #include <osl/diagnose.h>
31 
32 #ifndef _RTL_STRING_HXX_
33 //#include <rtl/string.hxx>
34 #endif
35 #include "simplemapi.hxx"
36 
37 #define WIN32_LEAN_AND_MEAN
38 #if defined _MSC_VER
39 #pragma warning(push, 1)
40 #endif
41 #include <windows.h>
42 #if defined _MSC_VER
43 #pragma warning(pop)
44 #endif
45 #include <tchar.h>
46 
47 #include <iostream>
48 #include <vector>
49 #include <sstream>
50 #include <stdexcept>
51 
52 #if OSL_DEBUG_LEVEL > 2
53     void dumpParameter();
54 #endif
55 
56 typedef std::vector<std::string> StringList_t;
57 typedef StringList_t::const_iterator StringListIterator_t;
58 typedef std::vector<MapiRecipDesc> MapiRecipientList_t;
59 typedef std::vector<MapiFileDesc> MapiAttachmentList_t;
60 
61 const int LEN_SMTP_PREFIX = 5; // "SMTP:"
62 
63 namespace /* private */
64 {
65     std::string gFrom;
66     std::string gSubject;
67     std::string gBody;
68     StringList_t gTo;
69     StringList_t gCc;
70     StringList_t gBcc;
71     StringList_t gAttachments;
72     int gMapiFlags = 0;
73 }
74 
75 /**
76     Add a prefix to an email address. MAPI requires that that
77     email addresses have an 'SMTP:' prefix.
78 
79     @param  aEmailAddress
80     [in] the email address.
81 
82     @param  aPrefix
83     [in] the prefix to be added to the email address.
84 
85     @returns
86     the email address prefixed with the specified prefix.
87 */
88 inline std::string prefixEmailAddress(
89     const std::string& aEmailAddress,
90     const std::string& aPrefix = "SMTP:")
91 {
92     return (aPrefix + aEmailAddress);
93 }
94 
95 /** @internal */
96 void addRecipient(
97     ULONG recipClass,
98     const std::string& recipAddress,
99     MapiRecipientList_t* pMapiRecipientList)
100 {
101     MapiRecipDesc mrd;
102     ZeroMemory(&mrd, sizeof(mrd));
103 
104     mrd.ulRecipClass = recipClass;
105     mrd.lpszName = const_cast<char*>(recipAddress.c_str()) + LEN_SMTP_PREFIX;
106     mrd.lpszAddress = const_cast<char*>(recipAddress.c_str());
107     pMapiRecipientList->push_back(mrd);
108 }
109 
110 /** @internal */
111 void initRecipientList(MapiRecipientList_t* pMapiRecipientList)
112 {
113     OSL_ASSERT(pMapiRecipientList->size() == 0);
114 
115     // add to recipients
116     StringListIterator_t iter = gTo.begin();
117     StringListIterator_t iter_end = gTo.end();
118     for (; iter != iter_end; ++iter)
119         addRecipient(MAPI_TO, *iter, pMapiRecipientList);
120 
121     // add cc recipients
122     iter = gCc.begin();
123     iter_end = gCc.end();
124     for (; iter != iter_end; ++iter)
125         addRecipient(MAPI_CC, *iter, pMapiRecipientList);
126 
127     // add bcc recipients
128     iter = gBcc.begin();
129     iter_end = gBcc.end();
130     for (; iter != iter_end; ++iter)
131         addRecipient(MAPI_BCC, *iter, pMapiRecipientList);
132 }
133 
134 /** @internal */
135 void initAttachementList(MapiAttachmentList_t* pMapiAttachmentList)
136 {
137     OSL_ASSERT(pMapiAttachmentList->size() == 0);
138 
139     StringListIterator_t iter = gAttachments.begin();
140     StringListIterator_t iter_end = gAttachments.end();
141     for (/**/; iter != iter_end; ++iter)
142     {
143         MapiFileDesc mfd;
144         ZeroMemory(&mfd, sizeof(mfd));
145         mfd.lpszPathName = const_cast<char*>(iter->c_str());
146         mfd.nPosition = sal::static_int_cast<ULONG>(-1);
147         pMapiAttachmentList->push_back(mfd);
148     }
149 }
150 
151 /** @internal */
152 void initMapiOriginator(MapiRecipDesc* pMapiOriginator)
153 {
154     ZeroMemory(pMapiOriginator, sizeof(MapiRecipDesc));
155 
156     pMapiOriginator->ulRecipClass = MAPI_ORIG;
157     pMapiOriginator->lpszName = "";
158     pMapiOriginator->lpszAddress = const_cast<char*>(gFrom.c_str());
159 }
160 
161 /** @internal */
162 void initMapiMessage(
163     MapiRecipDesc* aMapiOriginator,
164     MapiRecipientList_t& aMapiRecipientList,
165     MapiAttachmentList_t& aMapiAttachmentList,
166     MapiMessage* pMapiMessage)
167 {
168     ZeroMemory(pMapiMessage, sizeof(MapiMessage));
169 
170     pMapiMessage->lpszSubject = const_cast<char*>(gSubject.c_str());
171     pMapiMessage->lpszNoteText = (gBody.length() ? const_cast<char*>(gBody.c_str()) : NULL);
172     pMapiMessage->lpOriginator = aMapiOriginator;
173     pMapiMessage->lpRecips = aMapiRecipientList.size() ? &aMapiRecipientList[0] : 0;
174     pMapiMessage->nRecipCount = aMapiRecipientList.size();
175     pMapiMessage->lpFiles = &aMapiAttachmentList[0];
176     pMapiMessage->nFileCount = aMapiAttachmentList.size();
177 }
178 
179 char* KnownParameter[] =
180 {
181     "--to",
182     "--cc",
183     "--bcc",
184     "--from",
185     "--subject",
186     "--body",
187     "--attach",
188     "--mapi-dialog",
189     "--mapi-logon-ui"
190 };
191 
192 const size_t nKnownParameter = (sizeof(KnownParameter)/sizeof(KnownParameter[0]));
193 
194 /** @internal */
195 bool isKnownParameter(const char* aParameterName)
196 {
197     for (size_t i = 0; i < nKnownParameter; i++)
198         if (_tcsicmp(aParameterName, KnownParameter[i]) == 0)
199             return true;
200 
201     return false;
202 }
203 
204 /** @internal */
205 void initParameter(int argc, char* argv[])
206 {
207     for (int i = 1; i < argc; i++)
208     {
209         if (!isKnownParameter(argv[i]))
210         {
211             OSL_ENSURE(false, "Wrong parameter received");
212             continue;
213         }
214 
215         if ((_tcsicmp(argv[i], TEXT("--mapi-dialog")) == 0))
216         {
217             gMapiFlags |= MAPI_DIALOG;
218         }
219         else if ((_tcsicmp(argv[i], TEXT("--mapi-logon-ui")) == 0))
220         {
221             gMapiFlags |= MAPI_LOGON_UI;
222         }
223         else if ((i+1) < argc) // is the value of a parameter available too?
224         {
225             if (_tcsicmp(argv[i], TEXT("--to")) == 0)
226                 gTo.push_back(prefixEmailAddress(argv[i+1]));
227             else if (_tcsicmp(argv[i], TEXT("--cc")) == 0)
228                 gCc.push_back(prefixEmailAddress(argv[i+1]));
229             else if (_tcsicmp(argv[i], TEXT("--bcc")) == 0)
230                 gBcc.push_back(prefixEmailAddress(argv[i+1]));
231             else if (_tcsicmp(argv[i], TEXT("--from")) == 0)
232                 gFrom = prefixEmailAddress(argv[i+1]);
233             else if (_tcsicmp(argv[i], TEXT("--subject")) == 0)
234                 gSubject = argv[i+1];
235             else if (_tcsicmp(argv[i], TEXT("--body")) == 0)
236                 gBody = argv[i+1];
237             else if ((_tcsicmp(argv[i], TEXT("--attach")) == 0))
238                 gAttachments.push_back(argv[i+1]);
239 
240             i++;
241         }
242     }
243 }
244 
245 /**
246     Main.
247     NOTE: Because this is program only serves implementation
248     purposes and should not be used by any end user the
249     parameter checking is very limited. Every unknown parameter
250     will be ignored.
251 */
252 int main(int argc, char* argv[])
253 {
254     //MessageBox(NULL, "Debug", "Debug", MB_OK);
255 
256     initParameter(argc, argv);
257 
258 #if OSL_DEBUG_LEVEL > 2
259     dumpParameter();
260 #endif
261 
262     ULONG ulRet = MAPI_E_FAILURE;
263 
264     try
265     {
266         CSimpleMapi mapi;
267 
268         // #93007# we have to set the flag MAPI_NEW_SESSION,
269         // because in the case Outlook xxx (not Outlook Express!)
270         // is installed as Exchange and Mail Client a Profile
271         // selection dialog must appear because we specify no
272         // profile name, so the user has to specify a profile
273         FLAGS flFlag = MAPI_NEW_SESSION | MAPI_LOGON_UI;
274         LHANDLE hSession;
275         ulRet = mapi.MAPILogon(0, NULL, NULL, flFlag, 0L, &hSession);
276 
277         if (ulRet == SUCCESS_SUCCESS)
278         {
279             MapiRecipDesc mapiOriginator;
280             MapiRecipientList_t mapiRecipientList;
281             MapiAttachmentList_t mapiAttachmentList;
282             MapiMessage mapiMsg;
283 
284             initMapiOriginator(&mapiOriginator);
285             initRecipientList(&mapiRecipientList);
286             initAttachementList(&mapiAttachmentList);
287             initMapiMessage((gFrom.length() ? &mapiOriginator : NULL), mapiRecipientList, mapiAttachmentList, &mapiMsg);
288 
289             ulRet = mapi.MAPISendMail(hSession, 0, &mapiMsg, gMapiFlags, 0);
290 
291             mapi.MAPILogoff(hSession, 0, 0, 0);
292         }
293     }
294     catch (const std::runtime_error&
295     #if OSL_DEBUG_LEVEL > 0
296     ex
297     #endif
298     )
299     {
300         OSL_ENSURE(false, ex.what());
301     }
302     return ulRet;
303 }
304 
305 #if OSL_DEBUG_LEVEL > 2
306     void dumpParameter()
307     {
308         std::ostringstream oss;
309 
310         if (gFrom.length() > 0)
311             oss << "--from" << " " << gFrom << std::endl;
312 
313         if (gSubject.length() > 0)
314             oss << "--subject" << " " << gSubject << std::endl;
315 
316         if (gBody.length() > 0)
317             oss << "--body" << " " << gBody << std::endl;
318 
319         StringListIterator_t iter = gTo.begin();
320         StringListIterator_t iter_end = gTo.end();
321         for (/**/;iter != iter_end; ++iter)
322             oss << "--to" << " " << *iter << std::endl;
323 
324         iter = gCc.begin();
325         iter_end = gCc.end();
326         for (/**/;iter != iter_end; ++iter)
327             oss << "--cc" << " " << *iter << std::endl;
328 
329         iter = gBcc.begin();
330         iter_end = gBcc.end();
331         for (/**/;iter != iter_end; ++iter)
332             oss << "--bcc" << " " << *iter << std::endl;
333 
334         iter = gAttachments.begin();
335         iter_end = gAttachments.end();
336         for (/**/;iter != iter_end; ++iter)
337             oss << "--attach" << " " << *iter << std::endl;
338 
339         if (gMapiFlags & MAPI_DIALOG)
340             oss << "--mapi-dialog" << std::endl;
341 
342         if (gMapiFlags & MAPI_LOGON_UI)
343             oss << "--mapi-logon-ui" << std::endl;
344 
345         MessageBox(NULL, oss.str().c_str(), "Arguments", MB_OK | MB_ICONINFORMATION);
346     }
347 #endif
348