OSDN Git Service

Initial Import
[nethackexpress/trunk.git] / sys / winnt / mapimail.c
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. */
4
5 #ifdef MAX_BODY_SIZE
6 #undef MAX_BODY_SIZE
7 #define MAX_BODY_SIZE           2048    /* largest body held in ram in bytes */
8 #endif
9
10 #include "hack.h"
11 # ifdef LAN_MAIL
12 #include "win32api.h"
13 #include <mapi.h>
14
15 #define MAPI_MSGID_SIZE 512     /* as recommended */
16 #define MAPI_LIB_FAIL           1
17 #define MAPI_FUNC_FAIL          2
18
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   */
24 #ifdef MAPI_VERBOSE
25 FILE *dbgfile;
26 #define MAPIDEBUGFILENAME       "mapidebug.log"
27 #endif
28
29 /*
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)
33  */
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);
43
44 /*
45  * Declare the function pointers used to access MAPI routines
46  * from the MAPI32.DLL
47  */
48 LPMAPILOGON     fpMAPILogon;
49 LPMAPILOGOFF    fpMAPILogoff;
50 LPMAPIFINDNEXT  fpMAPIFindNext;
51 LPMAPIREADMAIL  fpMAPIReadMail;
52 LPMAPIFREEBUFFER fpMAPIFreeBuffer;
53
54
55 /*
56  * Data requiring synchronized access between the
57  * two thread contexts contained in this file
58  * (nethack thread and the MAPI-mail thread)
59  */
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!  */
65
66 /*
67  * Data updated by the NetHack thread only
68  * but read by the MAPI-mail thread.
69  *
70  */
71 char MAPI_username[120];
72 boolean debugmapi;
73
74 /*
75  * Data updated by the MAPI-mail thread only
76  * but read by the NetHack thread.
77  */
78 long mail_fetched = 0;
79
80 /*
81  * Data used only by the MAPI-mail thread.
82  */
83 long mailpasses;        /* counts the FindNext calls issued to MAPI */
84 char msgID[80];         /* message ID of msg under manipulation     */
85
86 /*===============================================================
87  * NetHack thread routines
88  *
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.
92  *
93  * These routines are referenced by shared code in
94  * sys/share/nhlan.c and they are prototyped in include/extern.h
95  *===============================================================
96  */
97 boolean mail_check()
98 {
99         if (!mailthread_stopping) {
100                 if (mail_fetched > 0)
101                         return TRUE;
102         } else lan_mail_terminate();
103         return FALSE;
104 }
105
106
107 boolean mail_fetch(msg)
108 struct lan_mail_struct *msg;
109 {
110         /* shouldn't need to check mailthread_stopping here
111            as the data should be valid anyway */
112         *msg = received_msg;
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();
118         return TRUE;
119 }
120
121 void mail_finish()
122 {
123         InterlockedDecrement(&mailthread_continue);
124 }
125
126 void mail_init(uname)
127 char *uname;
128 {
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.
133    */
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 */
142                 }
143         }
144         mailthread = 0;
145         nhmailthread_ID = 0;
146         mailthread_continue = 0;  /* no interlock needed yet */
147         mailthread_stopping = 0;  /* no interlock needed yet */
148 #ifdef MAPI_VERBOSE
149         if (getenv("DEBUG_MAPI")) debugmapi = TRUE; 
150 #endif
151         if (uname)
152                 strcpy(MAPI_username, uname);
153         else {
154 #ifdef MAPI_VERBOSE
155                 if (debugmapi) dbgfile = fopen(MAPIDEBUGFILENAME,"w");
156                 if (dbgfile) {
157                        fprintf(dbgfile,
158                               "mapi initialization bypassed because uname not available\n");
159                        fclose(dbgfile);
160                 }
161 #endif
162                 return;
163         }
164         mailthread = (HANDLE)_beginthreadex(
165                         (void *)0,
166                         (unsigned)0,
167                         start_mailthread,
168                         (void *)&nhmail_param,
169                         (unsigned)0, (unsigned *)&nhmailthread_ID);
170 #if 0
171         /* TODO: check for failure of the thread. For now nethack
172          *       doesn't care
173          */
174         if (!mailthread) {
175
176         }
177 #endif
178 }
179
180 /*===============================================================
181  * MAPI-mail thread routines
182  *
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).
187  *
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  *===============================================================
193  */
194
195 /*
196  * start_mailthread() is the entry point of the MAPI-mail thread.
197  *
198  */
199
200 static long __stdcall start_mailthread(LPVOID ThreadParam)
201 {
202     char *lu = MAPI_username;
203     if(MAPI_mail_init(lu)) {
204         InterlockedIncrement(&mailthread_continue);
205         while (mailthread_continue) {
206                 mailpasses++;
207                 if (MAPI_mail_check(msgID)) {
208                         if (MAPI_mail_fetch(msgID)) {
209                                 /* getting here means success */
210                         }
211                 }
212                 Sleep(MAILTHREADFREQ);
213         }
214 #ifdef MAPI_VERBOSE
215         if (debugmapi && !mailthread_continue) {
216           fprintf(dbgfile,
217                 "MAPI-thread detected mailthread_continue change.\n");
218           fprintf(dbgfile,
219                 "NetHack has requested that the MAPI-thread cease.\n");
220         }
221 #endif
222     }
223     return 0;
224 }
225
226 static int
227 MAPI_mail_context(mcount)
228 int *mcount;
229 {
230         unsigned long status;
231         char tmpID[80];
232         int count = 0;
233
234         tmpID[0] = '\0';
235         MAPIMessageID[0] = '\0';
236
237         /* Get the ID of the first unread message */
238         status = fpMAPIFindNext(MAPISession, 0, 0, 0,
239                 MAPI_UNREAD_ONLY | MAPI_GUARANTEE_FIFO,
240                 0, tmpID);
241         /* Now loop through them all until we have no more */
242         while (status == SUCCESS_SUCCESS) {
243                 strcpy(MAPIMessageID, tmpID);
244                 count++;
245                 status = fpMAPIFindNext(MAPISession, 0,
246                         0, MAPIMessageID,
247                         MAPI_UNREAD_ONLY | MAPI_GUARANTEE_FIFO,
248                         0, tmpID);
249         }
250         if (status == MAPI_E_NO_MESSAGES) {
251                 /* context is now at last message */
252                 if (mcount) *mcount = count;
253                 return SUCCESS_SUCCESS;
254         }
255         return status;
256 }
257
258 static boolean
259 MAPI_mail_check(mID)
260 char *mID;
261 {
262         unsigned long status;
263         char tmpID[80];
264
265         tmpID[0] = '\0';
266
267 #ifdef MAPI_VERBOSE
268         if (debugmapi) fprintf(dbgfile, "MAPI_mail_check() ");
269 #endif
270         if (mail_fetched) {
271 #ifdef MAPI_VERBOSE
272         if (debugmapi) fprintf(dbgfile, "returning FALSE (buffer occupied)\n");
273 #endif
274                 return FALSE; /* buffer occupied, don't bother */
275         }
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,
279                 0, tmpID);
280         if (status == SUCCESS_SUCCESS) {
281                 strcpy(mID, tmpID);
282 #ifdef MAPI_VERBOSE
283         if (debugmapi) fprintf(dbgfile, "returning TRUE\n");
284 #endif
285                 return TRUE;
286         }
287         if (status == MAPI_E_NO_MESSAGES) {
288 #ifdef MAPI_VERBOSE
289                 if (debugmapi) fprintf(dbgfile, "returning FALSE\n");
290 #endif
291                 return FALSE;
292         }
293 #ifdef MAPI_VERBOSE
294         if (debugmapi) fprintf(dbgfile,"Error, check_newmail() status: %d\n", status);
295         MAPI_mail_abort(status);
296 #endif
297         return FALSE;
298 }
299
300 static boolean
301 MAPI_mail_fetch(mID)
302 char *mID;
303 {
304         unsigned long status;
305
306 #ifdef MAPI_VERBOSE
307         if (debugmapi) fprintf(dbgfile, "MAPI_mail_fetch() ");
308 #endif
309         /*
310          *  Update context right away so we don't loop if there
311          *  was a problem getting the message
312          */
313         strcpy(MAPIMessageID, mID);
314
315         if (mail_fetched) {
316 #ifdef MAPI_VERBOSE
317         if (debugmapi) fprintf(dbgfile, "returning FALSE (buffer occupied)\n");
318 #endif
319                  return FALSE;  /* buffer occupied */
320         }
321
322         status = fpMAPIReadMail(MAPISession, 0, mID,
323                  MAPI_SUPPRESS_ATTACH | MAPI_PEEK,
324                  0, &MAPIMessage);
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);
334                 else
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);
344 #ifdef MAPI_VERBOSE
345                 if (debugmapi) fprintf(dbgfile, "returning TRUE\n");
346 #endif
347                 return TRUE;
348         }
349 #ifdef MAPI_VERBOSE
350         else
351                 if (debugmapi) fprintf(dbgfile,"MAPIRead failed, status = %d\n", status);
352         if (debugmapi) fprintf(dbgfile, "returning FALSE (failed)\n");
353 #endif
354         return FALSE;
355 }
356
357 static void
358 MAPI_mail_finish()
359 {
360         InterlockedIncrement(&mailthread_stopping);
361         (void) fpMAPILogoff(MAPISession,0,0,0);
362         (void) DeInitMAPI();
363 #ifdef MAPI_VERBOSE
364         if (debugmapi) fclose(dbgfile);
365 #endif
366         (void) _endthreadex(0);
367 }
368
369 static void
370 MAPI_mail_abort(reason)
371 unsigned long reason;
372 {
373 #ifdef MAPI_VERBOSE
374         if (debugmapi) fprintf(dbgfile,
375                 "Terminating MAPI-thread due to error %d.\n", reason);
376 #endif
377         MAPI_mail_finish();
378 }
379
380 static boolean
381 MAPI_mail_init(uname)
382 char *uname;
383 {
384         unsigned long status;
385         int count = 0;
386
387 #ifdef MAPI_VERBOSE
388         if (debugmapi) dbgfile = fopen(MAPIDEBUGFILENAME,"w");
389         if (debugmapi) fprintf(dbgfile,"Hello %s, NetHack is initializing MAPI.\n",
390                 uname);
391 #endif
392         status = InitMAPI();
393         if (status) {
394 #ifdef MAPI_VERBOSE
395             if (debugmapi) fprintf(dbgfile,"Error initializing MAPI %d\n", status);
396 #endif
397             return FALSE;
398         }
399         status = fpMAPILogon(0,uname,0L,0L,0L,(LPLHANDLE)&MAPISession);
400         if (status != SUCCESS_SUCCESS) {
401 #ifdef MAPI_VERBOSE
402             if (debugmapi) fprintf(dbgfile,"Status of MAPI logon is %d\n", status);
403 #endif
404             return FALSE;
405         }
406 #ifdef MAPI_VERBOSE
407         if (debugmapi) fprintf(dbgfile,
408                 "Stage 1 of MAPI initialization successful.\n");
409         if (debugmapi) fprintf(dbgfile,"MAPI Session handle: %d\n", MAPISession);
410 #endif
411         status = MAPI_mail_context(&count);
412         if (status == SUCCESS_SUCCESS) {
413 #ifdef MAPI_VERBOSE
414             if (debugmapi) fprintf(dbgfile,
415                     "Stage 2 of MAPI initialization successful.\n");
416             if (debugmapi) fprintf(dbgfile,"Detected %d old unread messages.\n",
417                     count);
418 #endif
419             return TRUE;
420         }
421 #ifdef MAPI_VERBOSE
422         if (debugmapi) fprintf(dbgfile,
423                 "Error, status of MAPI_mail_context() is %d.\n",
424                 status);
425         if (debugmapi) fprintf(dbgfile,
426                 "Dismantling MAPI interface and cleaning up.\n");
427 #endif
428         MAPI_mail_finish();
429         return FALSE;
430 }
431
432 int InitMAPI()
433 {
434
435     if (!(hLibrary = LoadLibrary("MAPI32.DLL")))
436       return MAPI_LIB_FAIL;
437
438     if ((fpMAPILogon = (LPMAPILOGON)GetProcAddress(hLibrary,"MAPILogon")) == NULL)
439       return MAPI_FUNC_FAIL;
440
441     if ((fpMAPILogoff = (LPMAPILOGOFF)GetProcAddress(hLibrary,"MAPILogoff")) == NULL)
442       return MAPI_FUNC_FAIL;
443
444     if ((fpMAPIFindNext= (LPMAPIFINDNEXT)GetProcAddress(hLibrary,"MAPIFindNext")) == NULL)
445       return MAPI_FUNC_FAIL;
446
447     if ((fpMAPIReadMail= (LPMAPIREADMAIL)GetProcAddress(hLibrary,"MAPIReadMail")) == NULL)
448       return MAPI_FUNC_FAIL;
449
450     if ((fpMAPIFindNext= (LPMAPIFINDNEXT)GetProcAddress(hLibrary,"MAPIFindNext")) == NULL)
451       return MAPI_FUNC_FAIL;
452
453     if ((fpMAPIFreeBuffer= (LPMAPIFREEBUFFER)GetProcAddress(hLibrary,"MAPIFreeBuffer")) == NULL)
454       return MAPI_FUNC_FAIL;
455
456 #ifdef MAPI_VERBOSE
457     if (debugmapi) {
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);
464     }
465 #endif
466     return 0;
467 }
468
469 int DeInitMAPI()
470 {
471
472     fpMAPILogon = NULL;
473     fpMAPILogoff= NULL;
474     fpMAPIFindNext= NULL;
475     fpMAPIReadMail= NULL;
476     fpMAPIFreeBuffer = NULL;
477     FreeLibrary(hLibrary);
478     return 0;
479 }
480
481 #endif /*LAN_MAIL*/
482