Commit 5f620059 5f620059586694fbcd9b2c9f27057df7b2aae690 by Jakob Kaivo

Implement mailx commands {C,c}opy, {S,s}ave, {W,w}rite, set

Beginning of mailx command mail (in send.c)
Merge printall into print, remove printall.c
1 parent 56301330
......@@ -8,6 +8,6 @@ mail_LDADD = ../mailbox/libmailbox.la ../lib/libmailutils.a -lreadline
mail_SOURCES = alias.c alt.c bang.c cd.c copy.c delete.c discard.c dp.c \
echo.c edit.c eq.c exit.c file.c folders.c followup.c from.c hash.c \
headers.c help.c hold.c if.c list.c mail.c mail.h mbox.c next.c pipe.c \
previous.c print.c printall.c quit.c relist.c reply.c retain.c save.c \
previous.c print.c quit.c relist.c reply.c retain.c save.c \
send.c set.c shell.c size.c source.c top.c touch.c unalias.c \
undelete.c unset.c util.c visual.c write.c z.c table.c
......
......@@ -23,9 +23,58 @@
* C[opy] [msglist]
*/
/*
* NOTE: outfolder variable, see save.c
*/
int
mail_copy (int argc, char **argv)
{
printf ("Function not implemented in %s line %d\n", __FILE__, __LINE__);
return 1;
message_t msg;
mailbox_t mbx;
char *filename = NULL;
int *msglist = NULL;
int num = 0, i = 0;
int sender = 0;
if (isupper (argv[0][0]))
sender = 1;
else if (argc >= 2)
filename = argv[--argc];
else
{
filename = strdup ("mbox");
}
num = util_expand_msglist (argc, argv, &msglist);
if (sender)
{
mailbox_get_message (mbox, num > 0 ? msglist[0] : cursor, 0);
/* get from */
/* filename = login name part */
}
mailbox_create (&mbx, filename, 0);
mailbox_open (mbx, MU_STREAM_WRITE | MU_STREAM_CREAT);
if (num > 0)
{
for (i=0; i < num; i++)
{
mailbox_get_message (mbox, msglist[i], &msg);
mailbox_append_message (mbx, msg);
}
}
else
{
mailbox_get_message (mbox, cursor, &msg);
mailbox_append_message (mbx, msg);
}
mailbox_close (mbx);
mailbox_destroy (&mbx);
free (msglist);
return 0;
}
......
......@@ -26,14 +26,14 @@ static struct argp_option options[] = {
{"exist", 'e', 0, 0, "Return true if mail exists"},
{"file", 'f', "FILE", OPTION_ARG_OPTIONAL,
"Operate on mailbox FILE (default ~/mbox)"},
{"FIXME", 'F', 0, 0, "Save messages according to sender"},
{"byname", 'F', 0, 0, "Save messages according to sender"},
{"headers", 'H', 0, 0, "Write a header summary and exit"},
{"ignore", 'i', 0, 0, "Ignore interrupts"},
{"norc", 'n', 0, 0, "Do not read the system mailrc file"},
{"nosum", 'N', 0, 0, "Do not display initial header summary"},
{"print", 'p', 0, 0, "Print all mail to standard out"},
{"print", 'p', 0, 0, "Print all mail to standard output"},
{"quit", 'q', 0, 0, "Cause interrupts to terminate program"},
{"read", 'r', 0, 0, "Write messages in FIFO order"},
{"read", 'r', 0, 0, "Same as -p"},
{"subject", 's', "SUBJ", 0, "Send a message with a Subject of SUBJ"},
{"to", 't', 0, 0, "Preced message by a list of addresses"},
{"user", 'u', "USER", 0, "Operate on USER's mailbox"},
......@@ -43,9 +43,7 @@ static struct argp_option options[] = {
struct arguments
{
char **args;
int exist, print, quit, read, to, header, ignore, norc, nosum;
char *file;
char *subject;
char *user;
};
......@@ -57,7 +55,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
switch (key)
{
case 'e':
args->exist = 1;
util_do_command ("set mode=exist");
break;
case 'f':
if (arg != NULL)
......@@ -78,35 +76,38 @@ parse_opt (int key, char *arg, struct argp_state *state)
}
break;
case 'p':
args->print = 1;
case 'r':
util_do_command ("set mode=print");
break;
case 'q':
args->quit = 1;
break;
case 'r':
args->read = 1;
util_do_command ("set quit");
break;
case 't':
args->to = 1;
util_do_command ("set mode=send");
break;
case 'H':
args->header = 1;
util_do_command ("set mode=headers");
break;
case 'i':
args->ignore = 1;
util_do_command ("set ignore");
break;
case 'n':
args->norc = 1;
util_do_command ("set norc");
break;
case 'N':
args->nosum = 1;
util_do_command ("set noheader");
break;
case 's':
args->subject = arg;
util_do_command ("set mode=send");
util_do_command ("set noasksub");
util_do_command ("set subject=\"%s\"", arg);
break;
case 'u':
args->user = arg;
break;
case 'F':
util_do_command ("set byname");
break;
default:
return ARGP_ERR_UNKNOWN;
}
......@@ -119,26 +120,69 @@ int
main (int argc, char **argv)
{
char *command = NULL, *cmd = NULL;
struct mail_env_entry *mode = NULL, *prompt = NULL;
int modelen = 0;
struct arguments args;
cursor = 1;
realcursor = cursor;
args.exist = 0;
args.print = 0;
args.quit = 0;
args.read = 0;
args.to = 0;
args.header = 0;
args.ignore = 0;
args.norc = 0;
args.nosum = 0;
/* set defaults for execution */
util_do_command ("set noallnet");
util_do_command ("set noappend");
if (isatty (fileno(stdin))) { util_do_command ("set asksub"); }
else { util_do_command ("set noasksub"); }
util_do_command ("set noaskbcc");
util_do_command ("set askcc");
util_do_command ("set noautoprint");
util_do_command ("set nobang");
util_do_command ("set nocmd");
util_do_command ("set nocrt");
util_do_command ("set nodebug");
util_do_command ("set nodot");
util_do_command ("set escape=~");
util_do_command ("set noflipr");
util_do_command ("set nofolder");
util_do_command ("set header");
util_do_command ("set nohold");
util_do_command ("set noignore");
util_do_command ("set noignoreeof");
util_do_command ("set indentprefix=\t");
util_do_command ("set nokeep");
util_do_command ("set nokeepsave");
util_do_command ("set nometoo");
util_do_command ("set noonehop");
util_do_command ("set nooutfolder");
util_do_command ("set nopage");
util_do_command ("set prompt=? "); /* FIXME: "set prompt=\"? \"" */
util_do_command ("set noquiet");
util_do_command ("set norecord");
util_do_command ("set save");
util_do_command ("set screen=%d", util_getlines());
util_do_command ("set nosendmail");
util_do_command ("set nosendwait");
util_do_command ("set noshowto");
util_do_command ("set nosign");
util_do_command ("set noSign");
util_do_command ("set toplines=5");
/* GNU extensions to the environment, for sparky's sanity */
util_do_command ("set mode=read");
util_do_command ("set nobyname");
util_do_command ("set rc");
util_do_command ("set noquit");
args.file = NULL;
args.subject = NULL;
args.user = NULL;
/* argument parsing */
argp_parse (&argp, argc, argv, 0, 0, &args);
/* Initialize readline */
rl_readline_name = "mail";
rl_attempted_completion_function = (CPPFunction *)util_command_completion;
/* open the mailbox */
if (args.file == NULL)
{
if (mailbox_create_default (&mbox, args.user) != 0)
......@@ -153,25 +197,34 @@ main (int argc, char **argv)
if (mailbox_messages_count (mbox, &total) != 0)
exit (EXIT_FAILURE);
if (args.exist)
/* how should we be running? */
if ((mode = util_find_env ("mode")) == NULL || mode->set == 0)
exit (EXIT_FAILURE);
modelen = strlen (mode->value);
if (strlen ("exist") == modelen && !strcmp ("exist", mode->value))
return (total < 1) ? 1 : 0;
else if (strlen ("print") == modelen && !strcmp ("print", mode->value))
return util_do_command ("print *");
else if (strlen ("headers") == modelen && !strcmp ("headers", mode->value))
return util_do_command ("from *");
else if (strlen ("send") == modelen && !strcmp ("send", mode->value))
{
if (total < 1)
exit (1);
else
exit (0);
/* set cmd to "mail [add1...]" */
cmd = strdup ("mail");
return util_do_command (cmd);
}
/* initial commands */
util_do_command ("from *");
/* Initialize readline */
rl_readline_name = "mail";
rl_attempted_completion_function = (CPPFunction *)util_command_completion;
prompt = util_find_env ("prompt");
while (1)
{
int len;
free (command);
command = readline ("? ");
command = readline (prompt->set && prompt->value != NULL ? prompt->value : "");
len = strlen (command);
while (command[len-1] == '\\')
{
......
......@@ -29,6 +29,7 @@
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdarg.h>
#include <argp.h>
......@@ -66,6 +67,12 @@ struct mail_command_entry {
char *synopsis;
};
struct mail_env_entry {
char *var;
int set;
char *value;
};
/* Global variables and constants*/
mailbox_t mbox;
unsigned int cursor;
......@@ -122,7 +129,7 @@ int mail_bang __P((int argc, char **argv)); /* command ! */
int mail_eq __P((int argc, char **argv)); /* command = */
int util_expand_msglist __P((const int argc, char **argv, int **list));
int util_do_command __P((const char *cmd));
int util_do_command __P((const char *cmd, ...));
int util_msglist_command __P((function_t *func, int argc, char **argv));
function_t* util_command_get __P((char *cmd));
char **util_command_completion __P((char *cmd, int start, int end));
......@@ -131,6 +138,8 @@ char *util_stripwhite __P((char *string));
struct mail_command_entry util_find_entry __P((char *cmd));
int util_getcols __P((void));
int util_getlines __P((void));
struct mail_env_entry *util_find_env __P((char *var));
int util_printenv __P((void));
#ifdef __cplusplus
}
......
......@@ -20,6 +20,8 @@
/*
* p[rint] [msglist]
* t[ype] [msglist]
* P[rint] [msglist]
* T[ype] [msglist]
*/
int
......@@ -36,14 +38,25 @@ mail_print (int argc, char **argv)
stream_t stream;
char buffer[BUFSIZ];
off_t off = 0;
size_t n = 0;
size_t n = 0, lines = 0;
FILE *out = stdout;
if (mailbox_get_message (mbox, cursor, &mesg) != 0)
{
printf ("Could not read message %d\n", cursor);
return 1;
message_lines (mesg, &lines);
if ((util_find_env("crt"))->set && lines > util_getlines ())
{
char *pager = getenv ("PAGER");
if (pager)
out = popen (pager, "w");
else
out = popen ("more", "w");
}
if (islower (argv[0][0]))
{
message_get_header (mesg, &hdr);
if (header_get_value (hdr, MU_HEADER_FROM, buffer, sizeof (buffer),
NULL) == 0)
......@@ -51,8 +64,8 @@ mail_print (int argc, char **argv)
printf ("From: %s\n", buffer);
/* free (buf); */
}
if (header_get_value (hdr, MU_HEADER_SUBJECT, buffer, sizeof (buffer),
NULL) == 0)
if (header_get_value (hdr, MU_HEADER_SUBJECT, buffer,
sizeof (buffer), NULL) == 0)
{
printf ("Subject: %s\n", buffer);
/* free (buf); */
......@@ -60,13 +73,19 @@ mail_print (int argc, char **argv)
message_get_body (mesg, &body);
body_get_stream (body, &stream);
}
else
message_get_stream (mesg, &stream);
while (stream_read (stream, buffer, sizeof (buffer) - 1, off, &n) == 0
&& n != 0)
{
buffer[n] = '\0';
printf ("%s", buffer);
fprintf (out, "%s", buffer);
off += n;
}
if (out != stdout)
pclose (out);
return 0;
}
return 1;
......
......@@ -23,9 +23,60 @@
* S[ave] [msglist]
*/
/*
* NOTE: outfolder variable
*/
int
mail_save (int argc, char **argv)
{
printf ("Function not implemented in %s line %d\n", __FILE__, __LINE__);
return 1;
message_t msg;
mailbox_t mbx;
char *filename = NULL;
int *msglist = NULL;
int num = 0, i = 0;
int sender = 0;
if (isupper (argv[0][0]))
sender = 1;
else if (argc >= 2)
filename = argv[--argc];
else
{
filename = strdup ("mbox");
}
num = util_expand_msglist (argc, argv, &msglist);
if (sender)
{
mailbox_get_message (mbox, num > 0 ? msglist[0] : cursor, 0);
/* get from */
/* filename = login name part */
}
mailbox_create (&mbx, filename, 0);
mailbox_open (mbx, MU_STREAM_WRITE | MU_STREAM_CREAT);
if (num > 0)
{
for (i=0; i < num; i++)
{
mailbox_get_message (mbox, msglist[i], &msg);
mailbox_append_message (mbx, msg);
/* mark as saved */
}
}
else
{
mailbox_get_message (mbox, cursor, &msg);
mailbox_append_message (mbx, msg);
/* mark as saved */
}
mailbox_close (mbx);
mailbox_destroy (&mbx);
free (msglist);
return 0;
}
......
......@@ -24,6 +24,25 @@
int
mail_send (int argc, char **argv)
{
char *to = NULL, *cc = NULL, *bcc = NULL, *subj = NULL;
if (argc < 2)
to = readline ("To: ");
else
{
/* figure it out from argv */
}
if ((util_find_env ("askcc"))->set)
cc = readline ("Cc: ");
if ((util_find_env ("askbcc"))->set)
bcc = readline ("Bcc: ");
if ((util_find_env ("asksub"))->set)
subj = readline ("Subject: ");
else
subj = (util_find_env ("subject"))->value;
printf ("Function not implemented in %s line %d\n", __FILE__, __LINE__);
return 1;
}
......
......@@ -21,22 +21,29 @@
* se[t] [name[=[string]] ...] [name=number ...] [noname ...]
*/
/*
* NOTE: ask is a synonym for asksub
*/
int
mail_set (int argc, char **argv)
{
if (argc < 2)
{
/* step through the environment */
return util_printenv ();
}
else
{
int i = 0;
char *var = NULL, *value = NULL;
struct mail_env_entry *entry = NULL;
for (i = 1; i < argc; i++)
{
if (!strncmp ("no", argv[i], 2))
{
/* unset variable */
entry = util_find_env (&argv[i][2]);
entry->set = 0;
free (entry->value);
}
else if (strchr (argv[i], '=') != NULL)
{
......@@ -49,13 +56,18 @@ mail_set (int argc, char **argv)
break;
}
value = strdup (&var[j+1]);
/* set var = value */
entry = util_find_env (var);
entry->set = 1;
free (entry->value);
entry->value = value;
free (var);
free (value);
}
else
{
/* set var = NULL */
entry = util_find_env(argv[i]);
entry->set = 1;
free (entry->value);
entry->value = NULL;
}
}
return 0;
......
......@@ -57,14 +57,14 @@ const struct mail_command_entry mail_command_table[] = {
{ "l", "list", mail_list, "l[ist]" },
{ "*", "*", mail_list, "*" },
{ "m", "mail", mail_send, "m[ail] address..." },
{ "m", "mail", mail_send, "m[ail] [address...]" },
{ "mb", "mbox", mail_mbox, "mb[ox] [msglist]" },
{ "n", "next", mail_next, "n[ext] [message]" },
{ "+", "+", mail_next, "+ [message]" },
{ "pi", "pipe", mail_pipe, "pi[pe] [[msglist] command]" },
{ "|", "|", mail_pipe, "| [[msglist] command]" },
{ "P", "Print", mail_printall, "P[rint] [msglist]" },
{ "T", "Type", mail_printall, "T[ype] [msglist]" },
{ "P", "Print", mail_print, "P[rint] [msglist]" },
{ "T", "Type", mail_print, "T[ype] [msglist]" },
{ "p", "print", mail_print, "p[rint] [msglist]" },
{ "t", "type", mail_print, "t[ype] [msglist]" },
{ "prev", "previous", mail_previous, "prev[ious] [message]" },
......@@ -93,7 +93,9 @@ const struct mail_command_entry mail_command_table[] = {
{ "u", "undelete", mail_undelete, "u[ndelete] [msglist]" },
{ "uns", "unset", mail_unset, "uns[et] name..." },
{ "v", "visual", mail_visual, "v[isual] [msglist]" },
{ "w", "write", mail_write, "w[rite] [msglist] file" },
{ "w", "write", mail_write,
"w[rite] [file]\nw[rite] [msglist] file" },
{ "W", "Write", mail_write, "W[rite] [msglist]" },
{ "z", "", mail_z, "z[+|-]" },
{ "!", "", mail_bang, "!command" },
{ "=", "=", mail_eq, "=" },
......
......@@ -18,19 +18,37 @@
#include "mail.h"
typedef struct _node {
/* for the msglist expander */
int data;
/* for the environment table */
struct mail_env_entry env_entry;
struct _node *next;
} node;
static node *environment = NULL;
static node *env_cursor = NULL;
/*
* add a new node to the list
*/
static node *
util_ll_add (node *c, int data)
{
c->next = malloc (sizeof (node));
c->data = data;
/* c->env_entry.var = NULL;
c->env_entry.set = 0;
c->env_entry.value = NULL;*/
c->next->env_entry.var = NULL;
c->next->env_entry.set = 0;
c->next->env_entry.value = NULL;
c->next->next = NULL;
return c->next;
}
/*
* free a linked list
*/
static void
util_ll_free (node *c)
{
......@@ -172,12 +190,17 @@ util_expand_msglist (const int argc, char **argv, int **list)
* returns exit status of the command
*/
int
util_do_command (const char *cmd)
util_do_command (const char *c, ...)
{
int argc = 0;
char **argv = NULL;
int status = 0;
function_t *command;
char *cmd = NULL;
va_list ap;
va_start (ap, c);
if (vasprintf (&cmd, c, ap) < 1)
return 0;
if (cmd[0] == '#')
return 0;
......@@ -346,3 +369,71 @@ util_getlines (void)
lines = strtol (lin, NULL, 10);
return lines;
}
/*
* find environment entry var
*/
struct mail_env_entry *
util_find_env (char *variable)
{
char *var = variable;
int len = strlen (var), need_free = 0;
node *t;
if (len == strlen ("ask") && !strcmp ("ask", var))
{
var = strdup ("asksub");
len = strlen (var);
need_free = 1;
}
if (environment == NULL)
{
environment = malloc (sizeof (node));
environment->env_entry.var = NULL;
environment->env_entry.set = 0;
environment->env_entry.value = NULL;
environment->next = NULL;
}
for (env_cursor = environment; env_cursor->next != NULL;
env_cursor = env_cursor->next)
{
if (strlen (env_cursor->env_entry.var) == len &&
!strcmp (var, env_cursor->env_entry.var))
{
if (need_free)
free (var);
return &(env_cursor->env_entry);
}
}
/* env_cursor = util_ll_add (env_cursor, 0); */
env_cursor->env_entry.var = strdup (var);
env_cursor->env_entry.set = 0;
env_cursor->env_entry.value = NULL;
t = env_cursor;
env_cursor = util_ll_add (env_cursor, 0);
if (need_free)
free (var);
return &(t->env_entry);
}
/*
* print the environment
*/
int
util_printenv (void)
{
for (env_cursor = environment; env_cursor != NULL;
env_cursor = env_cursor->next)
{
if (env_cursor->env_entry.set)
{
printf ("%s", env_cursor->env_entry.var);
if (env_cursor->env_entry.value != NULL)
printf ("=%s", env_cursor->env_entry.value);
printf ("\n");
}
}
return 0;
}
......
......@@ -18,12 +18,85 @@
#include "mail.h"
/*
* w[rite] [file] GNU extension
* w[rite] [msglist] file
* W[rite] [msglist] GNU extension
*/
/*
* NOTE: outfolder variable, see save.c
*/
int
mail_write (int argc, char **argv)
{
printf ("Function not implemented in %s line %d\n", __FILE__, __LINE__);
return 1;
message_t msg;
body_t bod;
stream_t stream;
FILE *output;
char *filename = NULL;
char buffer[BUFSIZ];
off_t off = 0;
size_t n = 0;
int *msglist = NULL;
int num = 0, i = 0;
int sender = 0;
if (isupper (argv[0][0]))
sender = 1;
else if (argc >= 2)
filename = argv[--argc];
else
{
filename = strdup ("mbox");
}
num = util_expand_msglist (argc, argv, &msglist);
if (sender)
{
mailbox_get_message (mbox, num > 0 ? msglist[0] : cursor, 0);
/* get from */
/* filename = login name part */
}
output = fopen (filename, "a");
if (num > 0)
{
for (i=0; i < num; i++)
{
mailbox_get_message (mbox, msglist[i], &msg);
message_get_body (msg, &bod);
body_get_stream (bod, &stream);
/* should there be a separator? */
while (stream_read(stream, buffer, sizeof (buffer) - 1, off, &n)
== 0 && n != 0)
{
buffer[n] = '\0';
fprintf (output, "%s", buffer);
off += n;
}
/* mark as saved */
}
}
else
{
mailbox_get_message (mbox, cursor, &msg);
message_get_body (msg, &bod);
body_get_stream (bod, &stream);
/* should there be a separator? */
while (stream_read(stream, buffer, sizeof (buffer) - 1, off, &n)
== 0 && n != 0)
{
buffer[n] = '\0';
fprintf (output, "%s", buffer);
off += n;
}
/* mark as save */
}
fclose (output);
free (msglist);
return 0;
}
......