/* * ======================================================================== * 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.24.1\r\n"); fprintf(ms_global->dfd, " Build date: %s\r\n", datestamp); fprintf(ms_global->dfd, " please report all bugs to chappa@gmx.com\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 * , * * 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 guaranteed 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,"", (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); }