/* * mailto.c * * Copyright 1997, Dave Davey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "port_before.h" #include #ifdef HAVE_STDLIB_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_UNAME #include #endif #include "port_after.h" #include "../mxw/TextField.h" #include "common.h" #include "../mxw/MyDialog.h" #include "Chimera.h" #include "ChimeraSource.h" #include "mime.h" /* * hacked by john a little bit so you know where the blames goes. * status messages are ugly. */ typedef struct MailtoInfoP MailtoInfo; typedef struct MailtoActionInfoP MailtoActionInfo; char *URLUnescape(MemPool mp, char *url); static char *sendmail _ArgProto((ChimeraResources, char *)); void InitModule_Mailto _ArgProto((ChimeraResources)); static void MailtoClassDestroy _ArgProto((void *)); static void *MailtoInit _ArgProto((ChimeraSource, ChimeraRequest *, void *)); static void MailtoCancel _ArgProto((void *)); static void MailtoDestroy _ArgProto((void *)); static void MailtoGetData _ArgProto((void *, byte **, size_t *, MIMEHeader *)); static void MakeMailtoForm _ArgProto((void *)); static void *MailtoActionInit _ArgProto((ChimeraSource, ChimeraRequest *, void *)); static void MailtoActionCancel _ArgProto((void *)); static void MailtoActionDestroy _ArgProto((void *)); static void MailtoActionGetData _ArgProto((void *, byte **, size_t *, MIMEHeader *)); typedef struct { MemPool mp; char *header; char *trailer; } MailtoClass; struct MailtoInfoP { MemPool mp; ChimeraSource ws; ChimeraResources cres; ChimeraRequest *wr; MailtoClass *mc; ChimeraTask wt; byte *data; size_t len; byte *address; MIMEHeader mh; }; struct MailtoActionInfoP { MemPool mp; ChimeraSource ws; ChimeraResources cres; ChimeraRequest *wr; ChimeraTask wt; byte *data; size_t len; MIMEHeader mh; }; /* * InitModule_Mailto */ void InitModule_Mailto(cres) ChimeraResources cres; { ChimeraSourceHooks ph; MailtoClass *mc; MemPool mp; mp = MPCreate(); mc = (MailtoClass *)MPCGet(mp, sizeof(MailtoClass)); mc->mp = mp; mc->header = ResourceGetString(cres, "mailto.dirheader"); if (mc->header == NULL) { mc->header = "

Mailto

    "; } mc->trailer = ResourceGetString(cres, "mailto.dirtrailer"); if (mc->trailer == NULL) mc->trailer = ""; memset(&ph, 0, sizeof(ph)); ph.class_closure = mc; ph.class_destroy = MailtoClassDestroy; ph.name = "mailto"; ph.init = MailtoInit; ph.destroy = MailtoDestroy; ph.stop = MailtoCancel; ph.getdata = MailtoGetData; SourceAddHooks(cres, &ph); memset(&ph, 0, sizeof(ph)); ph.name = "x-mailtoaction"; ph.init = MailtoActionInit; ph.destroy = MailtoActionDestroy; ph.stop = MailtoActionCancel; ph.getdata = MailtoActionGetData; SourceAddHooks(cres, &ph); return; } /* * MailtoClassDestroy */ static void MailtoClassDestroy(closure) void *closure; { MailtoClass *mc = (MailtoClass *)closure; MPDestroy(mc->mp); return; } /* * MailtoInit */ static void * MailtoInit(ws, wr, class_closure) ChimeraSource ws; ChimeraRequest *wr; void *class_closure; { /* ** get here when click on mailto link ** wr->url points to url including "mailto" */ MailtoInfo *mi; MemPool mp; ChimeraTaskProc func; char *p; if((p = strchr(wr->url, ':')) == NULL) return(NULL); mp = MPCreate(); mi = (MailtoInfo *)MPCGet(mp, sizeof(MailtoInfo)); mi->address = p+1; mi->mp = mp; mi->ws = ws; mi->wr = wr; mi->cres = SourceToResources(ws); mi->mc = (MailtoClass *)class_closure; func = MakeMailtoForm; mi->wt = TaskSchedule(mi->cres, func, mi); mi->mh = MIMECreateHeader(); MIMEAddField(mi->mh, "content-type", "text/html"); MIMEAddField(mi->mh, "x-url", mi->wr->url); return(mi); } /* * MailtoCancel */ static void MailtoCancel(closure) void *closure; { /* nothing to do here ? */ /* what if sendmail "hangs" ? */ return; } /* * MailtoDestroy */ static void MailtoDestroy(closure) void *closure; { MailtoInfo *mi = (MailtoInfo *)closure; if (mi->wt != NULL) TaskRemove(mi->cres, mi->wt); MPDestroy(mi->mp); return; } static void MailtoGetData(closure, data, len, mh) void *closure; byte **data; size_t *len; MIMEHeader *mh; { MailtoInfo *mi = (MailtoInfo *)closure; *data = mi->data; *len = mi->len; *mh = mi->mh; return; } enum { FROM, TO, CC, SUBJECT, MESSAGE }; struct MailHeader { char *name; char *contents; char *input_type; } MailHeaders[] = { { "From", "", "INPUT size=64" }, { "To", "", "INPUT size=64" }, { "Cc", "", "INPUT size=64" }, { "Subject", "", "INPUT size=64" }, { "Message", "", "TEXTAREA rows=20 cols=64" }, { NULL, NULL } }; /* * MakeMailForm */ static void MakeMailtoForm(closure) void *closure; { char *f; MailtoInfo *mi = (MailtoInfo *)closure; struct passwd *p; #ifdef HAVE_UNAME struct utsname uts; #endif char *sender; char *username; struct MailHeader *mh; if ((sender = ResourceGetString(mi->cres, "user.email")) == NULL) { #ifdef HAVE_UNAME if((p = getpwuid(getuid())) == NULL) username = "nobody"; else username = p->pw_name; uname(&uts); sender = (char *)MPCGet(mi->mp, strlen(username) + strlen(uts.nodename) + 2); strcpy(sender, username); strcat(sender, "@"); strcat(sender, uts.nodename); #else sender = ""; #endif } MailHeaders[FROM].contents = sender; MailHeaders[TO].contents = mi->address; MailHeaders[CC].contents = ""; MailHeaders[SUBJECT].contents = mi->wr->parent_url; MailHeaders[MESSAGE].contents = ""; f = (char *)MPCGet(mi->mp, BUFSIZ); strcpy(f, "\n\nChimera Mail\n\n"); strcat(f, "\n

    Chimera Mail

    \n
    \n"); strcat(f, "
    \n\n"); for(mh = MailHeaders; mh->name != NULL; mh++) { strcat(f, "\n"); } strcat(f, "
    \n

    "); strcat(f, mh->name); strcat(f, ":

    \n<"); strcat(f, mh->input_type); strcat(f, " name=\""); strcat(f, mh->name); strcat(f, "\" type=\"text\" value=\""); if(mh->contents) strcat(f, mh->contents); strcat(f, "\">\n"); strcat(f, "
    \n"); strcat(f, "\n"); strcat(f, "\n"); strcat(f, "
    \n\n\n"); mi->data = (byte *)f; mi->len = strlen(f); SourceInit(mi->ws, false); SourceEnd(mi->ws); mi->wt = NULL; return; } static void MailtoAction(closure) void *closure; { MailtoActionInfo *mi = (MailtoActionInfo *)closure; char *f; if (strstr(mi->wr->input_data, "Cancel") != NULL) { f = "mail cancelled by the user"; } else if (strstr(mi->wr->input_data, "SendMail") != NULL) { f = sendmail(mi->cres, mi->wr->input_data); } else f = "unexpected input_data"; mi->data = (byte *)f; mi->len = strlen(f); SourceInit(mi->ws, false); SourceEnd(mi->ws); mi->wt = NULL; return; } static char * sendmail(cres, data) ChimeraResources cres; char *data; { MemPool mp; FILE *fp; char *p; struct MailHeader *mh; char *mailer; char *f; if ((mailer = ResourceGetString(cres, "mailto.mailer")) == NULL) { #ifdef __EMX__ mailer = "sendmail -t"; #else mailer = "/usr/lib/sendmail -t"; #endif } if ((fp = popen(mailer, "w")) != NULL) { mp = MPCreate(); mh = MailHeaders; for(mh = MailHeaders; mh->name != NULL; mh++) { p = strstr(data, mh->name) + strlen(mh->name) + 1; data = strchr(data, '&'); *data++ = '\0'; mh->contents = URLUnescape(mp, p); if(strcmp(mh->name, "Message") == 0) fprintf(fp, "X-Mailer: Chimera\n\n"); else { if(mh->contents == NULL || strlen(mh->contents) == 0) continue; fprintf(fp,"%s: ", mh->name); } fprintf(fp, "%s\n", mh->contents); } /* signature ?? */ pclose(fp); MPDestroy(mp); f = "mail sent"; } else f = "popen() failed"; return(f); } /* * MailtoActionInit */ static void * MailtoActionInit(ws, wr, class_closure) ChimeraSource ws; ChimeraRequest *wr; void *class_closure; { /* ** get here when click on mailto link ** wr->url points to url including "x-mailtoaction" */ MailtoActionInfo *mi; MemPool mp; ChimeraTaskProc func; mp = MPCreate(); mi = (MailtoActionInfo *)MPCGet(mp, sizeof(MailtoActionInfo)); mi->mp = mp; mi->ws = ws; mi->wr = wr; mi->cres = SourceToResources(ws); func = MailtoAction; mi->wt = TaskSchedule(mi->cres, func, mi); mi->mh = MIMECreateHeader(); MIMEAddField(mi->mh, "content-type", "text/plain"); MIMEAddField(mi->mh, "x-url", mi->wr->url); return(mi); } /* * MailtoActionCancel */ static void MailtoActionCancel(closure) void *closure; { /* nothing to do here ? */ /* what if sendmail "hangs" ? */ return; } /* * MailtoActionDestroy */ static void MailtoActionDestroy(closure) void *closure; { MailtoActionInfo *mi = (MailtoActionInfo *)closure; if (mi->wt != NULL) TaskRemove(mi->cres, mi->wt); MPDestroy(mi->mp); return; } static void MailtoActionGetData(closure, data, len, mh) void *closure; byte **data; size_t *len; MIMEHeader *mh; { MailtoActionInfo *mi = (MailtoActionInfo *)closure; *data = mi->data; *len = mi->len; *mh = mi->mh; return; }