ctm_smail.c revision 16880
16081Sphk/* 28857Srgrimes * Send a compressed CTM delta to a recipient mailing list by encoding it 36081Sphk * in safe ASCII characters, in mailer-friendly chunks, and passing it 46081Sphk * to sendmail. The encoding is almost the same as MIME BASE64, and is 56081Sphk * protected by a simple checksum. 66081Sphk * 76081Sphk * Author: Stephen McKay 86081Sphk * 98857Srgrimes * NOTICE: This is free software. I hope you get some use from this program. 108857Srgrimes * In return you should think about all the nice people who give away software. 118857Srgrimes * Maybe you should write some free software too. 1216880Sgpalmer * 1316880Sgpalmer * $Id$ 146081Sphk */ 156081Sphk 166081Sphk#include <stdio.h> 1716880Sgpalmer#include <stdlib.h> 186081Sphk#include <string.h> 196290Sphk#include <unistd.h> 2016880Sgpalmer#include <fcntl.h> 216081Sphk#include <sys/types.h> 226081Sphk#include <sys/stat.h> 236081Sphk#include <errno.h> 246081Sphk#include <paths.h> 256081Sphk#include "error.h" 266081Sphk#include "options.h" 276081Sphk 286081Sphk#define DEF_MAX_MSG 64000 /* Default maximum mail msg minus headers. */ 296081Sphk 306081Sphk#define LINE_LENGTH 76 /* Chars per encode line. Divisible by 4. */ 316081Sphk 326081Sphkvoid chop_and_send(char *delta, off_t ctm_size, long max_msg_size, 336081Sphk char *mail_alias); 3416880Sgpalmervoid chop_and_queue(char *delta, off_t ctm_size, long max_msg_size, 3516880Sgpalmer char *queue_dir, char *mail_alias); 366081Sphkunsigned encode_body(FILE *sm_fp, FILE *delta_fp, long msg_size); 376081Sphkvoid write_header(FILE *sfp, char *mail_alias, char *delta, int pce, 386081Sphk int npieces); 396081Sphkvoid write_trailer(FILE *sfp, unsigned sum); 406081Sphkvoid apologise(char *delta, off_t ctm_size, long max_ctm_size, 416081Sphk char *mail_alias); 426081SphkFILE *open_sendmail(void); 436081Sphkint close_sendmail(FILE *fp); 4416880Sgpalmerint lock_queuedir(char *queue_dir); 4516880Sgpalmervoid free_lock(int lockf, char *queue_dir); 4616880Sgpalmervoid add_to_queue(char *queue_dir, char *mail_alias, char *delta, int npieces, char **tempnames); 476081Sphk 486290Sphkint 496081Sphkmain(int argc, char **argv) 506081Sphk { 516081Sphk char *delta_file; 526081Sphk char *mail_alias; 536081Sphk long max_msg_size = DEF_MAX_MSG; 546081Sphk long max_ctm_size = 0; 556081Sphk char *log_file = NULL; 5616880Sgpalmer char *queue_dir = NULL; 576081Sphk struct stat sb; 586081Sphk 596081Sphk err_prog_name(argv[0]); 606081Sphk 6116880Sgpalmer OPTIONS("[-l log] [-m maxmsgsize] [-c maxctmsize] [-q queuedir] ctm-delta mail-alias") 626081Sphk NUMBER('m', max_msg_size) 636081Sphk NUMBER('c', max_ctm_size) 646081Sphk STRING('l', log_file) 6516880Sgpalmer STRING('q', queue_dir) 666081Sphk ENDOPTS 676081Sphk 686081Sphk if (argc != 3) 696081Sphk usage(); 706081Sphk 716081Sphk if (log_file != NULL) 726081Sphk err_set_log(log_file); 736081Sphk 746081Sphk delta_file = argv[1]; 756081Sphk mail_alias = argv[2]; 766081Sphk 776081Sphk if (stat(delta_file, &sb) < 0) 786081Sphk { 796081Sphk err("%s: %s", delta_file, strerror(errno)); 806081Sphk exit(1); 816081Sphk } 828857Srgrimes 836081Sphk if (max_ctm_size != 0 && sb.st_size > max_ctm_size) 846081Sphk apologise(delta_file, sb.st_size, max_ctm_size, mail_alias); 8516880Sgpalmer else if (queue_dir == NULL) 8616880Sgpalmer chop_and_send(delta_file, sb.st_size, max_msg_size, mail_alias); 876081Sphk else 8816880Sgpalmer chop_and_queue(delta_file, sb.st_size, max_msg_size, queue_dir, mail_alias); 896081Sphk 906081Sphk return 0; 916081Sphk } 926081Sphk 936081Sphk 946081Sphk/* 956081Sphk * Carve our CTM delta into pieces, encode them, and send them. 966081Sphk */ 976081Sphkvoid 986081Sphkchop_and_send(char *delta, off_t ctm_size, long max_msg_size, char *mail_alias) 996081Sphk { 1006081Sphk int npieces; 1016081Sphk long msg_size; 1026081Sphk long exp_size; 1036081Sphk int pce; 1046081Sphk FILE *sfp; 1056081Sphk FILE *dfp; 1066081Sphk unsigned sum; 1076081Sphk 10816880Sgpalmer#ifdef howmany 10916880Sgpalmer#undef howmany 11016880Sgpalmer#endif 11116880Sgpalmer 11214707Sbde#define howmany(x, y) (((x) + ((y) - 1)) / (y)) 1136081Sphk 1146081Sphk /* 1156081Sphk * Work out how many pieces we need, bearing in mind that each piece 1166081Sphk * grows by 4/3 when encoded. We count the newlines too, but ignore 1176081Sphk * all mail headers and piece headers. They are a "small" (almost 1186081Sphk * constant) per message overhead that we make the user worry about. :-) 1196081Sphk */ 1206081Sphk exp_size = ctm_size * 4 / 3; 1216081Sphk exp_size += howmany(exp_size, LINE_LENGTH); 1226081Sphk npieces = howmany(exp_size, max_msg_size); 1236081Sphk msg_size = howmany(ctm_size, npieces); 1246081Sphk 1256081Sphk#undef howmany 1266081Sphk 1276081Sphk if ((dfp = fopen(delta, "r")) == NULL) 1286081Sphk { 1296081Sphk err("cannot open '%s' for reading.", delta); 1306081Sphk exit(1); 1316081Sphk } 1326081Sphk 1336081Sphk for (pce = 1; pce <= npieces; pce++) 1346081Sphk { 1356081Sphk sfp = open_sendmail(); 1366081Sphk if (sfp == NULL) 1376081Sphk exit(1); 1386081Sphk write_header(sfp, mail_alias, delta, pce, npieces); 1396081Sphk sum = encode_body(sfp, dfp, msg_size); 1406081Sphk write_trailer(sfp, sum); 1416081Sphk if (!close_sendmail(sfp)) 1426081Sphk exit(1); 1436081Sphk err("%s %d/%d sent to %s", delta, pce, npieces, mail_alias); 1446081Sphk } 1456081Sphk 1466081Sphk fclose(dfp); 1476081Sphk } 1486081Sphk 14916880Sgpalmer/* 15016880Sgpalmer * Carve our CTM delta into pieces, encode them, and drop them in the 15116880Sgpalmer * queue dir. 15216880Sgpalmer * 15316880Sgpalmer * Basic algorythm: 15416880Sgpalmer * 15516880Sgpalmer * - for (each piece) 15616880Sgpalmer * - gen. temp. file name (one which the de-queuer will ignore) 15716880Sgpalmer * - record in array 15816880Sgpalmer * - open temp. file 15916880Sgpalmer * - encode delta (including headers) into the temp file 16016880Sgpalmer * - close temp. file 16116880Sgpalmer * - end 16216880Sgpalmer * - lock queue directory 16316880Sgpalmer * - foreach (temp. file) 16416880Sgpalmer * - rename to the proper filename 16516880Sgpalmer * - end 16616880Sgpalmer * - unlock queue directory 16716880Sgpalmer * 16816880Sgpalmer * This is probably overkill, but it means that incomplete deltas 16916880Sgpalmer * don't get mailed, and also reduces the window for lock races 17016880Sgpalmer * between ctm_smail and the de-queueing process. 17116880Sgpalmer */ 1726081Sphk 17316880Sgpalmervoid 17416880Sgpalmerchop_and_queue(char *delta, off_t ctm_size, long max_msg_size, char *queue_dir, char *mail_alias) 17516880Sgpalmer{ 17616880Sgpalmer int npieces, pce, len; 17716880Sgpalmer long msg_size, exp_size; 17816880Sgpalmer FILE *sfp, *dfp; 17916880Sgpalmer unsigned sum; 18016880Sgpalmer char **tempnames, *tempnam, *sn; 18116880Sgpalmer 18216880Sgpalmer#define howmany(x, y) (((x) + ((y) - 1)) / (y)) 18316880Sgpalmer 18416880Sgpalmer /* 18516880Sgpalmer * Work out how many pieces we need, bearing in mind that each piece 18616880Sgpalmer * grows by 4/3 when encoded. We count the newlines too, but ignore 18716880Sgpalmer * all mail headers and piece headers. They are a "small" (almost 18816880Sgpalmer * constant) per message overhead that we make the user worry about. :-) 18916880Sgpalmer */ 19016880Sgpalmer exp_size = ctm_size * 4 / 3; 19116880Sgpalmer exp_size += howmany(exp_size, LINE_LENGTH); 19216880Sgpalmer npieces = howmany(exp_size, max_msg_size); 19316880Sgpalmer msg_size = howmany(ctm_size, npieces); 19416880Sgpalmer 19516880Sgpalmer#undef howmany 19616880Sgpalmer 19716880Sgpalmer /* 19816880Sgpalmer * allocate space for the array of filenames. Try to be portable 19916880Sgpalmer * by not assuming anything to do with sizeof(char *) 20016880Sgpalmer */ 20116880Sgpalmer tempnames = malloc(npieces * sizeof(char *)); 20216880Sgpalmer if (tempnames == NULL) 20316880Sgpalmer { 20416880Sgpalmer err("malloc for tempnames failed"); 20516880Sgpalmer exit(1); 20616880Sgpalmer } 20716880Sgpalmer 20816880Sgpalmer len = strlen(queue_dir) + 16; 20916880Sgpalmer tempnam = malloc(len); 21016880Sgpalmer if (tempnam == NULL) 21116880Sgpalmer { 21216880Sgpalmer err("malloc for tempnames failed"); 21316880Sgpalmer exit(1); 21416880Sgpalmer } 21516880Sgpalmer 21616880Sgpalmer if ((dfp = fopen(delta, "r")) == NULL) 21716880Sgpalmer { 21816880Sgpalmer err("cannot open '%s' for reading.", delta); 21916880Sgpalmer exit(1); 22016880Sgpalmer } 22116880Sgpalmer 22216880Sgpalmer if ((sn = strrchr(delta, '/')) == NULL) 22316880Sgpalmer sn = delta; 22416880Sgpalmer else 22516880Sgpalmer sn++; 22616880Sgpalmer 22716880Sgpalmer for (pce = 1; pce <= npieces; pce++) 22816880Sgpalmer { 22916880Sgpalmer if (snprintf(tempnam, len, "%s/.%08d-%03d", queue_dir, getpid(), pce) >= len) 23016880Sgpalmer err("Whoops! tempnam isn't long enough"); 23116880Sgpalmer 23216880Sgpalmer tempnames[pce - 1] = strdup(tempnam); 23316880Sgpalmer if (tempnames[pce - 1] == NULL) 23416880Sgpalmer { 23516880Sgpalmer err("strdup failed for temp. filename"); 23616880Sgpalmer exit(1); 23716880Sgpalmer } 23816880Sgpalmer 23916880Sgpalmer sfp = fopen(tempnam, "w"); 24016880Sgpalmer if (sfp == NULL) 24116880Sgpalmer exit(1); 24216880Sgpalmer 24316880Sgpalmer write_header(sfp, mail_alias, delta, pce, npieces); 24416880Sgpalmer sum = encode_body(sfp, dfp, msg_size); 24516880Sgpalmer write_trailer(sfp, sum); 24616880Sgpalmer 24716880Sgpalmer if (fclose(sfp) != 0) 24816880Sgpalmer exit(1); 24916880Sgpalmer 25016880Sgpalmer err("%s %d/%d created succesfully", sn, pce, npieces); 25116880Sgpalmer } 25216880Sgpalmer 25316880Sgpalmer add_to_queue(queue_dir, mail_alias, delta, npieces, tempnames); 25416880Sgpalmer 25516880Sgpalmer fclose(dfp); 25616880Sgpalmer 25716880Sgpalmer} 25816880Sgpalmer 25916880Sgpalmer 2606081Sphk/* 2616081Sphk * MIME BASE64 encode table. 2626081Sphk */ 2636081Sphkstatic char to_b64[0x40] = 2646081Sphk "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 2656081Sphk 2666081Sphk/* 2676081Sphk * This cheap plastic checksum effectively rotates our checksum-so-far 2686081Sphk * left one, then adds the character. We only want 16 bits of it, and 2696081Sphk * don't care what happens to the rest. It ain't much, but it's small. 2706081Sphk */ 2716081Sphk#define add_ck(sum,x) \ 2726081Sphk ((sum) += ((x)&0xff) + (sum) + (((sum)&0x8000) ? 1 : 0)) 2736081Sphk 2746081Sphk/* 2756081Sphk * Encode the body. Use an encoding almost the same as MIME BASE64. 2766081Sphk * 2776081Sphk * Characters are read from delta_fp and encoded characters are written 2786081Sphk * to sm_fp. At most 'msg_size' characters should be read from delta_fp. 2796081Sphk * 2806081Sphk * The body consists of lines of up to LINE_LENGTH characters. Each group 2816081Sphk * of 4 characters encodes 3 input characters. Each output character encodes 2826081Sphk * 6 bits. Thus 64 different characters are needed in this representation. 2836081Sphk */ 2846081Sphkunsigned 2856081Sphkencode_body(FILE *sm_fp, FILE *delta_fp, long msg_size) 2866081Sphk { 2876081Sphk unsigned short cksum = 0xffff; 2886081Sphk unsigned char *ip; 2896081Sphk char *op; 2906081Sphk int want, n, i; 2916081Sphk unsigned char inbuf[LINE_LENGTH*3/4]; 2926081Sphk char outbuf[LINE_LENGTH+1]; 2936081Sphk 2946081Sphk /* 2956081Sphk * Round up to the nearest line boundary, for the tiniest of gains, 2966081Sphk * and lots of neatness. :-) 2976081Sphk */ 2986081Sphk msg_size += (LINE_LENGTH*3/4) - 1; 2996081Sphk msg_size -= msg_size % (LINE_LENGTH*3/4); 3006081Sphk 3016081Sphk while (msg_size > 0) 3026081Sphk { 3036081Sphk want = (msg_size < sizeof(inbuf)) ? msg_size : sizeof(inbuf); 3046081Sphk if ((n = fread(inbuf, sizeof(char), want, delta_fp)) == 0) 3056081Sphk break; 3066081Sphk msg_size -= n; 3076081Sphk 3086081Sphk for (i = 0; i < n; i++) 3096081Sphk add_ck(cksum, inbuf[i]); 3106081Sphk 3116081Sphk /* 3126081Sphk * Produce a line of encoded data. Every line length will be a 3136081Sphk * multiple of 4, except for, perhaps, the last line. 3146081Sphk */ 3156081Sphk ip = inbuf; 3166081Sphk op = outbuf; 3176081Sphk while (n >= 3) 3186081Sphk { 3196081Sphk *op++ = to_b64[ip[0] >> 2]; 3206081Sphk *op++ = to_b64[(ip[0] << 4 & 0x3f) | ip[1] >> 4]; 3216081Sphk *op++ = to_b64[(ip[1] << 2 & 0x3f) | ip[2] >> 6]; 3226081Sphk *op++ = to_b64[ip[2] & 0x3f]; 3236081Sphk ip += 3; 3246081Sphk n -= 3; 3256081Sphk } 3266081Sphk if (n > 0) 3276081Sphk { 3286081Sphk *op++ = to_b64[ip[0] >> 2]; 3296081Sphk *op++ = to_b64[(ip[0] << 4 & 0x3f) | ip[1] >> 4]; 3306081Sphk if (n >= 2) 3316081Sphk *op++ = to_b64[ip[1] << 2 & 0x3f]; 3326081Sphk } 3336081Sphk *op++ = '\n'; 3346081Sphk fwrite(outbuf, sizeof(char), op - outbuf, sm_fp); 3356081Sphk } 3366081Sphk 3376081Sphk if (ferror(delta_fp)) 3386081Sphk { 3396081Sphk err("error reading input file."); 3406081Sphk exit(1); 3416081Sphk } 3426081Sphk 3436081Sphk if (ferror(sm_fp)) 3446081Sphk { 34516880Sgpalmer err("error writing encoded file"); 3466081Sphk exit(1); 3476081Sphk } 3486081Sphk 3496081Sphk return cksum; 3506081Sphk } 3516081Sphk 3526081Sphk 3536081Sphk/* 3546081Sphk * Write the mail header and data header. 3556081Sphk */ 3566081Sphkvoid 3576081Sphkwrite_header(FILE *sfp, char *mail_alias, char *delta, int pce, int npieces) 3586081Sphk { 3596081Sphk char *sn; 3606081Sphk 3616081Sphk if ((sn = strrchr(delta, '/')) == NULL) 3626081Sphk sn = delta; 3636081Sphk else 3646081Sphk sn++; 3656081Sphk 3666457Sphk fprintf(sfp, "From: owner-%s\n", mail_alias); 3676081Sphk fprintf(sfp, "To: %s\n", mail_alias); 3686081Sphk fprintf(sfp, "Subject: ctm-mail %s %d/%d\n\n", sn, pce, npieces); 3696081Sphk 3706081Sphk fprintf(sfp, "CTM_MAIL BEGIN %s %d %d\n", sn, pce, npieces); 3716081Sphk } 3726081Sphk 3736081Sphk 3746081Sphk/* 3756081Sphk * Write the data trailer. 3766081Sphk */ 3776081Sphkvoid 3786081Sphkwrite_trailer(FILE *sfp, unsigned sum) 3796081Sphk { 3806081Sphk fprintf(sfp, "CTM_MAIL END %ld\n", (long)sum); 3816081Sphk } 3826081Sphk 3836081Sphk 3846081Sphk/* 3856081Sphk * We're terribly sorry, but the delta is too big to send. 3866081Sphk */ 3876081Sphkvoid 3886081Sphkapologise(char *delta, off_t ctm_size, long max_ctm_size, char *mail_alias) 3896081Sphk { 3906081Sphk FILE *sfp; 3916081Sphk char *sn; 3926081Sphk 3936081Sphk sfp = open_sendmail(); 3946081Sphk if (sfp == NULL) 3956081Sphk exit(1); 3966081Sphk 3976081Sphk if ((sn = strrchr(delta, '/')) == NULL) 3986081Sphk sn = delta; 3996081Sphk else 4006081Sphk sn++; 4016081Sphk 4026081Sphk fprintf(sfp, "From: %s-owner\n", mail_alias); 4036081Sphk fprintf(sfp, "To: %s\n", mail_alias); 4046081Sphk fprintf(sfp, "Subject: ctm-notice %s\n\n", sn); 4056081Sphk 4066081Sphk fprintf(sfp, "%s is %ld bytes. The limit is %ld bytes.\n\n", sn, 4076081Sphk (long)ctm_size, max_ctm_size); 4086081Sphk fprintf(sfp, "You can retrieve this delta via ftpmail, or your good mate at the university.\n"); 4096081Sphk 4106081Sphk if (!close_sendmail(sfp)) 4116081Sphk exit(1); 4126081Sphk } 4136081Sphk 4146081Sphk 4156081Sphk/* 4166081Sphk * Start a pipe to sendmail. Sendmail will decode the destination 4176081Sphk * from the message contents. 4186081Sphk */ 4196081SphkFILE * 4206081Sphkopen_sendmail() 4216081Sphk { 4226081Sphk FILE *fp; 4236081Sphk char buf[100]; 4246081Sphk 4256081Sphk sprintf(buf, "%s -t", _PATH_SENDMAIL); 4266081Sphk if ((fp = popen(buf, "w")) == NULL) 4276081Sphk err("cannot start sendmail"); 4286081Sphk return fp; 4296081Sphk } 4306081Sphk 4316081Sphk 4326081Sphk/* 4336081Sphk * Close a pipe to sendmail. Sendmail will then do its bit. 4346081Sphk * Return 1 on success, 0 on failure. 4356081Sphk */ 4366081Sphkint 4376081Sphkclose_sendmail(FILE *fp) 4386081Sphk { 4396081Sphk int status; 4406081Sphk 4416081Sphk fflush(fp); 4426081Sphk if (ferror(fp)) 4436081Sphk { 4446081Sphk err("error writing to sendmail"); 4456081Sphk return 0; 4466081Sphk } 4476081Sphk 4486081Sphk if ((status = pclose(fp)) != 0) 4496081Sphk err("sendmail failed with status %d", status); 4506081Sphk 4516081Sphk return (status == 0); 4526081Sphk } 45316880Sgpalmer 45416880Sgpalmer/* 45516880Sgpalmer * Lock the queuedir so we're the only guy messing about in there. 45616880Sgpalmer */ 45716880Sgpalmerint 45816880Sgpalmerlock_queuedir(char *queue_dir) 45916880Sgpalmer{ 46016880Sgpalmer int fp, len; 46116880Sgpalmer char *buffer; 46216880Sgpalmer struct stat sb; 46316880Sgpalmer 46416880Sgpalmer len = strlen(queue_dir) + 8; 46516880Sgpalmer 46616880Sgpalmer buffer = malloc(len); 46716880Sgpalmer if (buffer == NULL) 46816880Sgpalmer { 46916880Sgpalmer err("malloc failed in lock_queuedir"); 47016880Sgpalmer exit(1); 47116880Sgpalmer } 47216880Sgpalmer 47316880Sgpalmer if (snprintf(buffer, len, "%s/.lock", queue_dir) >= len) 47416880Sgpalmer err("Whoops. lock buffer too small in lock_queuedir"); 47516880Sgpalmer 47616880Sgpalmer /* 47716880Sgpalmer * We do our own lockfile scanning to avoid unlink races. 60 47816880Sgpalmer * seconds should be enough to ensure that we won't get more races 47916880Sgpalmer * happening between the stat and the open/flock. 48016880Sgpalmer */ 48116880Sgpalmer 48216880Sgpalmer while (stat(buffer, &sb) == 0) 48316880Sgpalmer sleep(60); 48416880Sgpalmer 48516880Sgpalmer if ((fp = open(buffer, O_WRONLY | O_CREAT | O_EXLOCK, 0600)) < 0) 48616880Sgpalmer { 48716880Sgpalmer err("can't open `%s' in lock_queuedir", buffer); 48816880Sgpalmer exit(1); 48916880Sgpalmer } 49016880Sgpalmer 49116880Sgpalmer snprintf(buffer, len, "%8ld", getpid()); 49216880Sgpalmer write(fp, buffer, 8); 49316880Sgpalmer 49416880Sgpalmer free(buffer); 49516880Sgpalmer 49616880Sgpalmer return(fp); 49716880Sgpalmer} 49816880Sgpalmer 49916880Sgpalmer/* 50016880Sgpalmer * Lock the queuedir so we're the only guy messing about in there. 50116880Sgpalmer */ 50216880Sgpalmervoid 50316880Sgpalmerfree_lock(int lockf, char *queue_dir) 50416880Sgpalmer{ 50516880Sgpalmer int len; 50616880Sgpalmer char *path; 50716880Sgpalmer 50816880Sgpalmer /* 50916880Sgpalmer * Most important: free the lock before we do anything else! 51016880Sgpalmer */ 51116880Sgpalmer 51216880Sgpalmer close(lockf); 51316880Sgpalmer 51416880Sgpalmer len = strlen(queue_dir) + 7; 51516880Sgpalmer 51616880Sgpalmer path = malloc(len); 51716880Sgpalmer if (path == NULL) 51816880Sgpalmer { 51916880Sgpalmer err("malloc failed in free_lock"); 52016880Sgpalmer exit(1); 52116880Sgpalmer } 52216880Sgpalmer 52316880Sgpalmer if (snprintf(path, len, "%s/.lock", queue_dir) >= len) 52416880Sgpalmer err("lock path buffer too small in free_lock"); 52516880Sgpalmer 52616880Sgpalmer if (unlink(path) != 0) 52716880Sgpalmer { 52816880Sgpalmer err("can't unlink lockfile `%s'", path); 52916880Sgpalmer exit(1); 53016880Sgpalmer } 53116880Sgpalmer 53216880Sgpalmer free(path); 53316880Sgpalmer} 53416880Sgpalmer 53516880Sgpalmer/* move everything into the queue directory. */ 53616880Sgpalmer 53716880Sgpalmervoid 53816880Sgpalmeradd_to_queue(char *queue_dir, char *mail_alias, char *delta, int npieces, char **tempnames) 53916880Sgpalmer{ 54016880Sgpalmer char *queuefile, *sn; 54116880Sgpalmer int pce, len, lockf; 54216880Sgpalmer 54316880Sgpalmer if ((sn = strrchr(delta, '/')) == NULL) 54416880Sgpalmer sn = delta; 54516880Sgpalmer else 54616880Sgpalmer sn++; 54716880Sgpalmer 54816880Sgpalmer /* try to malloc all we need BEFORE entering the lock loop */ 54916880Sgpalmer 55016880Sgpalmer len = strlen(queue_dir) + strlen(sn) + 7; 55116880Sgpalmer queuefile = malloc(len); 55216880Sgpalmer if (queuefile == NULL) 55316880Sgpalmer { 55416880Sgpalmer err("can't malloc for queuefile"); 55516880Sgpalmer exit(1); 55616880Sgpalmer } 55716880Sgpalmer 55816880Sgpalmer /* 55916880Sgpalmer * We should be the only process mucking around in the queue 56016880Sgpalmer * directory while we add the new queue files ... it could be 56116880Sgpalmer * awkward if the de-queue process starts it's job while we're 56216880Sgpalmer * adding files ... 56316880Sgpalmer */ 56416880Sgpalmer 56516880Sgpalmer lockf = lock_queuedir(queue_dir); 56616880Sgpalmer for (pce = 0; pce < npieces; pce++) 56716880Sgpalmer { 56816880Sgpalmer struct stat sb; 56916880Sgpalmer 57016880Sgpalmer if (snprintf(queuefile, len, "%s/%s+%03d", queue_dir, sn, pce + 1) >= len) 57116880Sgpalmer err("whoops, queuefile buffer is too small"); 57216880Sgpalmer 57316880Sgpalmer if (stat(queuefile, &sb) == 0) 57416880Sgpalmer { 57516880Sgpalmer err("WOAH! Queue file `%s' already exists! Bailing out.", queuefile); 57616880Sgpalmer free_lock(lockf, queue_dir); 57716880Sgpalmer exit(1); 57816880Sgpalmer } 57916880Sgpalmer 58016880Sgpalmer rename(tempnames[pce], queuefile); 58116880Sgpalmer err("Queue file %s now exists", queuefile); 58216880Sgpalmer } 58316880Sgpalmer 58416880Sgpalmer free_lock(lockf, queue_dir); 58516880Sgpalmer 58616880Sgpalmer free(queuefile); 58716880Sgpalmer} 588