Logo Search packages:      
Sourcecode: jitterbug version File versions

new_message.c

/* 
   The Jitterbug report tracking system

   Copyright (C) Andrew Tridgell 1997

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

/*
  process a new piece of mail coming into the system. The mail is on stdin.
  The default directory to place the mail is given as the 2nd argument to the
  program. If this is not specified then "incoming" is assumed.
 */

#include "jitterbug.h"

int done_chroot = 0;
int guest = 0;
char *user="";

void fatal(char *why, ...)
{
      va_list ap;  

      va_start(ap, why);
      vfprintf(stderr, why, ap);
      va_end(ap);
      exit(1);
}

/* get the message subject of a email if possible */
static char *getsubject(char *mbuf)
{
      char *p1, *p2;

      mbuf = strdup(mbuf);
      if (!mbuf) return NULL;

      p1 = strstr(mbuf, "\nSubject:");

      if (p1) {
            p1 += 9;
            p2 = strchr(p1, '\n');
            if (p2) *p2 = 0;
            p1 = strdup(p1);
            trim_string(p1, " ", " ");
      }

      free(mbuf);

      return p1;
}


/* get the message id of a email if possible */
static int getid(char *mbuf)
{
      char *p1, *p2, *p3;
      int lpr;

      mbuf = strdup(mbuf);
      if (!mbuf) return 0;

      lpr = strlen(lp_pr_identifier());

      p1 = mbuf;
      while ((p1 = strstr(p1, "\nSubject:"))) {
            p1 += 9;
            p2 = strchr(p1, '\n');
            if (!p2) return 0;
            *p2++ = 0;
            p3 = p1;
            while ((p3 = strstr(p3,lp_pr_identifier()))) {
                  if (atoi(p3+lpr)) return atoi(p3+lpr);
                  p3 += lpr;
            }
            p1 = p2;
      }

      free(mbuf);
      return 0;
}

static void autoreply(char *mbuf, int id)
{
      char *subj, *from;
      char *p;
      int fd;
      struct stat st;

      if (!file_exists(AUTOREPLY, &st)) return;

      subj = getsubject(mbuf);
      if (!subj) return;

      if (strncasecmp(subj, "Re:", 3) == 0) return;

      p = strstr(mbuf,"X-Loop: ");
      if (p) {
            from = lp_from_address();
            p += 8;
            if (strncmp(p, from, strlen(from)) == 0) return;
      }

      /* it isn't a loop or a reply - send the autoreply! */
      from = getmailheader(mbuf, "Reply-To:", 0);
      if (!from) 
            from = getmailheader(mbuf, "From:", 0);
      if (!from) 
            from = getmailheader(mbuf, "Return-Path:", 0);

      if (!from) return;

      from = extract_address(from);

      p = (char *)malloc(strlen(subj)+100);
      if (!p) fatal("out of memory");
      sprintf(p,"Re: %s (%s%d)", subj, lp_pr_identifier(), id);

      fd = smtp_start_mail(lp_from_address(), from, NULL, NULL, 
                       p, st.st_size + 1024);

      if (fd == -1) return;

      smtp_write(fd, "X-Loop: %s\n", lp_from_address());
      smtp_write(fd, "\n");

      mbuf = load_file(AUTOREPLY, &st, 0);
      
      /* substitute in the id if wanted */
      p = strstr(mbuf,"%PRNUM%");
      if (p) {
            memset(p,' ',7);
            sprintf(p,"%d", id);
            p[strlen(p)] = ' ';
      }
      if (mbuf) {
            smtp_write_data(fd, mbuf);
      }
      smtp_end_mail(fd);
}


static void forward_mail(char *mbuf, char *to, int id)
{
      char *subj, *from;
      char *p;
      int fd;

      subj = getsubject(mbuf);
      if (!subj) return;

      from = getmailheader(mbuf, "Reply-To:", 0);
      if (!from) 
            from = getmailheader(mbuf, "From:", 0);
      if (!from) 
            from = getmailheader(mbuf, "Return-Path:", 0);

      if (!from) return;

      from = extract_address(from);

      if (strncasecmp(subj, "Re:", 3) == 0 &&
          match_string(from, lp_reply_strings())) return;

      if (strstr(subj, lp_pr_identifier())) {
            p = subj;
      } else {
            p = (char *)malloc(strlen(subj)+100);
            if (!p) fatal("out of memory");
            sprintf(p,"%s (%s%d)", subj, lp_pr_identifier(), id);
      }

      fd = smtp_start_mail(from, to, NULL, NULL, 
                       p, strlen(mbuf) + 1024);

      if (fd == -1) return;

      smtp_write(fd, "CC: %s\n", lp_from_address());
      smtp_write(fd, "X-Loop: %s\n", lp_from_address());
      smtp_write(fd, "\n");

      p = strstr(mbuf,"\n\n");
      if (p) p += 2;
      if (!p) {
            p = strstr(mbuf,"\r\n\r\n");
            if (p) p += 4;
      }
      if (!p) p = mbuf;

      smtp_write_data(fd, p);

      smtp_end_mail(fd);
}

/* This function should always return success */
static int mail_failure(char* from, char* to, char* content)
{
      int fd;
      fd = smtp_start_mail(from, to, NULL, NULL, "Request failed", strlen(content));
      if ( fd == -1 ) {
            fprintf(stderr, "Failed to send failure\n");
            return 0;
      }
      smtp_write(fd, "\n");
      smtp_write_data(fd, content);
      smtp_end_mail(fd);
      return 0; 
}

static int is_a_bug(char* name) 
{
      if (*name >= '1' && *name <= '9')
            return !is_directory(name);
      return 0;
}

static int get_bug(char *mbuf, char* to, char *query)
{
      int fd;
      char *from, *p;
      char *subject="Jitterbug results";
      char buf[1024];
      unsigned int size=0;
      char boundary[128];
      struct stat st;
      char *bug;
      char* msg_id;
      char *msg_list;

      snprintf(boundary, sizeof(boundary), "jitterbug-burp-%d-%d", getpid(), time(NULL));

      /* maybe check for lp_download? */
      /* maybe add info to audit? */
      from = lp_from_address();
      
      while (*query && *query == ' ') query++;
      if (!strncmp(query, "list", 4)) {
            char** dir_l, **file_l;
            int i, j;
            query += 4;
            fd = smtp_start_mail(from, to, NULL, NULL, subject, 0);
            if ( fd == -1 )
                  return 1;

            msg_id = getmailheader(mbuf, "Message-ID:", 0);
            if ( msg_id )
                  smtp_write(fd, "References: %s\n", msg_id);
            smtp_write(fd, "\nList for query: %s\n\n", query);
            trim_string(query, " ", " ");
            /* use strtok to allow multiple queries */
            if (!*query || *query == '/' || *query == '.') {
                  query = ".";
                  dir_l = load_dir_list(query, is_directory);
            } else {
                  dir_l = new_list();
                  add_list_item(dir_l, query);
            }
            for (i=0; dir_l && dir_l[i]; ++i) {
                  file_l = load_dir_list(dir_l[i], is_a_bug);
                  /* maybe add subject, from, ... */
                  for (j=0; file_l && file_l[j]; ++j)
                        smtp_write(fd, "%s/%s\n", dir_l[i], file_l[j]);
                  free_list(file_l);
            }
            free_list(dir_l);
            smtp_end_mail(fd);
            return 0;
      } else if (!strncmp(query, "get", 3)) {
            query += 3;
      } else if (!strncmp(query, "search", 6)) {
            query += 6;
            snprintf(buf, sizeof(buf), "Not implemeted (%s)\n", query);
            return mail_failure(from, to, buf);
      } else {
            snprintf(buf, sizeof(buf), "Not implemeted (%s)\n", query);
            return mail_failure(from, to, buf);
      }

      fd = smtp_start_mail(from, to, NULL, NULL, subject, 0);
      if ( fd == -1 )
            return 1;

      msg_id = getmailheader(mbuf, "Message-ID:", 0);
      if ( msg_id )
            smtp_write(fd, "References: %s\n", msg_id);
      smtp_write(fd, "Mime-Version: 1.0\n");
      smtp_write(fd, "Content-Type: multipart/mixed; boundary=%s\n\n", boundary);
      msg_list = strdup(query);
      for (query = strtok(msg_list, " \t,;"); query; query = strtok(NULL, " \t,;")) {
            smtp_write(fd, "\n--%s\nContent-Type: text/plain; charset=us-ascii\n", boundary);
            /* a few security checks */
            if (*query == '/' || strchr(query, '.') || !(p=strchr(query, '/'))) {
                  smtp_write(fd, "\nNot allowed (%s)\n", query);
                  continue;
            }
            *p = 0;
            if ( !is_directory(query) ) {
                  smtp_write(fd, "\nNot allowed (%s)\n", query);
                  continue;
            }
            *p = '/';
            bug = load_file(query, &st, 0);
            if ( !bug ) {
                  smtp_write(fd, "\nCannot load (%s)\n", query);
                  continue;
            }
            /* replace / with _ in filename */
            p = query;
            while(*p) {
                  if (*p == '/') *p = '_';
                  ++p;
            }
            smtp_write(fd, "Content-Disposition: attachment; filename=\"%s\"\n\n", query);
            smtp_write_data(fd, bug);
            free(bug);
      }
      free(msg_list);

      smtp_end_mail(fd);
      return 0;
}

int process_mail(char *def_dir)
{
      FILE *f = fopen(".newmsg","w");
      char buf[100], fname[1000];
      char *mbuf;
      int id, followup=0, nextid=0;
      char idname[20];
      char *p, *p2, *dir, *basename=NULL;
      char *from, *subject;

      /* read the message into a temporary file */
      while (!feof(stdin)) {
            int len = fread(buf, 1, sizeof(buf), stdin);
            if (len > 0)
                  fwrite(buf, 1, len, f);
      }
      fclose(f);

      fname[0] = 0;

      mbuf = load_file(".newmsg", NULL, 0);
      if (!mbuf) {
            fprintf(stderr,"Can't read .newmsg\n");
            return 1;
      }

      from = getmailheader(mbuf, "Reply-To:", 0);
      if (!from) 
            from = getmailheader(mbuf, "From:", 0);
      if (!from) 
            from = getmailheader(mbuf, "Return-Path:", 0);

      /* don't process corrupt mail */
      if (!from) {
            fprintf(stderr,"Corrupt mail headers\n");
            return 1;
      }

      from = extract_address(from);
      
      /* never process mail from ourselves! */
      if (strcmp(from, lp_from_address()) == 0) {
            fprintf(stderr,"Mail loop - discarding mail\n");
            return 1;
      }

      if (strncasecmp(from, "MAILER-DAEMON", 13) == 0) {
            fprintf(stderr,"Ignoring bounced mail\n");
            return 1;
      }

      /* work out if it has an existing id */
      id = getid(mbuf);
      sprintf(idname,"%d", id);

      if (id != 0) {
            basename = find_file(".", idname);
            if (basename) {
                  if (match_string(from, lp_reply_strings())) {
                        followup = count_replies(basename, NULL)+1;
                        check_overflow(strlen(basename)+20, sizeof(fname));
                        sprintf(fname,"%s.reply.%d", basename, followup);
                  } else {
                        followup = count_followups(basename, NULL)+1;
                        check_overflow(strlen(basename)+20, sizeof(fname));
                        sprintf(fname,"%s.followup.%d", basename, followup);
                  }
            }
      }
      
      subject = getmailheader(mbuf, "Subject:", 0);
      if (subject && !strncmp(subject, "GETBUG:", 7)) {
            unlink(".newnsg");
            return get_bug(mbuf, from, subject + 7);
      }

      if (! *fname) {
            char *idfile = load_file(".nextid", NULL, 0);
            nextid=1;
            if (idfile) nextid = atoi(idfile);
            sprintf(idname,"%d", nextid+1);
            save_file(".nextid", idname);
            sprintf(idname,"%d", nextid);
            check_overflow(strlen(def_dir)+20, sizeof(fname));
            sprintf(fname,"%s/%d", def_dir, nextid);
      }

      p = strrchr(fname,'/');
      if (!p) {
            fprintf(stderr,"invalid filename\n");
            exit(1);
      }
      *p = 0;
      dir = strdup(fname);
      *p = '/';

      if (!is_directory(dir)) {
            mkdir(dir,0755);
      }

      if (rename(".newmsg", fname)) {
            fprintf(stderr,"rename .newmsg %s failed\n", fname);
      }

      if (lp_forward_all()) {
            forward_mail(mbuf, lp_forward_all(), id?id:nextid);
      }

      /* forward to "forward public" if message not marked private */

      if (subject &&
          lp_forward_public() && !strstr(subject,"PRIVATE")) {
            forward_mail(mbuf, lp_forward_public(), id?id:nextid);
      }

      if (!id && strcmp(def_dir, lp_incoming())==0) autoreply(mbuf, nextid);
      
      chdir(dir);

      /* make sure we don't get a notification loop */
      p2 = "X-Notification: ";
      p = strstr(mbuf,p2);
      if (p && strncmp(p+strlen(p2), lp_from_address(), strlen(lp_from_address()))==0) {
            return 0;
      }

      notify_dir(dir, idname, "new message %s\n", fname);

      if (followup) {
            notify_msg(idname,"new followup %d\n", followup);
      }

      return 0;
}


int main(int argc, char *argv[])
{
      int ret;
      char *dir;

      if (argc <= 1) {
            fprintf(stderr,"You must specify a configuration to use\n");
            exit(1);
      }

      load_config(argv[1]);

      if (chdir(root_directory())) {
            fprintf(stderr,"Failed to chdir to %s : %s\n", 
                  root_directory(), strerror(errno));
            exit(1);
      }

      if (argc > 2)
            dir = argv[2];
      else
            dir = lp_incoming();

      umask(022);

      lock_system();
      ret = process_mail(dir);
      unlock_system();

      return ret;
}

Generated by  Doxygen 1.6.0   Back to index