#include <X11/Xaw/Cardinals.h>
#include "xmh.h"
#include "tocintrnl.h"
#include "actions.h"
static int SetScrn(Msg, Scrn, Boolean, XtCallbackList, XtCallbackList);
static void
SetEditable(Msg msg, Boolean edit)
{
Arg args[1];
if (edit)
XtSetArg(args[0], XtNeditType, XawtextEdit);
else
XtSetArg(args[0], XtNeditType, XawtextRead);
XtSetValues(msg->source, args, ONE);
}
static Boolean
IsEditable(Msg msg)
{
Arg args[1];
XawTextEditType type;
XtSetArg(args[0], XtNeditType, &type);
XtGetValues(msg->source, args, ONE);
return(type == XawtextEdit);
}
char *MsgName(Msg msg)
{
static char result[100];
(void) sprintf(result, "%s:%d", msg->toc->foldername, msg->msgid);
return result;
}
static void ResetMsgLabel(Scrn scrn)
{
Msg msg;
char str[200];
if (scrn) {
msg = scrn->msg;
if (msg == NULL) (void) strcpy(str, app_resources.banner);
else {
(void) strcpy(str, MsgName(msg));
switch (msg->fate) {
case Fdelete:
(void) strcat(str, " -> *Delete*");
break;
case Fcopy:
case Fmove:
(void) strcat(str, " -> ");
(void) strcat(str, msg->desttoc->foldername);
if (msg->fate == Fcopy)
(void) strcat(str, " (Copy)");
default:
break;
}
if (msg->temporary) (void)strcat(str, " [Temporary]");
}
ChangeLabel((Widget) scrn->viewlabel, str);
}
}
static void RedisplayMsg(Scrn scrn)
{
Msg msg;
XawTextPosition startPos, lastPos, nextPos;
int length; char str[100];
XawTextBlock block;
if (scrn) {
msg = scrn->msg;
if (msg) {
startPos = 0;
if (app_resources.hide_boring_headers && scrn->kind != STcomp) {
lastPos = XawTextSourceScan(msg->source, (XawTextPosition) 0,
XawstAll, XawsdRight, 1, FALSE);
while (startPos < lastPos) {
nextPos = startPos;
length = 0;
while (length < 8 && nextPos < lastPos) {
nextPos = XawTextSourceRead(msg->source, nextPos,
&block, 8 - length);
(void) strncpy(str + length, block.ptr, block.length);
length += block.length;
}
if (length == 8) {
if (strncmp(str, "From:", 5) == 0 ||
strncmp(str, "To:", 3) == 0 ||
strncmp(str, "Date:", 5) == 0 ||
strncmp(str, "Subject:", 8) == 0) break;
}
startPos = XawTextSourceScan(msg->source, startPos,
XawstEOL, XawsdRight, 1, TRUE);
}
if (startPos >= lastPos) startPos = 0;
}
XawTextSetSource(scrn->viewwidget, msg->source, startPos);
if (msg->startPos > 0) {
XawTextSetInsertionPoint(scrn->viewwidget, msg->startPos);
msg->startPos = 0;
}
} else {
XawTextSetSource(scrn->viewwidget, PNullSource,
(XawTextPosition)0);
}
}
}
static char tempDraftFile[100] = "";
static void TempMoveDraft(void)
{
char *ptr;
if (FileExists(draftFile)) {
do {
ptr = MakeNewTempFileName();
(void) strcpy(tempDraftFile, draftFile);
(void) strcpy(strrchr(tempDraftFile, '/'), strrchr(ptr, '/'));
} while (FileExists(tempDraftFile));
RenameAndCheck(draftFile, tempDraftFile);
}
}
static void RestoreDraft(void)
{
if (*tempDraftFile) {
RenameAndCheck(tempDraftFile, draftFile);
*tempDraftFile = 0;
}
}
char *MsgFileName(Msg msg)
{
static char result[500];
(void) sprintf(result, "%s/%d", msg->toc->path, msg->msgid);
return result;
}
int MsgSaveChanges(Msg msg)
{
int i;
Window w;
if (msg->source) {
if (XawAsciiSave(msg->source)) {
for (i=0; i < (int) msg->num_scrns; i++)
EnableProperButtons(msg->scrn[i]);
if (!msg->temporary)
TocMsgChanged(msg->toc, msg);
return True;
}
else {
char str[256];
(void) sprintf(str, "Cannot save changes to \"%s/%d\"!",
msg->toc->foldername, msg->msgid);
PopupError((Widget)NULL, str);
return False;
}
}
w= (msg->source?XtWindow(msg->source):None);
Feep(XkbBI_Failure,0,w);
return False;
}
static void ConfirmedNoScrn(
Widget widget,
XtPointer client_data,
XtPointer call_data)
{
Msg msg = (Msg) client_data;
register int i;
for (i=msg->num_scrns - 1 ; i >= 0 ; i--)
SetScrn((Msg)NULL, msg->scrn[i], TRUE, (XtCallbackList) NULL,
(XtCallbackList) NULL);
}
static void RemoveMsgConfirmed(Scrn scrn)
{
if (scrn->kind == STtocAndView && MsgChanged(scrn->msg)) {
Arg args[1];
XtSetArg(args[0], XtNtranslations, scrn->read_translations);
XtSetValues(scrn->viewwidget, args, (Cardinal) 1);
}
scrn->msg->scrn[0] = NULL;
scrn->msg->num_scrns = 0;
XawTextSetSource(scrn->viewwidget, PNullSource, (XawTextPosition) 0);
XtDestroyWidget(scrn->msg->source);
scrn->msg->source = NULL;
if (scrn->msg->temporary) {
(void) unlink(MsgFileName(scrn->msg));
TocRemoveMsg(scrn->msg->toc, scrn->msg);
MsgFree(scrn->msg);
}
}
static void SetScrnNewMsg(
Msg msg,
Scrn scrn)
{
scrn->msg = msg;
if (msg == NULL) {
XawTextSetSource(scrn->viewwidget, PNullSource, (XawTextPosition) 0);
ResetMsgLabel(scrn);
EnableProperButtons(scrn);
if (scrn->kind != STtocAndView && scrn->kind != STcomp) {
StoreWindowName(scrn, progName);
DestroyScrn(scrn);
}
} else {
msg->num_scrns++;
msg->scrn = (Scrn *) XtRealloc((char *)msg->scrn,
(unsigned) sizeof(Scrn)*msg->num_scrns);
msg->scrn[msg->num_scrns - 1] = scrn;
if (msg->source == NULL)
msg->source = CreateFileSource(scrn->viewwidget, MsgFileName(msg),
scrn->kind == STcomp);
ResetMsgLabel(scrn);
RedisplayMsg(scrn);
EnableProperButtons(scrn);
if (scrn->kind != STtocAndView)
StoreWindowName(scrn, MsgName(msg));
}
}
typedef struct _MsgAndScrn {
Msg msg;
Scrn scrn;
} MsgAndScrnRec, *MsgAndScrn;
static void ConfirmedWithScrn(
Widget widget,
XtPointer client_data,
XtPointer call_data)
{
MsgAndScrn mas = (MsgAndScrn) client_data;
RemoveMsgConfirmed(mas->scrn);
SetScrnNewMsg(mas->msg, mas->scrn);
XtFree((char *) mas);
}
static int SetScrn(
Msg msg,
Scrn scrn,
Boolean force,
XtCallbackList confirms,
XtCallbackList cancels)
{
register int i, num_scrns;
static XtCallbackRec yes_callbacks[] = {
{(XtCallbackProc) NULL, (XtPointer) NULL},
{(XtCallbackProc) NULL, (XtPointer) NULL},
{(XtCallbackProc) NULL, (XtPointer) NULL}
};
if (scrn == NULL) {
if (msg == NULL || msg->num_scrns == 0) return 0;
if (!force && XawAsciiSourceChanged(msg->source)) {
char str[100];
(void) sprintf(str,
"Are you sure you want to remove changes to %s?",
MsgName(msg));
yes_callbacks[0].callback = ConfirmedNoScrn;
yes_callbacks[0].closure = (XtPointer) msg;
yes_callbacks[1].callback = confirms[0].callback;
yes_callbacks[1].closure = confirms[0].closure;
PopupConfirm((Widget) NULL, str, yes_callbacks, cancels);
return NEEDS_CONFIRMATION;
}
ConfirmedNoScrn((Widget)NULL, (XtPointer) msg, (XtPointer) NULL);
return 0;
}
if (scrn->msg == msg) return 0;
if (scrn->msg) {
num_scrns = scrn->msg->num_scrns;
for (i=0 ; i<num_scrns ; i++)
if (scrn->msg->scrn[i] == scrn) break;
if (i >= num_scrns) Punt("Couldn't find scrn in SetScrn!");
if (num_scrns > 1)
scrn->msg->scrn[i] = scrn->msg->scrn[--(scrn->msg->num_scrns)];
else {
if (!force && XawAsciiSourceChanged(scrn->msg->source)) {
char str[100];
MsgAndScrn cb_data;
cb_data = XtNew(MsgAndScrnRec);
cb_data->msg = msg;
cb_data->scrn = scrn;
(void)sprintf(str,
"Are you sure you want to remove changes to %s?",
MsgName(scrn->msg));
yes_callbacks[0].callback = ConfirmedWithScrn;
yes_callbacks[0].closure = (XtPointer) cb_data;
yes_callbacks[1].callback = confirms[0].callback;
yes_callbacks[1].closure = confirms[0].closure;
PopupConfirm(scrn->viewwidget, str, yes_callbacks, cancels);
return NEEDS_CONFIRMATION;
}
RemoveMsgConfirmed(scrn);
}
}
SetScrnNewMsg(msg, scrn);
return 0;
}
int MsgSetScrn(
Msg msg,
Scrn scrn,
XtCallbackList confirms,
XtCallbackList cancels)
{
return SetScrn(msg, scrn, FALSE, confirms, cancels);
}
void MsgSetScrnForComp(Msg msg, Scrn scrn)
{
(void) SetScrn(msg, scrn, FALSE, (XtCallbackList) NULL,
(XtCallbackList) NULL);
}
void MsgSetScrnForce(Msg msg, Scrn scrn)
{
(void) SetScrn(msg, scrn, TRUE, (XtCallbackList) NULL,
(XtCallbackList) NULL);
}
void MsgSetFate(Msg msg, FateType fate, Toc desttoc)
{
Toc toc = msg->toc;
XawTextBlock block;
int i;
msg->fate = fate;
msg->desttoc = desttoc;
if (fate == Fignore && msg == msg->toc->curmsg)
block.ptr = "+";
else {
switch (fate) {
case Fignore: block.ptr = " "; break;
case Fcopy: block.ptr = "C"; break;
case Fmove: block.ptr = "^"; break;
case Fdelete: block.ptr = "D"; break;
}
}
block.firstPos = 0;
block.format = FMT8BIT;
block.length = 1;
if (toc->stopupdate)
toc->needsrepaint = TRUE;
if (toc->num_scrns && msg->visible && !toc->needsrepaint &&
*block.ptr != msg->buf[MARKPOS])
(void)XawTextReplace(msg->toc->scrn[0]->tocwidget,
msg->position + MARKPOS,
msg->position + MARKPOS + 1, &block);
else
msg->buf[MARKPOS] = *block.ptr;
for (i=0; i < (int) msg->num_scrns; i++)
ResetMsgLabel(msg->scrn[i]);
}
FateType MsgGetFate(Msg msg, Toc *toc)
{
if (toc) *toc = msg->desttoc;
return msg->fate;
}
void MsgSetTemporary(Msg msg)
{
int i;
msg->temporary = TRUE;
for (i=0; i < (int) msg->num_scrns; i++)
ResetMsgLabel(msg->scrn[i]);
}
void MsgSetPermanent(Msg msg)
{
int i;
msg->temporary = FALSE;
for (i=0; i < (int) msg->num_scrns; i++)
ResetMsgLabel(msg->scrn[i]);
}
int MsgGetId(Msg msg)
{
return msg->msgid;
}
char *MsgGetScanLine(Msg msg)
{
return msg->buf;
}
Toc MsgGetToc(Msg msg)
{
return msg->toc;
}
void MsgSetReapable(Msg msg)
{
int i;
msg->reapable = TRUE;
for (i=0; i < (int) msg->num_scrns; i++)
EnableProperButtons(msg->scrn[i]);
}
void MsgClearReapable(Msg msg)
{
int i;
msg->reapable = FALSE;
for (i=0; i < (int) msg->num_scrns; i++)
EnableProperButtons(msg->scrn[i]);
}
int MsgGetReapable(Msg msg)
{
return msg == NULL || (msg->reapable &&
(msg->source == NULL ||
!XawAsciiSourceChanged(msg->source)));
}
void MsgSetEditable(Msg msg)
{
int i;
if (msg && msg->source) {
SetEditable(msg, TRUE);
for (i=0; i < (int) msg->num_scrns; i++)
EnableProperButtons(msg->scrn[i]);
}
}
void MsgClearEditable(Msg msg)
{
int i;
if (msg && msg->source) {
SetEditable(msg, FALSE);
for (i=0; i < (int) msg->num_scrns; i++)
EnableProperButtons(msg->scrn[i]);
}
}
int MsgGetEditable(Msg msg)
{
return msg && msg->source && IsEditable(msg);
}
int MsgChanged(Msg msg)
{
return msg && msg->source && XawAsciiSourceChanged(msg->source);
}
void
MsgSetCallOnChange(Msg msg, void (*func)(XMH_CB_ARGS), XtPointer param)
{
Arg args[1];
static XtCallbackRec cb[] = { {NULL, NULL}, {NULL, NULL} };
if (func != NULL) {
cb[0].callback = func;
cb[0].closure = param;
XtSetArg(args[0], XtNcallback, cb);
}
else
XtSetArg(args[0], XtNcallback, NULL);
XtSetValues(msg->source, args, (Cardinal) 1);
}
void MsgSend(Msg msg)
{
FILEPTR from;
FILEPTR to;
int p, c, l, inheader, sendwidth, sendbreakwidth;
char *ptr, *ptr2, **argv, str[100];
static int sendcount = -1;
(void) MsgSaveChanges(msg);
from = FOpenAndCheck(MsgFileName(msg), "r");
sendcount = (sendcount + 1) % 10;
(void) sprintf(str, "%s%d", xmhDraftFile, sendcount);
to = FOpenAndCheck(str, "w");
sendwidth = app_resources.send_line_width;
sendbreakwidth = app_resources.break_send_line_width;
inheader = TRUE;
while ((ptr = ReadLine(from))) {
if (inheader) {
if (strncmpIgnoringCase(ptr, "sendwidth:", 10) == 0) {
if (atoi(ptr+10) > 0) sendwidth = atoi(ptr+10);
continue;
}
if (strncmpIgnoringCase(ptr, "sendbreakwidth:", 15) == 0) {
if (atoi(ptr+15) > 0) sendbreakwidth = atoi(ptr+15);
continue;
}
for (l = 0, ptr2 = ptr ; *ptr2 && !l ; ptr2++)
l = (*ptr2 != ' ' && *ptr2 != '\t' && *ptr != '-');
if (l) {
(void) fprintf(to, "%s\n", ptr);
continue;
}
inheader = FALSE;
if (sendbreakwidth < sendwidth) sendbreakwidth = sendwidth;
}
do {
for (p = c = l = 0, ptr2 = ptr;
*ptr2 && c < sendbreakwidth;
p++, ptr2++) {
if (*ptr2 == ' ' && c < sendwidth)
l = p;
if (*ptr2 == '\t') {
if (c < sendwidth) l = p;
c += 8 - (c % 8);
}
else
c++;
}
if (c < sendbreakwidth) {
(void) fprintf(to, "%s\n", ptr);
*ptr = 0;
}
else
if (l) {
ptr[l] = 0;
(void) fprintf(to, "%s\n", ptr);
ptr += l + 1;
}
else {
for (c = 0; c < sendwidth; ) {
if (*ptr == '\t') c += 8 - (c % 8);
else c++;
(void) fputc(*ptr++, to);
}
(void) fputc('\n', to);
}
} while (*ptr);
}
myfclose(from);
myfclose(to);
argv = MakeArgv(3);
argv[0] = "send";
argv[1] = "-push";
argv[2] = str;
DoCommand(argv, (char *) NULL, (char *) NULL);
XtFree((char *) argv);
}
void MsgLoadComposition(Msg msg)
{
static char *blankcomp = NULL;
static int compsize = 0;
static XawTextPosition startPos;
char *file, **argv;
int fid;
if (blankcomp == NULL) {
file = MakeNewTempFileName();
argv = MakeArgv(5);
argv[0] = "comp";
argv[1] = "-file";
argv[2] = file;
argv[3] = "-nowhatnowproc";
argv[4] = "-nodraftfolder";
DoCommand(argv, (char *) NULL, (char *) NULL);
XtFree((char *) argv);
compsize = GetFileLength(file);
if (compsize > 0) {
blankcomp = XtMalloc((Cardinal) compsize);
fid = myopen(file, O_RDONLY, 0666);
if (compsize != read(fid, blankcomp, compsize))
Punt("Error reading in MsgLoadComposition!");
myclose(fid);
DeleteFileAndCheck(file);
} else {
blankcomp = "To: \n--------\n";
compsize = strlen(blankcomp);
}
startPos = strchr(blankcomp, '\n') - blankcomp;
}
fid = myopen(MsgFileName(msg), O_WRONLY | O_TRUNC | O_CREAT, 0666);
if (compsize != write(fid, blankcomp, compsize))
Punt("Error writing in MsgLoadComposition!");
myclose(fid);
TocSetCacheValid(msg->toc);
msg->startPos = startPos;
}
void MsgLoadReply(
Msg msg,
Msg frommsg,
String *params,
Cardinal num_params)
{
char **argv;
char str[100];
int status;
TempMoveDraft();
argv = MakeArgv(5 + num_params);
argv[0] = "repl";
argv[1] = TocMakeFolderName(frommsg->toc);
(void) sprintf(str, "%d", frommsg->msgid);
argv[2] = str;
argv[3] = "-nowhatnowproc";
argv[4] = "-nodraftfolder";
memmove( (char *)(argv + 5), (char *)params, num_params * sizeof(String *));
status = DoCommand(argv, (char *) NULL, (char *) NULL);
XtFree(argv[1]);
XtFree((char*)argv);
if (!status) {
RenameAndCheck(draftFile, MsgFileName(msg));
RestoreDraft();
TocSetCacheValid(frommsg->toc);
TocSetCacheValid(msg->toc);
msg->startPos = GetFileLength(MsgFileName(msg));
}
}
void MsgLoadForward(
Scrn scrn,
Msg msg,
MsgList mlist,
String *params,
Cardinal num_params)
{
char **argv, str[100];
int i;
TempMoveDraft();
argv = MakeArgv(4 + mlist->nummsgs + num_params);
argv[0] = "forw";
argv[1] = TocMakeFolderName(mlist->msglist[0]->toc);
for (i = 0; i < mlist->nummsgs; i++) {
(void) sprintf(str, "%d", mlist->msglist[i]->msgid);
argv[2 + i] = XtNewString(str);
}
argv[2 + i] = "-nowhatnowproc";
argv[3 + i] = "-nodraftfolder";
memmove( (char *)(argv + 4 + i), (char *)params,
num_params * sizeof(String *));
DoCommand(argv, (char *) NULL, (char *) NULL);
for (i = 1; i < 2 + mlist->nummsgs; i++)
XtFree((char *) argv[i]);
XtFree((char *) argv);
RenameAndCheck(draftFile, MsgFileName(msg));
RestoreDraft();
TocSetCacheValid(msg->toc);
msg->source = CreateFileSource(scrn->viewlabel, MsgFileName(msg), True);
msg->startPos = XawTextSourceScan(msg->source, (XawTextPosition) 0,
XawstEOL, XawsdRight, 1, False);
}
void MsgLoadCopy(Msg msg, Msg frommsg)
{
char str[500];
(void)strcpy(str, MsgFileName(msg));
CopyFileAndCheck(MsgFileName(frommsg), str);
TocSetCacheValid(msg->toc);
}
void MsgCheckPoint(Msg msg)
{
int len;
char file[500];
if (!msg || !msg->source || !IsEditable(msg) ||
!XawAsciiSourceChanged(msg->source))
return;
if (*app_resources.checkpoint_name_format == '/') {
(void) sprintf(file, app_resources.checkpoint_name_format, msg->msgid);
} else {
(void) sprintf(file, "%s/", msg->toc->path);
len = strlen(file);
(void) sprintf(file + len, app_resources.checkpoint_name_format,
msg->msgid);
}
if (!XawAsciiSaveAsFile(msg->source, file)) {
char str[256];
(void) sprintf(str, "Unsaved edits cannot be checkpointed to %s.",
file);
PopupError((Widget)NULL, str);
}
TocSetCacheValid(msg->toc);
}
void MsgFree(Msg msg)
{
XtFree(msg->buf);
XtFree((char *)msg);
}
void XmhInsert(
Widget w,
XEvent *event,
String *params,
Cardinal *num_params)
{
Scrn scrn = ScrnFromWidget(w);
Msg msg = scrn->msg;
XawTextPosition pos;
XawTextBlock block;
if (msg == NULL || scrn->assocmsg == NULL) return;
if (app_resources.insert_filter && *app_resources.insert_filter) {
char command[1024];
char *argv[4];
argv[0] = "/bin/sh";
argv[1] = "-c";
sprintf(command, "%s %s", app_resources.insert_filter,
MsgFileName(scrn->assocmsg));
argv[2] = command;
argv[3] = 0;
block.ptr = DoCommandToString(argv);
block.length = strlen(block.ptr);
}
else {
block.ptr = XtNewString(MsgFileName(scrn->assocmsg));
block.length = strlen(block.ptr);
}
block.firstPos = 0;
block.format = FMT8BIT;
pos = XawTextGetInsertionPoint(scrn->viewwidget);
if (XawTextReplace(scrn->viewwidget, pos, pos, &block) != XawEditDone)
PopupError(scrn->parent, "Insertion failed!");
XtFree(block.ptr);
}
Widget
CreateFileSource(Widget w, String filename, Boolean edit)
{
Arg arglist[10];
Cardinal num_args = 0;
XtSetArg(arglist[num_args], XtNtype, XawAsciiFile); num_args++;
XtSetArg(arglist[num_args], XtNstring, filename); num_args++;
if (edit)
XtSetArg(arglist[num_args], XtNeditType, XawtextEdit);
else
XtSetArg(arglist[num_args], XtNeditType, XawtextRead);
num_args++;
return(XtCreateWidget("textSource", asciiSrcObjectClass, w,
arglist, num_args));
}