static void do_list(int act) { unsigned int i; if (!flaglist || (modsub.s == 0 && remote.s == 0)) strerr_die2x(100,FATAL,MSG(ERR_NOT_AVAILABLE)); if (!ismod) strerr_die2x(100,FATAL,MSG(ERR_NOT_ALLOWED)); hdr_subject(MSG(SUB_LIST)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); if (act == AC_LIST) { showsend("list"); (void) code_qputs(""); (void) code_qputs(MSG(TXT_LISTMEMBERS)); (void) code_qputs("\n"); i = putsubs(workdir,0L,52L,code_subto); } else { /* listn */ showsend("listn"); i = putsubs(workdir,0L,52L,dummy_to); } (void) code_qput("\n ======> ",11); (void) code_qput(strnum,fmt_ulong(strnum,i)); (void) code_qput("\n",1); copybottom(0); qmail_to(&qq,mod.s); }
void mod_bottom(void) { copy(&qq,"text/mod-sub",flagcd); copy(&qq,"text/bottom",flagcd); code_qputs(""); code_qputs(MSG(TXT_SUPPRESSED)); code_qputs("\n"); if (flagcd) hdr_boundary(1); if (flagcd == 'B') { encodeB("",0,&line,2); /* flush */ qmail_put(&qq,line.s,line.len); } qmail_from(&qq,from.s); }
void presub(unsigned long from,unsigned long to,stralloc *subject, int factype, /* action type (AC_THREAD,AC_GET,AC_DIGEST) */ char format) /* output format type (see idx.h) */ /* Starts within header, outputs "subject" and optional headers, terminates*/ /* header and handles output before table-of-contents */ { switch(format) { case MIME: case VIRGIN: case NATIVE: case MIXED: hdr_mime((format == MIXED) ? CTYPE_MULTIPART : CTYPE_DIGEST); hdr_add2("Subject: ",subject->s,subject->len); hdr_boundary(0); hdr_ctype(CTYPE_TEXT); hdr_transferenc(); /* content-transfer-enc header if needed */ break; case RFC1153: hdr_mime(CTYPE_TEXT); hdr_add2("Subject: ",subject->s,subject->len); qmail_puts(&qq,"\n"); flagcd = '\0'; /* We make 8-bit messages, not QP/base64 for rfc1153 */ break; /* Since messages themselves aren't encoded */ } if (!stralloc_cats(subject,"\n\n")) die_nomem(); code_qput(subject->s,subject->len); if (format != NATIVE && factype != AC_THREAD && factype != AC_INDEX) { strnum[fmt_ulong(strnum,from)] = 0; strnum2[fmt_ulong(strnum2,to)] = 0; code_qputs(MSG2(TXT_TOP_TOPICS,strnum,strnum2)); } }
void postsub(int factype, /* action type (AC_THREAD, AC_GET, AC_DIGEST) */ char format) /* output format type (see idx.h) */ /* output after TOC and before first message. */ { code_qputs(""); code_qputs(MSG(TXT_ADMINISTRIVIA)); code_qputs(""); if(factype == AC_DIGEST) { copy(&qq,"text/digest",flagcd); if (flagcd == 'B') { encodeB("",0,&line,2); /* flush */ qmail_put(&qq,line.s,line.len); } } else normal_bottom(format); if (!flagcd || format == RFC1153) qmail_puts(&qq,"\n----------------------------------------------------------------------\n"); else qmail_puts(&qq,"\n"); }
static void do_edit(const char *action) { unsigned int i; unsigned int len; char ch; /* only remote admins and only if -e is specified may edit */ if (!flagedit || remote.s == 0) strerr_die2x(100,FATAL,MSG(ERR_NOT_AVAILABLE)); if (!ismod) strerr_die2x(100,FATAL,MSG(ERR_NOT_ALLOWED)); len = str_len(ACTION_EDIT); if (!case_starts(action,ACTION_EDIT)) len = str_len(ALT_EDIT); if (action[len]) { /* -edit.file, not just -edit */ if (action[len] != '.') strerr_die2x(100,FATAL,MSG(ERR_BAD_REQUEST)); showsend2("edit ",action+len+1); stralloc_copys(&fnedit,"text/"); stralloc_cats(&fnedit,action+len+1); stralloc_0(&fnedit); case_lowerb(fnedit.s,fnedit.len); i = 5; /* after the "text/" */ while ((ch = fnedit.s[i++])) { if (((ch > 'z') || (ch < 'a')) && (ch != '_')) strerr_die2x(100,FATAL,MSG(ERR_BAD_NAME)); if (ch == '_') fnedit.s[i-1] = '-'; } switch(slurp(fnedit.s,&text,1024)) { /* entire file! */ case -1: strerr_die2sys(111,FATAL,MSG1(ERR_READ,fnedit.s)); case 0: strerr_die5x(100,FATAL,dir,"/",fnedit.s,MSG(ERR_NOEXIST)); } stralloc_copy(&line,&text); subst_nuls(&line); stralloc_cat(&line,&fnedit); /* including '\0' */ strnum[fmt_ulong(strnum,(unsigned long) when)] = 0; cookie(hash,key.s,key.len,strnum,line.s,"-e"); stralloc_copy(&confirm,&outlocal); stralloc_append(&confirm,'-'); stralloc_catb(&confirm,ACTION_ED,LENGTH_ED); stralloc_cats(&confirm,strnum); stralloc_append(&confirm,'.'); /* action part has been checked for bad chars */ stralloc_cats(&confirm,action + len + 1); stralloc_append(&confirm,'.'); stralloc_catb(&confirm,hash,COOKIE); stralloc_append(&confirm,'@'); stralloc_cat(&confirm,&outhost); stralloc_0(&confirm); set_cpconfirm(confirm.s,outlocal.len); set_cpaction(ACTION_ED); set_cphash(hash); set_cpwhen(when); qmail_puts(&qq,"Reply-To: "); quote2("ed,confirm.s); qmail_put(&qq,quoted.s,quoted.len); qmail_puts(&qq,"\n"); hdr_subject(MSG1(SUB_EDIT_REQUEST,action+len+1)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy(&qq,"text/edit-do",flagcd); (void) code_qputs(MSG(TXT_EDIT_START)); (void) code_qput(text.s,text.len); (void) code_qputs(MSG(TXT_EDIT_END)); } else { /* -edit only, so output list of editable files */ hdr_subject(MSG(SUB_EDIT_LIST)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy_act("text/edit-list"); } qmail_puts(&qq,"\n\n"); copybottom(0); qmail_to(&qq,mod.s); }
void main(int argc,char **argv) { char *def; char *local; const char *action = ""; char *psz; const char *err; int fd; unsigned int i,j; int flagremote; int match; int goodexit = 0; /* exit code for normal exit */ /* in manager this will be set to 0 */ unsigned long from,u,to,issue,prevmax; unsigned long mno = 0; unsigned long chunk; unsigned long subs = 0; unsigned int pos,pos1; unsigned int len; int opt; char outformat = 0; msgentry *msgtable; subentry *subtable; authentry *authtable; dateentry *datetable; struct datetime dt; char date[DATE822FMT]; (void) umask(022); sig_pipeignore(); when = now(); datetime_tai(&dt,when); opt = getconfopt(argc,argv,options,1,0); initsub(0); if (flagformat != 0) if (FORMATS[str_chr(FORMATS,flagformat[0])]) outformat = flagformat[0]; if (outformat == 0) { outformat = (getconf_line(&line,"digformat",0) && FORMATS[str_chr(FORMATS,line.s[0])]) ? line.s[0] : DEFAULT_FORMAT; } /* code to activate digest (-digest-code)*/ if ((digestcode = argv[opt]) == 0) { if (getconf_line(&digestcodefile,"digestcode",0) && digestcodefile.len > 0) { if (!stralloc_0(&digestcodefile)) die_nomem(); digestcode = digestcodefile.s; } } /* ignore any extra args */ if (!stralloc_copy(&subject,&outlocal)) die_nomem(); /* for subjects */ if (!stralloc_copy(&listname,&outlocal)) die_nomem(); /* for content disp */ local = env_get("LOCAL"); def = env_get("DEFAULT"); sender = get_sender(); if (local && *local) { /* in editor local = outlocal */ if (!sender) strerr_die2x(100,FATAL,MSG(ERR_NOSENDER)); if (!*sender) strerr_die2x(100,FATAL,MSG(ERR_BOUNCE)); if (str_equal(sender,"#@[]")) strerr_die2x(100,FATAL,MSG(ERR_BOUNCE)); if (!sender[str_chr(sender,'@')]) strerr_die2x(100,FATAL,MSG(ERR_ANONYMOUS)); if (def) { if (*def) { action = def; goodexit = 99; } else _exit(0); /* list-@host should do -help from manager */ } else { /* editor */ act = AC_DIGEST; /* on list-@host ! */ flageditor = 1; /* to avoid Mailing-list error on sublists */ /* when running out of dir/editor. */ } if (case_starts(action,"dig")) { action += 3; if (action[0] == '-' || action [0] == '.') { action++; if (!digestcode) strerr_die2x(100,FATAL,MSG(ERR_BAD_DIGCODE)); len = str_len(digestcode); if (len <= str_len(action) && case_startb(action,len,digestcode)) { if (FORMATS[str_chr(FORMATS,*(action+len))]) outformat = *(action+len); act = AC_DIGEST; } else strerr_die2x(100,FATAL,MSG(ERR_BAD_DIGCODE)); } } } else /* Command line operation */ act = AC_DIGEST; /* Things we deal with. If anything else just die with success! */ /* At the moment this is -index, -thread, and -get. */ /* If flagdo = 0 we only service -dig commands. This is to support*/ /* "secret" lists that are still archived and digested. -c on */ /* cmd line. */ if (act == AC_NONE) { if (case_equals(action,ACTION_DIGEST)) { act = AC_GET; /* list-digest@ => msg since last digest */ action = ACTION_GET; } else if (case_starts(action,ACTION_GET) || case_starts(action,ALT_GET)) act = AC_GET; else if (case_starts(action,ACTION_INDEX) || case_starts(action,ALT_INDEX)) act = AC_INDEX; else if (case_starts(action,ACTION_THREAD) || case_starts(action,ALT_THREAD)) act = AC_THREAD; } if (act == AC_NONE) /* not for us. Pass the buck. */ _exit(0); if (act != AC_INDEX) { /* need to do header processing */ if(!getconf(&digheaders,"digheaders",0)) { if(!stralloc_copys(&digheaders,digsz)) die_nomem(); if (!stralloc_0(&digheaders)) die_nomem(); psz = digheaders.s; while (*psz) { if (*psz == '\\') *psz = '\0'; ++psz; } } if (!constmap_init(&digheadersmap,digheaders.s,digheaders.len,0)) die_nomem(); } if (act != AC_DIGEST) { if (!flagdo) /* only do digests */ strerr_die2x(100,FATAL,MSG(ERR_NOCMD)); if (flagpublic < 0) flagpublic = !getconf_isset("modgetonly") && getconf_isset("public"); if (!flagpublic) { /* This all to take care of non-public lists. They should*/ /* still do digests, but do other things only for */ /* moderators that have remote access. Since this is rare*/ /* efforts have been made to keep everything that's not */ /* needed elsewhere in here. */ getconf_line(&moddir,"modsub",0); flagremote = getconf_line(&line,"remote",0); if (!flagremote) strerr_die2x(100,FATAL,MSG(ERR_NOT_PUBLIC)); if (!moddir.len) { if (line.len) { if (!stralloc_copy(&moddir,&line)) die_nomem(); } else { if (!stralloc_copys(&moddir,"mod")) die_nomem(); } } if (!stralloc_0(&moddir)) die_nomem(); ismod = issub(moddir.s,sender,&mod); if (!ismod) /* sender = moderator? */ strerr_die2x(100,FATAL,MSG(ERR_NOT_PUBLIC)); } } if (act == AC_DIGEST) { workdir = "digest"; if (!stralloc_cats(&outlocal,"-digest")) die_nomem(); if (getconf_line(&line,"chunk",0)) { if (!stralloc_0(&line)) die_nomem(); (void) scan_ulong(line.s,&chunk); /* same chunk as main list */ if (chunk == 0) /* limit range to 1-53 */ chunk = 1L; else if (chunk > 52) chunk = 52L; } else { chunk = 0L; } } else workdir = "."; if (!flagarchived) strerr_die2x(100,FATAL,MSG(ERR_NOT_ARCHIVED)); if (qmail_open(&qq) == -1) strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE)); set_cpnum(""); /* default for <#n#> replacement */ switch (act) { case AC_DIGEST: /* -dig{.|-}'digestcode'[f] returns an rfc1153 digest */ /* of messages from the archive. Messages */ /* dignum+1 through the last message received by the list are processed and */ /* dignum is updated to the last message processed. digissue is advanced. */ get_num(); /* max = last successful message */ to = max; lockup(); /* another digest could corrupt dignum */ /* but will be saved only if flagdigrange==0 */ if(getconf_line(&num,"dignum",0)) { if(!stralloc_0(&num)) die_nomem(); pos = scan_ulong(num.s,&prevmax); if (num.s[pos] == ':') pos++; pos += 1 + scan_ulong(num.s+pos,&cumsize); /* last cumsize */ if (num.s[pos] == ':') pos++; scan_ulong(num.s+pos,&digwhen); /* last reg dig */ } else { prevmax = 0L; cumsize = 0L; digwhen = 0L; } mno = prevmax + 1L; if(!max || mno > max) /* if a digest-list is "sending" the request, */ /* don't make noise: errors go to postmaster!*/ strerr_die2x(goodexit,FATAL,MSG(ERR_EMPTY_DIGEST)); szmsgnum[fmt_ulong(szmsgnum,mno)] = '\0'; set_cpnum(szmsgnum); /* for copy */ /* prepare subject to get entropy for tagmsg*/ if (!stralloc_cats(&subject," Digest ")) die_nomem(); if (!stralloc_catb(&subject,date,date822fmt(date,&dt)-1)) die_nomem(); /* skip trailing in date '\n' */ if (!stralloc_cats(&subject," Issue ")) die_nomem(); if (getconf_line(&num,"digissue",0)) { if(!stralloc_0(&num)) die_nomem(); scan_ulong(num.s,&issue); issue++; } else { issue = 1; } if (!stralloc_catb(&subject,strnum,fmt_ulong(strnum,issue))) die_nomem(); /* use the subject as entropy */ if (!stralloc_copy(&line,&subject)) die_nomem(); if (!stralloc_0(&line)) die_nomem(); if (!stralloc_ready(&seed,HASHLEN+1)) die_nomem(); seed.len = HASHLEN + 1; seed.s[HASHLEN] = '\0'; makehash(line.s,line.len,seed.s); if (chunk) { /* only if slaves are used */ qmail_puts(&qq,"Ezauth: "); qmail_put(&qq,seed.s,HASHLEN); qmail_puts(&qq,"\n"); } doheaders(); qmail_puts(&qq,"To: "); if (!quote("ed,&listname)) die_nomem(); qmail_put(&qq,quoted.s,quoted.len); qmail_puts(&qq,"@"); qmail_put(&qq,outhost.s,outhost.len); qmail_puts(&qq,"\n"); if (flagindexed && (outformat != NATIVE)) idx_mkthreads(&msgtable,&subtable,&authtable,&datetable, mno,to,max,flaglocked); else idx_mklist(&msgtable,&subtable,&authtable,mno,to); digest(msgtable,subtable,authtable,mno,to,&subject,AC_DIGEST,outformat); write_ulong(issue,0L,0L,"digissue","digissuen"); write_ulong(max,cumsizen, (unsigned long) when,"dignum","dignumn"); break; case AC_GET: /* -get[-|\.][[num].num2] copies archive num-num2. num & num2 are adjusted */ /* to be > 0 and <= last message, to num2 >= num and to num2-num <= MAXGET. */ zapnonsub(ACTION_GET); /* restrict to subs if requested */ tosender(); /* for rfc1153 */ if (!stralloc_cats(&subject," Digest of: ")) die_nomem(); if (!stralloc_cats(&subject,action)) die_nomem(); to = 0; pos = str_len(ACTION_GET); if (!case_starts(action,ACTION_GET)) pos = str_len(ALT_GET); if (FORMATS[str_chr(FORMATS,action[pos])]) { outformat = action[pos]; ++pos; } /* optional - or . after '-get' */ if (action[pos] == '-' || action[pos] == '.') pos++; get_num(); /* max = last successful message */ /* accept any separator. It may be */ /* the terminal '\n', but then */ /* scan will = 0 on the \0 so should*/ /* be safe */ if (!max) strerr_die2x(100,FATAL,MSG(ERR_EMPTY_LIST)); szmsgnum[fmt_ulong(szmsgnum,max)] = '\0'; set_cpnum(szmsgnum); /* for copy this is the latest message arch'd*/ doheaders(); if(action[pos += scan_ulong(action + pos,&u)]) scan_ulong(action + pos + 1, &to); if (u == 0 && to == 0) { /* default: messages since last */ /* digest, or last MAXGET if too many */ to= max; u = dignum(); if (u == 0) { /* no digest => last up to HISTGET msgs */ to = max; if (max > HISTGET) u = max - HISTGET; else u = 1; } if (to - u >= MAXGET) u = to - MAXGET + 1; /* max MAXGET */ } else if (u > max) { if (to) { /* -get.999999_x returns 30 and msg since last*/ to = max; /* digest 30*/ u = dignum(); if (u > HISTGET) u -= HISTGET; else u = 1; if (to - u >= MAXGET) u = to - MAXGET + 1; } else u = max; } if (u == 0) u = 1; /* -get.5 => 1-5 */ if (to < u) to = u; /* -get23_2 => 23 */ if (to >= u + MAXGET) to = u + MAXGET - 1; /* no more than MAXGET at a time */ if (to > max) to = max; if (flagindexed && (outformat != NATIVE)) /* fake out threading */ idx_mkthreads(&msgtable,&subtable,&authtable,&datetable, u,to,max,0); else idx_mklist(&msgtable,&subtable,&authtable,u,to); digest(msgtable,subtable,authtable,u,to,&subject,AC_GET,outformat); break; case AC_INDEX: /* -index[f][#|-|\.][[num][.num2] Show subject index for messages num-num2 in*/ /* sets of 100. */ /* Default last 2 sets. num and num2 are made reasonable as for get. num2 is */ /* limited to num+MAXINDEX to limit the amount of data sent. */ if (!flagindexed) strerr_die2x(100,FATAL,MSG(ERR_NOT_INDEXED)); zapnonsub(ACTION_INDEX); /* restrict to subs if requested */ to = 0; pos = str_len(ACTION_INDEX); if (!case_starts(action,ACTION_INDEX)) pos = str_len(ALT_INDEX); if (FORMATS[str_chr(FORMATS,action[pos])]) { outformat = action[pos]; /* ignored, but be nice ... */ ++pos; } get_num(); /* max = last successful message */ if (!max) strerr_die2x(100,FATAL,MSG(ERR_EMPTY_LIST)); szmsgnum[fmt_ulong(szmsgnum,max)] = '\0'; set_cpnum(szmsgnum); /* for copy this is the latest message arch'd*/ doheaders(); tosender(); if (!stralloc_cats(&subject," Result of: ")) die_nomem(); if (!stralloc_cats(&subject,action)) die_nomem(); presub(1,1,&subject,AC_INDEX,outformat); if (action[pos] == '-' || action[pos] == '.') pos++; if(action[pos += scan_ulong(action + pos,&u)]) scan_ulong(action + pos + 1, &to); if (u == 0 && to == 0) { to = max; u = max - 100; } if (u <= 0) u = 1; if (u > max) u = max; if (to < u) to = u; if (to > u + MAXINDEX) to = u+MAXINDEX; /* max MAXINDEX index files */ if (to > max) to = max; u /= 100; to /= 100; while (u <= to) { if (!stralloc_copys(&fn,"archive/")) die_nomem(); if (!stralloc_catb(&fn,strnum,fmt_ulong(strnum,u))) die_nomem(); if (!stralloc_cats(&fn,"/index")) die_nomem(); if (!stralloc_0(&fn)) die_nomem(); if (u == max/100) /* lock if last index file in archive */ lockup(); fd = open_read(fn.s); if (fd == -1) if (errno != error_noent) strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,fn.s)); else code_qputs(MSG(TXT_NOINDEX)); else { substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); for (;;) { if (getln(&sstext,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG1(ERR_READ,fn.s)); if (match) { if (line.s[0] != '\t') { /* subject line */ pos = byte_chr(line.s,line.len,' '); pos1 = 0; if (pos && pos != line.len && line.s[pos - 1] == ':') pos1 = pos + HASHLEN + 1; /* after hash */ if (pos1 >= line.len) { /* bad! */ pos = 0; pos1 = 0; /* output as is */ } if (!stralloc_copyb(&line2,line.s,pos)) die_nomem(); if (!stralloc_catb(&line2,line.s+pos1,line.len-pos1)) die_nomem(); } else { pos = byte_chr(line.s,line.len,';'); if (pos + HASHLEN + 1 < line.len && pos > 15 && line.s[pos + 1] != ' ') { if (!stralloc_copyb(&line2,line.s,pos - 15)) die_nomem(); pos++; if (!stralloc_catb(&line2,line.s + pos + HASHLEN, line.len - pos - HASHLEN)) die_nomem(); } else /* old format - no author hash */ if (!stralloc_copyb(&line2,line.s,line.len)) die_nomem(); } code_qput(line2.s,line2.len); } else break; } close(fd); } if (u == max/100) /* unlock if last index in archive file */ unlock(); u++; } normal_bottom(outformat); postmsg(outformat); break; case AC_THREAD: /* -thread[f][-|.]num returns messages with subject matching message */ /* 'num' in the subject index. If 'num' is not in[1..last_message] an error */ /* message is returned. */ if (!flagindexed) strerr_die2x(100,FATAL,MSG(ERR_NOT_INDEXED)); zapnonsub(ACTION_THREAD); /* restrict to subs if requested*/ get_num(); /* max = last successful message */ if (!max) strerr_die2x(100,FATAL,MSG(ERR_EMPTY_LIST)); szmsgnum[fmt_ulong(szmsgnum,max)] = '\0'; set_cpnum(szmsgnum); /* for copy this is the latest message arch'd*/ doheaders(); tosender(); /* for rfc1153 */ if (!stralloc_cats(&subject," Digest of: ")) die_nomem(); if (!stralloc_cats(&subject,action)) die_nomem(); to = 0; pos = str_len(ACTION_THREAD); if (!case_starts(action,ACTION_THREAD)) pos = str_len(ALT_THREAD); if (FORMATS[str_chr(FORMATS,action[pos])]) { outformat = action[pos]; ++pos; } if (action[pos] == '-' || action[pos] == '.') pos++; if(action[pos += scan_ulong(action + pos,&u)]) scan_ulong(action + pos + 1, &to); if(u == 0 || u > max) { hdr_add2("Subject: ",subject.s,subject.len); qmail_puts(&qq,"\n"); copy(&qq,"text/get-bad",flagcd); } else { /* limit range to at most u-THREAD_BEFORE to u+THREAD_AFTER */ if (u > THREAD_BEFORE) from = u-THREAD_BEFORE; else from = 1L; if (u + THREAD_AFTER > max) { idx_mkthread(&msgtable,&subtable,&authtable,from,max,u,max,0); digest(msgtable,subtable,authtable,from,max,&subject, AC_THREAD,outformat); } else { idx_mkthread(&msgtable,&subtable,&authtable, from,u+THREAD_AFTER,u,max,0); digest(msgtable,subtable,authtable,from,u+THREAD_AFTER, &subject,AC_THREAD,outformat); } } break; default: /* This happens if the initial check at the beginning of 'main' */ /* matches something that isn't matched here. Conversely, just */ /* adding an action here is not enough - it has to be added to the */ /* initial check as well. */ strerr_die2x(100,FATAL, "Program error: I'm supposed to deal with this but I didn't"); } if (!stralloc_copy(&line,&outlocal)) die_nomem(); if (act == AC_DIGEST) { if (chunk) { if (!stralloc_cats(&line,"-return-g-")) die_nomem(); } else if (!stralloc_cats(&line,"-return-")) die_nomem(); strnum[fmt_ulong(strnum,mno)] = '\0'; if (!stralloc_cats(&line,strnum)) die_nomem(); if (!stralloc_cats(&line,"-@")) die_nomem(); if (!stralloc_cat(&line,&outhost)) die_nomem(); if (!stralloc_cats(&line,"-@[]")) die_nomem(); } else { if (!stralloc_cats(&line,"-return-@")) die_nomem(); if (!stralloc_cat(&line,&outhost)) die_nomem(); } if (!stralloc_0(&line)) die_nomem(); qmail_from(&qq,line.s); if (act == AC_DIGEST) { /* Do recipients */ tagmsg(mno,seed.s,"d",hashout,qq.msgbytes,chunk); if (chunk) { if (!stralloc_copys(&line,"T")) die_nomem(); if (!stralloc_cat(&line,&outlocal)) die_nomem(); if (!stralloc_cats(&line,"-s-d-")) die_nomem(); if (!stralloc_catb(&line,hashout,COOKIE)) die_nomem(); if (!stralloc_cats(&line,"-")) die_nomem(); if (!stralloc_cats(&line,strnum)) die_nomem(); if (!stralloc_cats(&line,"-")) die_nomem(); if (!stralloc_copys(&line2,"@")) die_nomem(); if (!stralloc_cat(&line2,&outhost)) die_nomem(); if (!stralloc_0(&line2)) die_nomem(); j = 0; for (i = 0; i <= 52; i += chunk) { /* To slaves */ qmail_put(&qq,line.s,line.len); schar[0] = '0' + i / 10; schar[1] = '0' + (i % 10); qmail_put(&qq,schar,3); j += (chunk - 1); if (j > 52) j = 52; schar[0] = '0' + j / 10; schar[1] = '0' + (j % 10); qmail_put(&qq,schar,2); qmail_put(&qq,line2.s,line2.len); } } else subs = putsubs(workdir,0L,52L,&subto); } else { /* if local is set, sender is checked */ if (ismod) qmail_to(&qq,mod.s); else qmail_to(&qq,sender); } if (*(err = qmail_close(&qq)) == '\0') { /* Done. Skip rest. */ if (act == AC_DIGEST) { if (chunk) (void) logmsg(mno,0L,0L,2); else (void) logmsg(mno,0L,subs,4); } closesub(); /* close db connection */ unlock(); /* NOP if nothing locked */ strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; strerr_die2x(goodexit,"ezmlm-get: info: qp ",strnum); } else { /* failed. Reset last msg & issue for digest */ if(act == AC_DIGEST) { issue--; write_ulong(issue,0L,0L,"digissue","digissuen"); write_ulong(prevmax,cumsize,(unsigned long) digwhen,"dignum","dignumn"); } unlock(); /* NOP if nothing locked */ strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ",err + 1); } }