Back to index

lightning-sunbird  0.9+nobinonly
mapihook.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 //
00038 //  MAPI Hooks for Communicator
00039 //  Note: THIS LIVES IN COMMUNICATOR THOUGH IT IS IN THE MAPIDLL FOR
00040 //        BUILD REASONS
00041 //  Written by: Rich Pizzarro (rhp@netscape.com)
00042 //  November 1997
00043 
00044 #include <windows.h>
00045 #include <trace.h>
00046 
00047 #include <stdio.h>    
00048 #include <string.h>
00049 #include <stdlib.h>
00050 #include <sys/stat.h>
00051 
00052 #include "wfemsg.h"     // for WFE_MSGGetMaster()
00053 #include "msgmapi.h"    // For enumerating messages...
00054 #include "nsstrseq.h"
00055 #include "mapihook.h"
00056 #include "nscpmapi.h"
00057 #include "mapismem.h"
00058 #include "mapimail.h"
00059 #include "hiddenfr.h"
00060 #include "msgcom.h"
00061 
00062 #define   DELIMIT         "-{|}-"    // DON'T I18N THIS!
00063 
00064 //
00065 // Static defines for the MAPI support...
00066 //
00067 static CMAPIConnection *mapiConnections[MAX_CON] = {NULL, NULL, NULL, NULL};
00068 
00069 //
00070 // Forward declarations...
00071 //
00072 LONG    ProcessMAPILogon(MAPILogonType *logonInfo);
00073 LONG    ProcessMAPILogoff(MAPILogoffType *logoffInfo);
00074 LONG    ProcessMAPISendMail(MAPISendMailType *sendMailPtr);
00075 LONG    ProcessMAPISaveMail(MAPISendMailType *sendMailPtr);
00076 LONG    ProcessMAPISendDocuments(MAPISendDocumentsType *sendDocPtr);
00077 LONG    ProcessMAPIFindNext(MAPIFindNextType *findInfo);
00078 LONG    ProcessMAPIDeleteMail(MAPIDeleteMailType *delInfo);
00079 LONG    ProcessMAPIResolveName(MAPIResolveNameType *nameInfo);
00080 LONG    ProcessMAPIDetails(MAPIDetailsType *detailInfo);
00081 LONG    ProcessMAPIReadMail(MAPIReadMailType *readInfo);
00082 LONG    ProcessMAPIAddress(MAPIAddressType *addrInfo);
00083 
00084 //
00085 // This will store the CFrameWnd we startup for MAPI and if we do start
00086 // an instance of the browser, we will close it out when we leave.
00087 //
00088 static CFrameWnd  *pMAPIFrameWnd = NULL;
00089 
00090 void 
00091 StoreMAPIFrameWnd(CFrameWnd *pFrameWnd)
00092 {
00093   pMAPIFrameWnd = pFrameWnd;
00094 }
00095 
00096 // This is the result of a WM_COPYDATA message. This will be used to send requests
00097 // into Communicator for Simple MAPI commands.
00098 //
00099 // The description of the parameters coming into this call are:
00100 //
00101 //    wParam = (WPARAM) (HWND) hwnd;            // handle of sending window 
00102 //    lParam = (LPARAM) (PCOPYDATASTRUCT) pcds; // pointer to structure with data 
00103 //    context= needed for the context we will use in Communicator
00104 //
00105 //            typedef struct tagCOPYDATASTRUCT {  // cds  
00106 //                   DWORD dwData;               // the ID of the request
00107 //                   DWORD cbData;               // the size of the argument
00108 //                   PVOID lpData;               // Chunk of information defined specifically for each of the
00109 //                        // Simple MAPI Calls.
00110 //            } COPYDATASTRUCT; 
00111 //
00112 // Returns: The MAPI Return code for the operation:
00113 //
00114 //
00115 LONG ProcessNetscapeMAPIHook(WPARAM wParam, LPARAM lParam)
00116 {
00117   PCOPYDATASTRUCT      pcds = (PCOPYDATASTRUCT) lParam;
00118   MAPIIPCType       *ipcInfo; 
00119 #ifdef WIN32   
00120   HANDLE            hSharedMemory;
00121 #endif
00122 
00123        if (lParam == NULL)
00124        {
00125               return(MAPI_E_FAILURE);
00126        }
00127 
00128   //
00129   // Get shared memory info structure pointer...
00130   //
00131   ipcInfo = (MAPIIPCType *)pcds->lpData;
00132   if (ipcInfo == NULL)
00133        {
00134               return(MAPI_E_FAILURE);
00135        }
00136 
00137   //
00138   // Now connect to shared memory...or just set the
00139   // pointer for Win16
00140   //
00141 #ifdef WIN32
00142   CSharedMem *sMem = NSOpenExistingSharedMemory((LPCTSTR) ipcInfo->smemName, &hSharedMemory);
00143   if (!sMem)
00144        {
00145               return(MAPI_E_FAILURE);
00146        }
00147 #else
00148   if (!ipcInfo->lpsmem)
00149   {
00150     return(MAPI_E_FAILURE);
00151   }
00152 #endif
00153 
00154   TRACE("MAPI: MAPIHook Message ID = %d\n", pcds->dwData);
00155        switch (pcds->dwData) 
00156        {
00158   // MAPILogon
00160   case NSCP_MAPILogon:
00161     {
00162      MAPILogonType     *logonInfo;
00163 #ifdef WIN32
00164     logonInfo = (MAPILogonType *) &(sMem->m_buf[0]);
00165 #else    
00166     logonInfo = (MAPILogonType *) ipcInfo->lpsmem;
00167 #endif
00168 
00169     if (!logonInfo)
00170     {
00171       return(MAPI_E_FAILURE);
00172     }
00173   
00174     logonInfo->ipcWorked = 1;         // Set the worked flag
00175     return(ProcessMAPILogon(logonInfo));
00176     break;
00177     }
00178 
00180   // MAPILogoff
00182   case NSCP_MAPILogoff:
00183     {
00184     MAPILogoffType     *logoffInfo;
00185  
00186 #ifdef WIN32
00187     logoffInfo = (MAPILogoffType *) &(sMem->m_buf[0]);
00188 #else    
00189     logoffInfo = (MAPILogoffType *) ipcInfo->lpsmem;
00190 #endif
00191 
00192     if (!logoffInfo)
00193     {
00194       return(MAPI_E_FAILURE);
00195     }
00196 
00197     logoffInfo->ipcWorked = 1;         // Set the worked flag
00198     return(ProcessMAPILogoff(logoffInfo));
00199     break;
00200     }
00201 
00203   // NSCP_MAPISendMail
00205   case NSCP_MAPISendMail:
00206      {
00207      MAPISendMailType     *sendMailPtr;
00208 #ifdef WIN32
00209     sendMailPtr = (MAPISendMailType *) &(sMem->m_buf[0]);
00210 #else    
00211     sendMailPtr = (MAPISendMailType *) ipcInfo->lpsmem;
00212 #endif
00213 
00214     if (!sendMailPtr)
00215     {
00216       return(MAPI_E_FAILURE);
00217     }
00218 
00219     sendMailPtr->ipcWorked = 1;         // Set the worked flag
00220     return(ProcessMAPISendMail(sendMailPtr));
00221     break;
00222     }
00223 
00225   // MAPISendDocuments
00227   case NSCP_MAPISendDocuments:
00228      {
00229      MAPISendDocumentsType     *sendDocPtr;
00230 #ifdef WIN32
00231     sendDocPtr = (MAPISendDocumentsType *) &(sMem->m_buf[0]);
00232 #else    
00233     sendDocPtr = (MAPISendDocumentsType *) ipcInfo->lpsmem;
00234 #endif
00235 
00236     if (!sendDocPtr)
00237     {
00238       return(MAPI_E_FAILURE);
00239     }
00240 
00241     sendDocPtr->ipcWorked = 1;         // Set the worked flag
00242     return(ProcessMAPISendDocuments(sendDocPtr));
00243     break;
00244     }
00245 
00247   // MAPIFindNext
00249   case NSCP_MAPIFindNext:
00250     {
00251     MAPIFindNextType    *findInfo;
00252  
00253 #ifdef WIN32
00254     findInfo = (MAPIFindNextType *) &(sMem->m_buf[0]);
00255 #else    
00256     findInfo = (MAPIFindNextType *) ipcInfo->lpsmem;
00257 #endif
00258 
00259     if (!findInfo)
00260     {
00261       return(MAPI_E_FAILURE);
00262     }
00263 
00264     findInfo->ipcWorked = 1;         // Set the worked flag
00265     return(ProcessMAPIFindNext(findInfo));
00266     break;
00267     }
00268 
00270   // MAPIDeleteMail
00272   case NSCP_MAPIDeleteMail:
00273     {
00274     MAPIDeleteMailType    *delInfo;
00275  
00276 #ifdef WIN32
00277     delInfo = (MAPIDeleteMailType *) &(sMem->m_buf[0]);
00278 #else    
00279     delInfo = (MAPIDeleteMailType *) ipcInfo->lpsmem;
00280 #endif
00281 
00282     if (!delInfo)
00283     {
00284       return(MAPI_E_FAILURE);
00285     }
00286 
00287     delInfo->ipcWorked = 1;         // Set the worked flag
00288     return(ProcessMAPIDeleteMail(delInfo));
00289     break;
00290     }
00291 
00293   // MAPIResolveName
00295   case NSCP_MAPIResolveName:
00296     {
00297     MAPIResolveNameType    *nameInfo;
00298  
00299 #ifdef WIN32
00300     nameInfo = (MAPIResolveNameType *) &(sMem->m_buf[0]);
00301 #else    
00302     nameInfo = (MAPIResolveNameType *) ipcInfo->lpsmem;
00303 #endif
00304 
00305     if (!nameInfo)
00306     {
00307       return(MAPI_E_FAILURE);
00308     }
00309 
00310     nameInfo->ipcWorked = 1;         // Set the worked flag
00311     return(ProcessMAPIResolveName(nameInfo));
00312     break;
00313     }
00314 
00316   // MAPIDetails
00318   case NSCP_MAPIDetails:
00319     {
00320     MAPIDetailsType    *detailInfo;
00321  
00322 #ifdef WIN32
00323     detailInfo = (MAPIDetailsType *) &(sMem->m_buf[0]);
00324 #else    
00325     detailInfo = (MAPIDetailsType *) ipcInfo->lpsmem;
00326 #endif
00327 
00328     if (!detailInfo)
00329     {
00330       return(MAPI_E_FAILURE);
00331     }
00332 
00333     detailInfo->ipcWorked = 1;         // Set the worked flag
00334     return(ProcessMAPIDetails(detailInfo));
00335     break;
00336     }
00337 
00339   // MAPIReadMail
00341   case NSCP_MAPIReadMail:
00342     {
00343     MAPIReadMailType    *readInfo;
00344  
00345 #ifdef WIN32
00346     readInfo = (MAPIReadMailType *) &(sMem->m_buf[0]);
00347 #else    
00348     readInfo = (MAPIReadMailType *) ipcInfo->lpsmem;
00349 #endif
00350 
00351     if (!readInfo)
00352     {
00353       return(MAPI_E_FAILURE);
00354     }
00355 
00356     readInfo->ipcWorked = 1;         // Set the worked flag
00357     return(ProcessMAPIReadMail(readInfo));
00358     break;
00359     }
00360 
00362   // NSCP_MAPISaveMail
00364   case NSCP_MAPISaveMail:
00365      {
00366      MAPISendMailType     *sendMailPtr;
00367 #ifdef WIN32
00368     sendMailPtr = (MAPISendMailType *) &(sMem->m_buf[0]);
00369 #else    
00370     sendMailPtr = (MAPISendMailType *) ipcInfo->lpsmem;
00371 #endif
00372 
00373     if (!sendMailPtr)
00374     {
00375       return(MAPI_E_FAILURE);
00376     }
00377 
00378     sendMailPtr->ipcWorked = 1;         // Set the worked flag
00379     return(ProcessMAPISaveMail(sendMailPtr));
00380     break;
00381     }
00382 
00384   // MAPIAddress
00386   case NSCP_MAPIAddress:
00387     {
00388     MAPIAddressType    *addrInfo;
00389  
00390 #ifdef WIN32
00391     addrInfo = (MAPIAddressType *) &(sMem->m_buf[0]);
00392 #else    
00393     addrInfo = (MAPIAddressType *) ipcInfo->lpsmem;
00394 #endif
00395 
00396     if (!addrInfo)
00397     {
00398       return(MAPI_E_FAILURE);
00399     }
00400 
00401     addrInfo->ipcWorked = 1;         // Set the worked flag
00402     return(ProcessMAPIAddress(addrInfo));
00403     }
00404   
00405   case NSCP_MAPIFree:   // This should never hit Communicator, but if it does
00406 #ifdef WIN16
00407     return(SUCCESS_SUCCESS);       // Just return
00408 #else
00409     return(S_OK);       // Just return 
00410 #endif
00411 
00412        default:
00413     return(MAPI_E_NOT_SUPPORTED);     // Should never hit here!
00414               break;
00415        }
00416 
00417        return(SUCCESS_SUCCESS);
00418 }
00419 
00420 //
00421 // Find the default session for Communicator...
00422 //
00423 CMAPIConnection 
00424 *GetDefaultSession(void)
00425 {
00426   int i;
00427   
00428   for (i=0; i < MAX_CON; i++)
00429   {
00430     if (mapiConnections[i] != NULL)
00431     {
00432       if (mapiConnections[i]->IsDefault())
00433       {
00434         return mapiConnections[i];
00435       }
00436     }
00437   }
00438 
00439   return(NULL);
00440 }
00441 
00442 //
00443 // Find an open session slot...
00444 //
00445 LONG
00446 GetOpenSessionSlot( void )
00447 {
00448   int i;
00449   
00450   for (i=0; i < MAX_CON; i++)
00451   {
00452     if (mapiConnections[i] == NULL)
00453     {
00454       return(i);
00455     }
00456   }
00457 
00458   return(-1);
00459 }
00460 
00461 //
00462 // Returns TRUE if it was reassigned and FALSE if not.
00463 //
00464 BOOL
00465 TryDefaultReassignment(void)
00466 {
00467   int   i;
00468   int   loc = -1;
00469 
00470   // Find any sessions left?
00471   for (i=0; i < MAX_CON; i++)
00472   {
00473     if (mapiConnections[i] != NULL)
00474     {
00475       loc = i;
00476       break;
00477     }
00478   }
00479 
00480   // Set default state on the object to true
00481   if (loc >= 0)
00482   {
00483     mapiConnections[loc]->SetDefault(TRUE);
00484     return(TRUE);
00485   }
00486   else    
00487   {
00488     return(FALSE);
00489   }
00490 }
00491 
00492 LONG
00493 ProcessMAPILogon(MAPILogonType *logonInfo)
00494 {
00495   CMAPIConnection *defSession = GetDefaultSession();
00496   NSstringSeq strSeq = (LPSTR) logonInfo + sizeof(MAPILogonType);
00497   LPSTR lpszProfileName = NSStrSeqGet(strSeq, 0);
00498   LPSTR lpszPassword    = NSStrSeqGet(strSeq, 1);
00499 
00500   TRACE("MAPI: ProcessMAPILogon() ProfileName = [%s] Password = [%s]\n", 
00501                             lpszProfileName, lpszPassword);
00502   //
00503   // This is a query if lpszProfileName is NULL, lpszPassword is NULL and 
00504   // the MAPI_LOGON_UI is not set 
00505   //
00506   if ((lpszProfileName[0] == '\0') && (lpszPassword[0] == '\0') && 
00507     (!(logonInfo->flFlags & MAPI_LOGON_UI)) )
00508   {
00509     if (defSession == NULL)
00510     {
00511       return(MAPI_E_FAILURE);
00512     }
00513     else
00514     {
00515       defSession->IncrementSessionCount();
00516       logonInfo->lhSession = defSession->GetID();
00517       return(SUCCESS_SUCCESS);
00518     }
00519   }
00520 
00521   //
00522   // Only allow for sessions by a single profile name...
00523   //
00524   if ( ( defSession != NULL ) &&
00525        (
00526         (lstrcmp(lpszProfileName, defSession->GetProfileName() ) != 0) ||
00527         (lstrcmp(lpszPassword, defSession->GetPassword() ) != 0)
00528        )
00529      )
00530   {
00531     return(MAPI_E_TOO_MANY_SESSIONS);
00532   }
00533 
00534   //
00535   // Now create the new MAPI session if we have to...
00536   //
00537   BOOL createNew = FALSE;
00538   if ( 
00539       ( defSession == NULL ) ||
00540       // Indicates an attempt should be made to create a new session rather than acquire 
00541       // the environment's shared session. If the MAPI_NEW_SESSION flag is not set, MAPILogon 
00542       // uses an existing shared session.
00543       (logonInfo->flFlags & MAPI_NEW_SESSION) ||
00544       (defSession == NULL)      // No default session exists!
00545      ) 
00546   {
00547     createNew = TRUE;
00548   }
00549 
00550   //
00551   // Make sure only 4 max are allowed...
00552   //
00553   LONG  slot; 
00554   if ((createNew) && ((slot = GetOpenSessionSlot()) == -1))
00555   {
00556     return(MAPI_E_TOO_MANY_SESSIONS);
00557   }
00558 
00559   //
00560   // If we don't have to create a new session, just return the ID and
00561   // move on with life
00562   //
00563   if (!createNew)
00564   {
00565     if (defSession == NULL)
00566     {
00567       return(MAPI_E_FAILURE);
00568     }
00569 
00570     defSession->IncrementSessionCount();
00571     logonInfo->lhSession = defSession->GetID();
00572     return(SUCCESS_SUCCESS);
00573   }
00574 
00575   //
00576   // Finally, create a new session!
00577   //
00578   mapiConnections[slot] = new CMAPIConnection(slot, lpszProfileName, lpszPassword);
00579   if (defSession == NULL)
00580   {
00581     mapiConnections[slot]->SetDefault(TRUE);
00582   }
00583 
00584   logonInfo->lhSession = mapiConnections[slot]->GetID();
00585 
00586   //
00587   // Process Flags...
00588   //
00589   // Indicates an attempt should be made to download all of the user's messages before 
00590   // returning. If the MAPI_FORCE_DOWNLOAD flag is not set, messages can be downloaded 
00591   // in the background after the function call returns.
00592   if (logonInfo->flFlags & MAPI_FORCE_DOWNLOAD) 
00593   {
00594     MAPIGetNewMessagesInBackground();
00595   }
00596 
00597   // Indicates that a logon dialog box should be displayed to prompt the user for 
00598   // logon information. If the user needs to provide a password and profile name 
00599   // to enable a successful logon, MAPI_LOGON_UI must be set.
00600   if (logonInfo->flFlags & MAPI_LOGON_UI) 
00601   {
00602     TRACE("MAPI: ProcessMAPILogon() MAPI_LOGON_UI Unsupported.\n");
00603   }
00604 
00605 #ifdef WIN32
00606   // Indicates that MAPILogon should only prompt for a password and not allow the user 
00607   // to change the profile name. Either MAPI_PASSWORD_UI or MAPI_LOGON_UI should not be 
00608   // set, since the intent is to select between two different dialog boxes for logon.
00609   if (logonInfo->flFlags & MAPI_PASSWORD_UI)
00610   {
00611     TRACE("MAPI: ProcessMAPILogon() MAPI_PASSWORD_UI Unsupported.\n");
00612   }         
00613 #endif  
00614   
00615   return(SUCCESS_SUCCESS);
00616 }
00617 
00618 LONG    
00619 ProcessMAPILogoff(MAPILogoffType *logoffInfo)
00620 {
00621   TRACE("MAPI: ProcessMAPILogoff() Session ID = [%d]\n", logoffInfo->lhSession);
00622   //
00623   // Verify the session handle...
00624   //
00625   if (( (logoffInfo->lhSession-1) >= MAX_CON) || ( (logoffInfo->lhSession-1) < 0))
00626   {
00627     return(MAPI_E_INVALID_SESSION);
00628   }
00629 
00630   CMAPIConnection *logoffSession = mapiConnections[(logoffInfo->lhSession - 1)];
00631   if (logoffSession == NULL)
00632   {
00633     return(MAPI_E_INVALID_SESSION);
00634   }
00635   
00636   //
00637   // Decrement the session count, then if this is the last one 
00638   // connected to this session, then kill it...
00639   //
00640   logoffSession->DecrementSessionCount();
00641   if (logoffSession->GetSessionCount() <= 0)
00642   {
00643     //
00644     // If this was the default session "holder", then we need to 
00645     // assign that task to a new one if it exists, if not, then
00646     // it is all back to null.
00647     //
00648     BOOL needToReassign = logoffSession->IsDefault();
00649 
00650     delete logoffSession;
00651     mapiConnections[logoffInfo->lhSession - 1] = NULL;
00652 
00653     if (needToReassign)
00654     {
00655       TRACE("MAPI: ProcessMAPILogoff() Need to reassign default\n");
00656       if (!TryDefaultReassignment())
00657       {
00658         if (pMAPIFrameWnd != NULL)
00659         {
00660           pMAPIFrameWnd->PostMessage(WM_CLOSE);
00661           pMAPIFrameWnd = NULL;
00662         }
00663       }
00664     }
00665   }
00666 
00667   return(SUCCESS_SUCCESS);
00668 }
00669 
00670 //
00671 // Actually process the send mail operation...
00672 //
00673 LONG    
00674 ProcessMAPISendMail(MAPISendMailType *sendMailPtr)
00675 {
00676   CMAPIConnection *mySession;
00677   NSstringSeq     mailInfoSeq;
00678 
00679   TRACE("MAPI: ProcessMAPISendMail() Session ID = [%d]\n", sendMailPtr->lhSession);
00680   //
00681   // Verify the session handle...
00682   //
00683   if (((sendMailPtr->lhSession-1) >= MAX_CON) || ((sendMailPtr->lhSession-1) < 0))
00684   {
00685     return(MAPI_E_FAILURE);
00686   }
00687 
00688   mySession = mapiConnections[(sendMailPtr->lhSession - 1)];
00689   if (mySession == NULL)
00690   {
00691     return(MAPI_E_FAILURE);
00692   }
00693 
00694   //
00695   // Before we start, make sure things make sense...
00696   //
00697   if ( (!(sendMailPtr->flFlags & MAPI_DIALOG)) && (sendMailPtr->MSG_nRecipCount == 0) )
00698   {
00699     return(MAPI_E_UNKNOWN_RECIPIENT);
00700   }
00701 
00702   mailInfoSeq = (NSstringSeq) &(sendMailPtr->dataBuf[0]);
00703   TRACE("MAPI: ProcessMAPISendMail() Session ID = [%d]\n", sendMailPtr->lhSession);
00704 
00705   //
00706   // Now set the show window flag...
00707   //
00708   BOOL showWindow = (( sendMailPtr->flFlags & MAPI_DIALOG ) != 0);
00709   LONG rc = DoFullMAPIMailOperation(sendMailPtr, 
00710                                     NSStrSeqGet(mailInfoSeq, 1),
00711                                     showWindow);
00712   return(rc);
00713 }
00714 
00715 //
00716 // Actually process the send mail operation...
00717 //
00718 LONG    
00719 ProcessMAPISaveMail(MAPISendMailType *sendMailPtr)
00720 {
00721   CMAPIConnection *mySession;
00722   NSstringSeq     mailInfoSeq;
00723 
00724   TRACE("MAPI: ProcessMAPISaveMail() Session ID = [%d]\n", sendMailPtr->lhSession);
00725   //
00726   // Verify the session handle...
00727   //
00728   if (((sendMailPtr->lhSession-1) >= MAX_CON) || ((sendMailPtr->lhSession-1) < 0))
00729   {
00730     return(MAPI_E_FAILURE);
00731   }
00732 
00733   mySession = mapiConnections[(sendMailPtr->lhSession - 1)];
00734   if (mySession == NULL)
00735   {
00736     return(MAPI_E_FAILURE);
00737   }
00738 
00739   mailInfoSeq = (NSstringSeq) &(sendMailPtr->dataBuf[0]);
00740   TRACE("MAPI: ProcessMAPISaveMail() Session ID = [%d]\n", sendMailPtr->lhSession);
00741 
00742   //
00743   // Now process the save mail operation...
00744   //
00745   LONG rc = DoMAPISaveMailOperation(sendMailPtr, 
00746                                     NSStrSeqGet(mailInfoSeq, 1));
00747   return(rc);
00748 }
00749 
00750 //
00751 // Actually process the send documents operation...
00752 //
00753 LONG    
00754 ProcessMAPISendDocuments(MAPISendDocumentsType *sendDocPtr)
00755 {
00756   LONG rc = DoPartialMAPIMailOperation(sendDocPtr);    
00757   return(rc);
00758 }
00759 
00760 //
00761 // This is an ENUM procedure for messages that are in the system
00762 //
00763 LONG    
00764 ProcessMAPIFindNext(MAPIFindNextType *findInfo)
00765 {
00766   CMAPIConnection *mySession;
00767 
00768   //
00769   // Verify the session handle...
00770   //
00771   if (((findInfo->lhSession-1) >= MAX_CON) || ((findInfo->lhSession-1) < 0))
00772   {
00773     return(MAPI_E_INVALID_SESSION);
00774   }
00775 
00776   mySession = mapiConnections[(findInfo->lhSession - 1)];
00777   if (mySession == NULL)
00778   {
00779     return(MAPI_E_INVALID_SESSION);
00780   }
00781 
00782   //
00783   // If this is true, then this is the first call to this FindNext function
00784   // and we should start the enumeration operation.
00785   //
00786        MSG_FolderInfo  *inboxFolder = NULL;
00787        int32           folderRC = MSG_GetFoldersWithFlag(WFE_MSGGetMaster(),
00788                                                                              MSG_FOLDER_FLAG_INBOX, &inboxFolder, 1);
00789   if (folderRC <= 0)
00790   {
00791     return(MAPI_E_NO_MESSAGES);
00792   }
00793 
00794   // This is the first message
00795   if (mySession->GetMessageIndex() < 0)
00796   {
00797     MSG_MapiListContext *cookie;
00798 
00799     MessageKey keyFound = MSG_GetFirstKeyInFolder(inboxFolder, &cookie);
00800     if (keyFound == MSG_MESSAGEKEYNONE)
00801     {
00802       mySession->SetMapiListContext(NULL);
00803       mySession->SetMessageIndex(-1); // Reset to -1...
00804       return(MAPI_E_NO_MESSAGES);
00805     }
00806 
00807     TRACE("MAPI: ProcessMAPIFindNext() Found message id = %d\n", keyFound);
00808 
00809     wsprintf((LPSTR) findInfo->lpszMessageID, "%d", keyFound);
00810     mySession->SetMapiListContext(cookie);
00811     mySession->SetMessageIndex(keyFound); // Just set to 1 and then increment from there...
00812   }
00813   else
00814   {
00815     MSG_MapiListContext *cookie = (MSG_MapiListContext *)mySession->GetMapiListContext();
00816     
00817     // Sanity check the cookie value...
00818     if (cookie == NULL)
00819     {
00820       mySession->SetMapiListContext(NULL);
00821       mySession->SetMessageIndex(-1); // Reset to -1...
00822       return(MAPI_E_NO_MESSAGES);
00823     }
00824 
00825     MessageKey nextKey = MSG_GetNextKeyInFolder(cookie);
00826     if (nextKey == MSG_MESSAGEKEYNONE)
00827     {
00828       mySession->SetMapiListContext(NULL);
00829       mySession->SetMessageIndex(-1); // Reset to -1...
00830       return(MAPI_E_NO_MESSAGES);
00831     }
00832 
00833     TRACE("MAPI: ProcessMAPIFindNext() Found message id = %d\n", nextKey);
00834 
00835     wsprintf((LPSTR) findInfo->lpszMessageID, "%d", nextKey);
00836     mySession->SetMessageIndex(nextKey); // Set the key to the found one and move on...
00837   }
00838 
00839   return(SUCCESS_SUCCESS);
00840 }
00841 
00842 //
00843 // Actually process the delete mail operation!
00844 //
00845 LONG    
00846 ProcessMAPIDeleteMail(MAPIDeleteMailType *delInfo)
00847 {
00848   CMAPIConnection *mySession;
00849 
00850   //
00851   // Verify the session handle...
00852   //
00853   if (((delInfo->lhSession-1) >= MAX_CON) || ((delInfo->lhSession-1) < 0))
00854   {
00855     return(MAPI_E_INVALID_SESSION);
00856   }
00857 
00858   mySession = mapiConnections[(delInfo->lhSession - 1)];
00859   if (mySession == NULL)
00860   {
00861     return(MAPI_E_INVALID_SESSION);
00862   }
00863 
00864   BOOL    msgValid = TRUE;
00865 
00866   TRACE("MAPI: RICHIE TODO: ProcessMAPIDeleteMail() TRY TO FIND THE MESSAGE FROM THE IDENTIFIER:\n");
00867   TRACE("MAPI: RICHIE TODO: ProcessMAPIDeleteMail() [%s]\n", delInfo->lpszMessageID);
00868 
00869   if (msgValid)
00870   {
00871     TRACE("MAPI: RICHIE TODO: ProcessMAPIDeleteMail() DELETE THE MESSAGE!!!\n");
00872 
00873     return(SUCCESS_SUCCESS);
00874   }
00875   else
00876   {
00877     return(MAPI_E_INVALID_MESSAGE);
00878   }
00879 }
00880 
00881 // 
00882 // Process the name resolution for the address passed in.
00883 //
00884 LONG    
00885 ProcessMAPIResolveName(MAPIResolveNameType *nameInfo)
00886 {
00887   CMAPIConnection *mySession;
00888 
00889   //
00890   // Verify the session handle...
00891   //
00892   if (((nameInfo->lhSession-1) >= MAX_CON) || ((nameInfo->lhSession-1) < 0))
00893   {
00894     return(MAPI_E_INVALID_SESSION);
00895   }
00896 
00897   mySession = mapiConnections[(nameInfo->lhSession - 1)];
00898   if (mySession == NULL)
00899   {
00900     return(MAPI_E_INVALID_SESSION);
00901   }
00902 
00903   TRACE("MAPI: ProcessMAPIResolveName() TRY TO IDENTIFY THE ADDRESS INFO FOR THE NAME:\n");
00904   TRACE("MAPI: ProcessMAPIResolveName() [%s]\n", nameInfo->lpszName);
00905 
00906   DWORD numFound;
00907   LPSTR retFullName = NULL;
00908   LPSTR retAddr = NULL;
00909   
00910   AB_ContainerInfo  *ctr;
00911   ABID              id;
00912 
00913   numFound = AB_MAPI_ResolveName ( 
00914                 (char *)nameInfo->lpszName, // i.e. a nickname or part of the person's name to look up. Assumes First Last 
00915                 &ctr,                       // caller allocates the ctr ptr. BE fills Caller must close container when done with it
00916                 &id);                       // caller allocates the ABID, BE fills 
00917 
00918   if (numFound > 1)
00919   {
00920     return(MAPI_E_AMBIGUOUS_RECIPIENT);
00921   }
00922   else if (numFound <= 0)
00923   {
00924     return(MAPI_E_UNKNOWN_RECIPIENT);
00925   }
00926   else    // Here we found a single entry!
00927   {
00928     // Get the full name and email address...
00929     retFullName = AB_MAPI_GetFullName(ctr, id);
00930     retAddr = AB_MAPI_GetEmailAddress(ctr, id);
00931 
00932     // null out return values just in case...
00933     nameInfo->lpszABookName[0] = '\0';
00934     nameInfo->lpszABookAddress[0] = '\0';
00935 
00936     // if valid, copy the strings over...
00937     if (retFullName)
00938       lstrcpy((LPSTR) nameInfo->lpszABookName, retFullName);
00939     if (retAddr)
00940       lstrcpy((LPSTR) nameInfo->lpszABookAddress, retAddr);
00941 
00942     // Now get the string to use for an ID later on...
00943     LPSTR  abookIDString =  AB_MAPI_ConvertToDescription(ctr); 
00944 
00945     // build that string ID to pass back through the MAPI API
00946     wsprintf((LPSTR) nameInfo->lpszABookID, "%d%s", id, DELIMIT);
00947     lstrcat((LPSTR) nameInfo->lpszABookID, abookIDString);
00948     
00949     // Be nice and cleanup after ourselves...
00950     if (retAddr)
00951       XP_FREE(retAddr);
00952     if (retFullName)
00953       XP_FREE(retFullName);
00954     if (abookIDString)
00955       XP_FREE(abookIDString);
00956 
00957     return(SUCCESS_SUCCESS);
00958   }
00959 }
00960 
00961 //
00962 // This deals with the MAPIDetails call
00963 //
00964 LONG    
00965 ProcessMAPIDetails(MAPIDetailsType *detailInfo)
00966 {
00967   CMAPIConnection *mySession;
00968 
00969   //
00970   // Verify the session handle...
00971   //
00972   if (((detailInfo->lhSession-1) >= MAX_CON) || ((detailInfo->lhSession-1) < 0))
00973   {
00974     return(MAPI_E_INVALID_SESSION);
00975   }
00976 
00977   mySession = mapiConnections[(detailInfo->lhSession - 1)];
00978   if (mySession == NULL)
00979   {
00980     return(MAPI_E_INVALID_SESSION);
00981   }
00982 
00983   TRACE("MAPI: ProcessMAPIDetails() NEED TO LOCATE THE ENTRY FOR:\n");
00984   TRACE("MAPI: ProcessMAPIDetails() [%s]\n", detailInfo->lpszABookID);
00985 
00986   char    workString[MAX_NAME_LEN];
00987   char    *idString;
00988   char    *containerString;
00989 
00990   lstrcpy((LPSTR) workString, (LPSTR) detailInfo->lpszABookID);
00991 
00992   //
00993   // Now parse out the first and last names of the person...
00994   //
00995   int       totLen = lstrlen((LPSTR) workString);
00996   int       loc = 0;
00997   idString = &(workString[0]);
00998 
00999   while ( ( lstrlen((LPSTR) DELIMIT) + loc) < totLen)
01000   {
01001     if (strncmp((LPSTR)(workString + loc), DELIMIT, lstrlen(DELIMIT)) == 0)
01002     {
01003       workString[loc] = '\0';
01004       containerString = &(workString[loc + lstrlen(DELIMIT)]);
01005       break;
01006     }
01007 
01008     ++loc;
01009   }
01010     
01011   if ( (lstrlen((LPSTR) DELIMIT) + loc) >= totLen )
01012   {
01013     return(MAPI_E_INVALID_RECIPS);
01014   }
01015 
01016   // Now, convert the stuff to real values for the API...
01017   ABID              id = atoi((const char *) idString);
01018   AB_ContainerInfo  *container = AB_MAPI_ConvertToContainer(containerString);
01019   MSG_Pane          *personPane = NULL;
01020   extern MWContext         *GetUsableContext(void);
01021 
01022   // Need to first create a person entry pane and then call
01023   // FE_ShowPropertySheetAB2 on that pane - return 0 is problem
01024   int rc = AB_MAPI_CreatePropertySheetPane( 
01025             GetUsableContext(),
01026             WFE_MSGGetMaster(), 
01027             container, 
01028             id, 
01029             &personPane);  // BE will allocate a personPane and return a ptr to it here 
01030   if (!rc)
01031   {
01032     return(MAPI_E_INVALID_RECIPS);
01033   }
01034 
01035   // Now display the address book entry for this user. If the parameter
01036   // detailInfo->ulUIParam  is NULL, just doit and return, but if it is
01037   // not NULL, then we should do it as application modal.
01038   
01039   // RICHIE - THIS IS NOT IN THE BUILD YET! MUST WAIT
01040   //(void) FE_ShowPropertySheetForAB2(personPane, AB_Person);
01041 
01042   // cleanup the container and person pane...
01043   AB_MAPI_CloseContainer(&container);
01044   AB_ClosePane(personPane); 
01045 
01046   return(SUCCESS_SUCCESS);
01047 }
01048 
01049 //
01050 // CMAPIConnections object...should be in their own file...
01051 //
01052 CMAPIConnection::CMAPIConnection  ( LONG id, LPSTR name, LPSTR pw)
01053 {
01054   m_sessionCount = 1;
01055   m_defaultConnection = FALSE;
01056   m_ID = (id + 1);      // since zero is invalid, but have to make sure we 
01057                         // decrement by one when it is passed in again.
01058   m_messageIndex = -1;  // For tracing our way through the FindNext operation
01059   m_cookie = NULL;      // For doing the enumeration of messages
01060   m_messageFindInfo[0] = '\0';
01061   lstrcpy((LPSTR) m_profileName, name);
01062   lstrcpy((LPSTR) m_password, pw);  
01063 }
01064 
01065 CMAPIConnection::~CMAPIConnection ( )
01066 {
01067 }
01068 
01069 //
01070 // This is all needed to process a MAPIReadMail operation
01071 //
01072 static LPSTR
01073 CheckNull(LPSTR inStr)
01074 {
01075   static UCHAR  str[1];
01076 
01077   str[0] = '\0';
01078   if (inStr == NULL)
01079     return((LPSTR)str);
01080   else
01081     return(inStr);
01082 }
01083 
01084 LONG
01085 WriteTheMemoryBufferToDisk(LPSTR fName, UINT bufSize, LPSTR buf)
01086 {
01087   if (!buf)
01088   {
01089     return(-1);
01090   }
01091 
01092   HFILE hFile = _lcreat(fName, 0);
01093   if (hFile == HFILE_ERROR)
01094   {
01095     return(-1);
01096   }
01097 
01098   UINT writeCount = _lwrite(hFile, buf, bufSize);
01099   _lclose(hFile);
01100 
01101   if (writeCount != bufSize)
01102   {
01103     _unlink(fName);
01104     return(-1);
01105   }
01106 
01107   return(0);
01108 }
01109 
01110 static LPSTR
01111 GetTheTempDirectoryOnTheSystem(void)
01112 {
01113  static UCHAR retPath[_MAX_PATH];
01114   
01115   if (getenv("TEMP"))
01116   {
01117     lstrcpy((LPSTR) retPath, getenv("TEMP"));  // environmental variable
01118   } 
01119   else if (getenv("TMP"))
01120   {
01121     lstrcpy((LPSTR) retPath, getenv("TMP"));  // How about this environmental variable?
01122   }
01123   else
01124   {
01125     GetWindowsDirectory((LPSTR) retPath, sizeof(retPath));
01126   }
01127 
01128   return((LPSTR) &(retPath[0]));
01129 }
01130 
01131 #ifdef WIN16
01132 static int ISGetTempFileName(LPCSTR a_pDummyPath,  LPCSTR a_pPrefix, UINT a_uUnique, LPSTR a_pResultName)
01133 {
01134 #ifdef GetTempFileName      // we need the real thing comming up next...
01135 #undef GetTempFileName
01136 #endif
01137        return GetTempFileName(0, a_pPrefix, a_uUnique, a_pResultName);
01138 }
01139 #endif
01140 
01141 static DWORD 
01142 ValidateFile(LPCSTR szFile) 
01143 {
01144        struct _stat buf;
01145     int result;
01146 
01147     result = _stat( szFile, &buf );
01148     if (result != 0)
01149       return(1);
01150 
01151     if (!(buf.st_mode & S_IREAD))
01152       return(2);
01153 
01154     return(0);
01155 }
01156 
01157 static LONG
01158 GetTempAttachmentName(LPSTR fName) 
01159 {
01160   UINT        res;
01161   static UINT uUnique = 1;
01162 
01163   if (!fName)
01164     return(-1);
01165 
01166   LPSTR szTempPath = GetTheTempDirectoryOnTheSystem();
01167 
01168 TRYAGAIN:
01169 #ifdef WIN32
01170   res = GetTempFileName(szTempPath, "MAPI", uUnique++, fName);
01171 #else
01172   res = ISGetTempFileName(szTempPath, "MAPI", uUnique++, fName);
01173 #endif
01174 
01175   if (ValidateFile(fName) != 1) 
01176   {
01177     if (uUnique < 32000)
01178     {
01179       goto TRYAGAIN;
01180     }
01181     else
01182     {
01183       return(-1);
01184     }
01185   }
01186 
01187   return 0;
01188 }
01189 
01190 LONG    
01191 ProcessMAPIReadMail(MAPIReadMailType *readInfo)
01192 {
01193   CMAPIConnection *mySession;
01194   lpMapiMessage   message;      // this is the message we will receive
01195 
01196   //
01197   // Verify the session handle...
01198   //
01199   if (((readInfo->lhSession-1) >= MAX_CON) || ((readInfo->lhSession-1) < 0))
01200   {
01201     return(MAPI_E_INVALID_SESSION);
01202   }
01203 
01204   mySession = mapiConnections[(readInfo->lhSession - 1)];
01205   if (mySession == NULL)
01206   {
01207     return(MAPI_E_INVALID_SESSION);
01208   }
01209 
01210   // First, gotta get the inbox folder!
01211   MSG_FolderInfo  *inboxFolder = NULL;
01212        int32           folderRC = MSG_GetFoldersWithFlag(WFE_MSGGetMaster(),
01213                                                                              MSG_FOLDER_FLAG_INBOX, &inboxFolder, 1);
01214   if (folderRC <= 0)
01215   {
01216     return(MAPI_E_INVALID_MESSAGE);
01217   }
01218 
01219   // Convert the message id to a number!
01220   MessageKey lookupKey = atoi((const char *)readInfo->lpszMessageID);
01221   TRACE("MAPI: ProcessMAPIReadMail() Find this message = [%s] - [%d]\n", 
01222                           readInfo->lpszMessageID, lookupKey);
01223 
01224   // Now see if we can find this message!
01225   BOOL msgFound = MSG_GetMapiMessageById(inboxFolder, lookupKey, &message);
01226 
01227   // If we didn't find the message, then we need to bail!
01228   if (!msgFound)
01229   {
01230     TRACE("MAPI: ProcessMAPIReadMail() MESSAGE NOT FOUND\n");
01231     return(MAPI_E_INVALID_MESSAGE);
01232   }
01233 
01234   //
01235   // Now that we have found the message, we need to populate the chunk of
01236   // memory that we will write to disk and then move on. For now, we need
01237   // to setup all of the variables for the information we will need for the
01238   // message.
01239   //
01240   ULONG     i;
01241   DWORD     arrayCount = 0;         // Counter for array entries!
01242   DWORD     arrayTotal = 0;         // Total for array entries!
01243   FLAGS     msgFlags;               // unread, return or receipt                  
01244   ULONG     msgRecipCount = message->nRecipCount; // Number of recipients                   
01245   ULONG     msgFileAttachCount = message->nFileCount; // # of file attachments                  
01246 
01247   LPSTR     msgSubject = message->lpszSubject;          // Message Subject
01248   LPSTR     msgNoteText = NULL;                         // Message Text will be
01249   LPSTR     msgDateReceived = message->lpszDateReceived;// in YYYY/MM/DD HH:MM format
01250   LPSTR     msgThreadID = message->lpszConversationID;  // conversation thread ID
01251 
01252   //
01253   // The following are for the originator of the message. Only ONE of these.
01254   //
01255   LPSTR     origName = NULL;    // Originator name                           
01256   LPSTR     origAddress = NULL; // Originator address (optional)             
01257   ULONG     origRecipClass = MAPI_TO;               // Recipient class - MAPI_TO, MAPI_CC, MAPI_BCC, MAPI_ORIG
01258 
01259   // Now we have to make sure there is an originator and set the vars...
01260   if (message->lpOriginator)
01261   {
01262     origName    = message->lpOriginator->lpszName;
01263     origAddress = message->lpOriginator->lpszAddress;
01264   }
01265 
01266   if ( ! (readInfo->flFlags & MAPI_ENVELOPE_ONLY))
01267   {
01268       TRACE("MAPI: ProcessMAPIReadMail() GET NOTE TEXT - ONLY IF WE HAVE TO!\n"); 
01269       msgNoteText = message->lpszNoteText;
01270   }
01271 
01272   // First, figure out how many entries we need to have in a string array...
01273   arrayTotal = 6 + 1; // 6 for the first 6 strings and 1 for the final NULL    
01274 
01275   // Add the recipient information
01276   arrayTotal += (msgRecipCount * 3);
01277 
01278   // Now check to see if we are going to pass back attachments:
01279   //
01280   // MAPI_ENVELOPE_ONLY 
01281   // Indicates MAPIReadMail should read the message header only. File attachments are 
01282   // not copied to temporary files, and neither temporary file names nor message text 
01283   // is written. Setting this flag enhances performance. 
01284   //
01285   // MAPI_SUPPRESS_ATTACH 
01286   // Indicates MAPIReadMail should not copy file attachments but should write message 
01287   // text into the MapiMessage structure. MAPIReadMail ignores this flag if the 
01288   // calling application has set the MAPI_ENVELOPE_ONLY flag. Setting the 
01289   // MAPI_SUPPRESS_ATTACH flag enhances performance. 
01290   //
01291   if ((readInfo->flFlags & MAPI_SUPPRESS_ATTACH) ||
01292       (readInfo->flFlags & MAPI_ENVELOPE_ONLY) )
01293   {
01294     msgFileAttachCount = 0;
01295   }
01296 
01297   arrayTotal += (msgFileAttachCount * 2);
01298   
01299   // now allocate the memory for the string array 
01300   LPSTR *strArray = (LPSTR *) malloc((size_t) (sizeof(LPSTR) * arrayTotal));
01301   if (!strArray)
01302   {
01303     return(MAPI_E_INSUFFICIENT_MEMORY);
01304   }
01305 
01306   // Now assign the easy return values to the shared memory structure
01307   readInfo->MSG_flFlags     = msgFlags;           // unread, return or receipt                  
01308   readInfo->MSG_nRecipCount = msgRecipCount;      // Number of recipients                   
01309   readInfo->MSG_nFileCount  = msgFileAttachCount; // # of file attachments                  
01310   readInfo->MSG_ORIG_ulRecipClass = origRecipClass; //  Recipient class - MAPI_TO, MAPI_CC, MAPI_BCC, MAPI_ORIG
01311 
01312   // Now go through and fill out the array to create the string sequence
01313   strArray[0] = CheckNull(msgSubject);
01314   strArray[1] = CheckNull(msgNoteText);
01315   strArray[2] = CheckNull(msgDateReceived);
01316   strArray[3] = CheckNull(msgThreadID);
01317   strArray[4] = CheckNull(origName);
01318   strArray[5] = CheckNull(origAddress);
01319 
01320   arrayCount = 6;   // counter for the rest of the needed attachments
01321 
01322   // Now add all of the recipients
01323   for (i=0; i<msgRecipCount; i++)
01324   {
01325     UCHAR     tempString[128];
01326     ULONG     messageClass = message->lpRecips[i].ulRecipClass; // Get the recipient class...
01327 
01328     // Now get the following 3 items:
01329     //      String x: LPSTR lpszName;             // Recipient N name                           
01330     //      String x: LPSTR lpszAddress;          // Recipient N address (optional)             
01331     //      String x: LPSTR lpszRecipClass        // recipient class - sprintf of ULONG
01332     strArray[arrayCount++] = CheckNull(message->lpRecips[i].lpszName);
01333     strArray[arrayCount++] = CheckNull(message->lpRecips[i].lpszAddress);
01334 
01335     // 0      MAPI_ORIG     Indicates the original sender of the message. 
01336     // 1      MAPI_TO       Indicates a primary message recipient. 
01337     // 2      MAPI_CC       Indicates a recipient of a message copy. 
01338     // 3      MAPI_BCC      Indicates a recipient of a blind copy. 
01339     wsprintf((LPSTR) tempString, "%d", messageClass);
01340     strArray[arrayCount++] = CheckNull((LPSTR) tempString);
01341   }
01342 
01343   // Now, add all of the attachments to this blob
01344   for (i=0; i<msgFileAttachCount; i++)
01345   {
01346     //      String x: LPSTR lpszPathName // Fully qualified path of the attached file. 
01347     //                                   // This path should include the disk drive letter and directory name.
01348     //      String x: LPSTR lpszFileName // The display name for the attached file
01349     //
01350     strArray[arrayCount++] = CheckNull(message->lpFiles[i].lpszPathName);
01351     strArray[arrayCount++] = CheckNull(message->lpFiles[i].lpszFileName);
01352   }
01353 
01354   strArray[arrayCount] = NULL;
01355 
01356   // Create the string sequence
01357   NSstringSeq strSeq = NSStrSeqNew(strArray);
01358 
01359   // Now just cleanup the array....
01360   free(strArray);
01361  
01362   if (!strSeq)
01363   {
01364     return(MAPI_E_INSUFFICIENT_MEMORY);
01365   }
01366   
01367   // Now get the name of the file to write the blob to!
01368   if (GetTempAttachmentName((LPSTR)readInfo->lpszBlob) < 0)
01369   {
01370     NSStrSeqDelete(strSeq);
01371     return(MAPI_E_ATTACHMENT_WRITE_FAILURE);
01372   }
01373 
01374   // Now write the blob to disk and move on...
01375   if (WriteTheMemoryBufferToDisk((LPSTR) readInfo->lpszBlob, 
01376                       (UINT) NSStrSeqSize(strSeq), strSeq) != 0)
01377   {
01378     NSStrSeqDelete(strSeq);
01379     return(MAPI_E_ATTACHMENT_WRITE_FAILURE);
01380   }
01381 
01382   //
01383   // MAPI_PEEK 
01384   // Indicates MAPIReadMail does not mark the message as read. Marking a message as 
01385   // read affects its appearance in the user interface and generates a read receipt. 
01386   // If the messaging system does not support this flag, MAPIReadMail always marks 
01387   // the message as read. If MAPIReadMail encounters an error, it leaves the 
01388   // message unread.  
01389   if (!(readInfo->flFlags & MAPI_PEEK))
01390   {
01391     MSG_MarkMapiMessageRead (inboxFolder, lookupKey, TRUE);
01392   }
01393 
01394   // Now we have to free the message and the chunk of memory...
01395   MSG_FreeMapiMessage(message);
01396   NSStrSeqDelete(strSeq);
01397 
01398   return(SUCCESS_SUCCESS);
01399 }
01400 
01401 // necessary variables for 
01402 int           arrayCount   = 0;         // Counter for array entries!
01403 int           addressCount = 0;         // Counter for array entries!
01404 LPSTR         *addrArray;
01405 LPSTR         toString  = "1";
01406 LPSTR         ccString  = "2";
01407 LPSTR         bccString = "3";
01408  
01409 BOOL 
01410 AddressCallback(int totalCount, int currentIndex, 
01411                 int addrType, LPSTR addrString)
01412 {
01413   LPSTR     messageClass; 
01414 
01415   TRACE("TOTAL COUNT   = %d\n", totalCount);
01416   TRACE("CURRENT COUNT = %d\n", currentIndex);
01417   TRACE("CURRENT ADDR  = %s\n", addrString);
01418 
01419   // If this is the first entry, then we need to allocate the array...
01420   if (currentIndex == 0)
01421   {
01422     addressCount = totalCount;
01423     addrArray = (LPSTR *) malloc( (size_t) 
01424                             sizeof(LPSTR) * ((addressCount * 3) + 1) 
01425                           );
01426     if (!addrArray)
01427     {
01428       addressCount = 0;
01429       return FALSE;
01430     }
01431   }
01432 
01433   // if the array was not allocated...
01434   if (!addrArray)
01435   {
01436     addressCount = 0;
01437     return FALSE;
01438   }
01439 
01440   // Deal with the address type...
01441   if (addrType == MSG_CC_HEADER_MASK)
01442     messageClass = ccString;
01443   else if (addrType == MSG_BCC_HEADER_MASK)
01444     messageClass = bccString;
01445   else 
01446     messageClass = toString;
01447 
01448   // Now get the following 3 items:
01449   //      String x: LPSTR lpszName;             // Recipient N name                           
01450   //      String x: LPSTR lpszAddress;          // Recipient N address (optional)             
01451   //      String x: LPSTR lpszRecipClass        // recipient class - sprintf of ULONG
01452 
01453   char *ptr = strchr(addrString, '<');
01454   if (ptr)
01455   {
01456     addrString[strlen(addrString) - 1] = '\0';
01457     *(ptr-1) = '\0';
01458   }
01459   addrArray[arrayCount++] = CheckNull(addrString);
01460 
01461   if (ptr)
01462   {
01463     ptr++;
01464   }
01465   else
01466   {
01467     ptr = (char *) addrString;
01468   }
01469 
01470   addrArray[arrayCount++] = CheckNull(ptr);
01471 
01472   // 0 MAPI_ORIG     Indicates the original sender of the message. 
01473   // 1 MAPI_TO       Indicates a primary message recipient. 
01474   // 2 MAPI_CC       Indicates a recipient of a message copy. 
01475   // 3 MAPI_BCC      Indicates a recipient of a blindcopy. 
01476   addrArray[arrayCount++] = CheckNull(messageClass);
01477 
01478   return(TRUE);
01479 }
01480 
01481 int               getAddressCount = 0;
01482 MAPIAddressType   *getAddressPtr = NULL;
01483 NSstringSeq       addrSeq = NULL;
01484 
01485 // rhp - for MAPI calls...
01486 BOOL
01487 GetNextAddress(LPSTR *name, LPSTR *address, int *addrType)
01488 {
01489   if ( getAddressCount >= (getAddressPtr->nRecips * 3) )
01490   {
01491     return FALSE;
01492   }
01493 
01494   ULONG   aType = atoi(NSStrSeqGet(addrSeq, getAddressCount++));
01495 
01496   // return which type of address this is?
01497   if (aType == MAPI_CC)
01498     *addrType = MSG_CC_HEADER_MASK;
01499   else if (aType == MAPI_BCC)
01500     *addrType = MSG_BCC_HEADER_MASK;
01501   else
01502     *addrType = MSG_TO_HEADER_MASK;
01503       
01504   *name    = (LPSTR) NSStrSeqGet(addrSeq, getAddressCount++);
01505   *address = (LPSTR) NSStrSeqGet(addrSeq, getAddressCount++);
01506 
01507   return TRUE;
01508 }
01509 
01510 LONG
01511 ProcessMAPIAddress(MAPIAddressType *addrInfo)
01512 {
01513   CMAPIConnection *mySession;
01514 
01515   TRACE("MAPI: ProcessMAPIAddress() Incomming Addrs = %d\nCaption = [%s]\n",
01516                     addrInfo->nRecips,
01517                     addrInfo->lpszCaption);
01518   //
01519   // Verify the session handle...
01520   //
01521   if (((addrInfo->lhSession-1) >= MAX_CON) || ((addrInfo->lhSession-1) < 0))
01522   {
01523     return(MAPI_E_INVALID_SESSION);
01524   }
01525 
01526   mySession = mapiConnections[(addrInfo->lhSession - 1)];
01527   if (mySession == NULL)
01528   {
01529     return(MAPI_E_INVALID_SESSION);
01530   }
01531 
01532   // 
01533   // Put up the address dialog and do the right thing :-)
01534   // 
01535   addrSeq = (NSstringSeq) &(addrInfo->dataBuf[0]);
01536   getAddressCount = 0;  // Make sure to reset the counter for address info...
01537   getAddressPtr = addrInfo; // Address pointer for callback...
01538   arrayCount = 0;       // counter for the rest of the entries...
01539   theApp.m_pHiddenFrame->AddressDialog((LPSTR) (addrInfo->lpszCaption), 
01540                                             AddressCallback, GetNextAddress);
01541 
01542   // If the address count is zero, then we can return early...
01543   addrInfo->nNewRecips = addressCount;
01544   if (addressCount == 0)
01545   {
01546     return(SUCCESS_SUCCESS);
01547   }
01548 
01549   addrArray[arrayCount] = NULL;  
01550 
01551   // Create the string sequence
01552   NSstringSeq strSeq = NSStrSeqNew(addrArray);
01553   
01554   // Now just cleanup the array....
01555   free(addrArray);
01556   
01557   if (!strSeq)
01558   {
01559     return(MAPI_E_INSUFFICIENT_MEMORY);
01560   }
01561   
01562   // Now get the name of the file to write the blob to!
01563   if (GetTempAttachmentName((LPSTR)addrInfo->lpszBlob) < 0)
01564   {
01565     NSStrSeqDelete(strSeq);
01566     return(MAPI_E_INSUFFICIENT_MEMORY);
01567   }
01568 
01569   // Now write the blob to disk and move on...
01570   if (WriteTheMemoryBufferToDisk((LPSTR) addrInfo->lpszBlob, 
01571                       (UINT) NSStrSeqSize(strSeq), strSeq) != 0)
01572   {
01573     NSStrSeqDelete(strSeq);
01574     return(MAPI_E_INSUFFICIENT_MEMORY);
01575   }
01576 
01577   NSStrSeqDelete(strSeq);
01578   return(SUCCESS_SUCCESS);
01579 }