#include <pcre.h>
#include <ctype.h>
#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <sys/wait.h>
+#include <sysexits.h>
#include "cond.tab.h"
#include "umpf.h"
#define INT_TO_STRING_LEN ((sizeof(int)*4*CHAR_BIT)/10 + 6)
+void __attribute__ ((noreturn))
+bye(int code, char* msg, ...)
+{
+ va_list args;
+
+ if (current_body->tmpfile)
+ unlink(current_body->tmpfile);
+
+ if (msg) {
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ fputc('\n', stderr);
+ va_end(args);
+ }
+ exit(code);
+}
+
+void
+free_string(char* c)
+{
+ if (c != empty)
+ free(c);
+}
+
static void
clear_var(int var)
{
- if (var_tab[var])
- free(var_tab[var]);
+ if ((var_tab[var] != NULL))
+ free_string(var_tab[var]);
}
static void
{
clear_var(var);
var_tab[var] = xstrdup(value);
-
}
static char*
get_var(int var)
{
if (var < 0)
- return const_tab[-var];
- return var_tab[var];
+ return xstrdup(const_tab[-var]);
+ return xstrdup(var_tab[var]);
}
/* return var struct or NULL if not found */
{
char* res = xmalloc(strlen(left) + strlen(right) + 1);
- strcpy(res,left);
- strcat(left,right);
+ strcpy(res, left);
+ strcat(res, right);
- free(left);
- free(right);
+ free_string(left);
+ free_string(right);
return res;
}
+static char*
+fold(const char* value, int taken)
+{
+ int i;
+ char* ret;
+ int len = strlen(value);
+ int newlines[len / 78 + 5];
+ int newl = 0;
+ int curr_ws = -1;
+ int pos = 0;
+ int newl_done = 0;
+
+ if (len + taken <= 78)
+ return xstrdup(value);
+ for(i = 0; i < len; i++) {
+ if (value[i] == ' ' || value[i]=='\t')
+ curr_ws = i;
+ taken++;
+ if (taken >= 78) {
+ if (curr_ws > 0){
+ newlines[newl++] = curr_ws;
+ i = curr_ws;
+ while(value[i] && (value[i] == '\t'
+ || value[i] == ' '))
+ i++;
+ taken = i - curr_ws;
+ curr_ws = -1;
+ }
+ }
+ }
+ ret = xmalloc(2*newl + len + 1);
+ for (i = 0; i < len; i++) {
+ if (newl_done == newl) {
+ strcpy(ret + pos, value + i);
+ break;
+ }
+ if(i != newlines[newl_done])
+ ret[pos++] = value[i];
+ else {
+ newl++;
+ ret[pos++] = '\n';
+ ret[pos++] = ' ';
+ }
+ }
+ return ret;
+}
+
+static char*
+unfold(const char* u)
+{
+ char* new;
+ const char* pu = u;
+ char* pn;
+
+ new = xmalloc(strlen(u)+1);
+ pn = new;
+
+#define IS_WHITE(c) ((c) == '\t' || (c)==' ' || c=='\n')
+
+ while (IS_WHITE(*pu))
+ pu++;
+
+ while (*pu != 0){
+ if (IS_WHITE(*pu)){
+ while (IS_WHITE(*pu))
+ pu++;
+ if (*pu != 0)
+ *pn++ = ' ';
+ } else
+ *pn++ = *pu++;
+ }
+ *pn = 0;
+
+ return new;
+}
+
static void
modify_headers(struct list* headers, struct list* hash)
{
struct hlist* p;
int i;
struct variable* pv;
+ char* u, * value;
LIST_FOREACH(p, headers){
pv = get_var_struct(p->name, hash);
if (!pv)
continue;
- if (pv->modified){
+ u = unfold(p->value);
+ value = get_var(pv->varcode);
+ if (strcmp(u, value)){
pv->modified = 0;
- free(p->value);
- p->value = xstrdup(get_var(pv->varcode)); //FIXME: fold it
+ free_string(p->value);
+ p->value = fold(value,
+ strlen(p->name) + 2);
}
+ free_string(u);
+ free_string(value);
}
// find new headers
p = xmalloc(sizeof(struct hlist));
p->name = xstrdup(pv->name);
- p->value = xstrdup(get_var(pv->varcode));
+ p->value = get_var(pv->varcode);
list_add_last(headers,&p->car);
}
return new;
}
-static struct email*
+static struct email
prepare_email(struct list* hash)
{
- struct email* em;
-
- em = xmalloc(sizeof(struct email));
+ struct email em;
modify_headers(current_headers, hash);
- em->headers = copy_headers(current_headers);
- em->body_len = current_body->body_len;
- em->body = xmalloc(em->body_len);
- memcpy(em->body, current_body->body, em->body_len);
+ em.headers = copy_headers(current_headers);
+ em.body_len = current_body->body_len;
+ em.fd = current_body->fd;
+ if (current_body->body) {
+ em.body = xmalloc(em.body_len);
+ memcpy(em.body, current_body->body, em.body_len);
+ em.tmpfile = NULL;
+ } else {
+ em.tmpfile = xstrdup(current_body->tmpfile);
+ em.body = NULL;
+ }
return em;
}
+static void
+destroy_email(struct email em)
+{
+ if (em.body)
+ free_string(em.body);
+ if(em.tmpfile)
+ free_string(em.tmpfile);
+}
+
static void
do_string_ternary_op(struct code* p)
{
case OPC_RE:
result = xmalloc(INT_TO_STRING_LEN);
sprintf(result, "%d", regex_cmp(l, r));
+ break;
case OPC_NRE:
result = xmalloc(INT_TO_STRING_LEN);
sprintf(result, "%d", !regex_cmp(l, r));
+ break;
case OPC_CAT:
result = xcat(l, r);
+ break;
default:
break;
};
return !!v;
}
+static void
+deliver(char* where, int copy, struct list* hash)
+{
+ int res = 0;
+ struct email em = prepare_email(hash);
+
+ res = deliver_local_email(where, &em);
+
+ destroy_email(em);
+
+ if (!copy) {
+ if (res)
+ bye(EX_TEMPFAIL, "%m");
+ else
+ bye(0, NULL);
+ }
+}
+
+static void
+send_mail(char* where, int copy, struct list* hash)
+{
+ int pd[2];
+ int pid, status;
+ int res;
+ struct email em = prepare_email(hash);
+
+ res = pipe(pd);
+ if (res < 0)
+ goto end;
+
+ if ((pid = fork()) < 0)
+ goto end;
+ else if (pid == 0) {
+ close(0);
+ dup(pd[0]);
+ close(pd[0]);
+ //FIXME From?
+ res = execl("/usr/lib/sendmail", "sendmail", where, NULL);
+ }
+ close(pd[0]);
+ write_email_to_fd(pd[1], &em);
+ close(pd[1]);
+ wait(&status);
+end:
+ destroy_email(em);
+ if (!copy) {
+ if (res)
+ bye(EX_TEMPFAIL, "%m");
+ else
+ bye(0, NULL);
+ }
+}
+
void
-interp(struct list* ins)
+interp(struct list* ins, struct list* hash)
{
struct code* p;
char* result;
int v;
-
+
LIST_FOREACH(p, ins) {
switch (p->opcode) {
case OPC_SET:
case OPC_PIPE:
break;
case OPC_MAIL:
+ send_mail(get_var(p->u.arrow.what),
+ p->u.arrow.copy, hash);
break;
case OPC_DELIVER:
+ deliver(get_var(p->u.arrow.what),
+ p->u.arrow.copy, hash);
break;
case OPC_CALL_EXT:
break;
case OPC_DISCARD:
+ bye(0, NULL);
break;
}}
+ deliver(default_mailbox, 0, hash);
}
void
}
}
-static char*
-unfold(char* u)
-{
- char* new;
- char* pu = u;
- char* pn;
-
- new = xmalloc(strlen(u)+1);
- pn = new;
-
-#define IS_WHITE(c) ((c) == '\t' || (c)==' ' || c=='\n')
-
- while (IS_WHITE(*pu))
- pu++;
-
- while (*pu != 0){
- if (IS_WHITE(*pu)){
- while (IS_WHITE(*pu))
- pu++;
- if (*pu != 0)
- *pn++ = ' ';
- } else
- *pn++ = *pu++;
- }
- *pn = 0;
-
- return new;
-}
-
void
save_current_headers(struct list* hash)
{
continue;
u = unfold(p->value);
set_var(pv->varcode, u);
+ free_string(u);
pv->modified = 0;
p->have_var = 1;
}
-
-}
-
-static void
-get_default_mailbox(char* mb)
-{
- default_mailbox = mb;
}