home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
x
/
volume13
/
xmail
/
part05
/
parser.c
< prev
Wrap
C/C++ Source or Header
|
1991-06-15
|
17KB
|
466 lines
/*
* xmail - X window system interface to the mail program
*
* Copyright 1989 The University of Texas at Austin
*
* Author: Po Cheung
* Date: March 10, 1989
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation. The University of Texas at Austin makes no
* representations about the suitability of this software for any purpose.
* It is provided "as is" without express or implied warranty.
*
* Copyright 1990 by National Semiconductor Corporation
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of National Semiconductor Corporation not
* be used in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
*
* NATIONAL SEMICONDUCTOR CORPORATION MAKES NO REPRESENTATIONS ABOUT THE
* SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. IT IS PROVIDED "AS IS"
* WITHOUT EXPRESS OR IMPLIED WARRANTY. NATIONAL SEMICONDUCTOR CORPORATION
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO
* EVENT SHALL NATIONAL SEMICONDUCTOR CORPORATION BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* Author: Michael C. Wagnitz - National Semiconductor Corporation
*
*/
#define PARSER
#include "global.h"
#include "regex.h"
#include "xmailregex.h"
#define BYTEWIDTH 8
#define RE_BUFFER 100
extern void reset_mailbox();
/*
** @(#)compile() - regular expression patterns into a pattern table.
** A pattern table is an array of pattern records.
** Each pattern record consists of a regular expression,
** and a buffer for the to-be-compiled regular expression,
*/
static void
compile(patternTable)
PatternRec *patternTable;
{
PatternRec *p;
char fastmap[(1 << BYTEWIDTH)];
int i;
for (i=0; patternTable[i].pat; i++) {
p = &patternTable[i];
p->buf = (struct re_pattern_buffer *)
XtMalloc (sizeof (struct re_pattern_buffer));
p->buf->allocated = RE_BUFFER;
p->buf->buffer = (char *) XtMalloc (p->buf->allocated);
p->buf->fastmap = fastmap;
p->buf->translate = NULL;
re_compile_pattern(p->pat, strlen(p->pat), p->buf);
re_compile_fastmap(p->buf);
}
}
/*
** @(#)match() - string against regular expressions in pattern table.
** The best match is found, and function returns index to the pattern table.
*/
int
match(patternTable, string)
PatternRec *patternTable;
char *string;
{
int m, bestmatch = -1, index = -1, i;
if (strcmp(string, "") == NULL) return -1;
for (i=0; patternTable[i].pat; i++) {
m = re_match(patternTable[i].buf, string, strlen(string), 0, NULL);
if (m > bestmatch) {
bestmatch = m;
index = i;
}
}
return index;
}
/*
** @(#)parser_init()- compile output and command pattern tables.
*/
void
parser_init()
{
compile(output_pattern);
compile(command_pattern);
}
/*
** @(#)parse() - command and output and call appropriate handler
*/
void
parse(msg)
String msg;
{
Cardinal j, k, msgnum;
Widget button, icon, iw;
char tmp[128], *c, *s;
static Boolean first_time = True;
j = match(command_pattern, Command);
switch (j) {
/*
** If error on startup, mail has terminated connection. Remove our input
** handler, close the file from our end, and indicate that no connection
** exists. Otherwise, establish conversation requirements and display the
** current message. If *Show_Last: resource is NOT False, show latest, if
** none are newer. We delay setting the icon event handler until now, to
** ensure mail startup completed before being interrupted by a map event,
** for the case where we have been started iconic.
*/
case C_START : if (O_BELL == match(output_pattern, msg)) {
if (mailpid) {
XtRemoveInput(mailInputId);
close(mail_fd);
mailpid = 0;
}
LASTCH(msg) = '\0'; /* Don't ring Bell() for this */
Bell(msg);
(void) UpdateTitleBar("No current folder");
XtFree(msg);
*msg = '\0';
} else {
/*
** To prevent a race condition (?) when starting the application iconic,
** (which would cause this loop to repeat multiple times), test the value
** of the ``screen'' mail environment variable. If 10,000 then we're done.
*/
j = True;
if (c = GetMailEnv("screen")) {
j = (strcmp("10000", c) != 0) ? True : False;
XtFree(c);
}
if (j) { /* if not yet set to 10000... */
strcpy(tmp, "set screen=10000 toplines=100 ");
/* default action for xmail is hold (ala mailtool) */
if (c = GetMailrc("nohold")) XtFree(c);
else strcat(tmp, "hold");
c = QueryMail(tmp);
XtFree(c);
strcpy(tmp, "unset crt replyall");
c = QueryMail(tmp);
XtFree(c);
if (msgnum = file_handler()) {
sprintf(tmp, "%d", msgnum);
XtFree(msg);
msg = QueryMail(tmp);
}
Bell(""); /* reset any worthy-ness flag */
Bell(Default_Status_Info);
}
}
if (first_time) { /* only need to do this once */
first_time = False;
icon = XtNameToWidget(toplevel, "icon");
XtAddEventHandler(icon, StructureNotifyMask, False,
icon_handler, NULL);
if (In_Bogus_Mail_File) {
unlink(sprintf(tmp, "%s+", tmpName));
XtFree(msg);
*msg = '\0'; /* ignore 'skipping' message */
}
}
break;
/*
** In response to normal or change folder commands, test output. If an
** error, display message in status window, and ring bell unless command
** was save, Save to author, or undelete. If our current mail message
** folder is the bogus folder, erase any text and index and note state.
** If we have text of next mail message, tell index_handler to mark its
** number, else retrieve the appropriate message text (which also marks
** its number). If *Show_Last: resource is NOT False, file cmd shows
** latest, if none new.
*/
case C_EXEC :
case C_FILE : j = match(output_pattern, msg);
switch (j) {
case O_BELL :
if (strchr("Ssu", *Command))
LASTCH(msg) = '\0';
Bell(msg);
XtFree(msg);
/*
** Save our current message number, because asking about our 'file' status
** will reset mail's idea of the 'current message' count to one, regardless.
*/
msgnum = SelectionNumber(False);
/*
** Now ask for 'file' status to determine if we are still caught in our 'bogus'
** mailfile, in order to generate a more meaningful title-bar status message.
*/
msg = QueryMail("file");
if (strncmp(&msg[1], tmpName, strlen(tmpName)) == 0) {
(void) UpdateTitleBar("No current folder");
iw = XtNameToWidget(toplevel, "topBox");
writeTo(XtNameToWidget(iw, "indexWindow"), " ");
writeTo(XtNameToWidget(iw, "textWindow.text"), " ");
} else {
(void) UpdateTitleBar(msg);
XtFree(msg);
/*
** If not in our bogus mail folder, reset the current message
** number in Mail by again pointing at that numbered message.
*/
sprintf(tmp, "f %d", msgnum);
msg = QueryMail(tmp);
if (strchr("Ss", *Command))
markIndex(">S");
}
XtFree(msg);
*msg='\0';
break;
case O_EXEC : msgnum = index_handler(0, 0);
break;
case O_FILE : msgnum = file_handler();
c = strchr(msg, '\n');
if ((int)(c - msg) < strlen(msg) - 1) {
*c = '\0'; /* don't bell this */
Bell(""); /* clear worthy flag */
Bell(msg);
}
XtFree(msg);
*msg = '\0';
if (msgnum) {
sprintf(tmp, "%d", msgnum);
msg = QueryMail(tmp);
}
break;
}
break;
/*
** When deleting a message, simply mark that index line with a capital 'D'.
** If un-deleting, mark that index line with a blank ' '. If no current
** index, restore it. If autoprinting, mail will include text of next msg.
*/
case C_DELETE : if (O_BELL == match(output_pattern, msg)) {
Bell(msg);
XtFree(msg);
*msg = '\0';
} else {
msgnum = SelectionNumber(False);
if (*Command == 'd') {
if (msgnum) {
markIndex("D");
msgnum = index_handler(msgnum+1, 0);
}
} else { /* if we are 'undeleting' */
c = QueryMail("=");
sscanf(c, "%d", &msgnum);
XtFree(c);
iw = XtNameToWidget(toplevel, "topBox.indexWindow");
if (TextGetLastPos(iw) < (XawTextPosition) 4) {
c = QueryMail("h");
writeTo(iw, c);
XtFree(c);
}
msgnum = index_handler(msgnum, 1);
}
c = QueryMail("file"); /* resets current msg to 1 */
(void) UpdateTitleBar(c);
XtFree(c);
if (msgnum == 0) { /* if was last msg in file */
XtFree(msg);
msg = XtNewString("\n"); /* erase its text */
} else { /* reset mail's idea of the */
sprintf(tmp, "f %d", msgnum); /* current message */
c = QueryMail(tmp);
XtFree(c);
}
if (! *msg) /* Don't allow memory leaks */
XtFree(msg); /* to accumulate if no text */
}
break;
/*
** In response to a request to view new mail, first reset the mailbox flag.
** If mail came back with an error, complain to the user. Otherwise, clear
** the Newmail command button highlighting. Then display any new mail text.
*/
case C_NEWMAIL:
button = XtNameToWidget(toplevel, "topBox.commandPanel.Folder");
UnsetNewmail(button, NULL, NULL);
if (O_BELL == match(output_pattern, msg)) {
if (strncmp(msg, "No mail for ", 12) == 0) {
Bell("No mail in your system mailbox\n");
} else { Bell(msg); }
XtFree(msg);
*msg = '\0';
} else {
Bell(""); /* reset any worthy-ness flag */
Bell(Default_Status_Info);
msgnum = file_handler();
if (*msg) {
s = msg;
c = strchr(msg, '\n');
if ((c - s) + 1 < strlen(msg)) {
*c = '\0'; /* don't bell this */
Bell(msg);
}
}
XtFree(msg);
*msg = '\0';
if (msgnum) {
sprintf(tmp, "%d", msgnum);
msg = QueryMail(tmp);
}
}
break;
default: j = match(output_pattern, msg);
switch (j) {
case O_BELL:
Bell(msg);
XtFree(msg);
*msg = '\0';
break;
/*
** If output is from the print command, display a status message
*/
case O_PRINT:
sscanf(&Command[2], "%d", &j);
c = strrchr(msg, '/');
sscanf(c, "/%d", &k);
sprintf(tmp,
"Message %d sent to printer -- %d bytes\n", j, k);
Bell(tmp);
XtFree(msg);
*msg = '\0';
break;
}
break;
}
/*
** If any text remains, display it in the bottom (text) window.
*/
if (*msg) {
for (j = strlen(msg)-1; j > 1 && msg[j] == '\n' && msg[j-1] == '\n'; j--);
msg[++j] = '\0'; /* drop all but the last newline */
writeTo(XtNameToWidget(toplevel, "topBox.textWindow.text"), msg);
XtFree(msg);
*msg = '\0';
}
} /* parse */
#define FILEBUF 4096
/*
** @(#)QueryMail() - Sends a command and returns corresponding output.
** If called by the Xt input procedure readMail, no command is included.
*/
char *
QueryMail(cmd)
char *cmd;
{
int j, outputsize, size, length = strlen(MailPrompt);
char *temp, s[FILEBUF];
static char *output;
SetCursor(1);
/*
** allocate one block to 'output' to begin with
*/
outputsize = FILEBUF;
output = XtMalloc(outputsize);
output[0] = '\0';
if (! mailpid)
Bell("No current mail program connection\n");
else {
if (*cmd) { /* allow us to be called by readMail */
if (LASTCH(cmd) != '\n')
sprintf(s, "%s\n", cmd);
else
strcpy(s, cmd);
writeMail(s);
}
for (;;) {
if ((size = read(mail_fd, s, FILEBUF)) < 1) { /* EOF or an error? */
if (! *output) {
strcpy(output, "No current mail service connection\n");
if (mailpid) {
XtRemoveInput(mailInputId);
close(mail_fd);
mailpid = 0;
}
}
break;
}
if (size < FILEBUF)
s[size] = '\0';
if (strlen(output) + size > outputsize) {
outputsize += FILEBUF;
temp = XtRealloc(output, outputsize);
output = temp;
}
strcat(output, s);
j = strlen(output) - length; /* no accidents allowed here */
if (j < 0) j = 0; /* no references before zero */
if (strcmp(&output[j], MailPrompt) == 0) {
output[j] = '\0'; /* Drop prompt from end of text */
break; /* and return from read routine */
}
if (!strcmp(Command,"Start")) { /* see if somehow missed the prompt */
j = strlen(output) - 3; /* no accidents allowed here either */
if (j < 0) j = 0; /* no string references before zero */
if (strcmp(&output[j], "\n& ") == 0) { /* if default mail prompt */
output[++j] = '\0'; /* drop prompt from end of string */
XtFree(MailPrompt); /* intended prompt is now bogus */
MailPrompt = XtNewString("& "); /* reset the mail prompt */
break; /* and return from read routine */
}
}
if (O_BELL == match(output_pattern,output) && !strcmp(Command,"Start"))
break;
}
if (*cmd)
LASTCH(output) = '\0'; /* drop newline for normal queries */
}
temp = XtRealloc(output, strlen(output) + 1);
output = temp;
SetCursor(0);
return(output);
} /* QueryMail */