chimera2/proto/mailto.c

505 lines
10 KiB
C

/*
* mailto.c
*
* Copyright 1997, Dave Davey <daved@physiol.usyd.edu.au>
*
* 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 <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Toggle.h>
#include <X11/Xaw/Label.h>
#include <pwd.h>
#include <unistd.h>
#include <sys/param.h>
#ifdef HAVE_UNAME
#include <sys/utsname.h>
#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 = "<html><body><h2>Mailto</h2><ul>";
}
mc->trailer = ResourceGetString(cres, "mailto.dirtrailer");
if (mc->trailer == NULL) mc->trailer = "</body></html>";
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, "<HTML>\n<HEAD>\n<TITLE>Chimera Mail</TITLE>\n</HEAD>\n");
strcat(f, "<BODY>\n<H1>Chimera Mail</H1>\n<HR>\n");
strcat(f, "<FORM action=\"x-mailtoaction:void\">\n<TABLE>\n");
for(mh = MailHeaders; mh->name != NULL; mh++)
{
strcat(f, "<TR><TD>\n<P>");
strcat(f, mh->name);
strcat(f, ":</TD><TD>\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, "</TD></TR>\n");
}
strcat(f, "</TABLE>\n");
strcat(f, "<INPUT type=submit name=SendMail value=\"Send mail\">\n");
strcat(f, "<INPUT type=submit name=Cancel value=\"Cancel\">\n");
strcat(f, "</FORM>\n</BODY>\n</HTML>\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;
}