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