diff options
author | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
---|---|---|
committer | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
commit | 094ca96844842928810f14844413109fc6cdd890 (patch) | |
tree | e60efbb980f38ba9308ccb4fb2b77b87bbc115f3 /mapi | |
download | alpine-094ca96844842928810f14844413109fc6cdd890.tar.xz |
Initial Alpine Version
Diffstat (limited to 'mapi')
-rw-r--r-- | mapi/ReadmeMapi32.txt | 102 | ||||
-rw-r--r-- | mapi/instmapi.c | 406 | ||||
-rwxr-xr-x | mapi/makefile | 72 | ||||
-rw-r--r-- | mapi/pmapi.c | 2929 | ||||
-rw-r--r-- | mapi/pmapi.def | 17 | ||||
-rw-r--r-- | mapi/pmapi.h | 244 | ||||
-rw-r--r-- | mapi/pmapi.rc | 153 | ||||
-rw-r--r-- | mapi/resource.h | 19 | ||||
-rw-r--r-- | mapi/rfc1522.c | 557 | ||||
-rw-r--r-- | mapi/smapi.c | 653 |
10 files changed, 5152 insertions, 0 deletions
diff --git a/mapi/ReadmeMapi32.txt b/mapi/ReadmeMapi32.txt new file mode 100644 index 00000000..c19e7d43 --- /dev/null +++ b/mapi/ReadmeMapi32.txt @@ -0,0 +1,102 @@ +ReadmeMapi32.txt +January 27, 2009 +University of Washington + +NOTE: It is uncertain what remains to be done for pmapi to work with +alpine. This dll should work with a PC-Pine installation, but in +the future will be made to work with Alpine. Registry access and +Unicode support will have to change for that to happen. + + pmapi32 for Alpine 2.10 + +This distribution comes with two other files, instmapi.exe and +pmapi32.dll, for use with Aline. It is recommended that these files +be put in your pine directory (generally C:\Program Files\Alpine). + +pmapi32.dll - a Simple MAPI dynamically linked library. pmapi32.dll +is used by other applications to access your inbox or send mail +through Alpine. + +instmapi.exe - installs mapi32.dll such that registry values are set +according to the location of pmapi32.dll, and possibly copies +pmapi32.dll to the system directory if it is run on older systems. It +will also offer to set Alpine as your default mailer and newsreader +if it is not already set. The "-silent" option has been added to +assume that default mailer and newsreader should be set and also to +suppress a "Successful Completion" alert. This program can be run +repeatedly without side effects. + +instmapi.exe must be run at least once in order for pmapi32.dll to be +accessible to other applications. As of Alpine 4.30, instmapi.exe +may or may not need to be run in order for pmapi32.dll to work, +depending on Windows/Internet Explorer/Microsoft Office versions. To +manually set Alpine as your default mailer, you must open "Internet +Options" in your Control Panel and select the "Programs" tab. Under +"E-mail", select Alpine. + +Configuration: +Currently there is only one configuration option that is specific to +pmapi32.dll: + +pmapi-send-behavior: With the ability to send messages without dialogs +it was decided that the user might want to be prompted in this case. +There are three possible values for this variable: + always-prompt: Always prompt before sending. This is the default + behavior unless set otherwise. + always-send: Always send the message without prompting. + never-send: Never send the message + +pmapi-suppress-dialogs: MAPI Clients may tell pmapi32.dll that they +would like some dialogs allowing the user to edit the message before +sending. Since Alpine is not yet designed to properly handle this +(nor will it be unless there is sufficient demand for it), it may be +desired to forego the Alpine interaction if the message contains +enough information for it to be set. Possible values are: + no: Never suppress dialogs, this is the default behavior + yes: Always try sending it as is. You should be aware of the + implications before setting this + prompt: Prompt whether or not it should fire up PC-Pine to edit + the message + +pmapi-strict-no-dialog: Some MAPI clients will request pmapi32 not to +display any dialogs, even when it is absolutely necessary that a +dialog be displayed for the purpose of logging in. By default, +pmapi32 will just display the dialog, but this variable is available +for those who require a strict adherence of this request. The two +possible values for this variable are: + no: Show login dialogs when necessary, which is the default + behavior + yes: Suppress dialogs when it is requested by the client. It + should generally be safe to set this, as it more accurately + reflects the specification, but it is possible that setting + this will hide necessary authentication prompts. + + +To change the default setting of these variables, you will need to +either hand edit the pinerc or set a value in the Windows registry. +The pinerc setting always takes precedence over the registry setting. +An example of setting the value pmapi-send-behavior to "always-send" +in the pinerc would be to add the line: +pmapi-send-behavior=always-send +To add it to the registry, you would need to make sure the following +key exists (from the regedit program): + HKEY_CURRENT_USER\Software\University of Washington\PC-Pine\4.0\PmapiOpts +Then, you would add a string named "pmapi-send-behavior" with the +value of "always-send" + +Environment Variables: +Some sites may take advantage of environment variables in their +configurations, setting them via some program that gets executed +before running PC-Pine. There is a way to mimmick this behavior in +MAPI. First you would need to create the following key: + HKEY_CURRENT_USER\Software\University of Washington\Alpine\1.0\PmapiOpts\Env +Say there is a variable that contains the string "${LOGNAME}". To set +this for MAPI, you would add a string "LOGNAME" to the above key, and +have its value point to whatever the environment variable %LOGNAME% +would point to. + +Troubleshooting: To view debugging information, create a file called +mapi_debug.txt in your system's %TEMP% directory. Bug reports or +comments should be sent to pine@cac.washington.edu. + +Jeff Franklin <jpf@washington.edu> diff --git a/mapi/instmapi.c b/mapi/instmapi.c new file mode 100644 index 00000000..ab79f2f4 --- /dev/null +++ b/mapi/instmapi.c @@ -0,0 +1,406 @@ + +/* + * ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +/* installmapi.c : installs the Alpine version of mapi32.dll + * into the directory from which this program is run. The PC-Pine + * version is pmapi32.dll, and must be in the same directory as the + * program being run. Note that we will run into trouble if we want + * to name our dll mapi32.dll, unless we're putting it in the system + * directory + */ + +#include <windows.h> +#include <stdlib.h> +#include <stdio.h> +#include <io.h> +#include <string.h> +#include <direct.h> + +#define FIXREG 1 + +/* this program consists of two parts: + * (1) Updating the registry, + * most particulary the string of DLLPath in the key + * HKLM\Software\Clients\PC-Pine. + * (2) Deciding whether or not to copy pmapi32.dll into the system + * directory. Starting with Windows 2000, Internet Explorer 5.0 + * or Outlook 2000, mapi32.dll started to be a stub library, loading + * whichever mapi32.dll was defined in the registry (see (1)). We + * don't want to overwrite mapi32.dll if it is the stub library, but + * if the stub library isn't installed, then we want to install our + * own version of mapi32.dll. Since the method for detecting the + * stub library isn't very well documented (as of Feb 17, 2000), we + * should use a liberal policy of whether or not to copy our mapi + * into the system directory. Here are the criteria that determine + * that the stub library is correctly installed: + * i) Existence of mapistub.dll in the system directory + * ii) Existence of the exported function FixMAPI() in mapi32.dll + * If either of these two conditions fail, then we'll copy into the + * system directory (provided we have correct permissions for it). + * + * Jeff Franklin + * University of Washington + */ + +int check_defaults(int, int); +int check_url_commands(int); + +#define CD_MAILER 1 +#define CD_NEWS 2 + +#define CUC_MAILTO 1 +#define CUC_NEWS 2 +#define CUC_NNTP 3 + +int APIENTRY WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + char dir[1000], filename[1024], mapifile[1024], + buffer[3*1024], buffer2[3*1024]; + unsigned long bufflen = 3*1024; + DWORD dtype; + int copy = 0, success = 0, silent = 0; + FARPROC proc; + HKEY hKey; + HINSTANCE hDll; + LPSTR p, pp; + + for(pp = p = lpCmdLine; *(p-1); p++){ + if(*p == ' ' || *p == '\t' || *p == '\0'){ + if(strncmp("-silent", pp, strlen("-silent")) == 0) + silent = 1; + if(!*p) + break; + pp = p + 1; + } + } + + + /* This is the first part of writing the registry with our values */ + _getcwd(dir, 1000); + sprintf(filename, "%s%s", dir, dir[strlen(dir)-1] == '\\' ? + "pmapi32.dll": "\\pmapi32.dll"); + if(_access(filename, 00) == -1){ + sprintf(buffer, + "pmapi32.dll for PC-Pine not found in %s. Install not completed.", + dir); + MessageBox(NULL, buffer, "instmapi.exe", + MB_OK|MB_ICONERROR); + return 0; + } + + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Clients\\Mail", + 0, KEY_READ, &hKey) == ERROR_SUCCESS){ + RegCloseKey(hKey); + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Clients\\Mail", + 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS){ + MessageBox(NULL, + "Cannot install pmapi32.dll. Please make sure that you have permissions to update your registry.", + "instmapi.exe", + MB_OK|MB_ICONERROR); + return 0; + } + } + else { + MessageBox(NULL, + "Cannot install pmapi32.dll. Mailer information not found in registry.", + "instmapi.exe", + MB_OK|MB_ICONERROR); + return 0; + } + +#ifdef FIXREG + /* + * I want to take this out next release because it is only intended to fix + * problems that pine (<=4.43) set in the registry. + */ + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Clients\\Mail\\PC-Pine\\Protocols\\Mailto", + 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS){ + RegSetValueEx(hKey, "URL Protocol", 0, REG_SZ, "", 1); + RegCloseKey(hKey); + } + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Clients\\News\\PC-Pine\\Protocols\\news", + 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS){ + RegSetValueEx(hKey, "URL Protocol", 0, REG_SZ, "", 1); + RegCloseKey(hKey); + } + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Clients\\News\\PC-Pine\\Protocols\\nntp", + 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS){ + RegSetValueEx(hKey, "URL Protocol", 0, REG_SZ, "", 1); + RegCloseKey(hKey); + } + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Clients\\News\\PC-Pine\\shell\\open\\command", + 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS){ + char *tp; + + buffer[0] = '\0'; + bufflen = 1024*3; + RegQueryValueEx(hKey, "", 0, &dtype, buffer, &bufflen); + tp = buffer + strlen(buffer) - strlen(" -url news:%1"); + if((tp - buffer > 0) && (tp - buffer < (int)bufflen) + && (strcmp(tp, " -url news:%1") == 0)){ + *tp = '\0'; + RegSetValueEx(hKey, "", 0, dtype, buffer, strlen(buffer)); + } + RegCloseKey(hKey); + } +#endif + + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Clients\\Mail\\PC-Pine", + 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS){ + if(RegSetValueEx(hKey, "DLLPath", 0, REG_SZ, + filename, strlen(filename) + 1) != ERROR_SUCCESS){ + MessageBox(NULL, + "Could not update registry. Install not completed.", + "instmapi.exe", + MB_OK|MB_ICONERROR); + RegCloseKey(hKey); + return 0; + } + else + RegCloseKey(hKey); + } + else{ + MessageBox(NULL, + "No entry found for PC-Pine. Try running PC-Pine, and then run this program", + "instmapi.exe", + MB_OK|MB_ICONERROR); + return 0; + } + if(check_defaults(CD_MAILER, silent)) + MessageBox(NULL, + "Default mailer could not be set", + "instmapi.exe", + MB_OK|MB_ICONERROR); + if(check_defaults(CD_NEWS, silent)) + MessageBox(NULL, + "Default newsreader could not be set", + "instmapi.exe", + MB_OK|MB_ICONERROR); + + /* This next part determines whether or not we should write our mapi + * into the system directory + */ + if(GetSystemDirectory(dir, 1000)){ + sprintf(mapifile, "%s%s", dir, dir[strlen(dir)-1] == '\\' ? + "mapi32.dll" : "\\mapi32.dll"); + + hDll = LoadLibrary(mapifile); + if(hDll){ + if(proc = GetProcAddress(hDll,"GetPCPineVersion")){ + sprintf(buffer2, "pmapi32.dll exists in %s as mapi32.dll", + dir); + MessageBox(NULL, buffer2, + "instmapi.exe", + MB_APPLMODAL | MB_ICONINFORMATION | MB_OK); + success = 1; + } + if(!success){ + sprintf(buffer, "%s%s", dir, dir[strlen(dir)-1] == '\\' ? + "mapistub.dll" : "\\mapistub.dll"); + if(_access(buffer, 00) != 0) + copy = 1; + if(!copy){ + proc = GetProcAddress(hDll, "FixMAPI"); + if(!proc){ + copy = 1; + } + else + success = 1; + } + } + FreeLibrary(hDll); + } + else + copy = 1; + if(copy){ + sprintf(buffer2, "%s%s", dir, dir[strlen(dir)-1] == '\\' ? + "mapi32x.dll" : "\\mapi32x.dll"); + CopyFile(mapifile, buffer2, 0); + if(CopyFile(filename, mapifile, 0)){ + sprintf(buffer2, "pmapi32.dll has been copied to %s", + mapifile); + MessageBox(NULL, buffer2, "instmapi.exe", + MB_APPLMODAL | MB_ICONINFORMATION | MB_OK); + success = 1; + } + else{ + sprintf(buffer2, "pmapi32.dll could not be copied to %s", + mapifile); + MessageBox(NULL, buffer2, "instmapi.exe", + MB_APPLMODAL | MB_ICONINFORMATION | MB_OK); + } + } + } + + if(success && !silent){ + sprintf(buffer2, + "Installation of pmapi32.dll was successfully completed", + buffer); + MessageBox(NULL, buffer2, "instmapi.exe", + MB_APPLMODAL | MB_ICONINFORMATION | MB_OK); + } + else if(!success){ + sprintf(buffer2, + "Installation of pmapi32.dll may not have successfully completed", + buffer); + MessageBox(NULL, buffer2, "instmapi.exe", + MB_APPLMODAL | MB_ICONINFORMATION | MB_OK); + } + return 0; +} + +int +check_defaults(wdef, silent) + int wdef, silent; +{ + HKEY hKey; + DWORD dtype; + char buffer[1024*3]; + unsigned long bufflen = 1024*3; + int ret; + + if(wdef != CD_MAILER && wdef != CD_NEWS) + return(1); + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, wdef == CD_MAILER + ? "SOFTWARE\\Clients\\Mail" : "SOFTWARE\\Clients\\News", + 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS) + return(1); + bufflen = 1024*3; + RegQueryValueEx(hKey, "", 0, &dtype, buffer, &bufflen); + if(strcmp(buffer, "PC-Pine") == 0){ + RegCloseKey(hKey); + return(0); + } + ret = silent ? IDYES + : MessageBox (NULL, wdef == CD_MAILER + ? "Do you want to make PC-Pine your default mailer?" + : "Do you want to make PC-Pine your default newsreader?", + "instmapi.exe", + MB_APPLMODAL | MB_ICONQUESTION | MB_YESNO); + if(ret == IDYES){ + strcpy(buffer, "PC-Pine"); + bufflen = strlen(buffer)+1; + if(RegSetValueEx(hKey, "", 0, + REG_SZ, buffer, bufflen) != ERROR_SUCCESS){ + RegCloseKey(hKey); + return(1); + } + RegCloseKey(hKey); + if(wdef == CD_MAILER){ + if(check_url_commands(CUC_MAILTO)) + return(1); + } + else if(wdef == CD_NEWS){ + if(check_url_commands(CUC_NEWS) + || check_url_commands(CUC_NNTP)) + return(1); + } + } + return(0); +} + +int +check_url_commands(wdef) + int wdef; +{ + HKEY hKey, hKeyCP; + DWORD dtype; + char buffer[1024*3]; + unsigned long bufflen = 1024*3; + + if(wdef != CUC_MAILTO && wdef != CUC_NEWS && wdef != CUC_NNTP) + return(1); + if(RegOpenKeyEx(HKEY_CLASSES_ROOT, wdef == CUC_MAILTO + ? "mailto\\shell\\open\\command" + : (wdef == CUC_NEWS ? "news\\shell\\open\\command" + : "nntp\\shell\\open\\command"), + 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS) + return(1); + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, wdef == CUC_MAILTO + ? "SOFTWARE\\Clients\\Mail\\PC-Pine\\Protocols\\Mailto\\shell\\open\\command" + : (wdef == CUC_NEWS ? "SOFTWARE\\Clients\\News\\PC-Pine\\Protocols\\news\\shell\\open\\command" + : "SOFTWARE\\Clients\\News\\PC-Pine\\Protocols\\nntp\\shell\\open\\command"), + 0, KEY_ALL_ACCESS, &hKeyCP) != ERROR_SUCCESS){ + RegCloseKey(hKey); + return(1); + } + buffer[0] = '\0'; + bufflen = 1024*3; + if(RegQueryValueEx(hKeyCP, "", 0, &dtype, + buffer, &bufflen) != ERROR_SUCCESS + || RegSetValueEx(hKey, "", 0, REG_SZ, buffer, + bufflen) != ERROR_SUCCESS){ + RegCloseKey(hKey); + RegCloseKey(hKeyCP); + return(1); + } + RegCloseKey(hKey); + RegCloseKey(hKeyCP); + if(RegOpenKeyEx(HKEY_CLASSES_ROOT, wdef == CUC_MAILTO + ? "mailto\\DefaultIcon" + : (wdef == CUC_NEWS ? "news\\DefaultIcon" + : "nntp\\DefaultIcon"), + 0, KEY_ALL_ACCESS, + &hKey) != ERROR_SUCCESS) + return(1); + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, wdef == CUC_MAILTO + ? "SOFTWARE\\Clients\\Mail\\PC-Pine\\Protocols\\Mailto\\DefaultIcon" + : (wdef == CUC_NEWS ? "SOFTWARE\\Clients\\News\\PC-Pine\\Protocols\\news\\DefaultIcon" + : "SOFTWARE\\Clients\\News\\PC-Pine\\Protocols\\nntp\\DefaultIcon"), + 0, KEY_ALL_ACCESS, &hKeyCP) != ERROR_SUCCESS){ + RegCloseKey(hKey); + return(1); + } + buffer[0] = '\0'; + bufflen = 1024*3; + if(RegQueryValueEx(hKeyCP, "", 0, &dtype, buffer, &bufflen) != ERROR_SUCCESS + || RegSetValueEx(hKey, "", 0, REG_SZ, buffer, bufflen) != ERROR_SUCCESS){ + RegCloseKey(hKey); + RegCloseKey(hKeyCP); + return(1); + } + RegCloseKey(hKey); + RegCloseKey(hKeyCP); + + if(RegOpenKeyEx(HKEY_CLASSES_ROOT, wdef == CUC_MAILTO + ? "mailto" + : (wdef == CUC_NEWS ? "news" + : "nntp"), + 0, KEY_ALL_ACCESS, + &hKey) != ERROR_SUCCESS) + return(1); + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, wdef == CUC_MAILTO + ? "SOFTWARE\\Clients\\Mail\\PC-Pine\\Protocols\\Mailto" + : (wdef == CUC_NEWS ? "SOFTWARE\\Clients\\News\\PC-Pine\\Protocols\\news" + : "SOFTWARE\\Clients\\News\\PC-Pine\\Protocols\\nntp"), + 0, KEY_ALL_ACCESS, &hKeyCP) != ERROR_SUCCESS){ + RegCloseKey(hKey); + return(1); + } + buffer[0] = '\0'; + bufflen = 1024*3; + if(RegQueryValueEx(hKeyCP, "URL Protocol", 0, &dtype, buffer, &bufflen) != ERROR_SUCCESS + || RegSetValueEx(hKey, "URL Protocol", 0, REG_SZ, buffer, bufflen) != ERROR_SUCCESS){ + RegCloseKey(hKey); + RegCloseKey(hKeyCP); + return(1); + } + RegCloseKey(hKey); + RegCloseKey(hKeyCP); + + return(0); +} diff --git a/mapi/makefile b/mapi/makefile new file mode 100755 index 00000000..8031be64 --- /dev/null +++ b/mapi/makefile @@ -0,0 +1,72 @@ +# +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + + +# Nmake macros for building Windows 32-Bit apps + +all: pmapi32.dll instmapi.exe + +clean: + del *.obj *.res *.dll *.lib *.exe + +CC=cl +RC=rc +LINK=link + +CBASIC = -nologo -c -W3 -DWIN32 -D_WIN32 +CDEBUG = #-Zi -Od +LDEBUG = #/debug /debugtype:cv +CVARSDLL = -MD -D_DLL +CVARSEXE = -MT +CFLAGS = $(CBASIC) $(CDEBUG) $(EXTRACFLAGS) +RCFLAGS = /fo pmapi.res +DLLENTRY = @12 +DLLLFLAGS = -entry:_DllMainCRTStartup$(DLLENTRY) -dll $(EXTRALDFLAGS) +GUIFLAGS = -subsystem:windows +LFLAGS = $(LDEBUG) -nologo /NODEFAULTLIB +STDLIBS= ..\c-client-dll\cclient.lib winmm.lib crypt32.lib +LIBS = oldnames.lib kernel32.lib advapi32.lib ws2_32.lib user32.lib gdi32.lib comdlg32.lib winspool.lib +LIBSDLL = msvcrt.lib $(LIBS) $(EXTRALIBES) +LIBSEXE = libcmt.lib $(LIBS) + +# Update the object files if necessary + +pmapi.obj: pmapi.c ..\c-client-dll\mail.h pmapi.h + $(CC) $(CFLAGS) $(CVARSDLL) pmapi.c +smapi.obj: smapi.c ..\c-client-dll\mail.h pmapi.h + $(CC) $(CFLAGS) $(CVARSDLL) smapi.c +rfc1522.obj: rfc1522.c ..\c-client-dll\mail.h pmapi.h + $(CC) $(CFLAGS) $(CVARSDLL) rfc1522.c + +instmapi.obj: instmapi.c + $(CC) $(CFLAGS) instmapi.c + +# Update the import library + +pmapi.res: pmapi.rc + $(RC) $(RCFLAGS) pmapi.rc + +# Update the dynamic link library + +pmapi32.dll: pmapi.obj smapi.obj rfc1522.obj pmapi.def pmapi.res + ..\pico\blddate > bdate.c + $(CC) /c $(CFLAGS) bdate.c + $(LINK) $(LFLAGS) $(DLLLFLAGS)\ + -base:0x1C000000 \ + -out:pmapi32.dll \ + /DEF:pmapi.def \ + pmapi.obj smapi.obj rfc1522.obj bdate.obj pmapi.res $(STDLIBS) $(LIBSDLL) + +instmapi.exe: instmapi.obj + $(LINK) $(LFLAGS) $(GUIFLAGS) -out:instmapi.exe instmapi.obj $(LIBSEXE) + +distclean: diff --git a/mapi/pmapi.c b/mapi/pmapi.c new file mode 100644 index 00000000..7fa3b455 --- /dev/null +++ b/mapi/pmapi.c @@ -0,0 +1,2929 @@ + +/* + * ======================================================================== + * Copyright 2006-2009 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include "pmapi.h" + +static int xlate_key; + +mapi_global_s *ms_global = NULL; +#define SIZEOF_20KBUF (20480) +char tmp_20k_buf[SIZEOF_20KBUF]; + +void mm_searched (MAILSTREAM *stream,unsigned long number); +void mm_exists (MAILSTREAM *stream,unsigned long number); +void mm_expunged (MAILSTREAM *stream,unsigned long number); +void mm_flags (MAILSTREAM *stream,unsigned long number); +void mm_notify (MAILSTREAM *stream,char *string,long errflg); +void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes); +void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes); +void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status); +void mm_log (char *string,long errflg); +void mm_dlog (char *string); +int fetch_recursively(BODY *body, long msgno, char *prefix, + PART *part, long flags, FLAGS MAPIflags, + sessionlist_s *cs); +LRESULT CALLBACK Login(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +void mm_login (NETMBX *mb,char *user,char *pwd,long trial); +void mm_critical (MAILSTREAM *stream); +void mm_nocritical (MAILSTREAM *stream); +long mm_diskerror (MAILSTREAM *stream,long errcode,long serious); +void mm_fatal (char *string); +lpMapiFileDesc new_mapi_file_desc(int arraysize); +void free_mapi_file_desc(lpMapiFileDesc lpmfd, int arraysize); +file_s *new_file_s(); +void free_file_s(file_s *fs); +void init_prcvars(mapi_global_s *nmg); +void init_prcfeats(mapi_global_s *nmg); +void expand_env_vars(mapi_global_s *nmg); +void init_fcc_folder(mapi_global_s *nmg); +void init_pmapi_registry_vars(mapi_global_s *nmg); +void init_pmapi_vars(mapi_global_s *nmg); +char *copy_remote_to_local(char *pinerc, sessionlist_s *cs); +int read_pinerc(mapi_global_s *nmg, sessionlist_s *cs, + char *prc, char *pineconf, char *pinercex, int depth); +void free_mapi_global(mapi_global_s *nmg); +MAILSTREAM *first_open(sessionlist_s *cs); +int lookup_file_mime_type(char *fn, BODY *body); +int LookupMIMEFileExt(char *val, char *mime_type, DWORD *vallen); +int in_passfile(sessionlist_s *cs); +int set_text_data(BODY *body, char *txt); +int get_suggested_directory(char *dir); +int get_suggested_file_ext(char *file_ext, PART *part, DWORD *file_extlen); +int InitDebug(); +int GetPineData(); +int UnderlineSpace(char *s); +int GetOutlookVersion(); +char *pmapi_generate_message_id(); +SENDSTREAM *mapi_smtp_open(sessionlist_s *cs, char **servers, long options); +char *encode_mailto_addr_keyval(lpMapiRecipDesc lpmr); +char *encode_mailto_keyval(char *key, char* val); + + +void mm_searched (MAILSTREAM *stream,unsigned long number) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "IMAP mm_searched: not implemented\r\n"); + _flushall(); + } +} + +void mm_exists (MAILSTREAM *stream,unsigned long number) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "IMAP mm_exists: not implemented\r\n"); + _flushall(); + } +} + +void mm_expunged (MAILSTREAM *stream,unsigned long number) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "IMAP mm_expunged: not implemented\r\n"); + _flushall(); + } +} + +void mm_flags (MAILSTREAM *stream,unsigned long number) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "IMAP mm_flags: number is %d\r\n", number); + _flushall(); + } +} + +void mm_notify (MAILSTREAM *stream,char *string,long errflg) +{ + mapi_global_s *nmg; + + nmg = ms_global; + if(MSDEBUG){ + fprintf(nmg->dfd, "IMAP mm_notify:%s %s\r\n", + (errflg == NIL ? "" : + (errflg == WARN ? " WARN:": + (errflg == ERROR ? " ERROR:": + (errflg == PARSE ? " PARSE:":" BYE:")))), string); + _flushall(); + } +} + +void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "IMAP mm_list: not implemented\r\n"); + _flushall(); + } +} + +void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "IMAP mm_lsub: not implemented\r\n"); + _flushall(); + } +} + +void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "IMAP mm_status: not implemented\r\n"); + _flushall(); + } +} + +void mm_log (char *string,long errflg) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "IMAP mm_log:%s %s\r\n", + (errflg == NIL ? "" : + (errflg == WARN ? " WARN:": + (errflg == ERROR ? " ERROR:": + (errflg == PARSE ? " PARSE:":" BYE:")))), string); + _flushall(); + } + if(errflg == ERROR) + ErrorBox("ERROR: %s", string); +} + +void mm_dlog (char *string) +{ + if(MSDEBUG){ + time_t now; + struct tm *tm_now; + + now = time((time_t *)0); + tm_now = localtime(&now); + + fprintf(ms_global->dfd, "IMAP %2.2d:%2.2d:%2.2d %d/%d: %s\r\n", + tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec, + tm_now->tm_mon+1, tm_now->tm_mday, string); + _flushall(); + } +} + +int fetch_recursively(BODY *body, long msgno, char *prefix, PART *part, + long flags, FLAGS MAPIflags, sessionlist_s *cs) +{ + FILE *attfd; + PART *subpart; + mapi_global_s *nmg; + int num = 0, tmplen; + file_s *tfs, *tfs2; + unsigned long declen, numwritten; + void *decf; + char tmp[64], file_ext[64], filename[1024], dir[1024]; + DWORD file_extlen = 64; + char *tmpatt; + unsigned long tmpattlen; + + nmg = ms_global; + tmp[0] = '\0'; + if(body && body->type == TYPEMULTIPART){ + part = body->nested.part; + fetch_recursively(&part->body, msgno, prefix, part, + flags, MAPIflags, cs); + } + else{ + do{ + num++; + sprintf(tmp, "%s%s%d", prefix, (*prefix ? "." : ""), num); + if(part && part->body.type == TYPEMULTIPART){ + subpart = part->body.nested.part; + fetch_recursively(&subpart->body, msgno, tmp, + subpart, flags, MAPIflags, cs); + } + else{ + tmpatt = mail_fetch_body(cs->open_stream, msgno, + tmp, &tmpattlen, flags); + if(strcmp(tmp, "1") == 0){ + if(((part && part->body.type == TYPETEXT) || + (!part && body->type == TYPETEXT)) && + !(MAPIflags & MAPI_BODY_AS_FILE)){ + if(cs->lpm->lpszNoteText){ + fs_give((void **)&cs->lpm->lpszNoteText); + cs->lpm->lpszNoteText = NULL; + } + cs->lpm->lpszNoteText = mstrdup(tmpatt); + tmpatt = NULL; + } + else + cs->lpm->lpszNoteText = mstrdup(""); + if(MAPIflags & MAPI_SUPPRESS_ATTACH) + return 0; + } + if(tmpatt && part && part->body.encoding == ENCBASE64){ + decf = rfc822_base64(tmpatt, tmpattlen, &declen); + tmpatt = NULL; + } + else if(tmpatt && part && part->body.encoding == ENCQUOTEDPRINTABLE){ + decf = rfc822_qprint(tmpatt, tmpattlen, &declen); + tmpatt = NULL; + } + else{ + if(tmpatt){ + decf = mstrdup(tmpatt); + declen = tmpattlen; + } + else decf = NULL; + } + if(decf){ + dir[0] = '\0'; + get_suggested_directory(dir); + tmplen = strlen(dir); + if(dir[tmplen - 1] != '\\'){ + dir[tmplen] = '\\'; + dir[tmplen+1] = '\0'; + } + file_ext[0] = '\0'; + get_suggested_file_ext(file_ext,part, &file_extlen); + do{ + sprintf(filename, "%smapiapp%d%s", dir, nmg->attach_no, + file_ext); + nmg->attach_no++; + }while (_access(filename, 00) != -1); + attfd = fopen(filename, "wb"); + if(attfd){ + if(MSDEBUG) + fprintf(nmg->dfd,"preparing to write attachment to %s\r\n", + filename); + numwritten = fwrite(decf, sizeof(char), declen, attfd); + fclose(attfd); + fs_give((void **)&decf); + tfs = new_file_s(); + tfs->filename = mstrdup(filename); + if(!cs->fs) + cs->fs = tfs; + else{ + for(tfs2 = cs->fs; tfs2->next; tfs2 = tfs2->next); + tfs2->next = tfs; + } + } + else{ + if(MSDEBUG) + fprintf(nmg->dfd,"Failure in opening %s for attachment\r\n", + filename); + } + } + } + }while(part && (part = part->next)); + } + return 0; +} + +int fetch_structure_and_attachments(long msgno, long flags, + FLAGS MAPIflags, sessionlist_s *cs) +{ + BODY *body = NULL; + ENVELOPE *env; + ADDRESS *addr; + MESSAGECACHE *elt = NULL; + mapi_global_s *nmg; + file_s *tfs; + int num = 0, restore_seen = 0, file_count = 0, i; + unsigned long recips; + char tmp[1024]; /* don't know how much space we'll need */ + + nmg = ms_global; + env = mail_fetch_structure(cs->open_stream, msgno, &body, flags); + if(env == NULL || body == NULL){ + if(MSDEBUG) + fprintf(nmg->dfd, "mail_fetch_structure returned %p for env and %p for body\r\n", env, body); + return MAPI_E_FAILURE; + } + if(cs->lpm){ + if(MSDEBUG) + fprintf(nmg->dfd, "global lpm is set when it SHOULDN'T be! Freeing\r\n"); + if(free_mbuffer(cs->lpm)) + free_MapiMessage(cs->lpm, 1); + cs->lpm = NULL; + } + cs->lpm = new_MapiMessage(1); + if(env->subject) cs->lpm->lpszSubject = mstrdup(env->subject); + if(env->date){ + elt = mail_elt(cs->open_stream, msgno); + mail_parse_date(elt, env->date); + sprintf(tmp, "%d/%s%d/%s%d %s%d:%s%d", + elt->year+BASEYEAR, (elt->month < 10) ? "0": "", + elt->month, (elt->day < 10) ? "0":"", elt->day, + (elt->hours < 10) ? "0":"", elt->hours, + (elt->minutes < 10) ? "0":"", elt->minutes); + cs->lpm->lpszDateReceived = mstrdup(tmp); + } + if(env->from){ + cs->lpm->lpOriginator = new_MapiRecipDesc(1); + if(env->from->personal) + cs->lpm->lpOriginator->lpszName = mstrdup(env->from->personal); + if(env->from->mailbox && env->from->host){ + /* don't know if these could ever be empty */ + sprintf(tmp, "%s@%s", env->from->mailbox, env->from->host); + cs->lpm->lpOriginator->lpszAddress = mstrdup(tmp); + } + cs->lpm->lpOriginator->ulRecipClass = MAPI_ORIG; + } + if(env->to || env->cc || env->bcc){ /* should always be true */ + recips = 0; + if(env->to){ + addr = env->to; + while(addr){ + recips++; + addr = addr->next; + } + } + if(env->cc){ + addr = env->cc; + while(addr){ + recips++; + addr = addr->next; + } + } + if(env->bcc){ + addr = env->bcc; + while(addr){ + recips++; + addr = addr->next; + } + } + cs->lpm->nRecipCount = recips; + cs->lpm->lpRecips = new_MapiRecipDesc(recips); + recips = 0; + if(env->to){ + addr = env->to; + while(addr){ + cs->lpm->lpRecips[recips].ulRecipClass = MAPI_TO; + if(addr->personal) + cs->lpm->lpRecips[recips].lpszName = mstrdup(addr->personal); + if(addr->mailbox && addr->host){ + sprintf(tmp, "%s@%s", addr->mailbox, addr->host); + cs->lpm->lpRecips[recips].lpszAddress = mstrdup(tmp); + } + recips++; + addr = addr->next; + } + } + if(env->cc){ + addr = env->cc; + while(addr){ + cs->lpm->lpRecips[recips].ulRecipClass = MAPI_CC; + if(addr->personal) + cs->lpm->lpRecips[recips].lpszName = mstrdup(addr->personal); + if(addr->mailbox && addr->host){ + sprintf(tmp, "%s@%s", addr->mailbox, addr->host); + cs->lpm->lpRecips[recips].lpszAddress = mstrdup(tmp); + } + recips++; + addr = addr->next; + } + } + if(env->bcc){ + addr = env->bcc; + while(addr){ + cs->lpm->lpRecips[recips].ulRecipClass = MAPI_BCC; + if(addr->personal) + cs->lpm->lpRecips[recips].lpszName = mstrdup(addr->personal); + if(addr->mailbox && addr->host){ + sprintf(tmp, "%s@%s", addr->mailbox, addr->host); + cs->lpm->lpRecips[recips].lpszAddress = mstrdup(tmp); + } + recips++; + addr = addr->next; + } + } + } + + if(flags & FT_PEEK){ + /* gotta remember to unflag \Seen if we just want a peek */ + sprintf(tmp, "%d", msgno); + mail_fetch_flags(cs->open_stream, tmp, NIL); + elt = mail_elt(cs->open_stream, msgno); + if(!elt->seen){ + if(MSDEBUG) + fprintf(nmg->dfd, "Message has not been seen, and a PEEK is requested\r\n"); + restore_seen = 1; + } + else if(MSDEBUG) + fprintf(nmg->dfd, "Message has already been marked seen\r\n"); + } + if(!(MAPIflags & MAPI_ENVELOPE_ONLY)) + fetch_recursively(body, msgno, "", NULL, flags, MAPIflags, cs); + if(cs->fs){ + for(tfs = cs->fs; tfs; tfs = tfs->next) + file_count++; + cs->lpm->lpFiles = new_mapi_file_desc(file_count); + for(i = 0, tfs = cs->fs; i < file_count && tfs; i++, tfs = tfs->next){ + cs->lpm->lpFiles[i].lpszPathName = mstrdup(tfs->filename); + } + cs->lpm->nFileCount = file_count; + free_file_s(cs->fs); + cs->fs = NULL; + } + if(restore_seen){ + elt = mail_elt(cs->open_stream, msgno); + if(!elt->seen && MSDEBUG) + fprintf(nmg->dfd, "Fetched body and Message still isn't seen\r\n"); + else if(MSDEBUG) + fprintf(nmg->dfd, "Message has been seen, clearing flag\r\n"); + if(elt->seen){ + mail_flag(cs->open_stream, tmp, "\\SEEN", NIL); + elt = mail_elt(cs->open_stream, msgno); + if(MSDEBUG) + fprintf(nmg->dfd, "After calling mail_flag(), elt->seen is %s\r\n", + elt->seen ? "SET" : "UNSET"); + } + } + return SUCCESS_SUCCESS; +} + +LRESULT CALLBACK Login(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + mapi_global_s *nmg; + + nmg = ms_global; + + switch(message){ + case WM_INITDIALOG: + SetDlgItemText(hDlg, IDC_SERVER, nmg->tmpmbxptr); + if(/*nmg->flags.mapi_logon_ui &&*/ in_passfile(nmg->cs)){ + SetDlgItemText(hDlg, IDC_LOGIN, nmg->cs->dlge.edit1); + SetDlgItemText(hDlg, IDC_PASSWORD, nmg->cs->dlge.edit2); + } + else + SetDlgItemText(hDlg, IDC_LOGIN, + (*nmg->cs->mb->user) ? nmg->cs->mb->user + : nmg->prcvars[USER_ID]->val.p); + return TRUE; + case WM_COMMAND: + if(LOWORD(wParam) == IDOK){ + nmg->cs->flags.dlg_cancel = 0; + GetDlgItemText(hDlg, IDC_LOGIN, nmg->cs->dlge.edit1, EDITLEN); + GetDlgItemText(hDlg, IDC_PASSWORD, nmg->cs->dlge.edit2, EDITLEN); + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + } + else if(LOWORD(wParam) == IDCANCEL){ + nmg->cs->flags.dlg_cancel = 1; + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + } + break; + } + return FALSE; +} + +void mm_login (NETMBX *mb,char *user,char *pwd,long trial) +{ + mapi_global_s *nmg; + pw_cache_s *tpwc, *dpwc; + int tmp_set_mbx = 0; + + nmg = ms_global; + nmg->cs->mb = mb; + if(!nmg->cs->flags.dlg_cancel){ + for(tpwc = nmg->cs->pwc; tpwc; tpwc = tpwc->next){ + if(tpwc->validpw && strcmp(tpwc->host, mb->host) == 0) + break; + } + if(tpwc){ + strcpy(user, tpwc->user); + strcpy(pwd, tpwc->pwd); + tpwc->validpw = 0; + } + /* else if(!nmg->cs->flags.check_stream) { */ + else if(nmg->cs->flags.mapi_logon_ui || !nmg->pmapi_strict_no_dialog) { + if(!nmg->tmpmbxptr){ + tmp_set_mbx = 1; + nmg->tmpmbxptr = mb->host; + } + DialogBox(nmg->mhinst, MAKEINTRESOURCE(IDD_DIALOG1), + nmg->cs->mhwnd, (DLGPROC)Login); + if(tmp_set_mbx) + nmg->tmpmbxptr = NULL; + if(!nmg->cs->flags.dlg_cancel){ + strcpy(user, nmg->cs->dlge.edit1); + strcpy(pwd, nmg->cs->dlge.edit2); + tpwc = nmg->cs->pwc; + while(tpwc){ + if(tpwc->validpw == 0){ + dpwc = tpwc; + tpwc = tpwc->next; + if(dpwc == nmg->cs->pwc) + nmg->cs->pwc = dpwc->next; + fs_give((void **)&dpwc); + } + else + tpwc = tpwc->next; + } + if(nmg->cs->pwc == NULL){ + nmg->cs->pwc = (pw_cache_s *)fs_get(sizeof(pw_cache_s)); + tpwc = nmg->cs->pwc; + } + else { + for(tpwc = nmg->cs->pwc; tpwc->next; tpwc = tpwc->next); + tpwc->next = (pw_cache_s *)fs_get(sizeof(pw_cache_s)); + tpwc = tpwc->next; + } + memset(tpwc, 0, sizeof(pw_cache_s)); + strncpy(tpwc->user, nmg->cs->dlge.edit1, EDITLEN - 1); + strncpy(tpwc->pwd, nmg->cs->dlge.edit2, EDITLEN - 1); + strncpy(tpwc->host, mb->host, EDITLEN - 1); + } + } + } + nmg->cs->mb = NULL; +} + +void mm_critical (MAILSTREAM *stream) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "IMAP mm_critical: not implemented\r\n"); + _flushall(); + } +} + +void mm_nocritical (MAILSTREAM *stream) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "IMAP mm_nocritical: not implemented\r\n"); + _flushall(); + } +} + +long mm_diskerror (MAILSTREAM *stream,long errcode,long serious) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "IMAP mm_diskerror: not implemented\r\n"); + _flushall(); + } + return 1; +} + +void mm_fatal (char *string) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "IMAP mm_fatal: %s\r\n", string); + _flushall(); + } +} + +sessionlist_s *new_sessionlist() +{ + sessionlist_s *cs; + + cs = (sessionlist_s *)fs_get(sizeof(sessionlist_s)); + memset(cs, 0, sizeof(sessionlist_s)); + cs->session_number = ms_global->next_session++; + + return cs; +} + +sessionlist_s *free_sessionlist_node(sessionlist_s *cs) +{ + sessionlist_s *ts; + + ts = cs->next; + + if(cs->currently_open) + fs_give((void **)&cs->currently_open); + if(cs->fs) + free_file_s(cs->fs); + if(cs->lpm){ + if(free_mbuffer(cs->lpm)) + free_MapiMessage(cs->lpm, 1); + cs->lpm = NULL; + } + fs_give((void **)&cs); + + return ts; +} + +sessionlist_s *get_session(unsigned long num) +{ + mapi_global_s *nmg = ms_global; + sessionlist_s *ts; + + ts = nmg->sessionlist; + while(ts && ts->session_number != num) ts = ts->next; + return ts; +} + +/* +void *mm_cache (MAILSTREAM *stream,unsigned long msgno,long op){} +*/ +mapi_global_s *new_mapi_global() +{ + mapi_global_s *nmg; + int i; + + nmg = (mapi_global_s *)fs_get(sizeof(mapi_global_s)); + memset(nmg, 0, sizeof(mapi_global_s)); + for(i=0; i < NUMPRCVARS; i++){ + nmg->prcvars[i] = (rc_entry_s *)fs_get(sizeof(rc_entry_s)); + memset(nmg->prcvars[i], 0, sizeof(rc_entry_s)); + } + for(i=0; i < NUMPRCFEATS; i++){ + nmg->prcfeats[i] = (rc_feat_s *)fs_get(sizeof(rc_feat_s)); + memset(nmg->prcfeats[i], 0, sizeof(rc_feat_s)); + } + nmg->next_session = 1; + + return nmg; +} + +int InitPineSpecific(sessionlist_s *cs) +{ + mapi_global_s *nmg = ms_global; + + if(nmg->inited) return 0; + init_prcvars(ms_global); + init_prcfeats(ms_global); + init_pmapi_registry_vars(ms_global); + if(read_pinerc(ms_global, cs, ms_global->pinerc, + ms_global->pineconf, ms_global->pinercex, 0) == -1) + return -1; + expand_env_vars(ms_global); + init_fcc_folder(ms_global); + msprint1("Fcc folder defined: %s", ms_global->fccfolder); + init_pmapi_vars(ms_global); + nmg->inited = 1; + return 1; +} + +int +new_mbuffer(void *buf, int arraysize, BufType type) +{ + MBUFFER_LIST_S *tlist, *tlist2; + mapi_global_s *nmg = ms_global; + + tlist = (MBUFFER_LIST_S *)fs_get(sizeof(MBUFFER_LIST_S)); + memset(tlist, 0, sizeof(MBUFFER_LIST_S)); + tlist->buf = buf; + tlist->arraysize = arraysize; + tlist->type = type; + + if(!nmg->mapi_bufs) + nmg->mapi_bufs = tlist; + else{ + for(tlist2 = nmg->mapi_bufs; tlist2->next; tlist2 = tlist2->next); + tlist2->next = tlist; + } + + return(0); +} + +int +free_mbuffer(void *buf) +{ + MBUFFER_LIST_S *tlist, *pre_tlist = NULL; + mapi_global_s *nmg = ms_global; + sessionlist_s *session; + + for(tlist = nmg->mapi_bufs; tlist && tlist->buf != buf; pre_tlist = tlist, tlist = tlist->next); + if(!tlist){ + msprint1("ERROR: buf %p not found in list!\r\n", buf); + return 1; + } + if(tlist == nmg->mapi_bufs) + nmg->mapi_bufs = tlist->next; + else + pre_tlist->next = tlist->next; + switch (tlist->type) { + case RecipDesc: + free_MapiRecipDesc(tlist->buf, tlist->arraysize); + break; + case Message: + for(session = nmg->sessionlist; session; session = session->next){ + if(session->lpm == tlist->buf) + session->lpm = NULL; + } + free_MapiMessage(tlist->buf, tlist->arraysize); + break; + } + fs_give((void **)&tlist); + return 0; +} + +lpMapiRecipDesc +new_MapiRecipDesc(int arraysize) +{ + lpMapiRecipDesc lpmrd; + mapi_global_s *nmg = ms_global; + + lpmrd = (MapiRecipDesc *)fs_get(arraysize*sizeof(MapiRecipDesc)); + memset(lpmrd, 0, arraysize*sizeof(MapiRecipDesc)); + new_mbuffer((void *)lpmrd, arraysize, RecipDesc); + return lpmrd; +} + +void +free_MapiRecipDesc(lpMapiRecipDesc buf, int arraysize) +{ + int i; + + for(i = 0; i < arraysize; i++){ + if(buf[i].lpszName) + fs_give((void **)&buf[i].lpszName); + if(buf[i].lpszAddress) + fs_give((void **)&buf[i].lpszAddress); + } + fs_give((void **)&buf); +} + +lpMapiMessage +new_MapiMessage(int arraysize) +{ + lpMapiMessage lpmm; + mapi_global_s *nmg = ms_global; + + lpmm = (lpMapiMessage)fs_get(arraysize*sizeof(MapiMessage)); + memset(lpmm, 0, arraysize*sizeof(MapiMessage)); + new_mbuffer((void *)lpmm, arraysize, Message); + return lpmm; +} + +void +free_MapiMessage(lpMapiMessage buf, int arraysize) +{ + int i; + + for(i = 0; i < arraysize; i++){ + if(buf[i].lpszSubject) + fs_give((void **)&buf[i].lpszSubject); + if(buf[i].lpszNoteText) + fs_give((void **)&buf[i].lpszNoteText); + if(buf[i].lpszMessageType) + fs_give((void **)&buf[i].lpszMessageType); + if(buf[i].lpszDateReceived) + fs_give((void **)&buf[i].lpszDateReceived); + if(buf[i].lpszConversationID) + fs_give((void **)&buf[i].lpszConversationID); + if(buf[i].lpOriginator){ + if(free_mbuffer(buf[i].lpOriginator)) + free_MapiRecipDesc(buf[i].lpOriginator, 1); + } + if(buf[i].lpRecips){ + if(free_mbuffer(buf[i].lpRecips)) + free_MapiRecipDesc(buf[i].lpRecips, buf[i].nRecipCount); + } + if(buf[i].lpFiles) + free_mapi_file_desc(buf[i].lpFiles, buf[i].nFileCount); + } + fs_give((void **)&buf); +} + +lpMapiFileDesc new_mapi_file_desc(int arraysize) +{ + lpMapiFileDesc lpmfd; + + lpmfd = (MapiFileDesc *)fs_get(arraysize * sizeof (MapiFileDesc)); + memset(lpmfd, 0, arraysize * sizeof(MapiFileDesc)); + return lpmfd; +} + +void free_mapi_file_desc(lpMapiFileDesc lpmfd, int arraysize) +{ + int i; + + if(lpmfd == NULL) return; + + for(i = 0; i < arraysize; i++){ + if(lpmfd[i].lpszPathName) + fs_give((void **)&lpmfd[i].lpszPathName); + if(lpmfd[i].lpszFileName) + fs_give((void **)&lpmfd[i].lpszFileName); + /* NOTE: if lpFileType gets used, free it here */ + } + fs_give((void **)&lpmfd); +} + +file_s *new_file_s() +{ + file_s *tmp_fs; + + tmp_fs = (file_s *)fs_get(sizeof(file_s)); + memset(tmp_fs, 0, sizeof(file_s)); + return tmp_fs; +} + +void free_file_s(file_s *fs) +{ + if(fs == NULL) return; + if(fs->next) + free_file_s(fs->next); + if(fs->filename) + fs_give((void **)&fs->filename); + fs_give((void **)&fs); +} + +void +init_prcvars(mapi_global_s *nmg) +{ + int i=0; + + nmg->prcvars[USER_ID]->var = mstrdup("user-id"); + nmg->prcvars[PERSONAL_NAME]->var = mstrdup("personal-name"); + nmg->prcvars[USER_DOMAIN]->var = mstrdup("user-domain"); + nmg->prcvars[SMTP_SERVER]->var = mstrdup("smtp-server"); + nmg->prcvars[SMTP_SERVER]->islist = 1; + nmg->prcvars[INBOX_PATH]->var = mstrdup("inbox-path"); + nmg->prcvars[FEATURE_LIST]->var = mstrdup("feature-list"); + nmg->prcvars[FEATURE_LIST]->islist = 1; + nmg->prcvars[CHARACTER_SET]->var = mstrdup("character-set"); + nmg->prcvars[FOLDER_COLLECTIONS]->var = mstrdup("folder-collections"); + nmg->prcvars[FOLDER_COLLECTIONS]->islist = 1; + nmg->prcvars[PMAPI_SEND_BEHAVIOR]->var = mstrdup("pmapi-send-behavior"); + nmg->prcvars[PMAPI_SEND_BEHAVIOR]->ispmapivar = 1; + nmg->prcvars[DEFAULT_FCC]->var = mstrdup("default-fcc"); + nmg->prcvars[PMAPI_SUPPRESS_DIALOGS]->var = mstrdup("pmapi-suppress-dialogs"); + nmg->prcvars[PMAPI_SUPPRESS_DIALOGS]->ispmapivar = 1; + nmg->prcvars[PMAPI_STRICT_NO_DIALOG]->var = mstrdup("pmapi-strict-no-dialog"); + nmg->prcvars[PMAPI_STRICT_NO_DIALOG]->ispmapivar = 1; +} + +void +init_prcfeats(mapi_global_s *nmg) +{ + nmg->prcfeats[ENABLE8BIT]->var = mstrdup("enable-8bit-esmtp-negotiation"); +} + +void init_fcc_folder(mapi_global_s *nmg) +{ + char *fcc, **fc, *desc = NULL, *col = NULL, *tfcc, *p, *p2; + int i = 0; + + if(!nmg->prcvars[DEFAULT_FCC]->val.p) + nmg->prcvars[DEFAULT_FCC]->val.p = cpystr("sent-mail"); + fcc = nmg->prcvars[DEFAULT_FCC]->val.p; + if(!fcc || !(*fcc)) return; + if(strcmp(fcc, "\"\"") == 0) return; + if((*fcc == '{') || (isalpha(fcc[0]) && (fcc[1] == ':')) + || ((fcc[0] == '\\') && (fcc[1] == '\\'))){ + nmg->fccfolder = cpystr(fcc); + return; + } + fc = nmg->prcvars[FOLDER_COLLECTIONS]->val.l; + if(!fc || !fc[0] || !fc[0][0]) return; + get_pair(fc[i], &desc, &col, 0, 0); + if(desc) + fs_give((void **)&desc); + if(!col) + return; + p = strrchr(col, '['); + p2 = strrchr(col, ']'); + if((p2 < p) || (!p)){ + if(col) + fs_give((void **)&col); + return; + } + tfcc = (char *)fs_get((strlen(col) + strlen(fcc) + 1) * sizeof(char)); + *p = '\0'; + p2++; + sprintf(tfcc, "%s%s%s", col, fcc, p2); + nmg->fccfolder = tfcc; + if(col) + fs_give((void **)&col); +} + +void init_pmapi_registry_vars(mapi_global_s *nmg) +{ + HKEY hKey; + BYTE keyData[1024]; + DWORD keyDataSize = 1024; + DWORD keyDataType; + int i; + + if(RegOpenKeyEx(HKEY_CURRENT_USER, + "Software\\University of Washington\\Alpine\\1.0\\PmapiOpts", + 0, + KEY_QUERY_VALUE, + &hKey) != ERROR_SUCCESS) + return; + + for(i = 0; i < NUMPRCVARS; i++){ + if(nmg->prcvars[i]->ispmapivar && nmg->prcvars[i]->islist == 0){ + keyDataSize = 1024; + if((RegQueryValueEx(hKey, nmg->prcvars[i]->var, 0, &keyDataType, + keyData, &keyDataSize) == ERROR_SUCCESS) + && keyDataType == REG_SZ){ + if(nmg->prcvars[i]->val.p) + fs_give((void **)&nmg->prcvars[i]->val.p); + nmg->prcvars[i]->val.p = mstrdup(keyData); + } + } + } + + RegCloseKey(hKey); +} + +void init_pmapi_vars(mapi_global_s *nmg) +{ + char *b; + + if(b = nmg->prcvars[PMAPI_SEND_BEHAVIOR]->val.p){ + if(_stricmp(b, "always-prompt") == 0) + nmg->pmapi_send_behavior = PMSB_ALWAYS_PROMPT; + else if(_stricmp(b, "always-send") == 0) + nmg->pmapi_send_behavior = PMSB_ALWAYS_SEND; + else if(_stricmp(b, "never-send") == 0) + nmg->pmapi_send_behavior = PMSB_NEVER_SEND; + } + else + nmg->pmapi_send_behavior = PMSB_ALWAYS_PROMPT; + if(b = nmg->prcvars[PMAPI_SUPPRESS_DIALOGS]->val.p){ + if(_stricmp(b, "yes") == 0) + nmg->pmapi_suppress_dialogs = PMSD_YES; + else if(_stricmp(b, "prompt") == 0) + nmg->pmapi_suppress_dialogs = PMSD_PROMPT; + else if(_stricmp(b, "no") == 0) + nmg->pmapi_suppress_dialogs = PMSD_NO; + } + else + nmg->pmapi_suppress_dialogs = PMSD_NO; + if(b = nmg->prcvars[PMAPI_STRICT_NO_DIALOG]->val.p){ + if(_stricmp(b, "yes") == 0) + nmg->pmapi_strict_no_dialog = 1; + } + else + nmg->pmapi_strict_no_dialog = 0; +} + +char *copy_remote_to_local(char *pinerc, sessionlist_s *cs) +{ + mapi_global_s *nmg = ms_global; + char *tmptext, dir[1024], filename[1024]; + unsigned long tmptextlen, i = 0, numwritten; + FILE *prcfd; + + if(nmg->cs) return NULL; + if(!(cs->open_stream = mapi_mail_open(cs, NULL, pinerc, + ms_global->debug ? OP_DEBUG : NIL))){ + ErrorBox("Couldn't open %s for reading as remote pinerc", pinerc); + return NULL; + } + nmg->cs = NULL; + nmg->tmpmbxptr = NULL; + tmptext = mail_fetch_body(cs->open_stream, cs->open_stream->nmsgs, + "1", &tmptextlen, NIL); + dir[0] = '\0'; + get_suggested_directory(dir); + do{ + sprintf(filename, "%s%smapipinerc%d", dir, + dir[strlen(dir)-1] == '\\' ? "" : "\\", i); + i++; + }while (_access(filename, 00) != -1); + if(prcfd = fopen(filename, "wb")){ + if(MSDEBUG) + fprintf(ms_global->dfd,"preparing to write pinerc to %s\r\n", + filename); + numwritten = fwrite(tmptext, sizeof(char), tmptextlen, prcfd); + fclose(prcfd); + } + else{ + ErrorBox("Couldn't open temp file %s for writing", filename); + mail_close_full(cs->open_stream, NIL); + return NULL; + } + cs->open_stream = mail_close_full(cs->open_stream, NIL); + return(mstrdup(filename)); +} + +int read_pinerc(mapi_global_s *nmg, sessionlist_s *cs, + char *prc, char *pineconf, char *pinercex, int depth) +{ + FILE *prcfd; + int i, varnum, j, varlen, create_local = 0, k; + char line[BUFLEN], *local_pinerc, *p; + + if(nmg == NULL) return -1; + if(MSDEBUG){ + fprintf(nmg->dfd, + "read_pinerc called: prc: %s, pineconf: %s, pinercex: %s, depth: %d\r\n", + prc ? prc : "NULL", pineconf ? pineconf : "NULL", + pinercex ? pinercex : "NULL", depth); + } + if(pineconf){ + if(MSDEBUG) + fprintf(nmg->dfd, "Recursively calling read_pinerc for pineconf\r\n"); + read_pinerc(nmg, cs, pineconf, NULL, NULL, 1); + } + if(prc == NULL){ + ErrorBox("No value found for %s. Try running Alpine.", "pinerc"); + DEBUG_WRITE("No value found for %s\r\n","pinerc"); + _flushall(); + return -1; + } + if(*prc == '{'){ + if(MSDEBUG) + fprintf(ms_global->dfd, "REMOTE PINERC: %s\r\n", prc); + if(!(local_pinerc = copy_remote_to_local(prc, cs))){ + if(MSDEBUG) + fprintf(nmg->dfd, "Couldn't copy remote pinerc to local\r\n"); + return -1; + } + create_local = 1; + } + else{ + if(!(local_pinerc = mstrdup(prc))){ + ErrorBox("Couldn't fs_get for %s","pinerc"); + return -1; + } + } + if(MSDEBUG) + fprintf(nmg->dfd, "Preparing to open local pinerc %s\r\n", local_pinerc); + prcfd = fopen(local_pinerc, "r"); + if(prcfd == NULL){ + DEBUG_WRITE("Couldn't open %s\r\n","pinerc"); + _flushall(); + ErrorBox("Couldn't open %s\r\n","pinerc"); + if(local_pinerc) + fs_give((void **)&local_pinerc); + return -1; + } + DEBUG_WRITE("Opened %s for reading\r\n", "pinerc"); + for(i = 0; i < NUMPRCVARS && nmg->prcvars[i]->var; i++); + varnum = i; + while(fgets(line, BUFLEN, prcfd)){ + j = 0; + while(isspace(line[j])) j++; + if(line[j] != '#' && line[j] != '\0'){ + for(i = 0; i < varnum; i ++){ + varlen = strlen(nmg->prcvars[i]->var); + if(_strnicmp(nmg->prcvars[i]->var, line+j, varlen)==0){ + j += varlen; + if(line[j] == '='){ + /* we found a match in the pinerc */ + j++; + if(nmg->prcvars[i]->islist){ + while(isspace(line[j])) j++; + if(line[j] != '\0'){ + STRLIST_S *strl = NULL, *tl, *tln; + + if(nmg->prcvars[i]->val.l){ + for(k = 0; nmg->prcvars[i]->val.l[k]; k++) + fs_give((void **)&nmg->prcvars[i]->val.l[k]); + fs_give((void **)&nmg->prcvars[i]->val.l); + } + strl = (STRLIST_S *)fs_get(sizeof(STRLIST_S)); + memset(strl, 0, sizeof(STRLIST_S)); + tl = strl; + while(line[j]){ + while(isspace(line[j])) j++; + if(p = strchr(line+j, ',')) + *p = '\0'; + if(tl != strl || tl->str){ + tl->next = (STRLIST_S *)fs_get(sizeof(STRLIST_S)); + tl = tl->next; + memset(tl, 0, sizeof(STRLIST_S)); + } + varlen = strlen(line+j); + while(isspace((line+j)[varlen - 1])){ + varlen--; + (line+j)[varlen] = '\0'; + } + tl->str = mstrdup(line+j); + if(p){ + j = p - line + 1; + while(isspace(line[j])) j++; + if(!line[j]){ + fgets(line, BUFLEN, prcfd); + j = 0; + } + } + else + break; + } + for(tl = strl, k = 0; tl; tl = tl->next, k++); + nmg->prcvars[i]->val.l = (char **)fs_get((k+1)*sizeof(char *)); + for(tl = strl, k = 0; tl; tl = tln, k++){ + nmg->prcvars[i]->val.l[k] = tl->str; + tln = tl->next; + fs_give((void **)&tl); + } + nmg->prcvars[i]->val.l[k] = NULL; + } + } + else{ + while(isspace(line[j])) j++; + if(line[j] != '\0'){ + varlen = strlen(line+j); + while(isspace((line+j)[varlen-1])){ + varlen--; + (line+j)[varlen] = '\0'; + } + if(nmg->prcvars[i]->val.p) fs_give((void **)&nmg->prcvars[i]->val.p); + nmg->prcvars[i]->val.p = (char *)fs_get((varlen + 1)*sizeof(char)); + strncpy(nmg->prcvars[i]->val.p, line+j, varlen); + nmg->prcvars[i]->val.p[varlen] = '\0'; + } + } + } + } + } + } + } + if(!depth){ + if(pinercex){ + if(MSDEBUG) + fprintf(nmg->dfd, + "Recursively calling read_pinerc for exceptions\r\n"); + read_pinerc(nmg, cs, pinercex, NULL, NULL, 1); + } + } + _flushall(); + fclose(prcfd); + for(i = 0; nmg->prcvars[FEATURE_LIST]->val.l + && nmg->prcvars[FEATURE_LIST]->val.l[i]; i++){ + for(j = 0; j < NUMPRCFEATS; j++){ + if(strcmp(nmg->prcfeats[j]->var, nmg->prcvars[FEATURE_LIST]->val.l[i]) == 0) + nmg->prcfeats[j]->is_set = 1; + else if((strncmp("no-", nmg->prcvars[FEATURE_LIST]->val.l[i], 3) == 0) + && (strcmp(nmg->prcfeats[j]->var, + nmg->prcvars[FEATURE_LIST]->val.l[i] + 3) == 0)){ + nmg->prcfeats[j]->is_set = 0; + } + } + } + if(create_local && local_pinerc){ + if(MSDEBUG) + fprintf(nmg->dfd, "Removing %s\r\n", local_pinerc); + _unlink(local_pinerc); + } + if(local_pinerc) + fs_give((void **)&local_pinerc); + if(MSDEBUG){ + fprintf(nmg->dfd, "Current pinerc settings:\r\n"); + for(i = 0; i < varnum; i++){ + fprintf(nmg->dfd, "%s:", nmg->prcvars[i]->var); + if(!nmg->prcvars[i]->islist) + fprintf(nmg->dfd, " %s\r\n", + nmg->prcvars[i]->val.p ? nmg->prcvars[i]->val.p : " NOT DEFINED"); + else{ + if(!nmg->prcvars[i]->val.l) + fprintf(nmg->dfd, " NOT DEFINED\r\n"); + else { + for(j = 0; nmg->prcvars[i]->val.l[j]; j++) + fprintf(nmg->dfd, "\t%s\r\n", + nmg->prcvars[i]->val.l[j]); + } + } + } + } + return 0; +} + +void expand_env_vars(mapi_global_s *nmg) +{ + int i, j, check_reg = 0, islist; + DWORD keyDataSize = 1024, keyDataType; + char *p1, *p2, *p3, keyData[1024], *newstr, **valstrp; + HKEY hKey; + + + if(RegOpenKeyEx(HKEY_CURRENT_USER, + "Software\\University of Washington\\Alpine\\1.0\\PmapiOpts\\Env", + 0, + KEY_QUERY_VALUE, + &hKey) == ERROR_SUCCESS) + check_reg = 1; + for(i = 0; i < NUMPRCVARS; i++){ + islist = nmg->prcvars[i]->islist; + for(j = 0; islist ? (int)(nmg->prcvars[i]->val.l && nmg->prcvars[i]->val.l[j]) + : (j < 1); j++){ + valstrp = islist ? &nmg->prcvars[i]->val.l[j] : &nmg->prcvars[i]->val.p; + if(*valstrp == NULL) continue; + while((p1 = strstr(*valstrp, "${")) && (p2 = strchr(p1, '}'))){ + msprint1("%s -> ", *valstrp); + *p2 = '\0'; + p3 = NULL; + if((p3 = getenv(p1+2)) && *p3) + ; + else if(check_reg && (keyDataSize = 1024) + && (RegQueryValueEx(hKey, p1+2, 0, &keyDataType, + keyData, &keyDataSize) == ERROR_SUCCESS) + && keyDataType == REG_SZ) + p3 = keyData; + newstr = (char *)fs_get(sizeof(char)*(strlen(*valstrp) + + strlen(p3 ? p3 : "") + strlen(p2+1) + 1)); + *p1 = '\0'; + strcpy(newstr, *valstrp); + strcat(newstr, p3 && *p3 ? p3 : ""); + strcat(newstr, p2 + 1); + fs_give((void **)valstrp); + *valstrp = newstr; + msprint1(" %s\r\n", *valstrp); + } + } + } + if(check_reg) + RegCloseKey(hKey); +} + +void free_mapi_global(mapi_global_s *nmg) +{ + int i, j; + sessionlist_s *ts; + + if(nmg->pineExe) + fs_give((void **)&nmg->pineExe); + if(nmg->pineExeAlt) + fs_give((void **)&nmg->pineExeAlt); + if(nmg->pinerc) + fs_give((void **)&nmg->pinerc); + if(nmg->pineconf) + fs_give((void **)&nmg->pineconf); + if(nmg->pinercex) + fs_give((void **)&nmg->pinercex); + if(nmg->fccfolder) + fs_give((void **)&nmg->fccfolder); + if(nmg->attachDir) + fs_give((void **)&nmg->attachDir); + for(i = 0; i < NUMPRCFEATS; i++){ + if(nmg->prcfeats[i]->var) + fs_give((void **)&nmg->prcfeats[i]->var); + fs_give((void **)&nmg->prcfeats[i]); + } + for(i = 0; i < NUMPRCVARS; i++){ + if(nmg->prcvars[i]->var) + fs_give((void **)&nmg->prcvars[i]->var); + if(nmg->prcvars[i]->islist){ + if(nmg->prcvars[i]->val.l){ + for(j = 0; nmg->prcvars[i]->val.l[j]; j++) + fs_give((void **)&nmg->prcvars[i]->val.l[j]); + fs_give((void **)&nmg->prcvars[i]->val.l); + } + } + else { + if(nmg->prcvars[i]->val.p) + fs_give((void **)&nmg->prcvars[i]->val.p); + } + fs_give((void **)&nmg->prcvars[i]); + } + for(ts = nmg->sessionlist; ts;){ + if(ts->open_stream) + ts->open_stream = mail_close_full(ts->open_stream, NIL); + ts = free_sessionlist_node(ts); + } + if(nmg->debugFile) + fs_give((void **)&nmg->debugFile); + if(nmg->debug && nmg->dfd) + fclose(nmg->dfd); + nmg->debug = FALSE; + fs_give((void **)&nmg); +} + +MAILSTREAM *first_open(sessionlist_s *cs) +{ + mapi_global_s *nmg = ms_global; + /* cs->mhwnd = (HWND)ulUIParam; + * if(flFlags & MAPI_LOGON_UI) + * cs->flags.mapi_logon_ui = TRUE; + */ + /* if someone is logging in right now, return failure */ + if(nmg->cs) return NULL; + if(MSDEBUG) + fprintf(nmg->dfd, "Opening mailbox for the first time\r\n"); + if(nmg->prcvars[INBOX_PATH]->val.p == NULL){ + ErrorBox("No value set for %s!", "inbox"); + return NULL; + } + cs->open_stream = mapi_mail_open(cs, cs->open_stream, nmg->prcvars[INBOX_PATH]->val.p, + nmg->debug ? OP_DEBUG : NIL); + /* cs->flags.mapi_logon_ui = FALSE; */ + if(cs->open_stream){ + if(cs->currently_open){ + fs_give((void **)&cs->currently_open); + cs->currently_open = NULL; + } + cs->currently_open = mstrdup(nmg->prcvars[INBOX_PATH]->val.p); + if(nmg->debug) + mail_debug(cs->open_stream); + if(MSDEBUG){ + fprintf(nmg->dfd, "returning SUCCESS_SUCCESS\r\n"); + _flushall(); + } + return cs->open_stream; + } + else if(cs->flags.dlg_cancel){ + if(MSDEBUG){ + fprintf(nmg->dfd, "returning MAPI_E_FAILURE\r\n"); + _flushall(); + } + return NULL; + } + else{ + cs->dlge.edit1[0] = '\0'; + cs->dlge.edit2[0] = '\0'; + if(cs->currently_open){ + fs_give((void **)&cs->currently_open); + cs->currently_open = NULL; + } + if(MSDEBUG){ + fprintf(nmg->dfd, "returning MAPI_E_FAILURE\r\n"); + _flushall(); + } + return NULL; + } +} + +SENDSTREAM * +mapi_smtp_open(sessionlist_s *cs, char **servers, long options) +{ + mapi_global_s *nmg = ms_global; + SENDSTREAM *newstream; + pw_cache_s *tpwc, *dpwc; + + nmg->cs = cs; + nmg->tmpmbxptr = NULL; + nmg->cs->flags.dlg_cancel = 0; + newstream = smtp_open(servers, options); + nmg->cs = NULL; + nmg->tmpmbxptr = NULL; + + if(newstream){ /* if open stream, valid password */ + for(tpwc = cs->pwc; tpwc; tpwc = tpwc->next) + tpwc->validpw = 1; + } + else{ + for(tpwc = cs->pwc, dpwc = NULL; tpwc; dpwc = tpwc, tpwc = tpwc->next){ + if(tpwc->validpw == 0){ + if(tpwc == cs->pwc) + cs->pwc = tpwc->next; + else + dpwc->next = tpwc->next; + fs_give((void **)&tpwc); + } + } + } + return(newstream); +} + +MAILSTREAM * +mapi_mail_open(sessionlist_s *cs, MAILSTREAM *stream, char *name, long options) +{ + MAILSTREAM *newstream; + mapi_global_s *nmg = ms_global; + pw_cache_s *tpwc, *dpwc; + + nmg->cs = cs; + nmg->tmpmbxptr = name; + nmg->cs->flags.dlg_cancel = 0; + newstream = mail_open(stream, name, options); + nmg->tmpmbxptr = NULL; + nmg->cs = NULL; + + if(newstream){ /* if open stream, valid password */ + for(tpwc = cs->pwc; tpwc; tpwc = tpwc->next) + tpwc->validpw = 1; + } + else{ + tpwc = cs->pwc; + while(tpwc){ + if(tpwc->validpw == 0){ + dpwc = tpwc; + tpwc = tpwc->next; + if(dpwc == cs->pwc) + cs->pwc = dpwc->next; + fs_give((void **)&dpwc); + } + else + tpwc = tpwc->next; + } + } + + return (newstream); +} + + +MAILSTREAM *check_mailstream(sessionlist_s *cs) +{ + mapi_global_s *nmg; + + nmg = ms_global; + + if(!cs->open_stream){ + return(first_open(cs)); + } + cs->flags.check_stream = TRUE; + if(!mail_ping(cs->open_stream)){ + if(nmg->cs) return NULL; + cs->open_stream = mapi_mail_open(cs, cs->open_stream, + cs->currently_open ? cs->currently_open : + nmg->prcvars[INBOX_PATH]->val.p, + nmg->debug ? OP_DEBUG : NIL); + if(!cs->open_stream){ + fs_give((void **)&cs->currently_open); + cs->currently_open = NULL; + cs->dlge.edit1[0] = '\0'; + cs->dlge.edit2[0] = '\0'; + cs->flags.check_stream = FALSE; + return NULL; + } + } + cs->flags.check_stream = FALSE; + return cs->open_stream; +} + +/* pretty much changes a string to an integer, + * but if it is not a valid message number, then 0 is returned + */ +unsigned long convert_to_msgno(char *msgid) +{ + unsigned long place_holder = 1, msgno = 0; + int i, len; + + len = strlen(msgid); + for(i = 0; i < len; i++){ + if(msgid[len-1-i] - '0' < 0 || msgid[len-1-i] - '0' > 9) + return 0; + msgno += (msgid[len - 1 - i] - '0')*place_holder; + place_holder *= 10; + } + + return msgno; +} + +/* + * Lookup file's mimetype by its file extension + * fn - filename + * body - body in which to store new type, subtype + * + * A mime type is ALWAYS set + * + * Returns 0 if the file extension was found and mimetype was set accordingly + * 1 if otherwise + */ +int lookup_file_mime_type(char *fn, BODY *body) +{ + char *p, subkey[1024], val[1024]; + DWORD dtype, vallen = 1024; + HKEY hKey; + int i, rv = 0; + + if(body->subtype) + fs_give((void **)&body->subtype); + if((p = strrchr(fn, '.')) && p[1]){ + sprintf(subkey, "%.1020s", p); + if(RegOpenKeyEx(HKEY_CLASSES_ROOT, subkey, 0, KEY_READ, &hKey) == ERROR_SUCCESS){ + if(RegQueryValueEx(hKey, "Content Type", NULL, &dtype, val, &vallen) == ERROR_SUCCESS){ + RegCloseKey(hKey); + if((p = strrchr(val, '/')) && p[1]){ + *(p++) = '\0'; + body->subtype = mstrdup(p); + for(i=0; (i <= TYPEMAX) && body_types[i] && _stricmp(val, body_types[i]); i++); + if(i > TYPEMAX) + i = TYPEOTHER; + else if(!body_types[i]) + body_types[i] = mstrdup(val); + body->type = i; + return 0; + } + } + } + } + body->type = TYPEAPPLICATION; + body->subtype = "octet-stream"; + return 1; +} + +int LookupMIMEFileExt(char *val, char *mime_type, DWORD *vallen) +{ + HKEY hKey; + DWORD dtype; + LONG rv = !ERROR_SUCCESS; + char subkey[1024]; + + sprintf(subkey, "MIME\\Database\\Content Type\\%s", mime_type); + if(RegOpenKeyEx(HKEY_CLASSES_ROOT, subkey, 0, KEY_READ, &hKey) == ERROR_SUCCESS){ + rv = RegQueryValueEx(hKey,"extension",NULL, &dtype, val, vallen); + RegCloseKey(hKey); + } + + return(rv); +} + +/* + * xlate_out() - xlate_out the given character + */ +char +xlate_out(c) + char c; +{ + register int dti; + register int xch; + + if((c >= FIRSTCH) && (c <= LASTCH)){ + xch = c - (dti = xlate_key); + xch += (xch < FIRSTCH-TABSZ) ? 2*TABSZ : (xch < FIRSTCH) ? TABSZ : 0; + dti = (xch - FIRSTCH) + dti; + dti -= (dti >= 2*TABSZ) ? 2*TABSZ : (dti >= TABSZ) ? TABSZ : 0; + xlate_key = dti; + return(xch); + } + else + return(c); +} + +/* return TRUE if the pwd is found, FALSE if not */ +int in_passfile(sessionlist_s *cs) +{ + mapi_global_s *nmg; + char *tf, *tp, *ui[4], tmp[1024], *dir; + int i, j, n; + FILE *tfd; + + nmg = ms_global; + + if(*nmg->pinerc == '{') + dir = nmg->pineExe; + else + dir = nmg->pinerc; + + /* if(nmg->flags.passfile_checked) return FALSE; */ + if(!(tf = (char *)fs_get(sizeof(char)*(strlen(dir) + strlen("pine.pwd") + 1)))){ + /* nmg->flags.passfile_checked = TRUE; */ + return FALSE; + } + strcpy(tf,dir); + if(tp = strrchr(tf, '\\')){ + tp++; + strcpy(tp, "pine.pwd"); + } + else /* don't know when this will ever happen */ + strcpy(tf, "pine.pwd"); + if(_access(tf, 00) == 0){ + if(MSDEBUG) + fprintf(nmg->dfd,"found %s for passwords\r\n", tf); + if(!(tfd = fopen(tf,"r"))){ + fs_give((void **)&tf); + /* nmg->flags.passfile_checked = TRUE; */ + return FALSE; + } + else{ + for(n = 0; fgets(tmp, 1024, tfd); n++){ + /*** do any necessary DEcryption here ***/ + xlate_key = n; + for(i = 0; tmp[i]; i++) + tmp[i] = xlate_out(tmp[i]); + + if(i && tmp[i-1] == '\n') + tmp[i-1] = '\0'; /* blast '\n' */ + + ui[0] = ui[1] = ui[2] = ui[3] = NULL; + for(i = 0, j = 0; tmp[i] && j < 4; j++){ + for(ui[j] = &tmp[i]; tmp[i] && tmp[i] != '\t'; i++) + ; + + if(tmp[i]) + tmp[i++] = '\0'; + } + + if(ui[0] && ui[1] && ui[2]){ + if(strcmp(ui[2], cs->mb->host) == 0){ + if((cs->mb->altflag && ui[3] && *ui[3] == '1') + || (!cs->mb->altflag && (!ui[3] || (*ui[3] == '0')))){ + if(strcmp(ui[1], *cs->mb->user ? cs->mb->user + : nmg->prcvars[USER_ID]->val.p) == 0){ + /* winner */ + strcpy(cs->dlge.edit1, *cs->mb->user ? cs->mb->user + : nmg->prcvars[USER_ID]->val.p); + strcpy(cs->dlge.edit2, ui[0]); + fclose(tfd); + fs_give((void **)&tf); + /* nmg->flags.passfile_checked = TRUE; */ + return TRUE; + } + } + } + } + } + fclose(tfd); + fs_give((void **)&tf); + } + } + else{ + fs_give((void **)&tf); + /* nmg->flags.passfile_checked = TRUE; */ + return FALSE; + } + /* nmg->flags.passfile_checked = TRUE; */ + return FALSE; +} + +int get_suggested_directory(char *dir) +{ + char *tmpdir; + + if(tmpdir = getenv("TEMP")){ + strcpy(dir, tmpdir); + return TRUE; + } + else if(tmpdir = getenv("TMP")){ + strcpy(dir, tmpdir); + return TRUE; + } + else if(ms_global && ms_global->attachDir){ + strcpy(dir, ms_global->attachDir); + return TRUE; + } + else{ /* should NEVER get here */ + strcpy(dir, "C:\\"); + return TRUE; + } + return FALSE; +} + + +/* return TRUE if file_ext is modified, FALSE if not */ +int get_suggested_file_ext(char *file_ext, PART *part, DWORD *file_extlen) +{ + char mime_type[1024], *tmp_ext; + int rv = !ERROR_SUCCESS; + PARAMETER *param; + + if(part->body.subtype){ + sprintf(mime_type, "%s/%s", body_types[part->body.type], part->body.subtype); + rv = LookupMIMEFileExt(file_ext, mime_type, file_extlen); + } + if(rv == ERROR_SUCCESS) + return TRUE; + else{ + param = part->body.parameter; + while(param && (_stricmp("NAME", param->attribute))) + param = param->next; + if(!param){ + if(part->body.type == TYPEMESSAGE){ + /* don't try to recurse through attached messages yet */ + strcpy(file_ext, ".txt"); + return TRUE; + } + } + tmp_ext = strrchr(param->value, (int)'.'); + if(!tmp_ext) return FALSE; + strcpy(file_ext, tmp_ext); + } + return TRUE; +} + +/* return -1 for failure */ +int InitDebug() +{ + char path[1024]; + + if(!ms_global){ + if((ms_global = new_mapi_global()) == NULL) return -1; + } + /* + * if debug file exists, turn on debugging mode + */ + if(ms_global->debug == 1) /* debug file already initialized, somehow */ + return 1; + get_suggested_directory(path); + if(path[strlen(path-1)] != '\\') + strcat(path, "\\"); + strcat(path, "mapi_debug.txt"); + if(_access(path, 00) == 0){ + ms_global->debug = 1; + } + else{ + get_suggested_directory(path); + if(path[strlen(path-1)] != '\\') + strcat(path, "\\"); + strcat(path, "mapisend"); + if(_access(path, 00) == 0){ + ms_global->debug = 1; + } + } + + if(ms_global->debug){ + ms_global->dfd = fopen(path, "wb"); + if(!ms_global->dfd){ + ErrorBox("MAPISendMail: debug off: can't open debug file %.200s", + path); + ms_global->debug = 0; /* can't open the file, turn off debugging */ + } + else if(ms_global->debug == 1){ + ms_global->debugFile = (char *)fs_get((1+strlen(path))*sizeof(char)); + strcpy(ms_global->debugFile, path); + } + } + + if(ms_global->debug && (ms_global->dfd == NULL)) + ms_global->debug = 0; + + return ms_global->debug; +} + +int GetPineData() +{ + HKEY pineKey; + BYTE pineKeyData[1024]; + DWORD pineKeyDataSize; + DWORD pineKeyDataType; + char *defPath = "c:\\pine\\pine.exe"; + char *pineExe = strrchr(defPath, '\\')+1; + char *freepineExe = NULL; + char *defAttachDir = "c:\\tmp"; + char *penv = NULL; + + /* + * get name of and path to pine.exe from registry + */ + if (RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + "SOFTWARE\\University of Washington\\Alpine\\1.0", + 0, + KEY_QUERY_VALUE, + &pineKey) == ERROR_SUCCESS) { + pineKeyDataSize = sizeof(pineKeyData); + if (RegQueryValueEx( + pineKey, + "PineEXE", + 0, + &pineKeyDataType, + pineKeyData, + &pineKeyDataSize) == ERROR_SUCCESS) { + freepineExe = (char *)fs_get((pineKeyDataSize + 1) * sizeof(char)); + if ((pineExe = freepineExe) != NULL) { + strcpy(pineExe, pineKeyData); + } + else { + ErrorBox("MAPISendMail: can't fs_get %d bytes for pineExe", + pineKeyDataSize); + return 0; + } + if (MSDEBUG) { + fprintf(ms_global->dfd,"pine.exe pineKeyDataSize: %d\r\n", pineKeyDataSize); + fprintf(ms_global->dfd,"pine.exe pineKeyData: %s\r\n", pineKeyData); + } + } + pineKeyDataSize = sizeof(pineKeyData); + if (RegQueryValueEx( + pineKey, + "pinedir", + 0, + &pineKeyDataType, + pineKeyData, + &pineKeyDataSize) == ERROR_SUCCESS) { + ms_global->pineExe = (char *)fs_get(sizeof(char)*(pineKeyDataSize+strlen(pineExe))); + if (ms_global->pineExe) { + strncpy(ms_global->pineExe, pineKeyData, pineKeyDataSize); + strcat(ms_global->pineExe, pineExe); + } + else { + ErrorBox("MAPISendMail: can't fs_get %d bytes for av[0]", + pineKeyDataSize); + return 0; + } + if (MSDEBUG) { + fprintf(ms_global->dfd,"pine.exe pineKeyDataSize: %d\r\n", pineKeyDataSize); + fprintf(ms_global->dfd,"pine.exe pineKeyData: %s\r\n", pineKeyData); + } + } + RegCloseKey(pineKey); + } + if(!ms_global->pineExe){ + ms_global->pineExe = (char *)fs_get((1+strlen(defPath))*sizeof(char)); + if(!ms_global->pineExe){ + ErrorBox("Couldn't fs_get for %s","pineExe"); + return 0; + } + else + strcpy(ms_global->pineExe, defPath); + } + + if(freepineExe) + ms_global->pineExeAlt = freepineExe; + else{ + ms_global->pineExeAlt = (char *)fs_get((strlen(strrchr(defPath, '\\')+1)+1)*sizeof(char)); + if(!ms_global->pineExeAlt){ + ErrorBox("Couldn't fs_get for %s","pineExeAlt"); + return 0; + } + else + strcpy(ms_global->pineExeAlt, strrchr(defPath, '\\')+1); + } + + /* + * get path to pinerc from registry + */ + if (RegOpenKeyEx( + HKEY_CURRENT_USER, + "Software\\University of Washington\\Alpine\\1.0", + 0, + KEY_QUERY_VALUE, + &pineKey) == ERROR_SUCCESS) { + pineKeyDataSize = sizeof(pineKeyData); + if( RegQueryValueEx( + pineKey, + "PineRC", + 0, + &pineKeyDataType, + pineKeyData, + &pineKeyDataSize) == ERROR_SUCCESS) { + if(*pineKeyData != '{' || ms_global->pineExe) + ms_global->attachDir = (char *)fs_get(sizeof(char)*(*pineKeyData == '{' ? + pineKeyDataSize + 1 : + strlen(ms_global->pineExe)+1)); + ms_global->pinerc = (char *)fs_get(pineKeyDataSize); + if(ms_global->attachDir){ + char *p; + if(*pineKeyData != '{'){ + strncpy(ms_global->attachDir, pineKeyData, pineKeyDataSize); + ms_global->attachDir[pineKeyDataSize] = '\0'; + } + else + strcpy(ms_global->attachDir, ms_global->pineExe); + p = strrchr(ms_global->attachDir, '\\'); + if (p) *p = '\0'; + } + if(ms_global->pinerc) + strncpy(ms_global->pinerc, pineKeyData, pineKeyDataSize); + else { + ErrorBox("MAPISendMail: can't fs_get %d bytes for pinercPath", + pineKeyDataSize); + return 0; + } + if (MSDEBUG) { + fprintf(ms_global->dfd, "pinerc pineKeyDataSize: %d\r\n", pineKeyDataSize); + fprintf(ms_global->dfd, "pinerc pineKeyData: %s\r\n", pineKeyData); + fprintf(ms_global->dfd, "attachDir: %s\r\n", + ms_global->attachDir ? ms_global->attachDir : + "NOT YET DEFINED"); + } + } + pineKeyDataSize = sizeof(pineKeyData); + if( RegQueryValueEx( + pineKey, + "PineConf", + 0, + &pineKeyDataType, + pineKeyData, + &pineKeyDataSize) == ERROR_SUCCESS){ + ms_global->pineconf = mstrdup(pineKeyData); + msprint1("ms_global->pineconf: %s (due to Registry setting)\r\n", ms_global->pineconf); + } + RegCloseKey(pineKey); + } + + if(ms_global->attachDir == NULL){ + if(ms_global->attachDir = (char *)fs_get((strlen(defAttachDir)+1)*sizeof(char))) + strcpy(ms_global->attachDir, defAttachDir); + else + ErrorBox("Can't find TEMP directory for %s!","attachments"); + } + + + if(penv = getenv("PINERC")){ + if(ms_global->pinerc) + fs_give((void **)&ms_global->pinerc); + if(ms_global->pinerc = (char *)fs_get((strlen(penv)+1)*sizeof(char))) + strcpy(ms_global->pinerc, penv); + else + ErrorBox("Couldn't fs_get for %s", "pinerc"); + } + if(penv = getenv("PINECONF")){ + if(ms_global->pineconf) + fs_give((void **)&ms_global->pineconf); + if(ms_global->pineconf = (char *)fs_get((strlen(penv)+1)*sizeof(char))) + strcpy(ms_global->pineconf, penv); + else + ErrorBox("Couldn't fs_get for %s", "pineconf"); + } + else{ + + } + if(penv = getenv("PINERCEX")){ + if(ms_global->pinercex) + fs_give((void **)&ms_global->pinercex); + if(ms_global->pinercex = mstrdup(penv)) + strcpy(ms_global->pinercex, penv); + else + ErrorBox("Couldn't fs_get for %s", "pinercex"); + } + if(MSDEBUG){ + fprintf(ms_global->dfd,"ms_global->pineExe: %s\r\n", + (ms_global->pineExe) ? ms_global->pineExe : "NULL"); + fprintf(ms_global->dfd,"ms_global->pineExeAlt: %s\r\n", + ms_global->pineExeAlt ? ms_global->pineExeAlt : "NULL"); + fprintf(ms_global->dfd,"ms_global->attachDir: %s\r\n", + ms_global->attachDir ? ms_global->attachDir : "NULL"); + fprintf(ms_global->dfd,"ms_global->pinerc: %s\r\n", + ms_global->pinerc ? ms_global->pinerc : "NULL"); + fprintf(ms_global->dfd,"ms_global->pineconf: %s\r\n", + ms_global->pinerc ? ms_global->pineconf : "NULL"); + fprintf(ms_global->dfd,"ms_global->pinercex: %s\r\n", + ms_global->pinerc ? ms_global->pinercex : "NULL"); + } + return 1; +} + +BOOL APIENTRY DllMain( + HANDLE hInst, + DWORD ul_reason_being_called, + LPVOID lpReserved) +{ + switch(ul_reason_being_called){ + case DLL_THREAD_ATTACH: + /* if(ms_global) + * return 1; + */ + case DLL_PROCESS_ATTACH: + if(!ms_global) + ms_global = new_mapi_global(); + if(!ms_global) return 0; + ms_global->attached++; + ms_global->mhinst = hInst; + if(InitDebug() == -1){ + ErrorBox("Mapi32.dll could not %s", "initialize"); + return 0; + } + if(MSDEBUG && ms_global->attached <= 1){ + time_t now; + struct tm *tm_now; + extern char datestamp[], hoststamp[]; + + now = time((time_t *)0); + tm_now = localtime(&now); + fprintf(ms_global->dfd, "pmapi32.dll for Alpine Version 2.10r\n"); + fprintf(ms_global->dfd, " Build date: %s\r\n", datestamp); + fprintf(ms_global->dfd, + " please report all bugs to alpine-contact@u.washington.edu\r\n"); + if(tm_now) + fprintf(ms_global->dfd, + "Created: %2.2d:%2.2d:%2.2d %d/%d/%d\r\n", + tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec, + tm_now->tm_mon+1, tm_now->tm_mday, tm_now->tm_year+1900); + + fprintf(ms_global->dfd, "\r\n\r\n"); + } + DEBUG_WRITE("%s called. Debug initialized (in DllMain)\r\n", + ul_reason_being_called == DLL_PROCESS_ATTACH ? + "DLL_PROCESS_ATTACH":"DLL_THREAD_ATTACH"); + GetPineData(); +#include "../c-client-dll/linkage.c" + break; + case DLL_PROCESS_DETACH: + case DLL_THREAD_DETACH: + DEBUG_WRITE("\r\n%s called\r\n", + ul_reason_being_called == DLL_PROCESS_DETACH ? + "DLL_PROCESS_DETACH" : "DLL_THREAD_DETACH"); + ms_global->attached--; + /* if(ms_global->open_stream) + * ms_global->open_stream = mail_close_full(ms_global->open_stream, NIL); + */ + if(ms_global->attached <= 0 && + ul_reason_being_called == DLL_PROCESS_DETACH){ + if(MSDEBUG) + fprintf(ms_global->dfd, + "detaching last thread/process. freeing mapi global struct\r\n"); + free_mapi_global(ms_global); + } + break; + } + return 1; +} + +static char *V="\r\n@(#) Alpine Simple Mapi Library Ver. 1.3\r\n"; + +int +UnderlineSpace(char *s) +{ + char *p; + + if(p = strrchr(s, '\\')) + s = p++; + + for(; *s; s++) + if(*s == ' ') + *s = '_'; + return 1; +} + +/* + * Given source file name and destination directory, make a binary copy + * of the file and return the full name of the copy (mangled as necessary + * to avoid conflicts). The return value will be a fs_get'd string + */ +char * +TmpCopy(char *srcFile, int is_pinerc) +{ + char *dstName; /* constructed and fs_get'd full output pathname */ + char *srcTail; /* last component of source pathname */ + char *srcExt; /* extension, if any, of srcTail */ + char dstDir[1024]; + int i, cnt, c, len, spc = 0; + FILE *sfd, *dfd; + + if (!srcFile) { + ErrorBox("TmpCopy: srcFile is %s", "NULL"); + return NULL; + } + if(is_pinerc){ + len = strlen(srcFile); + for(i = 0; i < len; i++){ + if(srcFile[i] == ' ') spc = 1; + } + if(spc == 0) return mstrdup(srcFile); + } + + get_suggested_directory(dstDir); + if (!dstDir) { + ErrorBox("TmpCopy: dstDir is %s", "NULL"); + return NULL; + } + + dstName = (char *)fs_get(sizeof(char)*(strlen(srcFile) + 5 + + max(strlen(dstDir), strlen(PINERC_FILE)))); + + if (dstName == NULL) { + ErrorBox("TmpCopy: can't fs_get space %d bytes for dstName", + strlen(srcFile)+5+max(strlen(dstDir),strlen(PINERC_FILE))); + return NULL; + } + + if(!is_pinerc){ + srcTail = strrchr(srcFile, '\\'); + if (srcTail) + ++srcTail; + else + srcTail = srcFile; + + srcExt = strrchr(srcTail, '.'); + + sfd = fopen(srcFile, "rb"); + if (sfd == NULL) { + ErrorBox("TmpCopy: can't open %.200s for reading", srcFile); + fs_give((void **)&dstName); + return NULL; + } + + i = sprintf(dstName, "%s%s%s", dstDir, + dstDir[strlen(dstDir)-1] == '\\' ? "" : "\\", + srcTail); + UnderlineSpace(dstName); + for (cnt = 0; cnt < 1000; ++cnt) { + int handle = _open(dstName, _O_CREAT|_O_EXCL , _S_IREAD|_S_IWRITE); + if (handle != -1) { + if (_close(handle)) /* this shouldn't be able to happen */ + ErrorBox("TmpCopy: _close of new %.200s failed", dstName); + dfd = fopen(dstName, "wb"); + if (dfd) break; + } + if (srcExt) + sprintf(dstName+i-strlen(srcExt), "%03d%s", cnt, srcExt); + else + sprintf(dstName+i, "%03d", cnt); + } + if (dfd == NULL) { + ErrorBox("TmpCopy: can't create anything like %.200s", dstName); + fclose(sfd); + fs_give((void **)&dstName); + return NULL; + } + } + else{ /* is_pinerc */ + i = sprintf(dstName, "%s%s%s", dstDir, + dstDir[strlen(dstDir)-1] == '\\' ? "" : "\\", + PINERC_FILE); + dfd = fopen(dstName, "wb"); + if(!dfd){ + ErrorBox("Couldn't create temp %s for pine", "pinerc"); + fs_give((void **)&dstName); + return NULL; + } + sfd = fopen(srcFile, "rb"); + if (sfd == NULL) { + ErrorBox("TmpCopy: can't open %.200s for reading", srcFile); + fclose(dfd); + fs_give((void **)&dstName); + return NULL; + } + } + c = fgetc(sfd); + while(feof(sfd) == 0) { + putc(c, dfd); + c = fgetc(sfd); + } + if (ferror(dfd)) { + ErrorBox("TmpCopy: write error on %.200s", dstName); + fs_give((void **)&dstName); + fclose(dfd); + return NULL; + } + if (ferror(sfd)) { + ErrorBox("TmpCopy: read error on %.200s", srcFile); + fs_give((void **)&dstName); + fclose(sfd); + return NULL; + } + if (fclose(sfd)) { + ErrorBox("TmpCopy: fclose error on %.200s", srcFile); + } + if (fclose(dfd)) { + ErrorBox("TmpCopy: fclose error on %.200s", dstName); + } + + return dstName; +} + +int send_documents(char *files, char sep) +{ + int ac, i, tmplen, j; + char **av, *tmpfiles, *file, *tmpfree; + mapi_global_s *nmg; + + nmg = ms_global; + ac = 3; + tmplen = strlen(files); + tmpfiles = (char *)fs_get(sizeof(char)*(tmplen + 1)); + strcpy(tmpfiles,files); + for(i = 0; i <= tmplen; i++){ + if(files[i] == sep || files[i] == '\0') + ac += 2; + } + ac += 2; /* just for safe measure */ + av = (char **)fs_get(ac * sizeof(char *)); + if(nmg->pinerc){ + av[1] = mstrdup("-p"); + /* copy pinerc to temp directory just in case it too + * has spaces in its directory + */ + if(tmpfree = TmpCopy(nmg->pinerc, IS_PINERC)){ + av[2] = quote(tmpfree); + fs_give((void **)&tmpfree); + } + else + av[2] = quote(nmg->pinerc); + } + for(i = 0, j = 3, file = tmpfiles; i <= tmplen; i++){ + if(tmpfiles[i] == sep || i == tmplen){ + tmpfiles[i] = '\0'; + if(i - (file - tmpfiles) > 1){ + tmpfree = TmpCopy(file, NOT_PINERC); + if(tmpfree){ + av[j++] = mstrdup("-attach_and_delete"); + av[j++] = quote(tmpfree); + fs_give((void **)&tmpfree); + } + } + } + } + av[j] = NULL; + av[0] = quote(nmg->pineExe); + if(MSDEBUG){ + fprintf(ms_global->dfd, "spawning %s (else %s):\r\n", + ms_global->pineExe, ms_global->pineExeAlt); + fprintf(nmg->dfd, " av:\r\n"); + for(i = 0; av[i]; i++) + fprintf(nmg->dfd, " av[%d]: %s\r\n", i, av[i]); + } + + /* clean up quote()'s */ + if (_spawnvp(_P_NOWAIT, ms_global->pineExe, av) == -1 && + _spawnvp(_P_NOWAIT, ms_global->pineExeAlt, av) == -1){ + ErrorBox("MAPISendMail: _spawnvp of %s failed", ms_global->pineExe); + if(MSDEBUG) + fprintf(ms_global->dfd, "_spawnvp %s and %s failed\r\n", + ms_global->pineExe,ms_global->pineExeAlt); + return(MAPI_E_FAILURE); + } + for(i = 0; av[i]; i++) + fs_give((void **)&av[i]); + fs_give((void **)&av); + return SUCCESS_SUCCESS; +} + +char * +message_structure_to_mailto_url(lpMapiMessage lpm) +{ + char **keyvals, **keyvalp, *url; + int keyvallen; + unsigned long i, url_len = 0; + + if(lpm == NULL) + return NULL; + + keyvallen = lpm->nRecipCount + 4; /* subject + body + from + recips + NULL */ + keyvals = (char **)fs_get(keyvallen * sizeof(char *)); + keyvalp = keyvals; + + for(i = 0; i < lpm->nRecipCount; i++) + *keyvalp++ = encode_mailto_addr_keyval(&lpm->lpRecips[i]); + if(lpm->lpszSubject) + *keyvalp++ = encode_mailto_keyval("subject", lpm->lpszSubject); + if(lpm->lpOriginator) + *keyvalp++ = encode_mailto_addr_keyval(lpm->lpOriginator); + if(lpm->lpszNoteText) + *keyvalp++ = encode_mailto_keyval("body", lpm->lpszNoteText); + *keyvalp = NULL; + + if(*keyvals == NULL){ + fs_give((void **)&keyvals); + return(NULL); + } + + url_len = keyvallen + 10; /* mailto url extra chars */ + for(keyvalp = keyvals; *keyvalp; keyvalp++) + url_len += strlen(*keyvalp); + + url = (char *)fs_get(url_len * sizeof(char)); + sprintf(url, "mailto:?"); + for(keyvalp = keyvals; *keyvalp; keyvalp++){ + strcat(url, *keyvalp); + if(*(keyvalp+1)) + strcat(url, "&"); + fs_give((void **)&(*keyvalp)); + } + fs_give((void **)&keyvals); + return url; +} + +char * +encode_mailto_addr_keyval(lpMapiRecipDesc lpmr) +{ + ADDRESS *adr = NULL; + char *addr, *retstr; + int use_quotes = 0; + + adr = mapirecip2address(lpmr); + addr = (char *)fs_get((size_t)est_size(adr)); + addr[0] = '\0'; + rfc822_write_address(addr, adr); + mail_free_address(&adr); + + retstr = encode_mailto_keyval(lpmr->ulRecipClass == MAPI_CC ? "cc" + : (lpmr->ulRecipClass == MAPI_BCC ? "bcc" + : (lpmr->ulRecipClass == MAPI_ORIG ? "from" + : "to")), + addr); + fs_give((void **)&addr); + return(retstr); +} + + + +/* + * Hex conversion aids from alpine.h + */ +#define HEX_ARRAY "0123456789ABCDEF" +#define HEX_CHAR1(C) HEX_ARRAY[((C) & 0xf0) >> 4] +#define HEX_CHAR2(C) HEX_ARRAY[(C) & 0xf] + +/* strings.c macros */ +#define C2XPAIR(C, S) { \ + *(S)++ = HEX_CHAR1(C); \ + *(S)++ = HEX_CHAR2(C); \ + } + +#define RFC1738_SAFE "$-_.+" /* "safe" */ +#define RFC1738_EXTRA "!*'()," /* "extra" */ + +/* adapted from rfc1738_encode_mailto */ +char * +encode_mailto_keyval(char *key, char* val) +{ + char *d, *ret = NULL, *v = val; + + if(key && val){ + ret = (char *)fs_get(sizeof(char) * (strlen(key) + (3*strlen(val)) + 2)); + strcpy(ret, key); + d = ret + strlen(key); + *d++ = '='; + while(*v){ + if(isalnum((unsigned char)*v) + || strchr(RFC1738_SAFE, *v) + || strchr(RFC1738_EXTRA, *v)) + *d++ = *v++; + else{ + *d++ = '%'; + C2XPAIR(*v, d); + v++; + } + } + *d = '\0'; + } + + return(ret); +} + +unsigned long +send_msg_nodlg(LHANDLE lhSession, ULONG ulUIParam, lpMapiMessage lpMessage, + FLAGS flFlags, ULONG ulReserved) +{ + sessionlist_s *cs; + int tsession = 0, orig_in_recip = 0; + unsigned long i, orig_index; + ADDRESS *tadr = NULL, *tadr2 = NULL; + ENVELOPE *env = NULL; + BODY *body = NULL; + mapi_global_s *nmg = ms_global; + SENDSTREAM *sending_stream = NULL; + unsigned long rv; + time_t now; + struct tm *tm_now; + char *p = NULL; + + if(nmg->pmapi_send_behavior == PMSB_NEVER_SEND) + return MAPI_E_USER_ABORT; + else if(nmg->pmapi_send_behavior == PMSB_ALWAYS_PROMPT){ + if(MessageBox(NULL, "Really Send Message?", "pmapi32.dll", MB_YESNO|MB_ICONQUESTION) == IDNO) + return MAPI_E_USER_ABORT; + } + if((flFlags & MAPI_NEW_SESSION) || lhSession == 0){ + cs = new_sessionlist(); + tsession = 1; + } + else{ + cs = get_session(lhSession); + if(!cs) + return MAPI_E_INVALID_SESSION; + } + cs->flags.mapi_logon_ui = (flFlags & MAPI_LOGON_UI) || (flFlags & MAPI_DIALOG) ? 1 : 0; + if(InitPineSpecific(cs) == -1){ + rv = MAPI_E_LOGIN_FAILURE; + goto smn_cleanup; + } + msprint("Preparing to Send Message with no dialogs...\r\n"); + /* Make an envelope */ + env = (ENVELOPE *)fs_get(sizeof(ENVELOPE)); + memset(env, 0, sizeof(ENVELOPE)); + if(lpMessage->lpszSubject){ + p = rfc1522_encode(tmp_20k_buf, SIZEOF_20KBUF, lpMessage->lpszSubject, + nmg->prcvars[CHARACTER_SET]->val.p); + env->subject = mstrdup(p); + if(MSDEBUG) + fprintf(ms_global->dfd, " Subject: %s\r\n", env->subject); + } + /* + * Since it is "DateReceived", I think the right thing to do is ignore it, + * since we're sending, not receiving. + */ + rfc822_date(tmp_20k_buf); + env->date = mstrdup(tmp_20k_buf); + msprint1(" Date: %s\r\n", env->date); + env->message_id = pmapi_generate_message_id(); + msprint1(" Message-Id: %s\r\n", env->message_id); + + for(i = 0; i < lpMessage->nRecipCount; i++){ + if((&lpMessage->lpRecips[i])->ulRecipClass == MAPI_ORIG){ + orig_in_recip = 1; + orig_index = i; + } + } + + if(lpMessage->lpOriginator || orig_in_recip){ + if((env->from = mapirecip2address(lpMessage->lpOriginator + ? lpMessage->lpOriginator + : (&lpMessage->lpRecips[orig_index]))) + == NULL){ + rv = MAPI_E_INVALID_RECIPS; + goto smn_cleanup; + } + if(MSDEBUG){ + sprintf(tmp_20k_buf, "%.100s <%.100s@%.100s>", env->from->personal ? env->from->personal + : "", env->from->mailbox ? env->from->mailbox : "", + env->from->host ? env->from->host : ""); + msprint1("From: %s\r\n", tmp_20k_buf); + } + } + else if(nmg->prcvars[USER_ID]->val.p && nmg->prcvars[USER_DOMAIN]->val.p){ + /* + * judgment call: I guess we'll try to generate the from header if it's not + * given to us + */ + env->from = mail_newaddr(); + if(nmg->prcvars[PERSONAL_NAME]->val.p){ + p = rfc1522_encode(tmp_20k_buf, SIZEOF_20KBUF, nmg->prcvars[PERSONAL_NAME]->val.p, + nmg->prcvars[CHARACTER_SET]->val.p); + env->from->personal = mstrdup(p); + } + env->from->mailbox = mstrdup(nmg->prcvars[USER_ID]->val.p); + env->from->host = mstrdup(nmg->prcvars[USER_DOMAIN]->val.p); + if(MSDEBUG){ + sprintf(tmp_20k_buf, "%.100s <%.100s@%.100s>", env->from->personal ? env->from->personal + : "", env->from->mailbox ? env->from->mailbox : "", + env->from->host ? env->from->host : ""); + msprint1("From: %s\r\n", tmp_20k_buf); + } + } + for(i = 0; i < lpMessage->nRecipCount; i++){ + if((tadr = mapirecip2address(&lpMessage->lpRecips[i])) == NULL){ + rv = MAPI_E_INVALID_RECIPS; + goto smn_cleanup; + } + switch (lpMessage->lpRecips[i].ulRecipClass) { + case MAPI_TO: + case MAPI_ORIG: + if(!env->to) + env->to = tadr; + else{ + for(tadr2 = env->to; tadr2->next; tadr2 = tadr2->next); + tadr2->next = tadr; + } + msprint(" To: "); + break; + case MAPI_CC: + if(!env->cc) + env->cc = tadr; + else{ + for(tadr2 = env->cc; tadr2->next; tadr2 = tadr2->next); + tadr2->next = tadr; + } + msprint(" Cc: "); + break; + case MAPI_BCC: + if(!env->bcc) + env->bcc = tadr; + else{ + for(tadr2 = env->bcc; tadr2->next; tadr2 = tadr2->next); + tadr2->next = tadr; + } + msprint(" Bcc: "); + break; + default: + rv = MAPI_E_INVALID_RECIPS; + goto smn_cleanup; + break; + } + if(MSDEBUG){ + sprintf(tmp_20k_buf, "%.100s <%.100s@%.100s>", tadr->personal ? tadr->personal + : "", tadr->mailbox ? tadr->mailbox : "", + tadr->host ? tadr->host : ""); + msprint1("%s\r\n", tmp_20k_buf); + } + } + /* Now we have an envelope, let's make us a body */ + if(lpMessage->lpszNoteText == NULL) + msprint("Empty Message Text\r\n"); + body = mail_newbody(); + if(lpMessage->nFileCount){ + PART *p; + struct _stat sbuf; + unsigned long fsize, n; + FILE *sfd; + char c, *fn; + + msprint1("Number of files to be Attached: %d\r\n", (void *)lpMessage->nFileCount); + body->type = TYPEMULTIPART; + body->nested.part = mail_newbody_part(); + p = body->nested.part; + set_text_data(&p->body, lpMessage->lpszNoteText ? lpMessage->lpszNoteText + : ""); + + for(i = 0; i < lpMessage->nFileCount; i++){ + p->next = mail_newbody_part(); + p = p->next; + p->body.encoding = ENCBINARY; + if(lpMessage->lpFiles[i].lpszPathName == NULL) + return(MAPI_E_FAILURE); + if(lpMessage->lpFiles[i].lpszFileName == NULL + || lpMessage->lpFiles[i].lpszFileName[0] == '\0'){ + fn = strrchr(lpMessage->lpFiles[i].lpszPathName, '\\'); + if(!fn) + fn = lpMessage->lpFiles[i].lpszPathName; + else + fn++; + } + else + fn = lpMessage->lpFiles[i].lpszFileName; + if(lookup_file_mime_type(fn, &p->body) && (fn == lpMessage->lpFiles[i].lpszFileName)) + lookup_file_mime_type(lpMessage->lpFiles[i].lpszPathName, &p->body); + msprint1(" Attaching file %s;", lpMessage->lpFiles[i].lpszPathName); + if(_stat(lpMessage->lpFiles[i].lpszPathName, &sbuf)) + return(MAPI_E_FAILURE); + fsize = sbuf.st_size; + if((sfd = fopen(lpMessage->lpFiles[i].lpszPathName, "rb")) == NULL) + return(MAPI_E_FAILURE); + p->body.contents.text.data = fs_get((fsize+1)*sizeof(char)); + n = 0; + c = fgetc(sfd); + while(feof(sfd) == 0){ + p->body.contents.text.data[n++] = c; + if(n > fsize){ + fsize += 20000; + fs_resize((void **)&p->body.contents.text.data, (fsize+1)*sizeof(char)); + } + c = fgetc(sfd); + } + fclose(sfd); + p->body.contents.text.data[n] = '\0'; + p->body.contents.text.size = n; + msprint1(" File size: %d\r\n", (void *)n); + if(fn){ + p->body.parameter = mail_newbody_parameter(); + p->body.parameter->attribute = mstrdup("name"); + p->body.parameter->value = mstrdup(fn); + + p->body.disposition.type = mstrdup("attachment"); + p->body.disposition.parameter = mail_newbody_parameter(); + p->body.disposition.parameter->attribute = mstrdup("filename"); + p->body.disposition.parameter->value = mstrdup(fn); + } + } + } + else { + set_text_data(body, lpMessage->lpszNoteText ? lpMessage->lpszNoteText + : ""); + msprint1(" Message Body size: %d\r\n", (void *)body->contents.text.size); + } + + if(MSDEBUG){ + now = time((time_t *)0); + tm_now = localtime(&now); + fprintf(ms_global->dfd, "%2.2d:%2.2d:%2.2d %d/%d/%d ", + tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec, + tm_now->tm_mon+1, tm_now->tm_mday, tm_now->tm_year+1900); + } + if(nmg->prcvars[SMTP_SERVER]->val.l && nmg->prcvars[SMTP_SERVER]->val.l[0] + && nmg->prcvars[SMTP_SERVER]->val.l[0][0]){ + if(MSDEBUG){ + fprintf(ms_global->dfd, "Preparing to open SMTP connection (%s ...)\r\n", + nmg->prcvars[SMTP_SERVER]->val.l[0]); + _flushall(); + } + sending_stream = mapi_smtp_open(cs, nmg->prcvars[SMTP_SERVER]->val.l, + nmg->prcfeats[ENABLE8BIT]->is_set ? SOP_8BITMIME : NIL); + } + else { + rv = MAPI_E_FAILURE; + if(MSDEBUG){ + fprintf(ms_global->dfd, "Error! No SMTP server defined!\r\n"); + } + goto smn_cleanup; + } + if(!sending_stream){ + rv = MAPI_E_FAILURE; + if(MSDEBUG){ + fprintf(ms_global->dfd, "Couldn't open SMTP connection!\r\n"); + } + goto smn_cleanup; + } + if(!smtp_mail(sending_stream, "MAIL", env, body)){ + if(MSDEBUG){ + fprintf(ms_global->dfd, "Attempt to Send Failed\r\n"); + } + rv = MAPI_E_FAILURE; + } + else { + if(MSDEBUG){ + fprintf(ms_global->dfd, "Message SENT!\r\n"); + } + if(!nmg->fccfolder) + msprint("No fcc defined\r\n"); + else { /* Now try to write to fcc */ + STRBUFFER_S *sb; + MAILSTREAM *fccstream; + STRING msg; + + msprint1("FCCing to %s\r\n", nmg->fccfolder); + sb = (STRBUFFER_S *)fs_get(sizeof(STRBUFFER_S)); + sb->buf = (char *)fs_get(20000*sizeof(char)); + sb->cur_bytes = 0; + sb->increment = 20000; + sb->bufsize = 20000; + rfc822_output(tmp_20k_buf, env, body, pmapi_soutr, sb, 1); + INIT(&msg, mail_string, (void *)sb->buf, sb->cur_bytes); + fccstream = mapi_mail_open(cs, NULL, nmg->fccfolder, ms_global->debug ? OP_DEBUG : NIL); + if(fccstream){ + if(mail_append(fccstream, nmg->fccfolder, &msg) == NIL) + msprint1("Fcc to %s failed\r\n", nmg->fccfolder); + else + msprint1("Fcc to %s SUCCEEDED\r\n", nmg->fccfolder); + mail_close(fccstream); + } + else + msprint1("Open of %s failed, abandoning FCC\r\n", nmg->fccfolder); + if(sb->buf) + fs_give((void **)&sb->buf); + if(sb) + fs_give((void **)&sb); + } + if((flFlags & MAPI_LOGON_UI) || (flFlags & MAPI_DIALOG)) + MessageBox(NULL, "Message SENT!\r\n", "pmapi32.dll", MB_OK|MB_ICONINFORMATION); + rv = SUCCESS_SUCCESS; + } + smtp_close(sending_stream); + smn_cleanup: + if(env) + mail_free_envelope(&env); + if(body) + mail_free_body(&body); + if(tsession) + fs_give((void **)&cs); + return(rv); +} + +int +set_text_data(BODY *body, char *txt) +{ + char *p; + int has_8bit = 0; + PARAMETER *pm; + + for(p = txt; *p; p++) + if(*p & 0x80) + has_8bit++; + + body->contents.text.data = mstrdup(txt); + body->contents.text.size = strlen(txt); + if(has_8bit){ + body->encoding = ENC8BIT; + if(!body->parameter) + pm = body->parameter = mail_newbody_parameter(); + else { + for(pm = body->parameter; pm->next; pm = pm->next); + pm->next = mail_newbody_parameter(); + pm = pm->next; + } + pm->attribute = mstrdup("charset"); + if(ms_global->prcvars[CHARACTER_SET]->val.p) + pm->value = mstrdup(ms_global->prcvars[CHARACTER_SET]->val.p); + else + pm->value = mstrdup("X-UNKNOWN"); + } + return 0; +} + +long +pmapi_soutr(STRBUFFER_S *s, char *str) +{ + unsigned long i; + + if(s->cur_bytes >= s->bufsize){ + fs_resize((void **)&s->buf, s->bufsize+ s->increment); + s->bufsize += s->increment; + } + for(i = 0; str[i]; i++){ + s->buf[s->cur_bytes++] = str[i]; + if(s->cur_bytes >= s->bufsize){ + fs_resize((void **)&s->buf, s->bufsize+ s->increment); + s->bufsize += s->increment; + } + } + s->buf[s->cur_bytes] = '\0'; + return T; +} + +ADDRESS * +mapirecip2address(lpMapiRecipDesc lpmrd) +{ + ADDRESS *adr = NULL; + static char *fakedomain = "@", *p; + mapi_global_s *nmg = ms_global; + + if(!lpmrd->lpszAddress) + return(NULL); + rfc822_parse_adrlist(&adr, _strnicmp(lpmrd->lpszAddress, "SMTP:", 5) == 0 + ? lpmrd->lpszAddress + 5 : lpmrd->lpszAddress, + nmg->prcvars[USER_DOMAIN]->val.p + ? nmg->prcvars[USER_DOMAIN]->val.p : fakedomain); + if(!adr) + return(NULL); + if(adr->next || adr->error){ + mail_free_address(&adr); + return(NULL); + } + + if(lpmrd->lpszName && adr->personal) + fs_give((void **)&adr->personal); + if(lpmrd->lpszName){ + p = rfc1522_encode(tmp_20k_buf, SIZEOF_20KBUF, lpmrd->lpszName, + nmg->prcvars[CHARACTER_SET]->val.p); + adr->personal = mstrdup(p); + } + return(adr); +} + +/* + * given a fs_get'd string, return a newly fs_get'd quoted copy + */ +char * +quote(char *old) +{ + char *new, *newp, *oldp; + int newSize = strlen(old)*2+3; + + if (!old) return mstrdup(old); + if(!strchr(old, ' ')) return mstrdup(old); + + newp = new = (char *)fs_get(sizeof(char)*newSize); /* worst case */ + if (new == NULL) { + ErrorBox("quote: fs_get of %d bytes failed", newSize); + return old; + } + + *newp++ = '"'; + for (oldp=old; *oldp; ++oldp) { + switch(*oldp) { + case '"': *newp++ = '\\'; /* fall through */ + default : *newp++ = *oldp; + } + } + *newp++ = '"'; + *newp = '\0'; + return(new); +} + + +int GetPCPineVersion(int *major, int *minor, int *minorminor) +{ + *major = 4; + *minor = 52; + *minorminor = 0; + + return 1; +} + +int +msprint(char *str) +{ + if(MSDEBUG) + fprintf(ms_global->dfd, "%s", str); + _flushall(); + return 0; +} + +int +msprint1(char *str, void *arg1) +{ + if(MSDEBUG) + fprintf(ms_global->dfd, str, arg1); + _flushall(); + return 0; +} + +int +msprint_message_structure(lpMapiMessage lpm) +{ + unsigned long i; + + if(MSDEBUG){ + msprint1("lpMapiMessage: %p\r\n", lpm); + if(!lpm) + return 1; + msprint1(" ulReserved: %d\r\n", (void *)lpm->ulReserved); + msprint1(" lpszSubsect: %s\r\n", lpm->lpszSubject ? lpm->lpszSubject : "(NULL)"); + msprint1(" lpszNoteText size: %d\r\n", lpm->lpszNoteText + ? (void *)strlen(lpm->lpszNoteText) : (void *)0); + if(lpm->lpszNoteText) + msprint1("\tleading text: %.10s\r\n", lpm->lpszNoteText); + msprint1(" lpszMessageType: %s\r\n", lpm->lpszMessageType ? lpm->lpszMessageType : "(NULL)"); + msprint1(" lpszDateReceived: %s\r\n", lpm->lpszDateReceived ? lpm->lpszDateReceived : "(NULL)"); + msprint1(" lpszConversationID: %s\r\n", lpm->lpszConversationID ? lpm->lpszConversationID : "(NULL)"); + msprint1(" flFlags: %d\r\n", (void *)lpm->flFlags); + msprint(" Originator:\r\n"); + msprint_recipient_structure(lpm->lpOriginator, 0); + msprint1(" nRecipCount: %d\r\n", (void *)lpm->nRecipCount); + for(i = 0; i < lpm->nRecipCount; i++) + msprint_recipient_structure(&lpm->lpRecips[i], 1); + msprint1(" nFileCount: %d\r\n", (void *)lpm->nFileCount); + for(i = 0; i < lpm->nFileCount; i++) + msprint_file_structure(&lpm->lpFiles[i]); + msprint("\r\n"); + } + return 0; +} + +int +msprint_recipient_structure(lpMapiRecipDesc lmrd, int mapi_orig_is_unexpected) +{ + if(MSDEBUG){ + msprint1(" lpMapiRecipDesc: %p\r\n", (void *)lmrd); + if(lmrd == NULL) + return 1; + msprint1(" ulReserved: %d\r\n", (void *)lmrd->ulReserved); + msprint1(" ulRecipClass: %s\r\n", lmrd->ulRecipClass == MAPI_ORIG ? "MAPI_ORIG" + : lmrd->ulRecipClass == MAPI_TO ? "MAPI_TO" : lmrd->ulRecipClass == MAPI_CC + ? "MAPI_CC" : "MAPI_BCC"); + if(mapi_orig_is_unexpected && lmrd->ulRecipClass == MAPI_ORIG){ + msprint(" # NOTE: it is seemingly strange behavior that a MAPI client would use\r\n # MAPI_ORIG instead of the lpOriginator. This may result in unexpected behavior.\r\n"); + } + msprint1(" lpszName: %s\r\n", lmrd->lpszName ? lmrd->lpszName : "(NULL)"); + msprint1(" lpszAddress: %s\r\n", lmrd->lpszAddress ? lmrd->lpszAddress : "(NULL)"); + msprint1(" ulEIDSize: %p\r\n", (void *)lmrd->ulEIDSize); + msprint1(" lpEntryID: %p\r\n", (void *)lmrd->lpEntryID); + } + return 0; +} + + +int +msprint_file_structure(lpMapiFileDesc lmfd) +{ + if(MSDEBUG){ + msprint1(" lpMapiFileDesc: %p\r\n", (void *)lmfd); + if(lmfd == NULL) + return 1; + msprint1(" ulReserved: %d\r\n", (void *)lmfd->ulReserved); + msprint1(" flFlags: %d\r\n", (void *)lmfd->flFlags); + msprint1(" nPosition: %d\r\n", (void *)lmfd->nPosition); + msprint1(" lpszPathName: %s\r\n", lmfd->lpszPathName ? lmfd->lpszPathName : "(NULL)"); + msprint1(" lpszFileName: %s\r\n", lmfd->lpszFileName ? lmfd->lpszFileName : "(NULL)"); + msprint1(" lpFileType: %p\r\n", (void *)lmfd->lpFileType); + } + return 0; +} + + +char *mstrdup(char *old) +{ + char *tmp; + + tmp = fs_get((strlen(old)+1) * sizeof(char)); + strcpy(tmp, old); + + return tmp; +} + +int +est_size(a) + ADDRESS *a; +{ + int cnt = 0; + + for(; a; a = a->next){ + + /* two times personal for possible quoting */ + cnt += 2 * (a->personal ? strlen(a->personal) : 0); + cnt += (a->mailbox ? strlen(a->mailbox) : 0); + cnt += (a->adl ? strlen(a->adl) : 0); + cnt += (a->host ? strlen(a->host) : 0); + + /* + * add room for: + * possible single space between fullname and addr + * left and right brackets + * @ sign + * possible : for route addr + * , <space> + * + * So I really think that adding 7 is enough. Instead, I'll add 10. + */ + cnt += 10; + } + + return(max(cnt, 50)); /* just making sure */ +} + +void ErrorBoxFunc(char *msg) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd,"ErrorBox: %s\r\n", msg); + fclose(ms_global->dfd); + ms_global->dfd = fopen(ms_global->debugFile, "ab"); + if(!ms_global->dfd){ + MessageBox(NULL, "debug file problems! Debugging turned off.", + "mapi32.dll", + MB_OK|MB_ICONERROR); + ms_global->debug = 0; + fs_give((void **)&ms_global->debugFile); + ms_global->debugFile = NULL; + } + } + MessageBox(NULL, msg, "mapi32.dll", MB_OK|MB_ICONERROR); +} + +/*---------------------------------------------------------------------- + This was borrowed from reply.c, and modified + Generate a unique message id string. + + Args: ps -- The usual pine structure + + Result: Alloc'd unique string is returned + +Uniqueness is gaurenteed by using the host name, process id, date to the +second and a single unique character +*----------------------------------------------------------------------*/ +char * +pmapi_generate_message_id() +{ + static short osec = 0, cnt = 0; + char *id; + time_t now; + struct tm *now_x; + + now = time((time_t *)0); + now_x = localtime(&now); + id = (char *)fs_get(128 * sizeof(char)); + + if(now_x->tm_sec == osec){ + cnt++; + }else{ + cnt = 0; + osec = now_x->tm_sec; + } + sprintf(id,"<Pmapi32.%04d%02d%02d%02d%02d%02d%X.%d@%.50s>", + (now_x->tm_year) + 1900, now_x->tm_mon + 1, + now_x->tm_mday, now_x->tm_hour, now_x->tm_min, now_x->tm_sec, + cnt, getpid(), mylocalhost()); + + return(id); +} diff --git a/mapi/pmapi.def b/mapi/pmapi.def new file mode 100644 index 00000000..fb633335 --- /dev/null +++ b/mapi/pmapi.def @@ -0,0 +1,17 @@ +LIBRARY pmapi32 +VERSION 4.60 + +EXPORTS + MAPILogon @1 + MAPILogoff @2 + MAPIFindNext @3 + MAPIReadMail @4 + MAPISendMail @5 + MAPIAddress @6 + MAPIDeleteMail @7 + MAPIDetails @8 + MAPIFreeBuffer @9 + MAPIResolveName @10 + MAPISaveMail @11 + MAPISendDocuments @12 + GetPCPineVersion @13 diff --git a/mapi/pmapi.h b/mapi/pmapi.h new file mode 100644 index 00000000..2a8d28f8 --- /dev/null +++ b/mapi/pmapi.h @@ -0,0 +1,244 @@ +/* + * ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include "windows.h" + +#include "mapi.h" +#include "io.h" +#include "fcntl.h" +#include "sys/stat.h" +#include "string.h" +#include "stdio.h" +#include "errno.h" +#include "process.h" +#include "resource.h" +#include "time.h" +#undef ERROR +#include "../c-client-dll/mail.h" +#include "../c-client-dll/rfc822.h" +#include "../c-client-dll/osdep.h" +#include "../c-client-dll/smtp.h" +#include "../c-client-dll/misc.h" +#include "ctype.h" + +#define USER_ID 0 +#define PERSONAL_NAME 1 +#define USER_DOMAIN 2 +#define SMTP_SERVER 3 +#define INBOX_PATH 4 +#define FEATURE_LIST 5 +#define CHARACTER_SET 6 +#define FOLDER_COLLECTIONS 7 +#define PMAPI_SEND_BEHAVIOR 8 +#define DEFAULT_FCC 9 +#define PMAPI_SUPPRESS_DIALOGS 10 +#define PMAPI_STRICT_NO_DIALOG 11 +#define NUMPRCVARS 12 +#define ENABLE8BIT 0 +#define NUMPRCFEATS 1 +#define PMSB_ALWAYS_PROMPT 0 +#define PMSB_ALWAYS_SEND 1 +#define PMSB_NEVER_SEND 2 +#define PMSD_NO 0 +#define PMSD_YES 1 +#define PMSD_PROMPT 2 +#define errBufSize 300 /* for buffers to sprintf %.200s error messages into */ +#define BUFLEN 1024 +#define EDITLEN 128 +#define MSDEBUG ms_global && ms_global->debug +#define NOT_PINERC 0 +#define IS_PINERC 1 +#define PINERC_FILE "tmpmapiuwpinerc" +#define ErrorBox(msg,parm){ \ + char buf[errBufSize]; \ + sprintf(buf, msg, parm); \ + ErrorBoxFunc(buf); \ + } /* a macro so parm can be a pointer or a value as per % format */ +#define DEBUG_WRITE(msg, parm) { if(MSDEBUG) fprintf(ms_global->dfd,msg,parm);} + +#ifdef ANSI +#define PROTO(args) args +#else +#define PROTO(args) () +#endif + +/* used for pine pwd file */ +#define FIRSTCH 0x20 +#define LASTCH 0x7e +#define TABSZ (LASTCH - FIRSTCH + 1) + + +typedef struct rc_entry{ + char *var; + union { + char *p; + char **l; + } val; + int islist; + int ispmapivar; +} rc_entry_s; + +typedef struct rc_feat { + char *var; + int is_set; +} rc_feat_s; + +typedef struct STRLIST{ + char *str; + struct STRLIST *next; +} STRLIST_S; + +typedef struct file_struct{ + char *filename; + struct file_struct *next; +} file_s; + +typedef enum {RecipDesc, Message} BufType; + +typedef struct mbuffer_list{ + void *buf; + int arraysize; /* should always be 1 unless it's one of those silly arrays */ + BufType type; + struct mbuffer_list *next; +} MBUFFER_LIST_S; + +typedef struct strbuffer{ + char *buf; + unsigned long cur_bytes; + unsigned long increment; + unsigned long bufsize; +} STRBUFFER_S; + +typedef struct dlg_edits{ + char edit1[EDITLEN]; + char edit2[EDITLEN]; +} dlg_edits_s; + +typedef struct pw_cache { + char user[EDITLEN]; + char pwd[EDITLEN]; + char host[EDITLEN]; + int validpw; + struct pw_cache *next; +} pw_cache_s; + +typedef struct sessionl{ + NETMBX *mb; + dlg_edits_s dlge; + pw_cache_s *pwc; + MAILSTREAM *open_stream; + char *currently_open; + struct { + unsigned dlg_cancel:1; + unsigned int mapi_logon_ui:1; + unsigned int check_stream:1; + /* int passfile_checked; */ + } flags; + file_s *fs; + lpMapiMessage FAR lpm; + HWND mhwnd; + unsigned long session_number; + struct sessionl *next; +} sessionlist_s; + +typedef struct mapi_global{ + char *debugFile; + int debug; + FILE *dfd; + char *pineExe; + char *pineExeAlt; + char *pinerc; + char *pineconf; + char *pinercex; + char *fccfolder; + int inited; + char *tmpmbxptr; + rc_entry_s *prcvars[NUMPRCVARS]; + rc_feat_s *prcfeats[NUMPRCFEATS]; + int pmapi_send_behavior; + int pmapi_suppress_dialogs; + int pmapi_strict_no_dialog; + sessionlist_s *sessionlist; + sessionlist_s *cs; /* the current session, used for logins */ + unsigned long next_session; + unsigned long attach_no; + unsigned long attached; + MBUFFER_LIST_S *mapi_bufs; + char *attachDir; + HINSTANCE mhinst; +} mapi_global_s; + +extern struct mapi_global *ms_global; + +void ErrorBoxFunc(char *msg); +char *quote(char *old); +char *mstrdup(char *old); +int msprint(char *str); +int msprint1(char *str, void *arg1); +int msprint_message_structure(lpMapiMessage lpm); +int msprint_recipient_structure(lpMapiRecipDesc lmrd, int mapi_orig_is_unexpected); +int msprint_file_structure(lpMapiFileDesc lmfd); + +int est_size(ADDRESS *a); +int send_documents(char *files, char sep); +unsigned long send_msg_nodlg(LHANDLE lhSession, ULONG ulUIParam, + lpMapiMessage lpMessage, FLAGS flFlags, ULONG ulReserved); +ADDRESS *mapirecip2address(lpMapiRecipDesc lpmrd); +long pmapi_soutr(STRBUFFER_S *s, char *str); +char *TmpCopy(char *srcFile, int is_pinerc); +sessionlist_s *new_sessionlist(); +sessionlist_s *free_sessionlist_node(sessionlist_s *cs); +sessionlist_s *get_session(unsigned long num); +lpMapiRecipDesc new_MapiRecipDesc(int arraysize); +void free_MapiRecipDesc(lpMapiRecipDesc buf, int arraysize); +lpMapiMessage new_MapiMessage(int arraysize); +void free_MapiMessage(lpMapiMessage buf, int arraysize); +int new_mbuffer(void *buf, int arraysize, BufType type); +int free_mbuffer(void *buf); +int InitPineSpecific(sessionlist_s *cs); +MAILSTREAM *mapi_mail_open(sessionlist_s *cs, MAILSTREAM *stream, char *name, long options); +MAILSTREAM *check_mailstream(sessionlist_s *cs); +unsigned long convert_to_msgno(char *msgid); +int fetch_structure_and_attachments(long msgno, long flags, + FLAGS MAPIflags, sessionlist_s *cs); +char *message_structure_to_mailto_url(lpMapiMessage lpm); +ULONG FAR PASCAL MAPISendMail(LHANDLE lhSession, ULONG ulUIParam, lpMapiMessage lpMessage, + FLAGS flFlags, ULONG ulReserved); +ULONG FAR PASCAL MAPILogon(ULONG ulUIParam, LPTSTR lpszProfileName, LPTSTR lpszPassword, + FLAGS flFlags, ULONG ulReserved, LPLHANDLE lplhSession); +ULONG FAR PASCAL MAPILogoff (LHANDLE lhSession, ULONG ulUIParam, FLAGS flFlags, ULONG ulReserved); +ULONG FAR PASCAL MAPIFindNext (LHANDLE lhSession, ULONG ulUIParam, LPSTR lpszMessageType, + LPSTR lpszSeedMessageID, FLAGS flFlags, ULONG ulReserved, + LPSTR lpszMessageID); +ULONG FAR PASCAL MAPIReadMail(LHANDLE lhSession, ULONG ulUIParam, LPSTR lpszMessageID, + FLAGS flFlags, ULONG ulReserved, lpMapiMessage FAR *lppMessage); +ULONG FAR PASCAL MAPIAddress(LHANDLE lhSession, ULONG ulUIParam, LPTSTR lpszCaption, + ULONG nEditFields, LPTSTR lpszLabels, ULONG nRecips, + lpMapiRecipDesc lpRecips, FLAGS flFlags, ULONG ulReserved, + LPULONG lpnNewRecips, lpMapiRecipDesc FAR * lppNewRecips); +ULONG FAR PASCAL MAPIDeleteMail(LHANDLE lhSession, ULONG ulUIParam, LPTSTR lpszMessageID, + FLAGS flFlags, ULONG ulReserved); +ULONG FAR PASCAL MAPIDetails(LHANDLE lhSession, ULONG ulUIParam, lpMapiRecipDesc lpRecip, + FLAGS flFlags, ULONG ulReserved); +ULONG FAR PASCAL MAPIFreeBuffer(LPVOID pv); +ULONG FAR PASCAL MAPIResolveName(LHANDLE lhSession, ULONG ulUIParam, LPTSTR lpszName, + FLAGS flFlags, ULONG ulReserved, lpMapiRecipDesc FAR * lppRecip); +ULONG FAR PASCAL MAPISaveMail(LHANDLE lhSession, ULONG ulUIParam, lpMapiMessage lpMessage, + FLAGS flFlags, ULONG ulReserved, LPTSTR lpszMessageID); +ULONG FAR PASCAL MAPISendDocuments(ULONG ulUIParam, LPTSTR lpszDelimChar, LPTSTR lpszFullPaths, + LPTSTR lpszFileNames, ULONG ulReserved); + +/* rfc1522.c */ +char *rfc1522_encode PROTO((char *, size_t, unsigned char *, char *)); +void get_pair PROTO((char *, char **, char **, int, int)); +void removing_leading_and_trailing_white_space PROTO((char *)); diff --git a/mapi/pmapi.rc b/mapi/pmapi.rc new file mode 100644 index 00000000..a648cd14 --- /dev/null +++ b/mapi/pmapi.rc @@ -0,0 +1,153 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +#define IDC_STATIC (-1) // all static controls + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 284, 95 +STYLE DS_SYSMODAL | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Login" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Login: ",IDC_STATIC,20,44,20,8 + EDITTEXT IDC_LOGIN,45,42,158,12,ES_AUTOHSCROLL + LTEXT "Password: ",IDC_STATIC,7,57,36,8 + EDITTEXT IDC_PASSWORD,45,55,158,12,ES_PASSWORD | ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,7,73,50,14 + PUSHBUTTON "Cancel",IDCANCEL,57,73,50,14 + LTEXT "Attempting to open the following folder:",IDC_STATIC,7, + 18,131,8 + LTEXT "Some server here ",IDC_SERVER,7,30,269,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 276 + TOPMARGIN, 7 + BOTTOMMARGIN, 87 + END +END +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,01,0,0 + PRODUCTVERSION 2,01,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x29L +#else + FILEFLAGS 0x28L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "alpine info: http://www.washington.edu/alpine\0" + VALUE "CompanyName", "University of Washington\0" + VALUE "FileDescription", "Simple MAPI DLL for Alpine for Windows\0" + VALUE "FileVersion", "2.10\0" + VALUE "InternalName", "pmapi32\0" + VALUE "LegalCopyright", "Copyright ? 2006-2009\0" + VALUE "LegalTrademarks", "Apache License, Version 2.0\0" + VALUE "OriginalFilename", "pmapi32.dll\0" + VALUE "PrivateBuild", " \0" + VALUE "ProductName", "Simple MAPI for Alpine for Windows\0" + VALUE "ProductVersion", "2.10\0" + VALUE "SpecialBuild", " \0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/mapi/resource.h b/mapi/resource.h new file mode 100644 index 00000000..072b84c4 --- /dev/null +++ b/mapi/resource.h @@ -0,0 +1,19 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by select.rc +// +#define IDD_DIALOG1 101 +#define IDC_PASSWORD 1000 +#define IDC_LOGIN 1001 +#define IDC_SERVER 1003 +#define IDC_COMBO2 1005 +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1007 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/mapi/rfc1522.c b/mapi/rfc1522.c new file mode 100644 index 00000000..f77a8c27 --- /dev/null +++ b/mapi/rfc1522.c @@ -0,0 +1,557 @@ +/* + * ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +/* + * rfc1522.c + * + * right now this is just rfc1522_encode (taken straight out of pine/strings.c, + * but if were to become necessary, + * it could be made to do rfc1522_decode too, and it already has some strings functions. + */ +#include "pmapi.h" + +#define RFC1522_INIT "=?" +#define RFC1522_INIT_L 2 +#define RFC1522_TERM "?=" +#define RFC1522_TERM_L 2 +#define RFC1522_DLIM "?" +#define RFC1522_DLIM_L 1 +#define RFC1522_MAXW 75 +#define ESPECIALS "()<>@,;:\"/[]?.=" +#define RFC1522_OVERHEAD(S) (RFC1522_INIT_L + RFC1522_TERM_L + \ + (2 * RFC1522_DLIM_L) + strlen(S) + 1); +#define RFC1522_ENC_CHAR(C) (((C) & 0x80) || !rfc1522_valtok(C) \ + || (C) == '_' ) +#define SPACE ' ' /* space character */ +#define ESCAPE '\033' /* the escape */ +#define UNKNOWN_CHARSET "X-UNKNOWN" + +/* + * Hex conversion aids + */ +#define HEX_ARRAY "0123456789ABCDEF" +#define HEX_CHAR1(C) HEX_ARRAY[((C) & 0xf0) >> 4] +#define HEX_CHAR2(C) HEX_ARRAY[(C) & 0xf] + +#define C2XPAIR(C, S) { \ + *(S)++ = HEX_CHAR1(C); \ + *(S)++ = HEX_CHAR2(C); \ + } + + +int rfc1522_token PROTO((char *, int (*) PROTO((int)), char *, + char **)); +int rfc1522_valtok PROTO((int)); +int rfc1522_valenc PROTO((int)); +int rfc1522_valid PROTO((char *, char **, char **, char **, + char **)); +char *rfc1522_8bit PROTO((void *, int)); +char *rfc1522_binary PROTO((void *, int)); +unsigned char *rfc1522_encoded_word PROTO((unsigned char *, int, char *)); +char *strindex PROTO((char *, int)); +void sstrcpy PROTO((char **, char *)); +void sstrncpy PROTO((char **, char *, int)); + +int removing_double_quotes PROTO((char *)); + +static char *known_escapes[] = { + "(B", "(J", "$@", "$B", /* RFC 1468 */ + "(H", + NULL}; +/* different for non-Windows */ + +int +match_escapes(esc_seq) + char *esc_seq; +{ + char **p; + int n; + + for(p = known_escapes; *p && strncmp(esc_seq, *p, n = strlen(*p)); p++) + ; + + return(*p ? n + 1 : 0); +} + +/*---------------------------------------------------------------------- + A replacement for strchr or index ... + + Returns a pointer to the first occurrence of the character + 'ch' in the specified string or NULL if it doesn't occur + + ....so we don't have to worry if it's there or not. We bring our own. +If we really care about efficiency and think the local one is more +efficient the local one can be used, but most of the things that take +a long time are in the c-client and not in pine. + ----*/ +char * +strindex(buffer, ch) + char *buffer; + int ch; +{ + do + if(*buffer == ch) + return(buffer); + while (*buffer++ != '\0'); + + return(NULL); +} + +/*---------------------------------------------------------------------- + copy the source string onto the destination string returning with + the destination string pointer at the end of the destination text + + motivation for this is to avoid twice passing over a string that's + being appended to twice (i.e., strcpy(t, x); t += strlen(t)) + ----*/ +void +sstrcpy(d, s) + char **d; + char *s; +{ + while((**d = *s++) != '\0') + (*d)++; +} + +void +sstrncpy(d, s, n) + char **d; + char *s; + int n; +{ + while(n-- > 0 && (**d = *s++) != '\0') + (*d)++; +} + +/* + * rfc1522_token - scan the given source line up to the end_str making + * sure all subsequent chars are "valid" leaving endp + * a the start of the end_str. + * Returns: TRUE if we got a valid token, FALSE otherwise + */ +int +rfc1522_token(s, valid, end_str, endp) + char *s; + int (*valid) PROTO((int)); + char *end_str; + char **endp; +{ + while(*s){ + if((char) *s == *end_str /* test for matching end_str */ + && ((end_str[1]) + ? !strncmp((char *)s + 1, end_str + 1, strlen(end_str + 1)) + : 1)){ + *endp = s; + return(TRUE); + } + + if(!(*valid)(*s++)) /* test for valid char */ + break; + } + + return(FALSE); +} + + +/* + * rfc1522_valtok - test for valid character in the RFC 1522 encoded + * word's charset and encoding fields. + */ +int +rfc1522_valtok(c) + int c; +{ + return(!(c == SPACE || iscntrl(c & 0x7f) || strindex(ESPECIALS, c))); +} + + +/* + * rfc1522_valenc - test for valid character in the RFC 1522 encoded + * word's encoded-text field. + */ +int +rfc1522_valenc(c) + int c; +{ + return(!(c == '?' || c == SPACE) && isprint((unsigned char)c)); +} + + +/* + * rfc1522_valid - validate the given string as to it's rfc1522-ness + */ +int +rfc1522_valid(s, charset, enc, txt, endp) + char *s; + char **charset; + char **enc; + char **txt; + char **endp; +{ + char *c, *e, *t, *p; + int rv; + + rv = rfc1522_token(c = s+RFC1522_INIT_L, rfc1522_valtok, RFC1522_DLIM, &e) + && rfc1522_token(++e, rfc1522_valtok, RFC1522_DLIM, &t) + && rfc1522_token(++t, rfc1522_valenc, RFC1522_TERM, &p) + && p - s <= RFC1522_MAXW; + + if(charset) + *charset = c; + + if(enc) + *enc = e; + + if(txt) + *txt = t; + + if(endp) + *endp = p; + + return(rv); +} + + +/* + * rfc1522_encode - encode the given source string ala RFC 1522, + * IF NECESSARY, into the given destination buffer. + * Don't bother copying if it turns out encoding + * isn't necessary. + * + * Returns: pointer to either the destination buffer containing the + * encoded text, or a pointer to the source buffer if we didn't + * have to encode anything. + */ +char * +rfc1522_encode(d, len, s, charset) + char *d; + size_t len; /* length of d */ + unsigned char *s; + char *charset; +{ + unsigned char *p, *q; + int n; + + if(!s) + return((char *) s); + + if(!charset) + charset = UNKNOWN_CHARSET; + + /* look for a reason to encode */ + for(p = s, n = 0; *p; p++) + if((*p) & 0x80){ + n++; + } + else if(*p == RFC1522_INIT[0] + && !strncmp((char *) p, RFC1522_INIT, RFC1522_INIT_L)){ + if(rfc1522_valid((char *) p, NULL, NULL, NULL, (char **) &q)) + p = q + RFC1522_TERM_L - 1; /* advance past encoded gunk */ + } + else if(*p == ESCAPE && match_escapes((char *)(p+1))){ + n++; + } + + if(n){ /* found, encoding to do */ + char *rv = d, *t, + enc = (n > (2 * (p - s)) / 3) ? 'B' : 'Q'; + + while(*s){ + if(d-rv < len-1-(RFC1522_INIT_L+2*RFC1522_DLIM_L+1)){ + sstrcpy(&d, RFC1522_INIT); /* insert intro header, */ + sstrcpy(&d, charset); /* character set tag, */ + sstrcpy(&d, RFC1522_DLIM); /* and encoding flavor */ + *d++ = enc; + sstrcpy(&d, RFC1522_DLIM); + } + + /* + * feed lines to encoder such that they're guaranteed + * less than RFC1522_MAXW. + */ + p = rfc1522_encoded_word(s, enc, charset); + if(enc == 'B') /* insert encoded data */ + sstrncpy(&d, t = rfc1522_binary(s, p - s), len-1-(d-rv)); + else /* 'Q' encoding */ + sstrncpy(&d, t = rfc1522_8bit(s, p - s), len-1-(d-rv)); + + sstrncpy(&d, RFC1522_TERM, len-1-(d-rv)); /* insert terminator */ + fs_give((void **) &t); + if(*p) /* more src string follows */ + sstrncpy(&d, "\015\012 ", len-1-(d-rv)); /* insert cont. line */ + + s = p; /* advance s */ + } + + rv[len-1] = '\0'; + return(rv); + } + else + return((char *) s); /* no work for us here */ +} + + + +/* + * rfc1522_encoded_word -- cut given string into max length encoded word + * + * Return: pointer into 's' such that the encoded 's' is no greater + * than RFC1522_MAXW + * + * NOTE: this line break code is NOT cognizant of any SI/SO + * charset requirements nor similar strategies using escape + * codes. Hopefully this will matter little and such + * representation strategies don't also include 8bit chars. + */ +unsigned char * +rfc1522_encoded_word(s, enc, charset) + unsigned char *s; + int enc; + char *charset; +{ + int goal = RFC1522_MAXW - RFC1522_OVERHEAD(charset); + + if(enc == 'B') /* base64 encode */ + for(goal = ((goal / 4) * 3) - 2; goal && *s; goal--, s++) + ; + else /* special 'Q' encoding */ + for(; goal && *s; s++) + if((goal -= RFC1522_ENC_CHAR(*s) ? 3 : 1) < 0) + break; + + return(s); +} + + + +/* + * rfc1522_8bit -- apply RFC 1522 'Q' encoding to the given 8bit buffer + * + * Return: alloc'd buffer containing encoded string + */ +char * +rfc1522_8bit(src, slen) + void *src; + int slen; +{ + char *ret = (char *) fs_get ((size_t) (3*slen + 2)); + char *d = ret; + unsigned char c; + unsigned char *s = (unsigned char *) src; + + while (slen--) { /* for each character */ + if (((c = *s++) == '\015') && (*s == '\012') && slen) { + *d++ = '\015'; /* true line break */ + *d++ = *s++; + slen--; + } + else if(c == SPACE){ /* special encoding case */ + *d++ = '_'; + } + else if(RFC1522_ENC_CHAR(c)){ + *d++ = '='; /* quote character */ + C2XPAIR(c, d); + } + else + *d++ = (char) c; /* ordinary character */ + } + + *d = '\0'; /* tie off destination */ + return(ret); +} + + +/* + * rfc1522_binary -- apply RFC 1522 'B' encoding to the given 8bit buffer + * + * Return: alloc'd buffer containing encoded string + */ +char * +rfc1522_binary (src, srcl) + void *src; + int srcl; +{ + static char *v = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + unsigned char *s = (unsigned char *) src; + char *ret, *d; + + d = ret = (char *) fs_get ((size_t) ((((srcl + 2) / 3) * 4) + 1)); + for (; srcl; s += 3) { /* process tuplets */ + /* byte 1: high 6 bits (1) */ + *d++ = v[s[0] >> 2]; + /* byte 2: low 2 bits (1), high 4 bits (2) */ + *d++ = v[((s[0] << 4) + (--srcl ? (s[1] >> 4) : 0)) & 0x3f]; + /* byte 3: low 4 bits (2), high 2 bits (3) */ + *d++ = srcl ? v[((s[1] << 2) + (--srcl ? (s[2] >> 6) :0)) & 0x3f] :'='; + /* byte 4: low 6 bits (3) */ + *d++ = srcl ? v[s[2] & 0x3f] : '='; + if(srcl) + srcl--; /* count third character if processed */ + } + + *d = '\0'; /* tie off string */ + return(ret); /* return the resulting string */ +} + + +/* + * Function to parse the given string into two space-delimited fields + * Quotes may be used to surround labels or values with spaces in them. + * Backslash negates the special meaning of a quote. + * Unescaping of backslashes only happens if the pair member is quoted, + * this provides for backwards compatibility. + * + * Args -- string -- the source string + * label -- the first half of the string, a return value + * value -- the last half of the string, a return value + * firstws -- if set, the halves are delimited by the first unquoted + * whitespace, else by the last unquoted whitespace + * strip_internal_label_quotes -- unescaped quotes in the middle of the label + * are removed. This is useful for vars + * like display-filters and url-viewers + * which may require quoting of an arg + * inside of a _TOKEN_. + */ +void +get_pair(string, label, value, firstws, strip_internal_label_quotes) + char *string, **label, **value; + int firstws; + int strip_internal_label_quotes; +{ + char *p, *q, *tmp, *token = NULL; + int quoted = 0; + + *label = *value = NULL; + + /* + * This for loop just finds the beginning of the value. If firstws + * is set, then it begins after the first whitespace. Otherwise, it begins + * after the last whitespace. Quoted whitespace doesn't count as + * whitespace. If there is no unquoted whitespace, then there is no + * label, there's just a value. + */ + for(p = string; p && *p;){ + if(*p == '"') /* quoted label? */ + quoted = (quoted) ? 0 : 1; + + if(*p == '\\' && *(p+1) == '"') /* escaped quote? */ + p++; /* skip it... */ + + if(isspace((unsigned char)*p) && !quoted){ /* if space, */ + while(*++p && isspace((unsigned char)*p)) /* move past it */ + ; + + if(!firstws || !token) + token = p; /* remember start of text */ + } + else + p++; + } + + if(token){ /* copy label */ + *label = p = (char *)fs_get(((token - string) + 1) * sizeof(char)); + + /* make a copy of the string */ + tmp = (char *)fs_get(((token - string) + 1) * sizeof(char)); + strncpy(tmp, string, token - string); + tmp[token-string] = '\0'; + + removing_leading_and_trailing_white_space(tmp); + quoted = removing_double_quotes(tmp); + + for(q = tmp; *q; q++){ + if(quoted && *q == '\\' && (*(q+1) == '"' || *(q+1) == '\\')) + *p++ = *++q; + else if(!(strip_internal_label_quotes && *q == '"')) + *p++ = *q; + } + + *p = '\0'; /* tie off label */ + fs_give((void **)&tmp); + if(*label == '\0') + fs_give((void **)label); + } + else + token = string; + + if(token){ /* copy value */ + *value = p = (char *)fs_get((strlen(token) + 1) * sizeof(char)); + + tmp = cpystr(token); + removing_leading_and_trailing_white_space(tmp); + quoted = removing_double_quotes(tmp); + + for(q = tmp; *q ; q++){ + if(quoted && *q == '\\' && (*(q+1) == '"' || *(q+1) == '\\')) + *p++ = *++q; + else + *p++ = *q; + } + + *p = '\0'; /* tie off value */ + fs_give((void **)&tmp); + } +} + +void +removing_leading_and_trailing_white_space(string) + char *string; +{ + register char *p, *q = NULL; + + if(!string) + return; + + for(p = string; *p; p++) /* find the first non-blank */ + if(!isspace((unsigned char)*p)){ + while(*string = *p++){ /* copy back from there... */ + q = (!isspace((unsigned char)*string)) ? NULL : (!q) ? string : q; + string++; + } + + if(q) + *q = '\0'; + + return; + } + + if(*string != '\0') + *string = '\0'; +} + +/*---------------------------------------------------------------------- + Remove one set of double quotes surrounding string in place + Returns 1 if quotes were removed + + Args: string -- string to remove quotes from + ----*/ +int +removing_double_quotes(string) + char *string; +{ + register char *p; + int ret = 0; + + if(string && string[0] == '"' && string[1] != '\0'){ + p = string + strlen(string) - 1; + if(*p == '"'){ + ret++; + *p = '\0'; + for(p = string; *p; p++) + *p = *(p+1); + } + } + + return(ret); +} diff --git a/mapi/smapi.c b/mapi/smapi.c new file mode 100644 index 00000000..6beb87a8 --- /dev/null +++ b/mapi/smapi.c @@ -0,0 +1,653 @@ +/* + * ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include "pmapi.h" + +ULONG FAR PASCAL MAPISendMail( + LHANDLE lhSession, + ULONG ulUIParam, + lpMapiMessage lpMessage, + FLAGS flFlags, + ULONG ulReserved) +{ + ULONG i; + int ac = 0, rv = 0, can_suppress_dialog = 0, has_recips = 0; + char **av, *tmpfree, *url; + + if(MSDEBUG){ + fprintf(ms_global->dfd, "\r\nIn MAPISendMail\r\n"); + fprintf(ms_global->dfd, " MAPI_DIALOG is %s set\r\n", + flFlags & MAPI_DIALOG ? "" : "NOT"); + fprintf(ms_global->dfd, " MAPI_LOGON_UI is %s set\r\n", + flFlags & MAPI_LOGON_UI ? "" : "NOT"); + fprintf(ms_global->dfd, " MAPI_NEW_SESSION is %s set\r\n", + flFlags & MAPI_NEW_SESSION ? "" : "NOT"); + fprintf(ms_global->dfd, " session number is %p\r\n", lhSession); + _flushall(); + } + msprint_message_structure(lpMessage); + + url = message_structure_to_mailto_url(lpMessage); + + for(i = 0; i < lpMessage->nRecipCount; i++){ + if((&lpMessage->lpRecips[i])->ulRecipClass != MAPI_ORIG) + has_recips = 1; + } + if((flFlags & MAPI_DIALOG) && has_recips && + (lpMessage->lpszSubject + || lpMessage->lpszNoteText + || lpMessage->nFileCount)){ + if(ms_global->pmapi_suppress_dialogs == PMSD_YES) + can_suppress_dialog = 1; + else if(ms_global->pmapi_suppress_dialogs == PMSD_PROMPT){ + if(MessageBox(NULL, "Edit Message Before Sending?", "pmapi32.dll", MB_YESNO|MB_ICONQUESTION) == IDNO) + can_suppress_dialog = 1; + } + } + if(can_suppress_dialog || + ((flFlags & MAPI_DIALOG) == 0)){ + rv = send_msg_nodlg(lhSession, ulUIParam, lpMessage, flFlags, ulReserved); + return(rv); + } + + if (lpMessage == NULL){ + /* lpMessage->lpFiles == NULL || + lpMessage->lpFiles->lpszPathName == NULL) */ + /* this old code checked to see that there were attachments */ + /* I think it should be all right for there not to be attachments */ + + ErrorBox("MAPISendMail: %s pointer in lpMessage argument", "NULL"); + return 0; + } + + /* + * allocate space for spawn's argv array: + * 2 for each of the nFileCount attachments + * +4 for the -p pinerc, and av[0] and trailing NULL + * +2 for the url + */ + { + int avSize = (6+2*lpMessage->nFileCount)*sizeof(*av); + av = (char **)fs_get(avSize); + if (av == NULL) { + ErrorBox("MAPISendMail: fs_get of %d bytes for av failed", (avSize)); + return MAPI_E_FAILURE; + } + } + + /* + * establish a default path to the pine executable which will + * probably be replaced with a value from the registry + */ + if(ms_global && ms_global->pineExe){ + av[ac++] = quote(ms_global->pineExe); + if(!av[0]) { + ErrorBox("Cannot fs_get for %s","pine"); + return MAPI_E_FAILURE; + } + } + else return MAPI_E_FAILURE; + if(ms_global->pinerc){ + av[ac++] = mstrdup("-p"); + if(tmpfree = TmpCopy(ms_global->pinerc, IS_PINERC)){ + av[ac++] = quote(tmpfree); + fs_give((void **)&tmpfree); + } + else + av[ac++] = quote(ms_global->pinerc); + } + if(url){ + av[ac++] = mstrdup("-url"); + av[ac++] = url; + } + + /* + * make a temporary copy of each attachment in attachDir, + * add the new filename (suitably quoted) to pine's argument list + */ + for (i=0; i < lpMessage->nFileCount; ++i) { + char *oldPath = lpMessage->lpFiles[i].lpszPathName; + char *newCopy, *tmpfree; + tmpfree = TmpCopy(oldPath, NOT_PINERC); + if(tmpfree == NULL) + return MAPI_E_ATTACHMENT_NOT_FOUND; + newCopy = quote(tmpfree); + fs_give((void **)&tmpfree); + if (newCopy) { + av[ac++] = mstrdup("-attach_and_delete"); + av[ac++] = newCopy; + } + else{ + if(MSDEBUG) + fprintf(ms_global->dfd, "TmpCopy returned null\r\n"); + } + if (MSDEBUG) { + fprintf(ms_global->dfd,"Attachment %d: old path: %s\r\n--\r\n", + i,oldPath); + fprintf(ms_global->dfd,">>: %s\r\n--\r\n",ms_global->attachDir); + fprintf(ms_global->dfd,">>: tmp path: %s\r\n--\r\n", + (newCopy?newCopy:"NULL")); + } + } + av[ac++] = NULL; + + if(MSDEBUG) { + fprintf(ms_global->dfd, "spawning %s (else %s):\r\n", + ms_global->pineExe, ms_global->pineExeAlt); + for (i=0; av[i]; ++i) + fprintf(ms_global->dfd, "av[%d] = %s\r\n", i, av[i]); + } + + _flushall(); + if (_spawnvp(_P_NOWAIT, ms_global->pineExe, av) == -1 && + _spawnvp(_P_NOWAIT, ms_global->pineExeAlt, av) == -1) + { + ErrorBox("MAPISendMail: _spawnvp of %s failed", ms_global->pineExe); + if(MSDEBUG) fprintf(ms_global->dfd, "_spawnvp %s and %s failed\r\n", + ms_global->pineExe,ms_global->pineExeAlt); + return(MAPI_E_FAILURE); + } + + /* + * close and free allocated resources + */ + if (av[0]) fs_give((void **)&av[0]); + for (i=1; av[i]; i++) { + if (av[i]) fs_give((void **)&av[i]); + } + fs_give((void **)&av); + + return SUCCESS_SUCCESS; +} + + +ULONG FAR PASCAL MAPILogon( + ULONG ulUIParam, + LPTSTR lpszProfileName, + LPTSTR lpszPassword, + FLAGS flFlags, + ULONG ulReserved, + LPLHANDLE lplhSession) +{ + mapi_global_s *nmg = ms_global; + sessionlist_s *cs; + sessionlist_s *ts; + + if(MSDEBUG){ + fprintf(ms_global->dfd, "\r\nIn MAPILogon\r\n"); + fprintf(ms_global->dfd, " MAPI_FORCE_DOWNLOAD is %s set\r\n", + flFlags & MAPI_FORCE_DOWNLOAD ? "" : "NOT"); + fprintf(ms_global->dfd, " MAPI_NEW_SESSION is %s set\r\n", + flFlags & MAPI_NEW_SESSION ? "" : "NOT"); + fprintf(ms_global->dfd, " MAPI_LOGON_UI is %s set\r\n", + flFlags & MAPI_LOGON_UI ? "" : "NOT"); + fprintf(ms_global->dfd, " MAPI_PASSWORD_UI is %s set\r\n", + flFlags & MAPI_PASSWORD_UI ? "" : "NOT"); + fprintf(ms_global->dfd, " ulUIParam is %p\r\n", ulUIParam); + if(lpszProfileName) + fprintf(ms_global->dfd, " profile name is %s\r\n", lpszProfileName); + fprintf(ms_global->dfd, " lplhSession is %p\r\n", lplhSession); + if(lplhSession) + fprintf(ms_global->dfd, " session number is %p\r\n", *lplhSession); + fclose(ms_global->dfd); + ms_global->dfd = fopen(ms_global->debugFile, "ab"); + if(!ms_global->dfd){ + ms_global->debug = 0; + ErrorBox("Problem with debug file %s! Debugging turned off", + ms_global->debugFile); + fs_give((void **)&ms_global->debugFile); + ms_global->debugFile = NULL; + + } + } + if(lplhSession == NULL){ + if(MSDEBUG){ + fprintf(nmg->dfd, + "lplhSession is a NULL pointer, returning MAPI_E_FAILURE\r\n"); + } + return MAPI_E_FAILURE; + } + if((flFlags & MAPI_NEW_SESSION) || !nmg->sessionlist){ + cs = new_sessionlist(); + *lplhSession = cs->session_number; + + if(nmg->sessionlist == NULL) + nmg->sessionlist = cs; + else{ + ts = nmg->sessionlist; + while(ts->next) ts = ts->next; + ts->next = cs; + } + } + else{ + if(!*lplhSession) *lplhSession = nmg->sessionlist->session_number; + else + cs = get_session(*lplhSession); + if(!cs) + return MAPI_E_INVALID_SESSION; + } + cs->flags.mapi_logon_ui = ((flFlags & MAPI_LOGON_UI) || (flFlags & MAPI_PASSWORD_UI)) + ? 1 : 0; + if((flFlags & MAPI_LOGON_UI) || (flFlags & MAPI_PASSWORD_UI)) + if(InitPineSpecific(cs) == -1) return MAPI_E_FAILURE; + + if(MSDEBUG){ + fprintf(nmg->dfd, + "lplhSession is returning %p for session handle\r\n", *lplhSession); + _flushall(); + } + return SUCCESS_SUCCESS; +} + +ULONG FAR PASCAL MAPILogoff ( + LHANDLE lhSession, + ULONG ulUIParam, + FLAGS flFlags, + ULONG ulReserved) +{ + sessionlist_s *cs; + + if(MSDEBUG){ + fprintf(ms_global->dfd, "\r\nIn MAPILogoff\r\n"); + fprintf(ms_global->dfd, " session number is %p\r\n", lhSession); + _flushall(); + } + + cs = get_session(lhSession); + if(!cs) return MAPI_E_INVALID_SESSION; + if(!cs->open_stream) return SUCCESS_SUCCESS; + cs->open_stream = mail_close_full(cs->open_stream, 0); + cs->open_stream = NULL; + if(cs->currently_open){ + fs_give((void **)&cs->currently_open); + cs->currently_open = NULL; + } + cs->dlge.edit1[0] = '\0'; + cs->dlge.edit2[0] = '\0'; + /* ms_global->flags.passfile_checked = FALSE; */ + return SUCCESS_SUCCESS; +} + +ULONG FAR PASCAL MAPIFindNext ( + LHANDLE lhSession, + ULONG ulUIParam, + LPSTR lpszMessageType, + LPSTR lpszSeedMessageID, + FLAGS flFlags, + ULONG ulReserved, + LPSTR lpszMessageID) +{ + mapi_global_s *nmg = ms_global; + sessionlist_s *cs; + char tmp[1024], tmpseq[1024]; + int msg_found; + unsigned long tmp_msgno, i, cur_msg = 0; + MESSAGECACHE *telt; + + if(MSDEBUG){ + fprintf(nmg->dfd, "\r\nMAPIFindNext Called\r\n"); + fprintf(ms_global->dfd, " MAPI_GUARANTEE_FIFO is %s set\r\n", + flFlags & MAPI_GUARANTEE_FIFO ? "" : "NOT"); + fprintf(ms_global->dfd, " MAPI_LONG_MSGID is %s set\r\n", + flFlags & MAPI_LONG_MSGID ? "" : "NOT"); + fprintf(ms_global->dfd, " MAPI_MAPI_UNREAD_ONLY is %s set\r\n", + flFlags & MAPI_UNREAD_ONLY ? "" : "NOT"); + fprintf(ms_global->dfd, " session number is %p\r\n", lhSession); + fprintf(ms_global->dfd, " ulUIParam is %d\r\n", ulUIParam); + fprintf(ms_global->dfd, "message type is %s\r\n", + lpszMessageType ? lpszMessageType : "NOT SET"); + fprintf(ms_global->dfd, "seed message id is %s\r\n", + lpszSeedMessageID ? lpszSeedMessageID : "NOT SET"); + _flushall(); + } + + cs = get_session(lhSession); + if(!cs){ + if(MSDEBUG) + fprintf(ms_global->dfd, "Session number %p is invalid\r\n", lhSession); + return MAPI_E_INVALID_SESSION; + } + + if(InitPineSpecific(cs) == -1) return MAPI_E_FAILURE; + + if(!check_mailstream(cs)) + return MAPI_E_FAILURE; + if(lpszSeedMessageID == NULL || *lpszSeedMessageID == '\0') + cur_msg = 0; + else{ + cur_msg = convert_to_msgno(lpszSeedMessageID); + } + if(flFlags & MAPI_UNREAD_ONLY){ + if(cur_msg + 1 > cs->open_stream->nmsgs) + return MAPI_E_NO_MESSAGES; + tmp_msgno = cur_msg+1; + msg_found = FALSE; + while(!msg_found && tmp_msgno <= cs->open_stream->nmsgs){ + sprintf(tmp, "%d", tmp_msgno); + strcpy(tmpseq, tmp); + if(tmp_msgno+1 <= cs->open_stream->nmsgs){ + sprintf(tmp,":%d", min(cs->open_stream->nmsgs,tmp_msgno+100)); + strcat(tmpseq, tmp); + } + mail_fetch_flags(cs->open_stream, tmpseq, NIL); + for(i = tmp_msgno; + i <= (unsigned long)min(cs->open_stream->nmsgs,tmp_msgno+100); + i++){ + telt = mail_elt(cs->open_stream, i); + if(telt->seen == 0){ + msg_found = TRUE; + if(MSDEBUG) + fprintf(nmg->dfd, "msgno %d is the next UNREAD message after %d", + i, cur_msg); + break; + } + } + if(!msg_found){ + if(i == cs->open_stream->nmsgs){ + if(MSDEBUG) + fprintf(nmg->dfd,"No UNREAD messages found after %d\r\n", + cur_msg); + return MAPI_E_NO_MESSAGES; + } + tmp_msgno += 100; + } + } + if(msg_found) + cur_msg = i; + else return MAPI_E_NO_MESSAGES; + } + else{ + if(cur_msg+1 > cs->open_stream->nmsgs) + return MAPI_E_NO_MESSAGES; + cur_msg++; + } + + sprintf(lpszMessageID,"%d", cur_msg); + + if(MSDEBUG) + fprintf(nmg->dfd, " Next message found is %d\r\n", cur_msg); + return SUCCESS_SUCCESS; +} + + +ULONG FAR PASCAL MAPIReadMail( + LHANDLE lhSession, + ULONG ulUIParam, + LPSTR lpszMessageID, + FLAGS flFlags, + ULONG ulReserved, + lpMapiMessage FAR *lppMessage) +{ + mapi_global_s *nmg = ms_global; + unsigned rv; + unsigned long msgno = 0, flags; + sessionlist_s *cs; + + if(MSDEBUG){ + fprintf(nmg->dfd, "\r\nIn MAPIReadMail\r\n"); + fprintf(nmg->dfd, " MAPI_PEEK is %s\r\n", + flFlags & MAPI_PEEK ? "TRUE":"FALSE"); + fprintf(nmg->dfd, " MAPI_BODY_AS_FILE is %s\r\n", + flFlags & MAPI_BODY_AS_FILE ? "TRUE":"FALSE"); + fprintf(nmg->dfd, " MAPI_ENVELOPE_ONLY is %s\r\n", + flFlags & MAPI_ENVELOPE_ONLY ? "TRUE":"FALSE"); + fprintf(nmg->dfd, " MAPI_SUPPRESS_ATTACH is %s\r\n", + flFlags & MAPI_SUPPRESS_ATTACH ? "TRUE":"FALSE"); + fprintf(ms_global->dfd, " session number is %p\r\n", lhSession); + _flushall(); + } + + cs = get_session(lhSession); + if(!cs){ + if(MSDEBUG) + fprintf(ms_global->dfd, "Session number %p is invalid\r\n", lhSession); + return MAPI_E_INVALID_SESSION; + } + + if(InitPineSpecific(cs) == -1) return MAPI_E_FAILURE; + + if(!check_mailstream(cs)) + return MAPI_E_FAILURE; + + msgno = convert_to_msgno(lpszMessageID); + + if(msgno == 0){ + if(MSDEBUG) + fprintf(nmg->dfd, "Invalid Message ID: %s\r\n", lpszMessageID); + return MAPI_E_INVALID_MESSAGE; + } + + if(MSDEBUG){ + fprintf(nmg->dfd, "lpszMessageID: %s, converted msgno: %d\r\n", + lpszMessageID, msgno); + } + + if(flFlags & MAPI_PEEK) + flags = FT_PEEK; + else flags = NIL; + + rv = fetch_structure_and_attachments(msgno, flags, flFlags, cs); + if(rv == MAPI_E_FAILURE) + return rv; + else if(rv == SUCCESS_SUCCESS){ + *lppMessage = cs->lpm; + return rv; + } + else + return rv; +} + +ULONG FAR PASCAL MAPIAddress( + LHANDLE lhSession, + ULONG ulUIParam, + LPTSTR lpszCaption, + ULONG nEditFields, + LPTSTR lpszLabels, + ULONG nRecips, + lpMapiRecipDesc lpRecips, + FLAGS flFlags, + ULONG ulReserved, + LPULONG lpnNewRecips, + lpMapiRecipDesc FAR * lppNewRecips) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "\r\nIn MAPIAddress\r\n"); + fprintf(ms_global->dfd, " MAPI_LOGON_UI is %s set\r\n", + flFlags & MAPI_LOGON_UI ? "" : "NOT"); + fprintf(ms_global->dfd, " MAPI_NEW_SESSION is %s set\r\n", + flFlags & MAPI_NEW_SESSION ? "" : "NOT"); + fprintf(ms_global->dfd, " session number is %p\r\n", lhSession); + _flushall(); + } + return MAPI_E_NOT_SUPPORTED; +} + +ULONG FAR PASCAL MAPIDeleteMail( + LHANDLE lhSession, + ULONG ulUIParam, + LPTSTR lpszMessageID, + FLAGS flFlags, + ULONG ulReserved) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "\r\nIn MAPIDeleteMail\r\n"); + fprintf(ms_global->dfd, " session number is %p\r\n", lhSession); + _flushall(); + } + return MAPI_E_NOT_SUPPORTED; +} + +ULONG FAR PASCAL MAPIDetails( + LHANDLE lhSession, + ULONG ulUIParam, + lpMapiRecipDesc lpRecip, + FLAGS flFlags, + ULONG ulReserved) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "\r\nIn MAPIDetails\r\n"); + fprintf(ms_global->dfd, " MAPI_NO_MODIFY is %s set\r\n", + flFlags & MAPI_AB_NOMODIFY ? "" : "NOT"); + fprintf(ms_global->dfd, " MAPI_LOGON_UI is %s set\r\n", + flFlags & MAPI_LOGON_UI ? "" : "NOT"); + fprintf(ms_global->dfd, " MAPI_NEW_SESSION is %s set\r\n", + flFlags & MAPI_NEW_SESSION ? "" : "NOT"); + fprintf(ms_global->dfd, " session number is %p\r\n", lhSession); + _flushall(); + } + return MAPI_E_NOT_SUPPORTED; +} + +ULONG FAR PASCAL MAPIFreeBuffer( + LPVOID pv) +{ + mapi_global_s *nmg = ms_global; + + if(MSDEBUG){ + fprintf(nmg->dfd, "\r\nMAPIFreeBuffer called, buffer is %p\r\n", pv); + _flushall(); + } + free_mbuffer(pv); + return SUCCESS_SUCCESS; +} + +ULONG FAR PASCAL MAPIResolveName( + LHANDLE lhSession, + ULONG ulUIParam, + LPTSTR lpszName, + FLAGS flFlags, + ULONG ulReserved, + lpMapiRecipDesc FAR * lppRecip) +{ + mapi_global_s *nmg = ms_global; + sessionlist_s *cs, *tsession; + static char *fakedomain = "@"; + ADDRESS *adrlist = NULL; + char *adrstr, *tadrstr, *tadrstrbuf; + + if(MSDEBUG){ + fprintf(ms_global->dfd, "\r\nIn MAPIResolveName\r\n"); + fprintf(ms_global->dfd, " MAPI_NO_MODIFY is %sset\r\n", + flFlags & MAPI_AB_NOMODIFY ? "" : "NOT "); + fprintf(ms_global->dfd, " MAPI_DIALOG is %sset\r\n", + flFlags & MAPI_DIALOG ? "" : "NOT "); + fprintf(ms_global->dfd, " MAPI_LOGON_UI is %sset\r\n", + flFlags & MAPI_LOGON_UI ? "" : "NOT "); + fprintf(ms_global->dfd, " MAPI_NEW_SESSION is %sset\r\n", + flFlags & MAPI_NEW_SESSION ? "" : "NOT "); + fprintf(ms_global->dfd, " session number is %p\r\n", lhSession); + fprintf(ms_global->dfd, " String to Resolve is %s\r\n", lpszName); + _flushall(); + } + + if((flFlags & MAPI_NEW_SESSION) || lhSession == 0) + tsession = cs = new_sessionlist(); + else { + cs = get_session(lhSession); + if(!cs){ + if(MSDEBUG) + fprintf(ms_global->dfd, "Session number %p is invalid\r\n", lhSession); + return MAPI_E_INVALID_SESSION; + } + } + cs->flags.mapi_logon_ui = (flFlags & MAPI_LOGON_UI) ? 1 : 0; + if(InitPineSpecific(cs) == -1) return MAPI_E_FAILURE; + tadrstrbuf = tadrstr = mstrdup(lpszName); + removing_leading_and_trailing_white_space(tadrstr); + if(_strnicmp(tadrstr, "SMTP:", 5) == 0){ + tadrstr += 5; + if(tadrstr[0] == '(' && tadrstr[strlen(tadrstr) - 1] == ')'){ + tadrstr[strlen(tadrstr)-1] = '\0'; + tadrstr++; + removing_leading_and_trailing_white_space(tadrstr); + } + } + rfc822_parse_adrlist(&adrlist, tadrstr, + nmg->prcvars[USER_DOMAIN]->val.p ? nmg->prcvars[USER_DOMAIN]->val.p + : fakedomain); + fs_give((void **)&tadrstrbuf); + if(!adrlist || adrlist->next){ /* I guess there aren't supposed to be multiple addresses, */ + /* which is pretty lame */ + mail_free_address(&adrlist); + if(tsession) + fs_give((void **)&tsession); + msprint("Returning MAPI_E_AMBIGUOUS_RECIPIENT\r\n"); + return MAPI_E_AMBIGUOUS_RECIPIENT; + } + if(!adrlist->host || *adrlist->host == '@'){ + mail_free_address(&adrlist); + if(tsession) + fs_give((void **)&tsession); + msprint("Returning MAPI_E_AMBIGUOUS_RECIPIENT\r\n"); + return MAPI_E_AMBIGUOUS_RECIPIENT; + } + + (*lppRecip) = new_MapiRecipDesc(1); + if(adrlist->personal){ + (*lppRecip)->lpszName = mstrdup(adrlist->personal); + adrlist->personal = NULL; + } + adrstr = (char *)fs_get((8 + strlen(adrlist->mailbox) + strlen(adrlist->host)) * sizeof(char)); + sprintf(adrstr, "SMTP:%s@%s", adrlist->mailbox, adrlist->host); + (*lppRecip)->lpszAddress = adrstr; + + /* The spec says it's a recipient, so set the thing to MAPI_TO */ + (*lppRecip)->ulRecipClass = MAPI_TO; + + mail_free_address(&adrlist); + msprint1(" Returning with name: %s\r\n", (*lppRecip)->lpszName ? (*lppRecip)->lpszName : "(no name)"); + msprint1(" address: %s\r\n", (*lppRecip)->lpszAddress ? (*lppRecip)->lpszAddress : "(no address)"); + msprint(" ulRecipClass: MAPI_TO\r\n"); + msprint("Returning SUCCESS_SUCCESS\r\n"); + return SUCCESS_SUCCESS; +} + +ULONG FAR PASCAL MAPISaveMail( + LHANDLE lhSession, + ULONG ulUIParam, + lpMapiMessage lpMessage, + FLAGS flFlags, + ULONG ulReserved, + LPTSTR lpszMessageID) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "\r\nIn MAPISaveMail\r\n"); + fprintf(ms_global->dfd, " MAPI_LOGON_UI is %s set\r\n", + flFlags & MAPI_LOGON_UI ? "" : "NOT"); + fprintf(ms_global->dfd, " MAPI_LONG_MSGID is %s set\r\n", + flFlags & MAPI_LONG_MSGID ? "" : "NOT"); + fprintf(ms_global->dfd, " MAPI_NEW_SESSION is %s set\r\n", + flFlags & MAPI_NEW_SESSION ? "" : "NOT"); + fprintf(ms_global->dfd, " session number is %p\r\n", lhSession); + _flushall(); + } + return MAPI_E_NOT_SUPPORTED; +} + +ULONG FAR PASCAL MAPISendDocuments( + ULONG ulUIParam, + LPTSTR lpszDelimChar, + LPTSTR lpszFullPaths, + LPTSTR lpszFileNames, + ULONG ulReserved) +{ + if(MSDEBUG){ + fprintf(ms_global->dfd, "\r\nIn MAPISendDocuments\r\n"); + fprintf(ms_global->dfd, " lpszDelimChar: %c\r\n", *lpszDelimChar); + fprintf(ms_global->dfd, " lpszFullPaths: %s\r\n", lpszFullPaths); + fprintf(ms_global->dfd, " lpszFileNames: %s\r\n", lpszFileNames); + _flushall(); + } + + return send_documents(lpszFullPaths, *lpszDelimChar); +} |