1 /* SCCS Id: @(#)mapimail.c 3.4 $Date: 2002/07/24 08:25:20 $ */
2 /* Copyright (c) Michael Allison, 1997 */
3 /* NetHack may be freely redistributed. See license for details. */
7 #define MAX_BODY_SIZE 2048 /* largest body held in ram in bytes */
15 #define MAPI_MSGID_SIZE 512 /* as recommended */
16 #define MAPI_LIB_FAIL 1
17 #define MAPI_FUNC_FAIL 2
19 HANDLE hLibrary; /* Handle for MAPI32.DLL */
20 LHANDLE MAPISession; /* Handle for MAPI session */
21 char MAPIMessageID[MAPI_MSGID_SIZE]; /* Msg ID from provider */
22 lpMapiMessage MAPIMessage; /* Ptr to message from prov */
23 struct lan_mail_struct received_msg; /* store received msg here */
26 #define MAPIDEBUGFILENAME "mapidebug.log"
30 * Prototypes for functions in this file
31 * (Not in normal NetHack style, but its doubtful that any
32 * of the code in here is at all portable between platforms)
34 static long __stdcall start_mailthread(LPVOID ThreadParam);
35 static boolean MAPI_mail_check(char *);
36 static boolean MAPI_mail_fetch(char *);
37 static void MAPI_mail_finish(void);
38 static int MAPI_mail_context(int *);
39 static boolean MAPI_mail_init(char *);
40 static int InitMAPI(void);
41 static int DeInitMAPI(void);
42 static void MAPI_mail_abort(unsigned long);
45 * Declare the function pointers used to access MAPI routines
48 LPMAPILOGON fpMAPILogon;
49 LPMAPILOGOFF fpMAPILogoff;
50 LPMAPIFINDNEXT fpMAPIFindNext;
51 LPMAPIREADMAIL fpMAPIReadMail;
52 LPMAPIFREEBUFFER fpMAPIFreeBuffer;
56 * Data requiring synchronized access between the
57 * two thread contexts contained in this file
58 * (nethack thread and the MAPI-mail thread)
60 HANDLE mailthread = 0; /* handle for the mail-thread */
61 unsigned nhmailthread_ID; /* thread ID for mail-thread */
62 unsigned long nhmail_param; /* value passed to mail-thread */
63 long mailthread_continue = 0; /* nh -> mapi thread: shut down! */
64 long mailthread_stopping = 0; /* mapi -> nh thread: MAPI is ill! */
67 * Data updated by the NetHack thread only
68 * but read by the MAPI-mail thread.
71 char MAPI_username[120];
75 * Data updated by the MAPI-mail thread only
76 * but read by the NetHack thread.
78 long mail_fetched = 0;
81 * Data used only by the MAPI-mail thread.
83 long mailpasses; /* counts the FindNext calls issued to MAPI */
84 char msgID[80]; /* message ID of msg under manipulation */
86 /*===============================================================
87 * NetHack thread routines
89 * These routines run in the context of the main NetHack thread.
90 * They are used to provide an interface between the NetHack
91 * LAN_MAIL code and the MAPI-thread code.
93 * These routines are referenced by shared code in
94 * sys/share/nhlan.c and they are prototyped in include/extern.h
95 *===============================================================
99 if (!mailthread_stopping) {
100 if (mail_fetched > 0)
102 } else lan_mail_terminate();
107 boolean mail_fetch(msg)
108 struct lan_mail_struct *msg;
110 /* shouldn't need to check mailthread_stopping here
111 as the data should be valid anyway */
113 iflags.lan_mail_fetched = TRUE;
114 /* clear the marker now so new messages can arrive */
115 InterlockedDecrement(&mail_fetched);
116 /* check to see if the MAPI-mail thread is saying "stop" */
117 if (mailthread_stopping) lan_mail_terminate();
123 InterlockedDecrement(&mailthread_continue);
126 void mail_init(uname)
129 /* This routine invokes the _beginthreadex()
130 * run-time library call to start the execution
131 * of the MAPI-mail thread. It also performs
132 * few other preparatory tasks.
134 if (mailthread_continue) {
135 /* Impossible - something is really messed up */
136 /* We better do some sanity checking */
137 /* Is there a valid thread handle and ID? */
138 if (mailthread && nhmailthread_ID) {
139 /* TODO: check 'em via WIN32 call */
140 /* if valid, do something about them */
141 /* if not, clear them */
146 mailthread_continue = 0; /* no interlock needed yet */
147 mailthread_stopping = 0; /* no interlock needed yet */
149 if (getenv("DEBUG_MAPI")) debugmapi = TRUE;
152 strcpy(MAPI_username, uname);
155 if (debugmapi) dbgfile = fopen(MAPIDEBUGFILENAME,"w");
158 "mapi initialization bypassed because uname not available\n");
164 mailthread = (HANDLE)_beginthreadex(
168 (void *)&nhmail_param,
169 (unsigned)0, (unsigned *)&nhmailthread_ID);
171 /* TODO: check for failure of the thread. For now nethack
180 /*===============================================================
181 * MAPI-mail thread routines
183 * These routines run in the context of their own
184 * MAPI-mail thread. They were placed into their own
185 * thread, because MAPI calls can sometimes (often?) take
186 * a horribly long time to return (minutes even).
188 * Each of the routines below are referenced only by other
189 * routines below, with the exception of start_mailthread(),
190 * of course, which is started by a run-time library call
191 * issued from the main NetHack thread.
192 *===============================================================
196 * start_mailthread() is the entry point of the MAPI-mail thread.
200 static long __stdcall start_mailthread(LPVOID ThreadParam)
202 char *lu = MAPI_username;
203 if(MAPI_mail_init(lu)) {
204 InterlockedIncrement(&mailthread_continue);
205 while (mailthread_continue) {
207 if (MAPI_mail_check(msgID)) {
208 if (MAPI_mail_fetch(msgID)) {
209 /* getting here means success */
212 Sleep(MAILTHREADFREQ);
215 if (debugmapi && !mailthread_continue) {
217 "MAPI-thread detected mailthread_continue change.\n");
219 "NetHack has requested that the MAPI-thread cease.\n");
227 MAPI_mail_context(mcount)
230 unsigned long status;
235 MAPIMessageID[0] = '\0';
237 /* Get the ID of the first unread message */
238 status = fpMAPIFindNext(MAPISession, 0, 0, 0,
239 MAPI_UNREAD_ONLY | MAPI_GUARANTEE_FIFO,
241 /* Now loop through them all until we have no more */
242 while (status == SUCCESS_SUCCESS) {
243 strcpy(MAPIMessageID, tmpID);
245 status = fpMAPIFindNext(MAPISession, 0,
247 MAPI_UNREAD_ONLY | MAPI_GUARANTEE_FIFO,
250 if (status == MAPI_E_NO_MESSAGES) {
251 /* context is now at last message */
252 if (mcount) *mcount = count;
253 return SUCCESS_SUCCESS;
262 unsigned long status;
268 if (debugmapi) fprintf(dbgfile, "MAPI_mail_check() ");
272 if (debugmapi) fprintf(dbgfile, "returning FALSE (buffer occupied)\n");
274 return FALSE; /* buffer occupied, don't bother */
276 /* Get the ID of the next unread message if there is one */
277 status = fpMAPIFindNext(MAPISession, 0, 0, MAPIMessageID,
278 MAPI_UNREAD_ONLY | MAPI_GUARANTEE_FIFO,
280 if (status == SUCCESS_SUCCESS) {
283 if (debugmapi) fprintf(dbgfile, "returning TRUE\n");
287 if (status == MAPI_E_NO_MESSAGES) {
289 if (debugmapi) fprintf(dbgfile, "returning FALSE\n");
294 if (debugmapi) fprintf(dbgfile,"Error, check_newmail() status: %d\n", status);
295 MAPI_mail_abort(status);
304 unsigned long status;
307 if (debugmapi) fprintf(dbgfile, "MAPI_mail_fetch() ");
310 * Update context right away so we don't loop if there
311 * was a problem getting the message
313 strcpy(MAPIMessageID, mID);
317 if (debugmapi) fprintf(dbgfile, "returning FALSE (buffer occupied)\n");
319 return FALSE; /* buffer occupied */
322 status = fpMAPIReadMail(MAPISession, 0, mID,
323 MAPI_SUPPRESS_ATTACH | MAPI_PEEK,
325 if (status == SUCCESS_SUCCESS) {
326 strncpy(received_msg.subject,
327 MAPIMessage->lpszSubject,
328 sizeof(received_msg.subject) - 1);
329 if((MAPIMessage->lpOriginator->lpszName != (char *)0)
330 && MAPIMessage->lpOriginator->lpszName[0] != '\0')
331 strncpy(received_msg.sender,
332 MAPIMessage->lpOriginator->lpszName,
333 sizeof(received_msg.sender) - 1);
335 strncpy(received_msg.sender,
336 MAPIMessage->lpOriginator->lpszAddress,
337 sizeof(received_msg.sender) - 1);
338 strncpy(received_msg.body,
339 MAPIMessage->lpszNoteText,MAX_BODY_SIZE - 1);
340 received_msg.body[MAX_BODY_SIZE - 1] = '\0';
341 received_msg.body_in_ram = TRUE;
342 status = fpMAPIFreeBuffer(MAPIMessage);
343 InterlockedIncrement(&mail_fetched);
345 if (debugmapi) fprintf(dbgfile, "returning TRUE\n");
351 if (debugmapi) fprintf(dbgfile,"MAPIRead failed, status = %d\n", status);
352 if (debugmapi) fprintf(dbgfile, "returning FALSE (failed)\n");
360 InterlockedIncrement(&mailthread_stopping);
361 (void) fpMAPILogoff(MAPISession,0,0,0);
364 if (debugmapi) fclose(dbgfile);
366 (void) _endthreadex(0);
370 MAPI_mail_abort(reason)
371 unsigned long reason;
374 if (debugmapi) fprintf(dbgfile,
375 "Terminating MAPI-thread due to error %d.\n", reason);
381 MAPI_mail_init(uname)
384 unsigned long status;
388 if (debugmapi) dbgfile = fopen(MAPIDEBUGFILENAME,"w");
389 if (debugmapi) fprintf(dbgfile,"Hello %s, NetHack is initializing MAPI.\n",
395 if (debugmapi) fprintf(dbgfile,"Error initializing MAPI %d\n", status);
399 status = fpMAPILogon(0,uname,0L,0L,0L,(LPLHANDLE)&MAPISession);
400 if (status != SUCCESS_SUCCESS) {
402 if (debugmapi) fprintf(dbgfile,"Status of MAPI logon is %d\n", status);
407 if (debugmapi) fprintf(dbgfile,
408 "Stage 1 of MAPI initialization successful.\n");
409 if (debugmapi) fprintf(dbgfile,"MAPI Session handle: %d\n", MAPISession);
411 status = MAPI_mail_context(&count);
412 if (status == SUCCESS_SUCCESS) {
414 if (debugmapi) fprintf(dbgfile,
415 "Stage 2 of MAPI initialization successful.\n");
416 if (debugmapi) fprintf(dbgfile,"Detected %d old unread messages.\n",
422 if (debugmapi) fprintf(dbgfile,
423 "Error, status of MAPI_mail_context() is %d.\n",
425 if (debugmapi) fprintf(dbgfile,
426 "Dismantling MAPI interface and cleaning up.\n");
435 if (!(hLibrary = LoadLibrary("MAPI32.DLL")))
436 return MAPI_LIB_FAIL;
438 if ((fpMAPILogon = (LPMAPILOGON)GetProcAddress(hLibrary,"MAPILogon")) == NULL)
439 return MAPI_FUNC_FAIL;
441 if ((fpMAPILogoff = (LPMAPILOGOFF)GetProcAddress(hLibrary,"MAPILogoff")) == NULL)
442 return MAPI_FUNC_FAIL;
444 if ((fpMAPIFindNext= (LPMAPIFINDNEXT)GetProcAddress(hLibrary,"MAPIFindNext")) == NULL)
445 return MAPI_FUNC_FAIL;
447 if ((fpMAPIReadMail= (LPMAPIREADMAIL)GetProcAddress(hLibrary,"MAPIReadMail")) == NULL)
448 return MAPI_FUNC_FAIL;
450 if ((fpMAPIFindNext= (LPMAPIFINDNEXT)GetProcAddress(hLibrary,"MAPIFindNext")) == NULL)
451 return MAPI_FUNC_FAIL;
453 if ((fpMAPIFreeBuffer= (LPMAPIFREEBUFFER)GetProcAddress(hLibrary,"MAPIFreeBuffer")) == NULL)
454 return MAPI_FUNC_FAIL;
458 fprintf(dbgfile,"Entry Points:\n");
459 fprintf(dbgfile,"MAPILogon = %p\n",fpMAPILogon);
460 fprintf(dbgfile,"MAPILogoff = %p\n",fpMAPILogoff);
461 fprintf(dbgfile,"MAPIFindNext = %p\n",fpMAPIFindNext);
462 fprintf(dbgfile,"MAPIFreeBuffer = %p\n",fpMAPIReadMail);
463 fprintf(dbgfile,"MAPIReadMail = %p\n",fpMAPIFreeBuffer);
474 fpMAPIFindNext= NULL;
475 fpMAPIReadMail= NULL;
476 fpMAPIFreeBuffer = NULL;
477 FreeLibrary(hLibrary);