/* autorespond for qmail Copyright 1998 Eric Huss E-mail: e-huss@netmeridian.com Usage: autorespond time num message dir time - time in seconds to consider consecutive num - maximum number of messages to respond to within time seconds message - the message file dir - directory to store list of e-mail addresses */ /* Exit codes: 0 - OK 99 - OK...stop processing lines in .qmail 100 - hard error 111 - soft error */ /* SENDER - envelope sender NEWSENDER - forwarding evelope sender RECIPIENT - envelope "to" USER - the user HOME - your home directory HOST - host of recipient address LOCAL - local of recipient address EXT - .qmail extension...etc. DTLINE - Delivered-To RPLINE - Return-Path */ /*Change this value here to the location of your qmail*/ #define QMAIL_LOCATION "/var/qmail" #include #include #include #include #include #include #include #include #include #include #include void * safe_malloc(size_t size) { void * ptr; ptr = malloc(size); if(ptr==NULL) { /*exit...no memory*/ _exit(111); } return ptr; } void * safe_realloc(void * ptr, size_t size) { void * p; p = realloc(ptr,size); if(p==NULL) { /*exit...no memory*/ _exit(111); } return p; } char * read_file(char * filename) { FILE * f; unsigned long size; char * buffer; if(!filename) { /*failed*/ return NULL; } f = fopen(filename,"rb"); if(f==NULL) { /*failed*/ return NULL; } /*seek to end*/ if(fseek(f,0,SEEK_END)==-1) { /*failed*/ fclose(f); return NULL; } /*this may not be portable (although it almost always is)*/ size = ftell(f); /*return to the beginning*/ if(fseek(f,0,SEEK_SET)==-1) { fclose(f); return NULL; } buffer = (char *) safe_malloc(size+100); if(fread(buffer,1,size,f)!=size) { fclose(f); return NULL; } buffer[size]=0; /*for safety*/ fclose(f); return buffer; } /*see header file for more info*/ static char *binqqargs[2] = { "bin/qmail-queue", 0 }; static char *montab[12] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; /* A wrapper for qmail-queue*/ /* borrowed from djb*/ int send_message(char * msg, char * from, char ** recipients, int num_recipients) { /* ...Adds Date: ...Adds Message-Id:*/ int r; int wstat; int i; struct tm * dt; unsigned long msgwhen; FILE * fdm; FILE * fde; pid_t pid; int pim[2]; /*message pipe*/ int pie[2]; /*envelope pipe*/ /*open a pipe to qmail-queue*/ if(pipe(pim)==-1 || pipe(pie)==-1) { return -1; } pid = vfork(); if(pid == -1) { /*failure*/ return -1; } if(pid == 0) { /*I am the child*/ close(pim[1]); close(pie[1]); /*switch the pipes to fd 0 and 1 pim[0] goes to 0 (stdin)...the message*/ if(fcntl(pim[0],F_GETFL,0) == -1) { /* fprintf(stderr,"Failure getting status flags.\n");*/ _exit(120); } close(0); if(fcntl(pim[0],F_DUPFD,0)==-1) { /* fprintf(stderr,"Failure duplicating file descriptor.\n");*/ _exit(120); } close(pim[0]); /*pie[0] goes to 1 (stdout)*/ if(fcntl(pie[0],F_GETFL,0) == -1) { /* fprintf(stderr,"Failure getting status flags.\n");*/ _exit(120); } close(1); if(fcntl(pie[0],F_DUPFD,1)==-1) { /* fprintf(stderr,"Failure duplicating file descriptor.\n");*/ _exit(120); } close(pie[0]); if(chdir(QMAIL_LOCATION) == -1) { _exit(120); } execv(*binqqargs,binqqargs); _exit(120); } /*I am the parent*/ fdm = fdopen(pim[1],"wb"); /*updating*/ fde = fdopen(pie[1],"wb"); if(fdm==NULL || fde==NULL) { return -1; } close(pim[0]); close(pie[0]); /*prepare to add date and message-id*/ msgwhen = time(NULL); dt = gmtime((long *)&msgwhen); /*start outputting to qmail-queue date is in 822 format message-id could be computed a little better*/ fprintf(fdm,"Date: %u %s %u %02u:%02u:%02u -0000\n" "Message-ID: <%lu.%lu.blah>\n" "%s\n" ,dt->tm_mday,montab[dt->tm_mon],dt->tm_year+1900,dt->tm_hour,dt->tm_min,dt->tm_sec ,msgwhen,getpid() ,msg); fclose(fdm); /*send the envelopes*/ fprintf(fde,"F%s",from); fwrite("",1,1,fde); /*write a null char*/ for(i=0;i> 8)!=0) { /*non-zero exit status failed while waiting for qmail-queue*/ return -1; } return 0; } int main(int argc, char ** argv) { char * sender; char * message; unsigned int time_message; unsigned int timer; unsigned int num; char * message_filename; char * dir; char * msg; char * incoming_message; char * ptr; unsigned int k; unsigned int incoming_message_index; unsigned int i; unsigned int size; char * my_delivered_to; DIR * dirp; struct dirent * direntp; unsigned int message_time; char * address; unsigned int count; char * filename; FILE * f; setvbuf(stderr, NULL, _IONBF, 0); if(argc!=5) { fprintf(stderr, "AUTORESPOND: Invalid arguments.\n"); _exit(111); } time_message = strtoul(argv[1],NULL,10); timer = time(NULL); num = strtoul(argv[2],NULL,10); message_filename = argv[3]; dir = argv[4]; /*prepare the "delivered-to" string*/ my_delivered_to = "Delivered-To: Autoresponder\n"; /*load the incoming message into a variable*/ i = 0; incoming_message = (char *) safe_malloc(10005); size = 10000; while(1) { /*read in a bunch*/ k = read(0,incoming_message+i,10000); if(k==-1) { /*failed*/ fprintf(stderr,"Failure while reading standard input.\n"); _exit(111); /*soft error*/ } else if(k==0) { /*done reading*/ break; } else { i+=k; } if( size-i < 10000 ) { /*need to allocate more space*/ incoming_message = (char *) safe_realloc(incoming_message,size+10005); size+=10000; } } incoming_message[i]=0; message = read_file(message_filename); if(message==NULL) { fprintf(stderr, "AUTORESPOND: Failed to open message file.\n"); _exit(111); } /*don't autorespond in certain situations*/ sender = getenv("SENDER"); if(sender==NULL) sender = ""; /*don't autorespond to a mailer-daemon*/ if( sender[0]==0 || strncasecmp(sender,"mailer-daemon",13)==0 || strchr(sender,'@')==NULL || strcmp(sender,"#@[]")==0 ) { /*exit with success but request to stop parsing .qmail file*/ fprintf(stderr,"AUTORESPOND: Stopping on mail from [%s].\n",sender); _exit(99); } /*don't autorespond to myself*/ incoming_message_index = 0; while(1) { /*break once the headers are done*/ if( incoming_message[incoming_message_index]=='\n' || incoming_message[incoming_message_index]==0) break; /*check if this is not a continuing header*/ if( incoming_message[incoming_message_index]!=' ' && incoming_message[incoming_message_index]!='\t') { if(strncasecmp(incoming_message+incoming_message_index,"mailing-list:",13)==0) { /*don't support a message with a mailing-list header*/ fprintf(stderr,"AUTORESPOND: I can't handle a message with a Mailing-List header.\n"); _exit(100); /*hard error*/ } if(strncasecmp(incoming_message+incoming_message_index,my_delivered_to ,strlen(my_delivered_to))==0) { /*got one of my own messages...*/ fprintf(stderr,"AUTORESPOND: This message is looping...it has my Delivered-To header.\n"); _exit(100); } /*check for precedence header*/ if(strncasecmp(incoming_message+incoming_message_index,"precedence:",11)==0) { incoming_message_index += 11; /*could go too far...use temp*/ i = 0; while( incoming_message[incoming_message_index+i]==' ' || incoming_message[incoming_message_index+i]=='\t' || incoming_message[incoming_message_index+i]==10 || incoming_message[incoming_message_index+i]==13) { i++; } if( strncasecmp(incoming_message+incoming_message_index+i,"junk",4)==0 || strncasecmp(incoming_message+incoming_message_index+i,"bulk",4)==0 || strncasecmp(incoming_message+incoming_message_index+i,"list",4)==0) { fprintf(stderr,"AUTORESPOND: Junk mail received.\n"); _exit(100); } } /*end if precedence*/ } /*end if not continuation*/ /*get the end of the line*/ ptr = strchr(incoming_message+incoming_message_index,'\n'); if(ptr==NULL) ptr = strchr(incoming_message+incoming_message_index,0); /*assume this works*/ k = ptr-(incoming_message+incoming_message_index); incoming_message_index += k; /*newline will be skipped with ++ at end*/ if(incoming_message[incoming_message_index]==0) break; incoming_message_index++; } /*end while 1*/ /*check the logs*/ if(chdir(dir) == -1) { fprintf(stderr,"AUTORESPOND: Failed to change into directory.\n"); _exit(111); } /*add entry*/ filename = (char *) safe_malloc(100); sprintf(filename,"A%lu.%u",getpid(),timer); f = fopen(filename,"wb"); if(f==NULL) { fprintf(stderr,"AUTORESPOND: Unable to create file for [%s].",sender); _exit(111); } if(fwrite(sender,1,strlen(sender),f)!=strlen(sender)) { fprintf(stderr,"AUTORESPOND: Unable to create file for [%s].",sender); fclose(f); unlink(filename); _exit(111); } fclose(f); free(filename); /*check if there are too many responses in the logs*/ dirp = opendir("."); count = 0; while((direntp = readdir(dirp)) != NULL) { if(direntp->d_name[0] != 'A') continue; ptr = strchr(direntp->d_name,'.'); if(ptr==NULL) continue; message_time = strtoul(ptr+1,NULL,10); if(message_time < timer-time_message) { /*too old..ignore errors on unlink*/ unlink(direntp->d_name); } else { address = read_file(direntp->d_name); if(address==NULL) { /*ignore this?*/ continue; } if(strcasecmp(address,sender)==0) { count++; } free(address); } } if(count>num) { fprintf(stderr,"AUTORESPOND: too many received from [%s]\n",sender); _exit(99); } msg = (char *) safe_malloc(strlen(message) + strlen(my_delivered_to) + strlen(sender) + strlen(incoming_message) + 1000); sprintf(msg,"%s" "To: %s\n" "%s\n" "\n" "%s\n" ,my_delivered_to ,sender ,message ,incoming_message); /*send the autoresponse...ignore errors?*/ send_message(msg,"",&sender,1); _exit(0); return 0; /*compiler warning squelch*/ }