]> mj.ucw.cz Git - umpf.git/blobdiff - int.c
fix saving bodies
[umpf.git] / int.c
diff --git a/int.c b/int.c
index 69f22852b80d1376f666b69e9420a495fa82b155..e1c906f058342ada6c8d264876d5f4fcc48bed35 100644 (file)
--- a/int.c
+++ b/int.c
@@ -3,6 +3,11 @@
 #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
@@ -25,15 +54,14 @@ set_var(int var, char* value)
 {
        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 */
@@ -78,32 +106,114 @@ xcat(char* left, char* right)
 {
        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 
@@ -114,7 +224,7 @@ modify_headers(struct list* headers, struct list* hash)
 
                                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);
                        }
@@ -142,22 +252,36 @@ copy_headers(struct list* orig)
        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)
 {
@@ -169,11 +293,14 @@ 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;
        };
@@ -253,13 +380,66 @@ eval_cond(int var)
        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:
@@ -310,14 +490,20 @@ interp(struct list* ins)
                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
@@ -332,35 +518,6 @@ print_vars(struct list* hash)
        }
 }
 
-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)
 {
@@ -374,14 +531,8 @@ 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;
 }