diff options
| author | manuel <manuel@mausz.at> | 2013-02-04 00:08:53 +0100 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2013-02-04 00:08:53 +0100 |
| commit | 69aec538b456402170dc723af417ba5c05389c32 (patch) | |
| tree | e6f34c543f17c6392447ea337b2e2868212424d1 | |
| download | qmail-69aec538b456402170dc723af417ba5c05389c32.tar.gz qmail-69aec538b456402170dc723af417ba5c05389c32.tar.bz2 qmail-69aec538b456402170dc723af417ba5c05389c32.zip | |
qmail 1.03 import
| -rw-r--r-- | BIN.Makefile | 24 | ||||
| -rw-r--r-- | BIN.README | 19 | ||||
| -rw-r--r-- | BLURB | 43 | ||||
| -rw-r--r-- | BLURB2 | 26 | ||||
| -rw-r--r-- | BLURB3 | 93 | ||||
| -rw-r--r-- | BLURB4 | 44 | ||||
| -rw-r--r-- | CHANGES | 1460 | ||||
| -rw-r--r-- | FAQ | 706 | ||||
| -rw-r--r-- | FILES | 433 | ||||
| -rw-r--r-- | INSTALL | 84 | ||||
| -rw-r--r-- | INSTALL.alias | 40 | ||||
| -rw-r--r-- | INSTALL.ctl | 38 | ||||
| -rw-r--r-- | INSTALL.ids | 72 | ||||
| -rw-r--r-- | INSTALL.maildir | 59 | ||||
| -rw-r--r-- | INSTALL.mbox | 53 | ||||
| -rw-r--r-- | INSTALL.vsm | 50 | ||||
| -rw-r--r-- | INTERNALS | 156 | ||||
| -rw-r--r-- | Makefile | 2141 | ||||
| -rw-r--r-- | PIC.local2alias | 37 | ||||
| -rw-r--r-- | PIC.local2ext | 41 | ||||
| -rw-r--r-- | PIC.local2local | 40 | ||||
| -rw-r--r-- | PIC.local2rem | 38 | ||||
| -rw-r--r-- | PIC.local2virt | 44 | ||||
| -rw-r--r-- | PIC.nullclient | 38 | ||||
| -rw-r--r-- | PIC.relaybad | 8 | ||||
| -rw-r--r-- | PIC.relaygood | 33 | ||||
| -rw-r--r-- | PIC.rem2local | 36 | ||||
| -rw-r--r-- | README | 269 | ||||
| -rw-r--r-- | REMOVE.binmail | 16 | ||||
| -rw-r--r-- | REMOVE.sendmail | 28 | ||||
| -rw-r--r-- | SECURITY | 131 | ||||
| -rw-r--r-- | SENDMAIL | 76 | ||||
| -rw-r--r-- | SYSDEPS | 17 | ||||
| -rw-r--r-- | TARGETS | 387 | ||||
| -rw-r--r-- | TEST.deliver | 82 | ||||
| -rw-r--r-- | TEST.receive | 41 | ||||
| -rw-r--r-- | THANKS | 337 | ||||
| -rw-r--r-- | THOUGHTS | 418 | ||||
| -rw-r--r-- | TODO | 23 | ||||
| -rw-r--r-- | UPGRADE | 66 | ||||
| -rw-r--r-- | VERSION | 1 | ||||
| -rw-r--r-- | addresses.5 | 260 | ||||
| -rw-r--r-- | alloc.3 | 62 | ||||
| -rw-r--r-- | alloc.c | 32 | ||||
| -rw-r--r-- | alloc.h | 8 | ||||
| -rw-r--r-- | alloc_re.c | 17 | ||||
| -rw-r--r-- | auto-gid.c | 51 | ||||
| -rw-r--r-- | auto-int.c | 40 | ||||
| -rw-r--r-- | auto-int8.c | 40 | ||||
| -rw-r--r-- | auto-str.c | 44 | ||||
| -rw-r--r-- | auto-uid.c | 51 | ||||
| -rw-r--r-- | auto_break.h | 6 | ||||
| -rw-r--r-- | auto_patrn.h | 6 | ||||
| -rw-r--r-- | auto_qmail.h | 6 | ||||
| -rw-r--r-- | auto_spawn.h | 6 | ||||
| -rw-r--r-- | auto_split.h | 6 | ||||
| -rw-r--r-- | auto_uids.h | 16 | ||||
| -rw-r--r-- | auto_usera.h | 6 | ||||
| -rw-r--r-- | binm1+df.sh | 11 | ||||
| -rw-r--r-- | binm1.sh | 10 | ||||
| -rw-r--r-- | binm2+df.sh | 11 | ||||
| -rw-r--r-- | binm2.sh | 10 | ||||
| -rw-r--r-- | binm3+df.sh | 11 | ||||
| -rw-r--r-- | binm3.sh | 10 | ||||
| -rw-r--r-- | bouncesaying.1 | 71 | ||||
| -rw-r--r-- | bouncesaying.c | 41 | ||||
| -rw-r--r-- | byte.h | 13 | ||||
| -rw-r--r-- | byte_chr.c | 20 | ||||
| -rw-r--r-- | byte_copy.c | 14 | ||||
| -rw-r--r-- | byte_cr.c | 16 | ||||
| -rw-r--r-- | byte_diff.c | 16 | ||||
| -rw-r--r-- | byte_rchr.c | 23 | ||||
| -rw-r--r-- | byte_zero.c | 13 | ||||
| -rw-r--r-- | case.3 | 100 | ||||
| -rw-r--r-- | case.h | 13 | ||||
| -rw-r--r-- | case_diffb.c | 21 | ||||
| -rw-r--r-- | case_diffs.c | 19 | ||||
| -rw-r--r-- | case_lowerb.c | 14 | ||||
| -rw-r--r-- | case_lowers.c | 12 | ||||
| -rw-r--r-- | case_starts.c | 18 | ||||
| -rw-r--r-- | cdb.3 | 62 | ||||
| -rw-r--r-- | cdb.h | 12 | ||||
| -rw-r--r-- | cdb_hash.c | 16 | ||||
| -rw-r--r-- | cdb_seek.c | 95 | ||||
| -rw-r--r-- | cdb_unpack.c | 12 | ||||
| -rw-r--r-- | cdbmake.h | 35 | ||||
| -rw-r--r-- | cdbmake_add.c | 117 | ||||
| -rw-r--r-- | cdbmake_hash.c | 10 | ||||
| -rw-r--r-- | cdbmake_pack.c | 11 | ||||
| -rw-r--r-- | cdbmss.c | 65 | ||||
| -rw-r--r-- | cdbmss.h | 16 | ||||
| -rw-r--r-- | chkshsgr.c | 9 | ||||
| -rw-r--r-- | chkspawn.c | 48 | ||||
| -rw-r--r-- | coe.3 | 25 | ||||
| -rw-r--r-- | coe.c | 8 | ||||
| -rw-r--r-- | coe.h | 6 | ||||
| -rw-r--r-- | commands.c | 40 | ||||
| -rw-r--r-- | commands.h | 12 | ||||
| -rw-r--r-- | condredirect.1 | 63 | ||||
| -rw-r--r-- | condredirect.c | 85 | ||||
| -rw-r--r-- | conf-break | 9 | ||||
| -rw-r--r-- | conf-cc | 3 | ||||
| -rw-r--r-- | conf-groups | 6 | ||||
| -rw-r--r-- | conf-ld | 3 | ||||
| -rw-r--r-- | conf-patrn | 6 | ||||
| -rw-r--r-- | conf-qmail | 11 | ||||
| -rw-r--r-- | conf-spawn | 5 | ||||
| -rw-r--r-- | conf-split | 3 | ||||
| -rw-r--r-- | conf-users | 15 | ||||
| -rw-r--r-- | config-fast.sh | 30 | ||||
| -rw-r--r-- | config.sh | 64 | ||||
| -rw-r--r-- | constmap.c | 114 | ||||
| -rw-r--r-- | constmap.h | 20 | ||||
| -rw-r--r-- | control.c | 130 | ||||
| -rw-r--r-- | control.h | 10 | ||||
| -rw-r--r-- | date822fmt.c | 29 | ||||
| -rw-r--r-- | date822fmt.h | 7 | ||||
| -rw-r--r-- | datemail.sh | 1 | ||||
| -rw-r--r-- | datetime.3 | 73 | ||||
| -rw-r--r-- | datetime.c | 55 | ||||
| -rw-r--r-- | datetime.h | 20 | ||||
| -rw-r--r-- | datetime_un.c | 35 | ||||
| -rw-r--r-- | direntry.3 | 36 | ||||
| -rw-r--r-- | direntry.h1 | 8 | ||||
| -rw-r--r-- | direntry.h2 | 8 | ||||
| -rw-r--r-- | dns.c | 400 | ||||
| -rw-r--r-- | dns.h | 14 | ||||
| -rw-r--r-- | dnscname.c | 25 | ||||
| -rw-r--r-- | dnsdoe.c | 16 | ||||
| -rw-r--r-- | dnsdoe.h | 6 | ||||
| -rw-r--r-- | dnsfq.c | 32 | ||||
| -rw-r--r-- | dnsip.c | 34 | ||||
| -rw-r--r-- | dnsmxip.c | 40 | ||||
| -rw-r--r-- | dnsptr.c | 27 | ||||
| -rw-r--r-- | dot-qmail.9 | 394 | ||||
| -rw-r--r-- | elq.sh | 1 | ||||
| -rw-r--r-- | env.3 | 31 | ||||
| -rw-r--r-- | env.c | 113 | ||||
| -rw-r--r-- | env.h | 17 | ||||
| -rw-r--r-- | envelopes.5 | 231 | ||||
| -rw-r--r-- | envread.c | 30 | ||||
| -rw-r--r-- | error.3 | 45 | ||||
| -rw-r--r-- | error.c | 95 | ||||
| -rw-r--r-- | error.h | 23 | ||||
| -rw-r--r-- | error_str.3 | 19 | ||||
| -rw-r--r-- | error_str.c | 276 | ||||
| -rw-r--r-- | error_temp.3 | 27 | ||||
| -rw-r--r-- | error_temp.c | 80 | ||||
| -rw-r--r-- | except.1 | 33 | ||||
| -rw-r--r-- | except.c | 37 | ||||
| -rw-r--r-- | exit.h | 6 | ||||
| -rw-r--r-- | extra.h | 7 | ||||
| -rw-r--r-- | fd.h | 7 | ||||
| -rw-r--r-- | fd_copy.3 | 44 | ||||
| -rw-r--r-- | fd_copy.c | 13 | ||||
| -rw-r--r-- | fd_move.3 | 41 | ||||
| -rw-r--r-- | fd_move.c | 11 | ||||
| -rw-r--r-- | fifo.c | 10 | ||||
| -rw-r--r-- | fifo.h | 6 | ||||
| -rw-r--r-- | fifo_make.3 | 24 | ||||
| -rw-r--r-- | find-systype.sh | 144 | ||||
| -rw-r--r-- | fmt.h | 25 | ||||
| -rw-r--r-- | fmt_str.c | 12 | ||||
| -rw-r--r-- | fmt_strn.c | 12 | ||||
| -rw-r--r-- | fmt_uint.c | 6 | ||||
| -rw-r--r-- | fmt_uint0.c | 10 | ||||
| -rw-r--r-- | fmt_ulong.c | 13 | ||||
| -rw-r--r-- | fmtqfn.c | 24 | ||||
| -rw-r--r-- | fmtqfn.h | 8 | ||||
| -rw-r--r-- | forgeries.7 | 104 | ||||
| -rw-r--r-- | fork.h1 | 7 | ||||
| -rw-r--r-- | fork.h2 | 7 | ||||
| -rw-r--r-- | forward.1 | 24 | ||||
| -rw-r--r-- | forward.c | 60 | ||||
| -rw-r--r-- | gen_alloc.h | 7 | ||||
| -rw-r--r-- | gen_allocdefs.h | 34 | ||||
| -rw-r--r-- | getln.3 | 51 | ||||
| -rw-r--r-- | getln.c | 20 | ||||
| -rw-r--r-- | getln.h | 7 | ||||
| -rw-r--r-- | getln2.3 | 64 | ||||
| -rw-r--r-- | getln2.c | 31 | ||||
| -rw-r--r-- | gfrom.c | 10 | ||||
| -rw-r--r-- | gfrom.h | 6 | ||||
| -rw-r--r-- | headerbody.c | 87 | ||||
| -rw-r--r-- | headerbody.h | 6 | ||||
| -rw-r--r-- | hfield.c | 125 | ||||
| -rw-r--r-- | hfield.h | 38 | ||||
| -rw-r--r-- | hier.c | 252 | ||||
| -rw-r--r-- | home+df.sh | 9 | ||||
| -rw-r--r-- | home.sh | 7 | ||||
| -rw-r--r-- | hostname.c | 17 | ||||
| -rw-r--r-- | idedit.c | 147 | ||||
| -rw-r--r-- | install-big.c | 285 | ||||
| -rw-r--r-- | install.c | 164 | ||||
| -rw-r--r-- | instcheck.c | 108 | ||||
| -rw-r--r-- | ip.c | 53 | ||||
| -rw-r--r-- | ip.h | 11 | ||||
| -rw-r--r-- | ipalloc.c | 7 | ||||
| -rw-r--r-- | ipalloc.h | 14 | ||||
| -rw-r--r-- | ipme.c | 95 | ||||
| -rw-r--r-- | ipme.h | 12 | ||||
| -rw-r--r-- | ipmeprint.c | 24 | ||||
| -rw-r--r-- | lock.h | 8 | ||||
| -rw-r--r-- | lock_ex.c | 11 | ||||
| -rw-r--r-- | lock_exnb.c | 11 | ||||
| -rw-r--r-- | lock_un.c | 11 | ||||
| -rw-r--r-- | maildir.5 | 239 | ||||
| -rw-r--r-- | maildir.c | 108 | ||||
| -rw-r--r-- | maildir.h | 12 | ||||
| -rw-r--r-- | maildir2mbox.1 | 53 | ||||
| -rw-r--r-- | maildir2mbox.c | 162 | ||||
| -rw-r--r-- | maildirmake.1 | 15 | ||||
| -rw-r--r-- | maildirmake.c | 24 | ||||
| -rw-r--r-- | maildirwatch.1 | 23 | ||||
| -rw-r--r-- | maildirwatch.c | 125 | ||||
| -rw-r--r-- | mailsubj.1 | 38 | ||||
| -rw-r--r-- | mailsubj.sh | 7 | ||||
| -rw-r--r-- | make-compile.sh | 1 | ||||
| -rw-r--r-- | make-load.sh | 2 | ||||
| -rw-r--r-- | make-makelib.sh | 16 | ||||
| -rw-r--r-- | mbox.5 | 235 | ||||
| -rw-r--r-- | myctime.c | 37 | ||||
| -rw-r--r-- | myctime.h | 6 | ||||
| -rw-r--r-- | ndelay.c | 13 | ||||
| -rw-r--r-- | ndelay.h | 7 | ||||
| -rw-r--r-- | ndelay_off.c | 13 | ||||
| -rw-r--r-- | newfield.c | 68 | ||||
| -rw-r--r-- | newfield.h | 12 | ||||
| -rw-r--r-- | now.3 | 14 | ||||
| -rw-r--r-- | now.c | 8 | ||||
| -rw-r--r-- | now.h | 8 | ||||
| -rw-r--r-- | open.h | 10 | ||||
| -rw-r--r-- | open_append.c | 6 | ||||
| -rw-r--r-- | open_excl.c | 6 | ||||
| -rw-r--r-- | open_read.c | 6 | ||||
| -rw-r--r-- | open_trunc.c | 6 | ||||
| -rw-r--r-- | open_write.c | 6 | ||||
| -rw-r--r-- | pinq.sh | 1 | ||||
| -rw-r--r-- | predate.c | 116 | ||||
| -rw-r--r-- | preline.1 | 57 | ||||
| -rw-r--r-- | preline.c | 90 | ||||
| -rw-r--r-- | prioq.c | 58 | ||||
| -rw-r--r-- | prioq.h | 15 | ||||
| -rw-r--r-- | proc+df.sh | 9 | ||||
| -rw-r--r-- | proc.sh | 7 | ||||
| -rw-r--r-- | prot.c | 21 | ||||
| -rw-r--r-- | prot.h | 7 | ||||
| -rw-r--r-- | qail.sh | 1 | ||||
| -rw-r--r-- | qbiff.1 | 31 | ||||
| -rw-r--r-- | qbiff.c | 113 | ||||
| -rw-r--r-- | qlx.h | 18 | ||||
| -rw-r--r-- | qmail-clean.8 | 13 | ||||
| -rw-r--r-- | qmail-clean.c | 98 | ||||
| -rw-r--r-- | qmail-command.8 | 149 | ||||
| -rw-r--r-- | qmail-control.9 | 78 | ||||
| -rw-r--r-- | qmail-getpw.9 | 114 | ||||
| -rw-r--r-- | qmail-getpw.c | 88 | ||||
| -rw-r--r-- | qmail-header.5 | 332 | ||||
| -rw-r--r-- | qmail-inject.8 | 309 | ||||
| -rw-r--r-- | qmail-inject.c | 773 | ||||
| -rw-r--r-- | qmail-limits.9 | 30 | ||||
| -rw-r--r-- | qmail-local.8 | 99 | ||||
| -rw-r--r-- | qmail-local.c | 698 | ||||
| -rw-r--r-- | qmail-log.5 | 261 | ||||
| -rw-r--r-- | qmail-lspawn.8 | 46 | ||||
| -rw-r--r-- | qmail-lspawn.c | 234 | ||||
| -rw-r--r-- | qmail-newmrh.9 | 41 | ||||
| -rw-r--r-- | qmail-newmrh.c | 70 | ||||
| -rw-r--r-- | qmail-newu.9 | 43 | ||||
| -rw-r--r-- | qmail-newu.c | 137 | ||||
| -rw-r--r-- | qmail-pop3d.8 | 43 | ||||
| -rw-r--r-- | qmail-pop3d.c | 305 | ||||
| -rw-r--r-- | qmail-popup.8 | 65 | ||||
| -rw-r--r-- | qmail-popup.c | 183 | ||||
| -rw-r--r-- | qmail-pw2u.9 | 241 | ||||
| -rw-r--r-- | qmail-pw2u.c | 312 | ||||
| -rw-r--r-- | qmail-qmqpc.8 | 29 | ||||
| -rw-r--r-- | qmail-qmqpc.c | 159 | ||||
| -rw-r--r-- | qmail-qmqpd.8 | 25 | ||||
| -rw-r--r-- | qmail-qmqpd.c | 174 | ||||
| -rw-r--r-- | qmail-qmtpd.8 | 32 | ||||
| -rw-r--r-- | qmail-qmtpd.c | 268 | ||||
| -rw-r--r-- | qmail-qread.8 | 24 | ||||
| -rw-r--r-- | qmail-qread.c | 175 | ||||
| -rw-r--r-- | qmail-qstat.8 | 18 | ||||
| -rw-r--r-- | qmail-qstat.sh | 7 | ||||
| -rw-r--r-- | qmail-queue.8 | 155 | ||||
| -rw-r--r-- | qmail-queue.c | 254 | ||||
| -rw-r--r-- | qmail-remote.8 | 205 | ||||
| -rw-r--r-- | qmail-remote.c | 427 | ||||
| -rw-r--r-- | qmail-rspawn.8 | 21 | ||||
| -rw-r--r-- | qmail-rspawn.c | 103 | ||||
| -rw-r--r-- | qmail-send.9 | 246 | ||||
| -rw-r--r-- | qmail-send.c | 1612 | ||||
| -rw-r--r-- | qmail-showctl.8 | 12 | ||||
| -rw-r--r-- | qmail-showctl.c | 306 | ||||
| -rw-r--r-- | qmail-smtpd.8 | 179 | ||||
| -rw-r--r-- | qmail-smtpd.c | 421 | ||||
| -rw-r--r-- | qmail-start.9 | 94 | ||||
| -rw-r--r-- | qmail-start.c | 120 | ||||
| -rw-r--r-- | qmail-tcpok.8 | 24 | ||||
| -rw-r--r-- | qmail-tcpok.c | 35 | ||||
| -rw-r--r-- | qmail-tcpto.8 | 30 | ||||
| -rw-r--r-- | qmail-tcpto.c | 85 | ||||
| -rw-r--r-- | qmail-upq.sh | 14 | ||||
| -rw-r--r-- | qmail-users.9 | 113 | ||||
| -rw-r--r-- | qmail.7 | 66 | ||||
| -rw-r--r-- | qmail.c | 125 | ||||
| -rw-r--r-- | qmail.h | 24 | ||||
| -rw-r--r-- | qreceipt.1 | 33 | ||||
| -rw-r--r-- | qreceipt.c | 131 | ||||
| -rw-r--r-- | qsmhook.c | 137 | ||||
| -rw-r--r-- | qsutil.c | 46 | ||||
| -rw-r--r-- | qsutil.h | 12 | ||||
| -rw-r--r-- | quote.c | 83 | ||||
| -rw-r--r-- | quote.h | 8 | ||||
| -rw-r--r-- | rcpthosts.c | 60 | ||||
| -rw-r--r-- | rcpthosts.h | 7 | ||||
| -rw-r--r-- | readsubdir.c | 49 | ||||
| -rw-r--r-- | readsubdir.h | 20 | ||||
| -rw-r--r-- | readwrite.h | 7 | ||||
| -rw-r--r-- | received.c | 71 | ||||
| -rw-r--r-- | received.h | 6 | ||||
| -rw-r--r-- | remoteinfo.c | 77 | ||||
| -rw-r--r-- | remoteinfo.h | 6 | ||||
| -rw-r--r-- | scan.h | 27 | ||||
| -rw-r--r-- | scan_8long.c | 11 | ||||
| -rw-r--r-- | scan_ulong.c | 11 | ||||
| -rw-r--r-- | seek.h | 15 | ||||
| -rw-r--r-- | seek_cur.c | 7 | ||||
| -rw-r--r-- | seek_end.c | 7 | ||||
| -rw-r--r-- | seek_set.c | 7 | ||||
| -rw-r--r-- | seek_trunc.c | 5 | ||||
| -rw-r--r-- | select.h1 | 8 | ||||
| -rw-r--r-- | select.h2 | 9 | ||||
| -rw-r--r-- | sendmail.c | 129 | ||||
| -rw-r--r-- | sgetopt.3 | 28 | ||||
| -rw-r--r-- | sgetopt.c | 54 | ||||
| -rw-r--r-- | sgetopt.h | 21 | ||||
| -rw-r--r-- | sig.h | 43 | ||||
| -rw-r--r-- | sig_alarm.c | 7 | ||||
| -rw-r--r-- | sig_block.c | 40 | ||||
| -rw-r--r-- | sig_bug.c | 17 | ||||
| -rw-r--r-- | sig_catch.c | 18 | ||||
| -rw-r--r-- | sig_child.c | 7 | ||||
| -rw-r--r-- | sig_hup.c | 7 | ||||
| -rw-r--r-- | sig_misc.c | 17 | ||||
| -rw-r--r-- | sig_pause.c | 14 | ||||
| -rw-r--r-- | sig_pipe.c | 5 | ||||
| -rw-r--r-- | sig_term.c | 7 | ||||
| -rw-r--r-- | slurpclose.c | 19 | ||||
| -rw-r--r-- | slurpclose.h | 6 | ||||
| -rw-r--r-- | spawn.c | 259 | ||||
| -rw-r--r-- | splogger.8 | 60 | ||||
| -rw-r--r-- | splogger.c | 72 | ||||
| -rw-r--r-- | str.h | 14 | ||||
| -rw-r--r-- | str_chr.c | 19 | ||||
| -rw-r--r-- | str_cpy.c | 16 | ||||
| -rw-r--r-- | str_diff.c | 17 | ||||
| -rw-r--r-- | str_diffn.c | 18 | ||||
| -rw-r--r-- | str_len.c | 15 | ||||
| -rw-r--r-- | str_rchr.c | 22 | ||||
| -rw-r--r-- | str_start.c | 15 | ||||
| -rw-r--r-- | stralloc.3 | 160 | ||||
| -rw-r--r-- | stralloc.h | 21 | ||||
| -rw-r--r-- | stralloc_arts.c | 12 | ||||
| -rw-r--r-- | stralloc_cat.c | 9 | ||||
| -rw-r--r-- | stralloc_catb.c | 15 | ||||
| -rw-r--r-- | stralloc_cats.c | 10 | ||||
| -rw-r--r-- | stralloc_copy.c | 9 | ||||
| -rw-r--r-- | stralloc_eady.c | 6 | ||||
| -rw-r--r-- | stralloc_opyb.c | 14 | ||||
| -rw-r--r-- | stralloc_opys.c | 10 | ||||
| -rw-r--r-- | stralloc_pend.c | 5 | ||||
| -rw-r--r-- | strerr.h | 80 | ||||
| -rw-r--r-- | strerr_die.c | 37 | ||||
| -rw-r--r-- | strerr_sys.c | 12 | ||||
| -rw-r--r-- | subfd.h | 15 | ||||
| -rw-r--r-- | subfderr.c | 7 | ||||
| -rw-r--r-- | subfdin.c | 13 | ||||
| -rw-r--r-- | subfdins.c | 13 | ||||
| -rw-r--r-- | subfdout.c | 7 | ||||
| -rw-r--r-- | subfdouts.c | 7 | ||||
| -rw-r--r-- | subgetopt.3 | 357 | ||||
| -rw-r--r-- | subgetopt.c | 79 | ||||
| -rw-r--r-- | subgetopt.h | 24 | ||||
| -rw-r--r-- | substdi.c | 91 | ||||
| -rw-r--r-- | substdio.c | 15 | ||||
| -rw-r--r-- | substdio.h | 47 | ||||
| -rw-r--r-- | substdio_copy.c | 18 | ||||
| -rw-r--r-- | substdo.c | 108 | ||||
| -rw-r--r-- | tcp-env.1 | 67 | ||||
| -rw-r--r-- | tcp-env.c | 129 | ||||
| -rw-r--r-- | tcp-environ.5 | 62 | ||||
| -rw-r--r-- | tcpto.c | 165 | ||||
| -rw-r--r-- | tcpto.h | 8 | ||||
| -rw-r--r-- | tcpto_clean.c | 20 | ||||
| -rw-r--r-- | timeoutconn.c | 59 | ||||
| -rw-r--r-- | timeoutconn.h | 6 | ||||
| -rw-r--r-- | timeoutread.c | 22 | ||||
| -rw-r--r-- | timeoutread.h | 6 | ||||
| -rw-r--r-- | timeoutwrite.c | 22 | ||||
| -rw-r--r-- | timeoutwrite.h | 6 | ||||
| -rw-r--r-- | token822.c | 513 | ||||
| -rw-r--r-- | token822.h | 37 | ||||
| -rw-r--r-- | trigger.c | 41 | ||||
| -rw-r--r-- | trigger.h | 8 | ||||
| -rw-r--r-- | triggerpull.c | 16 | ||||
| -rw-r--r-- | triggerpull.h | 6 | ||||
| -rw-r--r-- | trycpp.c | 7 | ||||
| -rw-r--r-- | trydrent.c | 8 | ||||
| -rw-r--r-- | tryflock.c | 8 | ||||
| -rw-r--r-- | trylsock.c | 4 | ||||
| -rw-r--r-- | trymkffo.c | 7 | ||||
| -rw-r--r-- | trynpbg1.c | 26 | ||||
| -rw-r--r-- | tryrsolv.c | 4 | ||||
| -rw-r--r-- | trysalen.c | 11 | ||||
| -rw-r--r-- | trysgact.c | 10 | ||||
| -rw-r--r-- | trysgprm.c | 10 | ||||
| -rw-r--r-- | tryshsgr.c | 14 | ||||
| -rw-r--r-- | trysysel.c | 8 | ||||
| -rw-r--r-- | trysyslog.c | 9 | ||||
| -rw-r--r-- | tryulong32.c | 11 | ||||
| -rw-r--r-- | tryvfork.c | 4 | ||||
| -rw-r--r-- | trywaitp.c | 7 | ||||
| -rw-r--r-- | uint32.h1 | 6 | ||||
| -rw-r--r-- | uint32.h2 | 6 | ||||
| -rw-r--r-- | wait.3 | 93 | ||||
| -rw-r--r-- | wait.h | 14 | ||||
| -rw-r--r-- | wait_nohang.c | 12 | ||||
| -rw-r--r-- | wait_pid.c | 39 | ||||
| -rw-r--r-- | warn-auto.sh | 2 | ||||
| -rw-r--r-- | warn-shsgr | 3 |
433 files changed, 31460 insertions, 0 deletions
diff --git a/BIN.Makefile b/BIN.Makefile new file mode 100644 index 0000000..f46c537 --- /dev/null +++ b/BIN.Makefile | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | SHELL=/bin/sh | ||
| 2 | |||
| 3 | # Files are edited in the installation directory, then copied. | ||
| 4 | # There are 40 arguments to idedit after the filename, | ||
| 5 | # showing the positions of each byte in the following ten ints: | ||
| 6 | # uida, uidd, uidl, uido, uidp, uidq, uidr, uids, gidq, gidn. | ||
| 7 | # Normal little-endian positions are n n+1 n+2 ... n+39 for some n. | ||
| 8 | # Normal big-endian positions are n+3 n+2 n+1 n n+7 ... n+36 for some n. | ||
| 9 | |||
| 10 | setup: | ||
| 11 | mkdir /var/qmail | ||
| 12 | ./idedit install-big XXX | ||
| 13 | ./idedit qmail-lspawn XXX | ||
| 14 | ./idedit qmail-queue XXX | ||
| 15 | ./idedit qmail-rspawn XXX | ||
| 16 | ./idedit qmail-showctl XXX | ||
| 17 | ./idedit qmail-start XXX | ||
| 18 | ./install-big | ||
| 19 | cp /var/qmail/boot/binm1+df /var/qmail/rc | ||
| 20 | chmod 755 /var/qmail/rc | ||
| 21 | echo '|fastforward -d /etc/aliases.cdb' > /var/qmail/alias/.qmail-default | ||
| 22 | chmod 644 /var/qmail/alias/.qmail-default | ||
| 23 | hostname | grep -q '\.' | ||
| 24 | ./config-fast `hostname` | ||
diff --git a/BIN.README b/BIN.README new file mode 100644 index 0000000..6beeee1 --- /dev/null +++ b/BIN.README | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | Like any other piece of software (and information generally), qmail | ||
| 2 | comes with NO WARRANTY. | ||
| 3 | |||
| 4 | Configuration: The qmail home directory is /var/qmail. (This must be a | ||
| 5 | local directory, not shared among machines. Under Linux, make sure that | ||
| 6 | all mail-handling filesystems are mounted with synchronous metadata.) | ||
| 7 | The user-ext delimiter is -. The silent concurrency limit is 120. The | ||
| 8 | queue subdirectory split is 23. | ||
| 9 | |||
| 10 | To install: | ||
| 11 | # make setup | ||
| 12 | |||
| 13 | To set up qmail to receive and deliver mail, follow the instructions in | ||
| 14 | /var/qmail/doc/fastforward/ALIASES, and then start at step 9 of | ||
| 15 | /var/qmail/doc/INSTALL. | ||
| 16 | |||
| 17 | Compilation environment: Oops, the package creator forgot to edit this! | ||
| 18 | He's supposed to list his OS version, compiler version, hardware, and | ||
| 19 | name. | ||
| @@ -0,0 +1,43 @@ | |||
| 1 | qmail is a secure, reliable, efficient, simple message transfer agent. | ||
| 2 | It is meant as a replacement for the entire sendmail-binmail system on | ||
| 3 | typical Internet-connected UNIX hosts. | ||
| 4 | |||
| 5 | Secure: Security isn't just a goal, but an absolute requirement. Mail | ||
| 6 | delivery is critical for users; it cannot be turned off, so it must be | ||
| 7 | completely secure. (This is why I started writing qmail: I was sick of | ||
| 8 | the security holes in sendmail and other MTAs.) | ||
| 9 | |||
| 10 | Reliable: qmail's straight-paper-path philosophy guarantees that a | ||
| 11 | message, once accepted into the system, will never be lost. qmail also | ||
| 12 | supports maildir, a new, super-reliable user mailbox format. Maildirs, | ||
| 13 | unlike mbox files and mh folders, won't be corrupted if the system | ||
| 14 | crashes during delivery. Even better, not only can a user safely read | ||
| 15 | his mail over NFS, but any number of NFS clients can deliver mail to him | ||
| 16 | at the same time. | ||
| 17 | |||
| 18 | Efficient: On a Pentium under BSD/OS, qmail can easily sustain 200000 | ||
| 19 | local messages per day---that's separate messages injected and delivered | ||
| 20 | to mailboxes in a real test! Although remote deliveries are inherently | ||
| 21 | limited by the slowness of DNS and SMTP, qmail overlaps 20 simultaneous | ||
| 22 | deliveries by default, so it zooms quickly through mailing lists. (This | ||
| 23 | is why I finished qmail: I had to get a big mailing list set up.) | ||
| 24 | |||
| 25 | Simple: qmail is vastly smaller than any other Internet MTA. Some | ||
| 26 | reasons why: (1) Other MTAs have separate forwarding, aliasing, and | ||
| 27 | mailing list mechanisms. qmail has one simple forwarding mechanism that | ||
| 28 | lets users handle their own mailing lists. (2) Other MTAs offer a | ||
| 29 | spectrum of delivery modes, from fast+unsafe to slow+queued. qmail-send | ||
| 30 | is instantly triggered by new items in the queue, so the qmail system | ||
| 31 | has just one delivery mode: fast+queued. (3) Other MTAs include, in | ||
| 32 | effect, a specialized version of inetd that watches the load average. | ||
| 33 | qmail's design inherently limits the machine load, so qmail-smtpd can | ||
| 34 | safely run from your system's inetd. | ||
| 35 | |||
| 36 | Replacement for sendmail: qmail supports host and user masquerading, | ||
| 37 | full host hiding, virtual domains, null clients, list-owner rewriting, | ||
| 38 | relay control, double-bounce recording, arbitrary RFC 822 address lists, | ||
| 39 | cross-host mailing list loop detection, per-recipient checkpointing, | ||
| 40 | downed host backoffs, independent message retry schedules, etc. In | ||
| 41 | short, it's up to speed on modern MTA features. qmail also includes a | ||
| 42 | drop-in ``sendmail'' wrapper so that it will be used transparently by | ||
| 43 | your current UAs. | ||
| @@ -0,0 +1,26 @@ | |||
| 1 | Mailing list management is one of qmail's strengths. Notable features: | ||
| 2 | |||
| 3 | * qmail lets each user handle his own mailing lists. The delivery | ||
| 4 | instructions for user-whatever go into ~user/.qmail-whatever. | ||
| 5 | |||
| 6 | * qmail makes it really easy to set up mailing list owners. If the user | ||
| 7 | touches ~user/.qmail-whatever-owner, all bounces will come back to him. | ||
| 8 | |||
| 9 | * qmail supports VERPs, which permit completely reliable automated | ||
| 10 | bounce handling for mailing lists of any size. | ||
| 11 | |||
| 12 | * SPEED---qmail blasts through mailing lists an order of magnitude | ||
| 13 | faster than sendmail. For example, one message was successfully | ||
| 14 | delivered to 150 hosts around the world in just 70 seconds, with qmail's | ||
| 15 | out-of-the-box configuration. | ||
| 16 | |||
| 17 | * qmail automatically prevents mailing list loops, even across hosts. | ||
| 18 | |||
| 19 | * qmail allows inconceivably gigantic mailing lists. No random limits. | ||
| 20 | |||
| 21 | * qmail handles aliasing and forwarding with the same simple mechanism. | ||
| 22 | For example, Postmaster is controlled by ~alias/.qmail-postmaster. This | ||
| 23 | means that cross-host loop detection also applies to aliases. | ||
| 24 | |||
| 25 | * qmail supports the ezmlm mailing list manager, which easily and | ||
| 26 | automatically handles bounces, subscription requests, and archives. | ||
| @@ -0,0 +1,93 @@ | |||
| 1 | Here are some of qmail's features. | ||
| 2 | |||
| 3 | Setup: | ||
| 4 | * automatic adaptation to your UNIX variant---no configuration needed | ||
| 5 | * AIX, BSD/OS, FreeBSD, HP/UX, Irix, Linux, OSF/1, SunOS, Solaris, and more | ||
| 6 | * automatic per-host configuration (config, config-fast) | ||
| 7 | * quick installation---no big list of decisions to make | ||
| 8 | |||
| 9 | Security: | ||
| 10 | * clear separation between addresses, files, and programs | ||
| 11 | * minimization of setuid code (qmail-queue) | ||
| 12 | * minimization of root code (qmail-start, qmail-lspawn) | ||
| 13 | * five-way trust partitioning---security in depth | ||
| 14 | * optional logging of one-way hashes, entire contents, etc. (QUEUE_EXTRA) | ||
| 15 | |||
| 16 | Message construction (qmail-inject): | ||
| 17 | * RFC 822, RFC 1123 | ||
| 18 | * full support for address groups | ||
| 19 | * automatic conversion of old-style address lists to RFC 822 format | ||
| 20 | * sendmail hook for compatibility with current user agents | ||
| 21 | * header line length limited only by memory | ||
| 22 | * host masquerading (control/defaulthost) | ||
| 23 | * user masquerading ($MAILUSER, $MAILHOST) | ||
| 24 | * automatic Mail-Followup-To creation ($QMAILMFTFILE) | ||
| 25 | |||
| 26 | SMTP service (qmail-smtpd): | ||
| 27 | * RFC 821, RFC 1123, RFC 1651, RFC 1652, RFC 1854 | ||
| 28 | * 8-bit clean | ||
| 29 | * 931/1413/ident/TAP callback (tcp-env) | ||
| 30 | * relay control---stop unauthorized relaying by outsiders (control/rcpthosts) | ||
| 31 | * no interference between relay control and forwarding | ||
| 32 | * tcpd hook---reject SMTP connections from known abusers | ||
| 33 | * automatic recognition of local IP addresses | ||
| 34 | * per-buffer timeouts | ||
| 35 | * hop counting | ||
| 36 | |||
| 37 | Queue management (qmail-send): | ||
| 38 | * instant handling of messages added to queue | ||
| 39 | * parallelism limit (control/concurrencyremote, control/concurrencylocal) | ||
| 40 | * split queue directory---no slowdown when queue gets big | ||
| 41 | * quadratic retry schedule---old messages tried less often | ||
| 42 | * independent message retry schedules | ||
| 43 | * automatic safe queueing---no loss of mail if system crashes | ||
| 44 | * automatic per-recipient checkpointing | ||
| 45 | * automatic queue cleanups (qmail-clean) | ||
| 46 | * queue viewing (qmail-qread) | ||
| 47 | * detailed delivery statistics (qmailanalog, available separately) | ||
| 48 | |||
| 49 | Bounces (qmail-send): | ||
| 50 | * QSBMF bounce messages---both machine-readable and human-readable | ||
| 51 | * HCMSSC support---language-independent RFC 1893 error codes | ||
| 52 | * double bounces sent to postmaster | ||
| 53 | |||
| 54 | Routing by domain (qmail-send): | ||
| 55 | * any number of names for local host (control/locals) | ||
| 56 | * any number of virtual domains (control/virtualdomains) | ||
| 57 | * domain wildcards (control/virtualdomains) | ||
| 58 | * configurable percent hack support (control/percenthack) | ||
| 59 | * UUCP hook | ||
| 60 | |||
| 61 | SMTP delivery (qmail-remote): | ||
| 62 | * RFC 821, RFC 974, RFC 1123 | ||
| 63 | * 8-bit clean | ||
| 64 | * automatic downed host backoffs | ||
| 65 | * artificial routing---smarthost, localnet, mailertable (control/smtproutes) | ||
| 66 | * per-buffer timeouts | ||
| 67 | * passive SMTP queue---perfect for SLIP/PPP (serialmail, available separately) | ||
| 68 | |||
| 69 | Forwarding and mailing lists (qmail-local): | ||
| 70 | * address wildcards (.qmail-default, .qmail-foo-default, etc.) | ||
| 71 | * sendmail .forward compatibility (dot-forward, available separately) | ||
| 72 | * fast forwarding databases (fastforward, available separately) | ||
| 73 | * sendmail /etc/aliases compatibility (fastforward/newaliases) | ||
| 74 | * mailing list owners---automatically divert bounces and vacation messages | ||
| 75 | * VERPs---automatic recipient identification for mailing list bounces | ||
| 76 | * Delivered-To---automatic loop prevention, even across hosts | ||
| 77 | * automatic mailing list management (ezmlm, available separately) | ||
| 78 | |||
| 79 | Local delivery (qmail-local): | ||
| 80 | * user-controlled address hierarchy---fred controls fred-anything | ||
| 81 | * mbox delivery | ||
| 82 | * reliable NFS delivery (maildir) | ||
| 83 | * user-controlled program delivery: procmail etc. (qmail-command) | ||
| 84 | * optional new-mail notification (qbiff) | ||
| 85 | * optional NRUDT return receipts (qreceipt) | ||
| 86 | * conditional filtering (condredirect, bouncesaying) | ||
| 87 | |||
| 88 | POP3 service (qmail-popup, qmail-pop3d): | ||
| 89 | * RFC 1939 | ||
| 90 | * UIDL support | ||
| 91 | * TOP support | ||
| 92 | * APOP hook | ||
| 93 | * modular password checking (checkpassword, available separately) | ||
| @@ -0,0 +1,44 @@ | |||
| 1 | qmail's modular, lightweight design and sensible queue management make | ||
| 2 | it the fastest available message transfer agent. Here's how it stacks up | ||
| 3 | against the competition in five different speed measurements. | ||
| 4 | |||
| 5 | * Scheduling: I sent a message to 8192 ``trash'' recipients on my home | ||
| 6 | machine. All the deliveries were done in a mere 78 seconds---a rate of | ||
| 7 | over 9 million deliveries a day! Compare this to the speed advertised | ||
| 8 | for Zmailer's scheduling: 1.1 million deliveries a day on a | ||
| 9 | SparcStation-10/50. (My home machine is a 16MB Pentium-100 under BSD/OS, | ||
| 10 | with the default qmail configuration. qmail's logs were piped through | ||
| 11 | accustamp and written to disk as usual.) | ||
| 12 | |||
| 13 | * Local mailing lists: When qmail is delivering a message to a mailbox, | ||
| 14 | it physically writes the message to disk before it announces success--- | ||
| 15 | that way, mail doesn't get lost if the power goes out. I tried sending a | ||
| 16 | message to 1024 local mailboxes on the same disk on my home machine; all | ||
| 17 | the deliveries were done in 25.5 seconds. That's more than 3.4 million | ||
| 18 | deliveries a day! Sending 1024 copies to a _single_ mailbox was just as | ||
| 19 | fast. Compare these figures to Zmailer's advertised rate for throwing | ||
| 20 | recipients away without even delivering the message---only 0.48 million | ||
| 21 | per day on the SparcStation. | ||
| 22 | |||
| 23 | * Mailing lists with remote recipients: qmail uses the same delivery | ||
| 24 | strategy that makes LSOFT's LSMTP so fast for outgoing mailing lists--- | ||
| 25 | you choose how many parallel SMTP connections you want to run, and qmail | ||
| 26 | runs exactly that many. Of course, performance varies depending on how | ||
| 27 | far away your recipients are. The advantage of qmail over other packages | ||
| 28 | is its smallness: for example, one Linux user is running 60 simultaneous | ||
| 29 | connections, without swapping, on a machine with just 16MB of memory! | ||
| 30 | |||
| 31 | * Separate local messages: What LSOFT doesn't tell you about LSMTP is | ||
| 32 | how many _separate_ messages it can handle in a day. Does it get bogged | ||
| 33 | down as the queue fills up? On my home machine, I disabled qmail's | ||
| 34 | deliveries and then sent 5000 separate messages to one recipient. The | ||
| 35 | messages were all safely written to the queue disk in 23 minutes, with | ||
| 36 | no slowdown as the queue filled up. After I reenabled deliveries, all | ||
| 37 | the messages were delivered to the recipient's mailbox in under 12 | ||
| 38 | minutes. End-to-end rate: more than 200000 individual messages a day! | ||
| 39 | |||
| 40 | * Overall performance: What really matters is how well qmail performs | ||
| 41 | with your mail load. Red Hat Software found one day that their mail hub, | ||
| 42 | a 48MB Pentium running sendmail 8.7, was running out of steam at 70000 | ||
| 43 | messages a day. They shifted the load to qmail---on a _smaller_ machine, | ||
| 44 | a 16MB 486/66---and now they're doing fine. | ||
| @@ -0,0 +1,1460 @@ | |||
| 1 | 19980615 version: qmail 1.03. | ||
| 2 | 19980614 doc: eliminated BIN.setup in favor of a web page. | ||
| 3 | 19980614 code: added other auto* to qmail-showctl output. | ||
| 4 | 19980614 doc: added pointer to immhf.html in qmail-header.5. | ||
| 5 | 19980614 doc: added note to TEST.receive about SMTP command format. | ||
| 6 | 19980614 doc: added FAQ 5.6 on qmail-qmqpd. | ||
| 7 | 19980614 code: removed unused variables in idedit.c. | ||
| 8 | 19980613 code: changed conf-patrn to 002. | ||
| 9 | 19980613 doc: moved SENDMAIL lower in INSTALL. | ||
| 10 | 19980612 code: added install-big. | ||
| 11 | 19980612 code: added BIN.Makefile. | ||
| 12 | 19980612 doc: added BIN.README, BIN.setup. | ||
| 13 | 19980612 code: switched to new install. | ||
| 14 | 19980611 code: added idedit. | ||
| 15 | 19980611 doc: added FAQ 1.3 on $QMAILMFTFILE. | ||
| 16 | 19980611 doc: used bouncesaying in FAQ 5.5. | ||
| 17 | 19980611 code: added except. | ||
| 18 | 19980611 code: added bouncesaying. | ||
| 19 | 19980611 code: allowed unbracketed IP addresses in dns_ipplus() and | ||
| 20 | dns_mxip(). | ||
| 21 | 19980611 code: allowed spaces after colon in non-bracketed addresses in | ||
| 22 | qmail-smtpd. | ||
| 23 | 19980611 doc: cleaned up UPGRADE. | ||
| 24 | 19980528 bug: qmail-smtpd skips first character in rcpthosts() call. | ||
| 25 | tnx NND. impact: qmail-smtpd crashes on empty address; and it | ||
| 26 | allows relaying to ""@any.host. fix: use addr.s. | ||
| 27 | 19980515 doc: expanded flock discussion in INSTALL.mbox. | ||
| 28 | 19980515 doc: eliminated flock warning from INSTALL.maildir. | ||
| 29 | 19980515 doc: split REMOVE.binmail out of INSTALL. | ||
| 30 | 19980515 doc: split REMOVE.sendmail out of INSTALL. | ||
| 31 | 19980515 doc: split TEST.deliver and TEST.receive out of INSTALL and | ||
| 32 | UPGRADE. | ||
| 33 | 19980515 doc: integrated INSTALL.boot into INSTALL. | ||
| 34 | 19980515 code: cleaned up final output in qmail-qmqpd.c. | ||
| 35 | 19980514 doc: updated procmail notes in INSTALL.mbox. tnx JRM. | ||
| 36 | 19980514 doc: changed FAQ 4.4 to point to INSTALL.mbox for procmail. | ||
| 37 | tnx JRM. | ||
| 38 | 19980514 code: separated HELO and EHLO; single-line response for HELO. | ||
| 39 | tnx to various people. | ||
| 40 | 19980430 version: qmail 1.02. | ||
| 41 | 19980430 doc: updated SECURITY. | ||
| 42 | 19980430 doc: fixed FAQ 4.9. tnx KB. | ||
| 43 | 19980430 code: changed quote2() to avoid quoting <>. | ||
| 44 | 19980429 code: changed quote_need() to quote empty local parts. tnx HHO. | ||
| 45 | 19980428 doc: added status notes to INSTALL and UPGRADE. | ||
| 46 | 19980428 code: skip setting environment in sendmail.c if PROTO is set. | ||
| 47 | 19980428 code: eliminated recipientmap. | ||
| 48 | 19980428 code: added virtual users to qmail-send.c. tnx RN. | ||
| 49 | 19980428 code: eliminated domain from rewrite() in qmail-send.c. | ||
| 50 | 19980428 code: added binm1, binm1+df, binm2, binm2+df, binm3, binm3+df. | ||
| 51 | 19980428 doc: eliminated most Mailbox references from INSTALL, UPGRADE. | ||
| 52 | 19980428 code: added config-fast. | ||
| 53 | 19980428 code: renamed qmail-config as config. | ||
| 54 | 19980428 code: supported QMAILMFTFILE in qmail-inject.c. | ||
| 55 | 19980428 code: recognized Mail-Followup-To in hfield.c. | ||
| 56 | 19980428 code: replaced rwrecip() with rwappend() in qmail-inject.c. | ||
| 57 | 19980428 code: cleaned up doheaderfile() in qmail-inject.c. | ||
| 58 | 19980426 code: eliminated -type test from qmail-qstat to speed it up. | ||
| 59 | tnx FT. | ||
| 60 | 19980421 doc: eliminated remove-rcpthosts comments from FAQ. | ||
| 61 | 19980421 doc: updated FAQ 4.3 to point to Russ Allbery's FAQ. | ||
| 62 | 19980421 doc: took account of /var/qmail/boot in INSTALL, UPGRADE, and | ||
| 63 | INSTALL.vsm. | ||
| 64 | 19980421 code: added /var/qmail/boot, with home, home+df, proc, proc+df. | ||
| 65 | 19980421 doc: skipped make and make man in INSTALL. | ||
| 66 | 19980420 doc: cleaned up mbox description in SENDMAIL. | ||
| 67 | 19980420 code: changed QMQP port to official port 628. | ||
| 68 | 19980402 doc: updated qmsmac references to fastforward. | ||
| 69 | 19980402 doc: replaced qmail-upgrade man page with doc/SENDMAIL. | ||
| 70 | 19980402 code: added qmqpservers output to qmail-showctl. | ||
| 71 | 19980402 code: added qmail-qmqpd. | ||
| 72 | 19980402 code: added qmail-qmqpc. | ||
| 73 | 19980304 code: eliminated del_saywhynoexit in qmail-send.c. | ||
| 74 | 19980304 code: eliminated concurrencynodel in qmail-send.c. | ||
| 75 | 19980222 code: added status() to qmail-send.c. | ||
| 76 | 19980222 code: added concurrencyused to qmail-send.c. | ||
| 77 | 19980128 doc: added note to qmail-getpw.9 about ETXTBSY. | ||
| 78 | 19980127 code: eliminated err_seenmail() in qmail-smtpd.c. tnx PO. | ||
| 79 | 19980126 doc: used $DEFAULT in FAQ where possible. | ||
| 80 | 19980126 code: added DEFAULT in qmail-local. | ||
| 81 | 19980126 code: added -/ to qmail-pw2u. | ||
| 82 | 19980126 code: revamped qmeopen() as qmesearch() with more sensible | ||
| 83 | semantics, separating dash from ext cleanly. | ||
| 84 | 19980126 code: split qmeexists() out of qmeopen() in qmail-local.c. | ||
| 85 | 19980126 code: introduced safeext in qmail-local.c. | ||
| 86 | 19980126 code: changed ~alias to mode 2755, to put files into group | ||
| 87 | qmail rather than group nofiles under System V. | ||
| 88 | 19980126 doc: switched to /var/qmail/rc in INSTALL*, UPGRADE, FAQ. | ||
| 89 | 19980126 code: added rc. | ||
| 90 | 19980119 doc: added .qmail creation warning to condredirect.1. | ||
| 91 | 19980118 code: made auto_uids.c creation atomic in Makefile. tnx HHO. | ||
| 92 | 19980118 doc: added PIC.*. | ||
| 93 | 19980117 portability problem: Solaris 2.5.1 incorrectly converts | ||
| 94 | O_NDELAY into O_NONBLOCK for sockets, so that ndelay_off() | ||
| 95 | fails to undo ndelay_on(). impact: none, since all the network | ||
| 96 | readers here use select() via timeoutread(). fix: use | ||
| 97 | O_NONBLOCK if it is defined. | ||
| 98 | 19980115 code: reformatted qmail-qmtpd.c. | ||
| 99 | 19980115 doc: changed tcpcontrol references in FAQ. | ||
| 100 | 19980115 doc: documented morercpthosts in qmail-qmtpd.9. | ||
| 101 | 19980115 code: eliminated unused datetime in qmail-qmtpd.c. | ||
| 102 | 19980115 code: eliminated sigalrm() in qmail-qmtpd.c. | ||
| 103 | 19980115 code: used rcpthosts() in qmail-smtpd.c, qmail-qmtpd.c. | ||
| 104 | 19980115 code: introduced rcpthosts.c. | ||
| 105 | 19980115 code: added morercpthosts.cdb support to qmail-showctl. | ||
| 106 | 19980115 code: added morercpthosts support to qmail-showctl. | ||
| 107 | 19980115 code: do_lst now returns file-exists in qmail-showctl. | ||
| 108 | 19980112 doc: documented morercpthosts in qmail-smtpd.9. | ||
| 109 | 19980112 code: added qmail-newmrh. | ||
| 110 | 19980112 code: used commands.c in qmail-popup. | ||
| 111 | 19980112 code: used commands.c in qmail-pop3d. | ||
| 112 | 19980112 code: introduced fakehelo in qmail-smtpd. | ||
| 113 | 19980112 code: moved flagbarf setting out of bmfcheck(). | ||
| 114 | 19980112 code: allowed more address misformatting in qmail-smtpd. | ||
| 115 | 19980112 code: eliminated qmail@pobox.com help address in qmail-smtpd. | ||
| 116 | 19980112 code: reorganized qmail-smtpd. | ||
| 117 | 19980112 code: reformatted qmail-smtpd. | ||
| 118 | 19980112 code: used commands.c in qmail-smtpd. | ||
| 119 | 19980112 code: switched from 0 to "" for no arg in commands(). | ||
| 120 | 19980112 code: added commands.c. | ||
| 121 | 19971230 doc: added -s to FreeBSD commands in INSTALL.ids. tnx TM. | ||
| 122 | 19971224 doc: added pointer to qmail pictures in README. | ||
| 123 | 19971223 doc: added note in FAQ about qmail-pop3d using maildir. | ||
| 124 | 19971219 code: added HOST2, HOST3, HOST4. | ||
| 125 | 19971219 code: renamed extx as x in qmail-local.c. | ||
| 126 | 19971219 doc: partitioned qmail-command.0. | ||
| 127 | 19971219 doc: updated FAQ 4.3 to point to newer majordomo patches. | ||
| 128 | 19971219 doc: eliminated qlist2 from FAQ. | ||
| 129 | 19971219 doc: eliminated qlist discussion from SECURITY. | ||
| 130 | 19971219 code: moved qlist, qlist2 to separate package. | ||
| 131 | 19971213 doc: added FAQ 4.10 on qmail-users generally. | ||
| 132 | 19971213 doc: added FAQ 4.9 on dealing with NFS outages. | ||
| 133 | 19971031 doc: added Linux and FreeBSD commands to INSTALL.ids. tnx TM. | ||
| 134 | 19971026 doc: added note about smtplf in qmail-smtpd.8. tnx S2S. | ||
| 135 | 19971014 doc: some tweaks to THOUGHTS. | ||
| 136 | 19971012 doc: used MAILER-DAEMON in UUCP example in INSTALL. | ||
| 137 | 19971003 code: eliminated dataline and getln() from qmail-remote.c. | ||
| 138 | 19971003 code: revamped blast() in qmail-remote.c. | ||
| 139 | 19971002 doc: added FAQ entries for .forward and /etc/aliases. | ||
| 140 | 19971002 doc: rewrote INSTALL.mbox and INSTALL.vsm. | ||
| 141 | 19971002 doc: renamed INSTALL.qsmhook as INSTALL.vsm. | ||
| 142 | 19971002 doc: emphasized the qmail-popup argv0 in FAQ. | ||
| 143 | 19971001 doc: added dot-forward note to BLURB3. | ||
| 144 | 19971001 doc: added more configuration notes to qmail-upgrade.9. | ||
| 145 | 19971001 doc: added note in INSTALL.qsmhook about dot-forward. | ||
| 146 | 19970930 code: token822_parse() now supports backslash as a quoting | ||
| 147 | character in atoms. | ||
| 148 | 19970929 doc: suggested symbolic links in INSTALL.mbox. | ||
| 149 | 19970925 doc: added note to INTERNALS about bounce stability. | ||
| 150 | 19970925 doc: added section to THOUGHTS discussing CNAME lookups. | ||
| 151 | 19970925 code: qmail-remote no longer does CNAME lookup on sender. tnx | ||
| 152 | C2F. | ||
| 153 | 19970923 portability problem: under SCO OSR5, splogger needs socket | ||
| 154 | libraries. impact: couldn't compile. fix: socket.lib. tnx RB. | ||
| 155 | 19970906 portability problem: under RISC/OS, Mail invokes sendmail -bm. | ||
| 156 | impact: can't send mail using Mail on RISC/OS. fix: ignore -bm. | ||
| 157 | tnx NW. | ||
| 158 | 19970813 code: implemented databytes in qmail-qmtpd. | ||
| 159 | 19970813 code: implemented databytes. tnx M4S for sample code. | ||
| 160 | 19970813 code: replaced execvp() with execv() for sh in qmail-local. | ||
| 161 | 19970813 doc: said in qmail-control.9 that recipientmap allows comments. | ||
| 162 | 19970813 code: used strerr in qmail-local.c. | ||
| 163 | 19970813 code: changed timeoutread(), timeoutwrite() interface. | ||
| 164 | 19970813 code: eliminated shutdown() in timeoutread(), timeoutwrite(). | ||
| 165 | 19970813 code: revamped I/O in qmail-smtpd.c. | ||
| 166 | 19970813 code: used timeoutread(), timeoutwrite() in qmail-smtpd.c. | ||
| 167 | 19970813 code: simplified getcontrol() logic in qmail-remote.c; some | ||
| 168 | out-of-memory messages are now cannot-read-control messages. | ||
| 169 | 19970813 code: eliminated scan_nbblong(). | ||
| 170 | 19970813 code: reformatted qmail-remote.c. | ||
| 171 | 19970813 code: renamed flaganyrecipok as flagbother in qmail-remote.c. | ||
| 172 | 19970813 code: integrated status report into quit() in qmail-remote.c. | ||
| 173 | 19970813 code: revamped smtpcode() in qmail-remote.c. | ||
| 174 | 19970813 code: added flagcritical in qmail-remote.c. eliminates | ||
| 175 | possible-duplicate warning if dot has not yet been sent. | ||
| 176 | 19970813 code: revamped I/O in qmail-remote.c. | ||
| 177 | 19970813 code: quit immediately after sending QUIT in qmail-remote.c. | ||
| 178 | 19970813 code: made many more globals in qmail-remote.c. | ||
| 179 | 19970813 code: switched qmail-remote.c from subfdin to home-grown. | ||
| 180 | 19970813 code: switched qmail-remote.c from subfdout to subfdoutsmall. | ||
| 181 | 19970813 code: added LAST support to qmail-pop3d. | ||
| 182 | 19970812 code: changed qmail_close() success return from 0 to "". | ||
| 183 | 19970812 code: revamped I/O in qmail-qmtpd.c. | ||
| 184 | 19970812 code: added qmail-tcpok. | ||
| 185 | 19970812 code: used strerr in maildirmake.c. | ||
| 186 | 19970812 code: reformatted maildirmake.c. | ||
| 187 | 19970812 code: printed qp in condredirect.c. | ||
| 188 | 19970812 code: printed qqx in condredirect.c. | ||
| 189 | 19970812 code: revamped I/O in condredirect.c. | ||
| 190 | 19970812 code: reformatted condredirect.c. | ||
| 191 | 19970812 code: used strerr in preline.c. | ||
| 192 | 19970812 code: revamped I/O in preline.c. | ||
| 193 | 19970812 code: reformatted preline.c. | ||
| 194 | 19970812 code: printed qp in forward.c. | ||
| 195 | 19970812 code: printed qqx in forward.c. | ||
| 196 | 19970812 code: revamped I/O in forward.c. | ||
| 197 | 19970812 code: used strerr in forward.c. | ||
| 198 | 19970812 code: reformatted forward.c. | ||
| 199 | 19970812 code: used strerr in predate.c. | ||
| 200 | 19970812 code: forced failure in qmail-qmtpd if no recipients; saves | ||
| 201 | time for qmail-send. | ||
| 202 | 19970812 code: added smtpd() to sendmail.c. | ||
| 203 | 19970812 code: added mailq() to sendmail.c. | ||
| 204 | 19970812 code: added die_usage() to sendmail.c. | ||
| 205 | 19970812 code: reformatted sendmail.c. | ||
| 206 | 19970812 code: used byte_zero() in qmail-popup.c. | ||
| 207 | 19970812 code: reformatted qmail-popup.c. | ||
| 208 | 19970812 code: eliminated unused header files in qmail-popup.c. | ||
| 209 | 19970812 code: changed I/O system in qmail-popup.c to match qmail-pop3d. | ||
| 210 | 19970812 doc: pointed people to the mailing list in INSTALL and UPGRADE. | ||
| 211 | 19970810 code: added TXTBSY check to qmail-getpw.c. this gives vendors | ||
| 212 | the opportunity to make getpwnam() reliable. | ||
| 213 | 19970810 code: moved non-deleted messages from new/ to cur/ in | ||
| 214 | qmail-pop3d. tnx to various people. | ||
| 215 | 19970810 code: introduced list() in qmail-pop3d.c. | ||
| 216 | 19970810 code: reformatted qmail-pop3d.c. | ||
| 217 | 19970810 code: merged dataline and newname into line in qmail-pop3d.c. | ||
| 218 | 19970810 code: chopped filenames in qmail-pop3d at colons for UIDL. tnx | ||
| 219 | to various people. | ||
| 220 | 19970810 code: eliminated printint(), printlong() in qmail-pop3d.c. | ||
| 221 | 19970810 code: revamped I/O in qmail-pop3d.c. | ||
| 222 | 19970810 code: used timeoutread(), timeoutwrite() in qmail-pop3d.c. | ||
| 223 | 19970810 code: eliminated die_prot() in qmail-pop3d.c. | ||
| 224 | 19970810 code: eliminated unused header files in qmail-pop3d.c. | ||
| 225 | 19970810 code: switched qmail-pop3d to use maildir.c. tnx MD. | ||
| 226 | 19970809 code: added uid/gid printing to qmail-showctl. tnx PGF. | ||
| 227 | 19970808 code: switched control.c from scan_nbblong to scan_ulong. | ||
| 228 | 19970808 code: cleaned up wait_pid to use waitpid() when possible, and | ||
| 229 | to support at least one extra child otherwise. | ||
| 230 | 19970807 code: in qmail-smtpd, treat long envelope addresses as a syntax | ||
| 231 | error, instead of waiting for qmail-queue to reject them. | ||
| 232 | 19970803 code: changed condredirect, forward, qlist, qmail-inject, | ||
| 233 | qmail-local, qmail-qmtpd, qmail-send, qmail-smtpd, qreceipt for | ||
| 234 | new qmail_close() interface. | ||
| 235 | 19970803 code: revised qmail_close() to handle qmail-queue exit codes. | ||
| 236 | 19970802 doc: documented SMTP-related exit codes in qmail-queue.8. | ||
| 237 | 19970802 doc: documented qmail-queue exit codes in qmail-queue.8. | ||
| 238 | 19970802 code: revamped qmail-queue exit codes. | ||
| 239 | 19970802 doc: noted linking restrictions in qmail-queue.8. | ||
| 240 | 19970802 doc: rewrote INSTALL.mbox. | ||
| 241 | 19970802 doc: split INSTALL.maildir off of INSTALL.mbox. | ||
| 242 | 19970802 code: added /var/qmail/doc/ creation to qmail-hier. | ||
| 243 | 19970802 doc: added ezmlm note to FAQ. | ||
| 244 | 19970802 doc: replaced qlist blurbs with ezmlm blurbs in BLURB*. | ||
| 245 | 19970802 doc: added various notes to qmail-start.9. | ||
| 246 | 19970728 doc: eliminated RFC*. | ||
| 247 | 19970714 doc: added daemontools notes to FAQ. | ||
| 248 | 19970714 code: eliminated ESMTP parameter syntax checking. | ||
| 249 | 19970701 doc: changed ``forwarded'' to ``resent'' in qmail-header.5. | ||
| 250 | 19970629 code: reformatted constmap.c. | ||
| 251 | 19970628 code: changed straynewline() message in qmail-smtpd.c to point | ||
| 252 | to http://pobox.com/~djb/smtplf.html. tnx RDM. | ||
| 253 | 19970609 doc: added preline to vacation example in dot-qmail.9. tnx C2S. | ||
| 254 | 19970421 code: cleaned up slurpclose to handle interrupts. | ||
| 255 | 19970421 code: set qmail-popup to mode 711. tnx MD. | ||
| 256 | 19970421 doc: fixed qmail-local -n example in dot-qmail.9. | ||
| 257 | 19970415 version: qmail 1.01. | ||
| 258 | 19970414 doc: tightened up qmail-upgrade.7. | ||
| 259 | 19970414 code: rewrote rewrite(). | ||
| 260 | 19970414 code: implemented recipientmap. suggested by RDM. | ||
| 261 | 19970414 doc: auto-configured qmail home directory in qmail-control.5, | ||
| 262 | qmail-newu.8, qmail-pw2u.8, qmail-start.8, qmail-users.5. | ||
| 263 | 19970414 port: Solaris needs socket libs for gethostname. impact: can't | ||
| 264 | compile under Solaris. fix: use socket.lib for qmail-local. | ||
| 265 | 19970412 code: introduced stralloc_starts. | ||
| 266 | 19970412 code: introduced str_equal. | ||
| 267 | 19970412 code: introduced str_start. | ||
| 268 | 19970412 code: introduced byte_equal. | ||
| 269 | 19970412 code: made an optional aliasempty arg for qmail-start. | ||
| 270 | 19970412 code: made an aliasempty arg for qmail-lspawn. | ||
| 271 | 19970412 code: changed ALIAS_EMPTY to an arg for qmail-local. | ||
| 272 | 19970412 port: UnixWare returns >0 for SIOCGIFCONF. impact: ipme fails | ||
| 273 | under UnixWare. fix: check for >=0, not =0. tnx JD. | ||
| 274 | 19970412 port: DGUX does not have ranlib. impact: can't compile under | ||
| 275 | DGUX. fix: added dgux line to make-makelib. tnx HWM. | ||
| 276 | 19970412 code: changed maildir library to skip any filename beginning | ||
| 277 | with dot. tnx SP. | ||
| 278 | 19970412 doc: added FAQ entry about aliases with dots. | ||
| 279 | 19970412 doc: clarified in qmail-inject.8 that default envelope sender | ||
| 280 | is the same as _default_ From address. | ||
| 281 | 19970411 code: renamed qmail-makectl as qmail-config. | ||
| 282 | 19970411 code: renamed qmail-alias as qmail-local. | ||
| 283 | 19970411 code: switched from signal library to sig library. | ||
| 284 | 19970411 code: switched from qqtalk library to qmail library. | ||
| 285 | 19970411 code: switched from getline library to getln library. | ||
| 286 | 19970411 code: massive library cleanups. | ||
| 287 | 19970411 code: revamped autoconfiguration system. | ||
| 288 | 19970411 code: revamped configuration interface. | ||
| 289 | 19970411 code: eliminated qmail-home. | ||
| 290 | 19970411 code: eliminated tokenize. | ||
| 291 | 19970220 qmail 1.00. | ||
| 292 | 19970219 change: various documentation tweaks. | ||
| 293 | 19970218 change: updated THOUGHTS. | ||
| 294 | 19970218 change: talked about SPAWN_NUMD in FAQ. tnx EC. | ||
| 295 | 19970210 change: noted in maildir.5 that readers should skip any name | ||
| 296 | starting with a dot. tnx SP. | ||
| 297 | 19970209 change: added note to splogger.8 about reliability. tnx BT. | ||
| 298 | 19970209 change: added section to FAQ on slow sendmail switch. tnx BT. | ||
| 299 | 19970206 change: added section to FAQ about dtcm. tnx PJG. | ||
| 300 | 19970206 change: tweaked maildir.5. | ||
| 301 | 19970201 change: added MH spost note to FAQ. tnx TU. | ||
| 302 | 19970131 change: reorganized FAQ. | ||
| 303 | 19970131 change: added web references to FAQ. | ||
| 304 | 19970124 change: tweaked qmail-upgrade man page. | ||
| 305 | 19970120 qmail 0.96, gamma. | ||
| 306 | 19970120 change: removed various try* in auto-configuration. | ||
| 307 | 19970120 bug: qmail-inject fails to quote argument addresses. impact: | ||
| 308 | addresses containing special characters could be misinterpreted | ||
| 309 | or rejected. tnx C2F. fix: use quote2(). | ||
| 310 | 19970120 portability problem: ESIX puts syslog() and openlog() into | ||
| 311 | -lgen. impact: can't compile under ESIX. fix: put -lgen into | ||
| 312 | LIBS for unix_sv. tnx RN. | ||
| 313 | 19961221 qmail 0.95, gamma. | ||
| 314 | 19961218 change: added various try* to TARGETS. tnx SA. | ||
| 315 | 19961216 change: clarified in qmail-send.8 that virtualdomains does not | ||
| 316 | apply to domains listed in locals. | ||
| 317 | 19961216 change: slurpclose() now closes fd on out-of-memory. makes it | ||
| 318 | more widely applicable. | ||
| 319 | 19961215 change: replaced elm instructions in INSTALL.mbox with an | ||
| 320 | explanation of what source change to make. tnx AB. | ||
| 321 | 19961212 portability problem: under NEWS-OS, time_t needs sys/types.h. | ||
| 322 | impact: couldn't compile under NEWS-OS. fix: include | ||
| 323 | sys/types.h in predate.c. tnx TU. | ||
| 324 | 19961211 change: used timeoutread, timeoutwrite in remoteinfo(). tnx | ||
| 325 | REB. | ||
| 326 | 19961210 portability problem: apparently some SGIs produce a systype of | ||
| 327 | irix64. impact: couldn't compile on those systems. fix: handle | ||
| 328 | irix64 in make-cmds. tnx M3S. | ||
| 329 | 19961208 change: added note to maildir2mbox.1 about mbox locking. | ||
| 330 | 19961208 qmail 0.94, gamma. | ||
| 331 | 19961207 change: added QMAILDEFAULTDOMAIN, QMAILDEFAULTHOST, | ||
| 332 | QMAILIDHOST, QMAILPLUSDOMAIN. tnx BTW. | ||
| 333 | 19961206 cleanup: readsubdir() protects itself against name overflow, | ||
| 334 | rather than depending on caller. | ||
| 335 | 19961204 change: changed FAQ 7.3 to prohibit fixup relaying. | ||
| 336 | 19961203 change: added note to FAQ about possibly having to put a space | ||
| 337 | before "$SENDER" for uux. tnx FW. | ||
| 338 | 19961202 change: added FAQ entry on QUEUE_EXTRA. | ||
| 339 | 19961202 change: added FAQ entry on backups. tnx DP. | ||
| 340 | 19961202 change: added note to INSTALL.mbox about qpopper. tnx VV. | ||
| 341 | 19961201 change: replaced logger with splogger in FAQ 5.1. tnx FPL. | ||
| 342 | 19961201 change: used netmask example for tcpcontrol in FAQ. tnx FPL. | ||
| 343 | 19961201 change: added note to README about the mailing list. tnx FPL. | ||
| 344 | 19961201 change: documented rcpthosts wildcards. tnx RN. | ||
| 345 | 19961201 change: added note to FAQ about making mailx use datemail. | ||
| 346 | 19961201 change: added datemail. function requested by several people; | ||
| 347 | approach suggested by TG. | ||
| 348 | 19961201 change: added predate. | ||
| 349 | 19961129 change: added QUEUE_EXTRA, QUEUE_EXTRALEN. | ||
| 350 | 19961129 change: qmail-remote bounces messages with partial final lines. | ||
| 351 | 19961129 change: added atomcheck() to quote crappy atoms. | ||
| 352 | 19961129 change: revised atomok() to let atoms deal with more crap. | ||
| 353 | 19961127 change: qmail-send adds note to deferral if flagdying. tnx TG. | ||
| 354 | 19961127 change: split off maildirbounce, maildir2qmtp, and maildir2smtp | ||
| 355 | into a separate serialmail package. | ||
| 356 | 19961126 change: eliminated beta success reports from README. | ||
| 357 | 19961124 change: forced res_query() return value to fit inside incoming | ||
| 358 | buffer size. allegedly there are buggy versions of res_query() | ||
| 359 | that don't guarantee this. | ||
| 360 | 19961122 qmail 0.93, gamma. | ||
| 361 | 19961122 change: allowed empty arg list in forward. | ||
| 362 | 19961121 change: qmail-smtpd now uses unknown (like qmail-qmtpd) rather | ||
| 363 | than dying if environment variables are not set. | ||
| 364 | 19961121 cleanup: reorganized helo handling in qmail-smtpd.c. | ||
| 365 | 19961121 cleanup: eliminated newfield_rec. | ||
| 366 | 19961121 cleanup: introduced DATE822FMT. used it in received.c. | ||
| 367 | 19961121 cleanup: introduced received.c. used it in qmail-qmtpd.c, | ||
| 368 | qmail-smtpd.c. | ||
| 369 | 19961121 change: qmail-smtpd now generates a new timestamp for each | ||
| 370 | message. tnx PJG. | ||
| 371 | 19961121 cleanup: used stralloc in newfield. | ||
| 372 | 19961121 cleanup: eliminated newfield_cc. | ||
| 373 | 19961121 change: eliminated hfield_mort(). | ||
| 374 | 19961119 change: added 2-minute damper on tcpto. | ||
| 375 | 19961118 change: wrote defaults for readfile controls in showctl. | ||
| 376 | 19961117 change: control_readfile() now allows comments and blank lines. | ||
| 377 | tnx LW. | ||
| 378 | 19961117 change: qmail-start sets logger gid to GID_NOFILES. | ||
| 379 | 19961117 bug: ipme_init() uses a fixed-length buffer for SIOCGIFCONF. | ||
| 380 | impact: qmail-smtpd and qmail-remote will die if there are too | ||
| 381 | many local IP addresses. tnx MD. fix: ipme_init() now | ||
| 382 | dynamically allocates space, up to 200000 bytes, as long as | ||
| 383 | SIOCGIFCONF keeps failing. note that this is a very widespread | ||
| 384 | bug; it's in amd, exim, mrouted, named, nntpd, rarpd, sendmail, | ||
| 385 | tcpdump, timed, xntpd, and probably dozens more programs. | ||
| 386 | 19961117 portability problem: on BSD 4.4 and various other systems, | ||
| 387 | SIOCGIFCONF will truncate long lists and return success. | ||
| 388 | impact: on those systems, qmail-smtpd and qmail-remote will | ||
| 389 | miss some local IP addresses if there are too many. fix: | ||
| 390 | ipme_init() now checks whether there is enough space left in | ||
| 391 | the buffer for another ifreq, plus 64 bytes JIC. yuck. | ||
| 392 | 19961117 change: ipmeprint now flushes only at end. | ||
| 393 | 19961117 cleanup: introduced subfdinsmall. used it in qmail-clean.c, | ||
| 394 | qmail-qmtpd.c. | ||
| 395 | 19961117 cleanup: introduced subfdoutsmall. used it in hostname.c, | ||
| 396 | printbreak.c, printnumd.c, printsplit.c, qmail-alias.c, | ||
| 397 | qmail-clean.c, qmail-getpw.c, qmail-qmtpd.c, maildir2smtp.c, | ||
| 398 | maildir2qmtp.c. | ||
| 399 | 19961117 change: moved subfderr buf up to 256 characters. | ||
| 400 | 19961117 change: added maildirbounce. tnx MD, TG. | ||
| 401 | 19961116 change: maildir2smtp and maildir2qmtp now print filenames for | ||
| 402 | permanent bounces. tnx MD. | ||
| 403 | 19961116 change: in SECURITY, ``eleven most recent sendmail security | ||
| 404 | holes, five'' -> ``twelve most recent sendmail security holes, | ||
| 405 | six.'' | ||
| 406 | 19961116 change: rewrote qmail-showctl more professionally. | ||
| 407 | 19961115 change: added several tests to find-systype.sh. this will | ||
| 408 | affect many systypes. | ||
| 409 | 19961115 change: qmail-alias now treats most exit codes as soft errors. | ||
| 410 | 19961115 change: revamped exit codes everywhere for 0, 100, 111. | ||
| 411 | 19961114 change: added splogger. | ||
| 412 | 19961114 portability problem: Sun's cc recognizes sqrt() as a builtin, | ||
| 413 | even if math.h is not included and sqrt is defined statically. | ||
| 414 | yuck. impact: when qmail is compiled with Sun's cc, next-retry | ||
| 415 | times are all screwed up. tnx PJG. fix: my sqrt() is now called | ||
| 416 | squareroot(). | ||
| 417 | 19961114 change: dns_ip() now recognizes [1.2.3.4]. tnx DS. | ||
| 418 | 19961112 change: enabled x option in sendmail. tnx DS. | ||
| 419 | 19961111 change: added SIGHUP handling to qmail-send. suggested by many | ||
| 420 | people. | ||
| 421 | 19961111 bug: control routines returned incorrect codes for some | ||
| 422 | out-of-memory conditions. impact: none; conditions cannot | ||
| 423 | happen with sane control files. fix: return -1. | ||
| 424 | 19961111 change: added SIGALRM handling to qmail-send. suggested by many | ||
| 425 | people. | ||
| 426 | 19961111 change: eliminated flagnobreak (-b/-B) from qmail-pw2u. | ||
| 427 | 19961111 change: qmail-getpw now allows hyphens inside usernames. | ||
| 428 | 19961111 change: added users/append to qmail-pw2u. tnx G2A. | ||
| 429 | 19961111 change: added badmailfrom to qmail-smtpd. requested by several | ||
| 430 | people. | ||
| 431 | 19961110 change: replaced elm instructions in INSTALL.mbox with a simple | ||
| 432 | note to set incomingfolders in elm.rc. tnx AB. | ||
| 433 | 19961110 change: replaced ``owner hack'' with ``variable envelope | ||
| 434 | return paths'' throughout the documentation. tnx DS. | ||
| 435 | 19961110 change: qmail-setup installs man pages as well as cat pages. | ||
| 436 | 19961110 change: renamed qmail-newuser as qmail-newu. tnx G2A. | ||
| 437 | 19961110 change: renamed qmail-pw2user as qmail-pw2u. tnx G2A. | ||
| 438 | 19961105 change: set path in INSTALL.boot. tnx TJH. | ||
| 439 | 19961105 change: noted in qmail-smtpd.8 that addresses without @ are | ||
| 440 | always allowed through. | ||
| 441 | 19961105 change: indicated at various spots in FAQ that rcpthosts has to | ||
| 442 | be updated. suggested by various people. | ||
| 443 | 19961105 change: indicated at various spots in FAQ that qmail has to be | ||
| 444 | restarted. suggested by various people. | ||
| 445 | 19961029 change: fixed typo in maildir2qmtp.1. tnx BG. | ||
| 446 | 19961026 qmail 0.92, gamma. | ||
| 447 | 19961026 bug: qmail-getpw did not 0-terminate usernames. tnx CF. impact: | ||
| 448 | qmail-getpw would crash on some systems, deferring local | ||
| 449 | deliveries. fix: 0-terminate. | ||
| 450 | 19961025 cleanup: renamed auto-hassgprm.h to hassgprm.h. | ||
| 451 | 19961025 cleanup: renamed auto-hassgact.h to hassgact.h. | ||
| 452 | 19961024 change: replaced qmail-alias.0 with dot-qmail.0 in | ||
| 453 | INSTALL.alias. tnx MW. | ||
| 454 | 19961022 change: switched uids as early as possible in qmail-start.c. | ||
| 455 | 19961022 change: in SECURITY, ``ten most recent sendmail security | ||
| 456 | holes, five'' -> ``eleven most recent sendmail security holes, | ||
| 457 | five.'' | ||
| 458 | 19961022 change: quote_need() now treats non-ASCII characters the same | ||
| 459 | way as control characters. | ||
| 460 | 19961022 change: added version and home page to qmail.7. | ||
| 461 | 19961022 cleanup: introduced slurpclose.c. used it in qmail-alias.c, | ||
| 462 | qmail-lspawn.c. | ||
| 463 | 19961021 portability problem: AT&T NCR boxes need stdio.h before | ||
| 464 | arpa/nameser.h. impact: dns.c would not compile. fix: include | ||
| 465 | stdio.h. tnx HS. | ||
| 466 | 19961021 change: added AIX section to INSTALL.ids. tnx SSB. | ||
| 467 | 19961021 change: added qmail-pw2user. | ||
| 468 | 19961020 change: added qmail-pw2user.8. | ||
| 469 | 19961020 change: qmail-alias now dies soft on EACCES/EPERM for .qmail. | ||
| 470 | 19961020 change: eliminated root comments from INSTALL.qsmhook. | ||
| 471 | 19961020 change: various improvements in FAQ. | ||
| 472 | 19961017 change: added QLX_ROOT. | ||
| 473 | 19961017 change: renamed hosts in FAQ. tnx SLB. | ||
| 474 | 19961017 change: in dot-qmail.5, documented envnoathost effects. tnx RN. | ||
| 475 | 19961017 change: revamped addresses.5. | ||
| 476 | 19961017 change: added stripvdomprepend() for better bounces. tnx PT. | ||
| 477 | 19961012 portability problem: under HP-UX 9, can't setgroups() to 65537. | ||
| 478 | impact: couldn't compile under HP-UX 9. fix: use 0 instead of | ||
| 479 | 65537 in chkshsgr.c. tnx HHO. | ||
| 480 | 19961008 change: added several qlx codes. | ||
| 481 | 19961008 cleanup: eliminated qlx from qmail-alias. | ||
| 482 | 19961008 change: qmail-lspawn runs qmail-getpw as UID_PW. | ||
| 483 | 19961008 change: added qmail-newuser. | ||
| 484 | 19961008 change: added cdb support to qmail-lspawn. | ||
| 485 | 19961008 change: integrated cdb. | ||
| 486 | 19961007 change: added qmail-users.5. | ||
| 487 | 19961007 change: eliminated usermap. | ||
| 488 | 19961007 cleanup: switched execvp to execv in sendmail, qmail-lspawn. | ||
| 489 | 19961007 change: used qmail-getpw in qmail-lspawn. | ||
| 490 | 19961007 change: renamed LSPAWN_USERLEN as GETPW_USERLEN. | ||
| 491 | 19961007 change: added qmail-getpw. | ||
| 492 | 19961007 change: created users subdirectory of CONF_HOME. | ||
| 493 | 19961007 change: fixed typo in FAQ. tnx J1B. | ||
| 494 | 19961006 change: replaced subfdout with a small ss in qmail-alias. | ||
| 495 | 19961006 change: reduced qmail-alias buffer sizes to 1024. | ||
| 496 | 19961003 change: added note to maildir2smtp.0 about maildirmake. tnx SM. | ||
| 497 | 19961003 bug: if ipme_init() returned -1, qmail-remote would continue, | ||
| 498 | blindly assuming that all addresses are local. impact: on | ||
| 499 | systems with too many aliases, all remote deliveries fail. tnx | ||
| 500 | MD. fix: qmail-remote now dies with temp_oserr() on any result | ||
| 501 | other than 1. | ||
| 502 | 19961003 portability problem: all pre-4.9.4 versions of bind barf, | ||
| 503 | badly, on CNAME queries to lame servers. what a crappy system. | ||
| 504 | even if the resolver doesn't barf, the next name server down | ||
| 505 | the line may barf. impact: qmail can't get mail through to | ||
| 506 | domains that are (1) lame and (2) running old versions of bind. | ||
| 507 | fix: never, ever, do a CNAME query. dns_cname() now does an ANY | ||
| 508 | query instead. this, like sendmail's analogous procedure, is | ||
| 509 | unreliable when a CNAME is mixed with other records. | ||
| 510 | 19961001 cleanup: switched to libfd in qmail-start.c. | ||
| 511 | 19960929 cleanup: renamed auto-hasmkffo.h to hasmkffo.h. | ||
| 512 | 19960928 cleanup: reorganized qmail-start.c. | ||
| 513 | 19960928 cleanup: used libfd in preline.c, qmail-lspawn.c, | ||
| 514 | qmail-popup.c, qmail-rspawn.c, qmail-start.c, qqtalk.c, | ||
| 515 | qsmhook.c. | ||
| 516 | 19960928 cleanup: added libfd. | ||
| 517 | 19960927 change: in SECURITY, ``nine most recent sendmail security | ||
| 518 | holes, four'' -> ``ten most recent sendmail security holes, | ||
| 519 | five.'' | ||
| 520 | 19960926 change: added tcpcontrol notes to FAQ. | ||
| 521 | 19960926 change: qmail-smtpd now immediately closes connection, with a | ||
| 522 | warning message dedicated to Solaris, if stray newlines show up | ||
| 523 | in the incoming data. | ||
| 524 | 19960926 change: added INSTALL.boot. | ||
| 525 | 19960926 portability problem: on systems that can handle IP interface | ||
| 526 | aliases (i.e., on sa_len systems), SIOCGIFADDR returns the | ||
| 527 | primary address for an alias. impact: ipme_init() did not | ||
| 528 | include alias addresses. fix: ipme_init() avoids SIOCGIFADDR on | ||
| 529 | sa_len systems; on these systems, the address we want is | ||
| 530 | already in ifr. tnx DM. | ||
| 531 | 19960926 change: qmail-alias kills itself if locking takes longer than | ||
| 532 | 30 seconds. | ||
| 533 | 19960926 change: qmail-pop3d no longer moves messages. tnx RS. | ||
| 534 | 19960924 change: added note to FAQ about descriptors limit. tnx RD. | ||
| 535 | 19960922 change: open_trunc() now uses 644. | ||
| 536 | 19960922 change: qmail-setup now does umask(077). | ||
| 537 | 19960922 change: maildir2mbox now does umask(077). | ||
| 538 | 19960922 change: moved subfderr buf up to 64 characters. | ||
| 539 | 19960920 change: in SECURITY, ``eight most recent sendmail security | ||
| 540 | holes, three'' -> ``nine most recent sendmail security holes, | ||
| 541 | four.'' | ||
| 542 | 19960920 portability problem: init run commands are subject to job | ||
| 543 | control signals under more systems than HP-UX. impact: on some | ||
| 544 | systems (e.g., Solaris), qmail daemons would be killed. fix: | ||
| 545 | INSTALL now tells everybody to use csh -cf. | ||
| 546 | 19960920 change: added queue-run section to FAQ. | ||
| 547 | 19960920 change: in pine-crashing question in FAQ, added -oem and -oi, | ||
| 548 | so that change will work with the real sendmail too. | ||
| 549 | 19960919 change: added CNAME section to FAQ. tnx to various people. | ||
| 550 | 19960919 change: eliminated QQX_EXECHARD and QQT_EXECHARD. this means | ||
| 551 | that all qmail-queue invocation failures are now soft, even | ||
| 552 | things like EPERM. | ||
| 553 | 19960919 change: replaced ``No such address'' with ``Sorry, no mailbox | ||
| 554 | here by that name.'' tnx G2A. | ||
| 555 | 19960919 change: qmail-remote now includes host name in no-such-host | ||
| 556 | messages. tnx G2A. | ||
| 557 | 19960919 change: replaced ``Temporarily unable to canonicalize address'' | ||
| 558 | with ``CNAME lookup failed temporarily.'' | ||
| 559 | 19960918 change: improved an error message in qmail-alias.c. tnx TG. | ||
| 560 | 19960918 change: added SHELL=/bin/sh to Makefile. tnx JL. | ||
| 561 | 19960916 change: reorganized INSTALL.ids a bit. | ||
| 562 | 19960916 change: ``from smtpd'' is now ``from network''. | ||
| 563 | 19960916 change: SMTPD is now DAEMON. | ||
| 564 | 19960916 change: qmail-start sets logger uid to UID_LOG. tnx JLH. | ||
| 565 | 19960916 change: added CONF_USERL. | ||
| 566 | 19960916 change: iaafmt() now puts a dot on in-addr.arpa. | ||
| 567 | 19960915 change: added UPGRADE. suggested by several people. | ||
| 568 | 19960915 change: added qsutil error messages to qmail-log.5. | ||
| 569 | 19960915 change: qsutil error messages are now alerts. | ||
| 570 | 19960915 portability problem: on some systems, logger appears to use | ||
| 571 | syslog(pri,buf) instead of syslog(pri,"%s",buf). tnx JC. | ||
| 572 | impact: logger could barf or crash if fed messages containing | ||
| 573 | %. an attacker could easily cause a crash, eliminating qmail's | ||
| 574 | logs. fix: % is no longer considered safe for logs. | ||
| 575 | 19960912 cleanup: split seek.c into seek_*.c. | ||
| 576 | 19960912 cleanup: replaced seek_to() with seek_set(). | ||
| 577 | 19960912 cleanup: introduced libseek.a. | ||
| 578 | 19960907 cleanup: split case.c into case_*.c. | ||
| 579 | 19960907 cleanup: introduced libcase.a. | ||
| 580 | 19960907 cleanup: split wait.c into wait_*.c. | ||
| 581 | 19960907 cleanup: introduced libwait.a. | ||
| 582 | 19960907 cleanup: renamed auto-haswaitp.h to haswaitp.h. | ||
| 583 | 19960907 cleanup: split open.c into open_*.c. | ||
| 584 | 19960907 cleanup: introduced libopen.a. | ||
| 585 | 19960904 change: added generic pointer to qmail-control.5. tnx HW. | ||
| 586 | 19960904 change: rewrote rcpthosts section in FAQ. tnx HW. | ||
| 587 | 19960904 change: added organization section to FAQ. tnx HW. | ||
| 588 | 19960902 qmail 0.91, gamma. | ||
| 589 | 19960902 change: control_readfile() can now handle partial lines. tnx | ||
| 590 | JDHB. | ||
| 591 | 19960902 change: eliminated non-fqdn note from FAQ. next version of | ||
| 592 | tcpserver will use DNS directly. | ||
| 593 | 19960902 change: qlist now uses NEWSENDER, not SENDER. | ||
| 594 | 19960902 change: qmail-pop3d no longer obtains a lock. tnx RS. | ||
| 595 | 19960902 change: put }g on all seds in Makefile. | ||
| 596 | 19960831 change: noted in qmail-control.5 that comments are not allowed | ||
| 597 | in control files. tnx J2B. | ||
| 598 | 19960829 change: used double union in alloc.c. tnx ME. | ||
| 599 | 19960829 change: replaced semicolon with colon for smtproutes port. | ||
| 600 | 19960829 change: in INSTALL, put make man just before make setup. | ||
| 601 | 19960829 change: changed a few qmail messages into alerts. | ||
| 602 | 19960829 cleanup: renamed datetime_gmt as datetime_tai. | ||
| 603 | 19960829 change: added note to UUCP question that some UUCP software | ||
| 604 | doesn't want preline -f. tnx SB. | ||
| 605 | 19960829 change: added question 2.4 to FAQ on SLIP/PPP. | ||
| 606 | 19960828 change: replaced owner- with owner-@host-@[] in qmail-inject. | ||
| 607 | 19690828 change: replaced owner- with owner-@host-@[] in qmail-alias. | ||
| 608 | 19960828 change: replaced owner- with owner-@host-@[] in injectbounce(). | ||
| 609 | 19960828 change: replaced owner- with owner-@host-@[] in senderadd() for | ||
| 610 | owner hack. | ||
| 611 | 19960828 change: qmail-inject -n now prints Return-Path. | ||
| 612 | 19960825 cleanup: revised ending code in token_addrlist(). | ||
| 613 | 19960825 change: tokenize now uses linelen 0 for unparse. | ||
| 614 | 19960825 change: if linelen is 0 in token822_unparse, no length limit. | ||
| 615 | 19960825 change: added LINELEN macro to qmail-inject for unparse. | ||
| 616 | 19960825 change: token822_unparse now takes linelen argument. (leaving | ||
| 617 | two spaces on the right before linelen.) | ||
| 618 | 19960824 cleanup: renamed token as token822. | ||
| 619 | 19960822 portability problem: under NEWS-OS, /bin/mail and /usr/ucb/mail | ||
| 620 | invoke sendmail with -E and -J options. tnx TU. impact: | ||
| 621 | couldn't send mail with those programs. fix: accept opts, | ||
| 622 | including _optional_ args. ugh. | ||
| 623 | 19960821 change: sendmail now quits if invoked as newaliases. tnx TU. | ||
| 624 | 19960821 portability problem: under NEWS-OS, dirent.h needs sys/types.h. | ||
| 625 | tnx TU. this POSIX violation also appears in some versions of | ||
| 626 | FreeBSD. impact: couldn't compile under NEWS-OS. fix: include | ||
| 627 | sys/types.h in direntry.h* and trydrent.c. [sigh] | ||
| 628 | 19960821 change: added concurrencyremote question to FAQ. | ||
| 629 | 19960821 change: added chkspawn. | ||
| 630 | 19960821 change: moved default SPAWN_NUMD up to 120. | ||
| 631 | 19960818 change: allowed ;port in smtproutes. tnx AL. | ||
| 632 | 19960818 change: introduced port in qmail-remote.c. | ||
| 633 | 19960818 change: qmail-queue records qp in Received lines. 2 lines of | ||
| 634 | code. tnx ME. | ||
| 635 | 19960818 change: in SECURITY, ``seven most recent sendmail security | ||
| 636 | holes'' -> ``eight most recent sendmail security holes.'' | ||
| 637 | 19960818 change: qmail-pop3d now appends an extra blank line to every | ||
| 638 | message, for compatibility with popper. some clients can't | ||
| 639 | deal with the right thing, unfortunately. tnx FPL. | ||
| 640 | 19960818 change: added qmail-tcpto. | ||
| 641 | 19960818 change: eliminated cc -posix for NeXTs. tnx SA. | ||
| 642 | 19960818 change: eliminated loadfifo. tnx SA. | ||
| 643 | 19960818 change: integrated auto-configured fifo.c code from SA. | ||
| 644 | 19960817 change: put SYSDEPS into a more reasonable order. | ||
| 645 | 19960813 change: indicated possibility of duplication when qmail-remote | ||
| 646 | gets a dead connection after DATA. tnx ME. | ||
| 647 | 19960813 change: documented qmail-inject environment variables. | ||
| 648 | 19960813 change: supported per-recipient owner hack in qmail-inject. | ||
| 649 | 19960813 change: supported per-message owner hack in qmail-inject. | ||
| 650 | 19960813 change: introduced hackedruser into qmail-inject. | ||
| 651 | 19960813 change: introduced QMAILRUSER, QMAILRHOST. | ||
| 652 | 19960812 change: added QMAILINJECT option to allow address-comment form. | ||
| 653 | 19960812 change: made name-address form the default in qmail-inject. | ||
| 654 | 19960812 change: added QMAILINJECT options f and m to delete From and | ||
| 655 | Message-ID on input. tnx LL. | ||
| 656 | 19960812 change: added QMAILINJECT environment variable. | ||
| 657 | 19960812 change: added QMAILHOST, QMAILUSER, QMAILNAME to override | ||
| 658 | MAILHOST, MAILUSER, MAILNAME. tnx MG. | ||
| 659 | 19960812 change: added qmail-showctl. | ||
| 660 | 19960812 portability problem: under Solaris 2.4 and possibly other | ||
| 661 | systems, the linker does not give generic alignment to an array | ||
| 662 | of 4096 chars. tnx JP. impact: some subset of the programs | ||
| 663 | would (reliably) die with a bus error; in the Solaris case, | ||
| 664 | maildir2mbox. fix: redefine space in alloc.c to be aligned. | ||
| 665 | 19960812 change: qmail-remote no longer does CNAME lookups if there's an | ||
| 666 | artificial SMTP route. tnx ME. | ||
| 667 | 19960812 change: added flagcname arg to addrmangle() in qmail-remote. | ||
| 668 | 19960812 cleanup: moved host/relayhost processing earlier in | ||
| 669 | qmail-remote. | ||
| 670 | 19960812 change: qmail-remote stops before DATA if no RCPTs were | ||
| 671 | successful. tnx JLH. | ||
| 672 | 19960812 change: rewrote rcpthosts explanation in FAQ. | ||
| 673 | 19960811 change: added qmail-log.5. | ||
| 674 | 19960811 change: introduced ALIAS_PATERNALISM. configurability requested | ||
| 675 | by several people. | ||
| 676 | 19960811 change: eliminated go-writability test for qmeox(). the alleged | ||
| 677 | value of paternalism is nonexistent if nobody even notices | ||
| 678 | you're doing it. | ||
| 679 | 19960811 change: in qbiff, changed no-/-allowed to no-/-at-beginning, | ||
| 680 | no-dots-allowed, must-be-nonempty. tnx MD. | ||
| 681 | 19960811 change: in mbox.5, discouraged mail readers from looking for | ||
| 682 | From_ lines only after blank lines. too much crap in the world. | ||
| 683 | 19960811 change: added subject line to qreceipt success notices. | ||
| 684 | 19960811 change: added subject line to qmail-send bounce messages. | ||
| 685 | 19960811 change: qmail-alias now expects dash arg. this finally gives | ||
| 686 | lspawn complete control over the local -> ~user/.qmail-ext map. | ||
| 687 | 19960811 change: qmail-lspawn passes dash arg to qmail-alias. | ||
| 688 | 19960811 change: reorganized qlist acknowledgment format. again. | ||
| 689 | 19960811 change: documented EXT, EXT2, EXT3, EXT4. tnx BB. | ||
| 690 | 19960810 change: qmail-makectl now copies locals to rcpthosts. should be | ||
| 691 | a better default. suggested by TK. | ||
| 692 | 19960805 portability problem: new makefile generator put in tabs again. | ||
| 693 | sigh. impact: couldn't compile under some systems. fix: same as | ||
| 694 | before. tnx TG. | ||
| 695 | 19960804 change: added tcpserver instructions to FAQ. | ||
| 696 | 19960804 change: reorganized FAQ server instructions into a new section. | ||
| 697 | 19960801 qmail 0.90, gamma. | ||
| 698 | 19960801 change: qmail-qmtpd now supports rcpthosts, RELAYCLIENT. | ||
| 699 | 19960731 change: default NUMD is now 29. this prepares for weird systems | ||
| 700 | where getpwnam() needs more than one descriptor (but the | ||
| 701 | descriptor limit is still 64! ... you never know), and for | ||
| 702 | possible future getpwnam() replacements. | ||
| 703 | 19960731 change: popped subfderr buffer up to 32 characters. made sure | ||
| 704 | that everybody flushed subfderr as necessary. | ||
| 705 | 19960731 change: maildir2qmtp now prints filenames and responses. | ||
| 706 | 19960731 change: maildir2smtp now prints filenames it's trying and | ||
| 707 | relevant portion of SMTP responses. | ||
| 708 | 19960731 change: used succwrite() in maildir2smtp, maildir2qmtp. | ||
| 709 | simplifies code quite a bit. | ||
| 710 | 19960731 change: qmail-remote's blast() checks sooner for write errors. | ||
| 711 | 19960731 change: added better -e option to sendmail. tnx TG. | ||
| 712 | 19960731 change: added maildir2qmtp. | ||
| 713 | 19960730 cleanup: eliminated die_nomem() in maildir2smtp.c. | ||
| 714 | 19960730 change: dns_cname now pretends that "foo." is a CNAME for "foo" | ||
| 715 | to give the desired behavior for people who misuse DNS and | ||
| 716 | violate RFC 822. tnx RN. | ||
| 717 | 19960730 change: dns_cname now tests for empty names and ] on every | ||
| 718 | loop. | ||
| 719 | 19960730 change: used LSPAWN_BREAK in qmail-send.c for usermap. | ||
| 720 | 19960730 change: updated header example in qmail-header.5. | ||
| 721 | 19960730 change: added printbreak. auto-configured BREAK in dot-qmail.5, | ||
| 722 | qmail-lspawn.7, qmail-send.8, qmail-upgrade.7, qlist2. | ||
| 723 | 19960730 change: added printnumd. auto-configured NUMD in qmail-send.8, | ||
| 724 | qmail-limits.8. | ||
| 725 | 19960730 change: added printsplit. auto-configured split in qmail-upq. | ||
| 726 | 19960730 change: added dot-qmail.5. | ||
| 727 | 19960730 change: qmail-smtpd now treats HELO as including RSET. | ||
| 728 | 19960730 change: added moreinfo to qlist usage message. | ||
| 729 | 19960729 change: improved an error message in qmail-alias. | ||
| 730 | 19960729 cleanup: merged qmeox(), qmeodx(). | ||
| 731 | 19960729 bug: failure to stat .qmail-owner was not an error. impact: if | ||
| 732 | stat failed temporarily (e.g., because of NFS), .qmail-owner | ||
| 733 | would be incorrectly ignored, so outgoing message would have | ||
| 734 | wrong envelope sender. fix: qmail-alias does temp_nfsqmail() if | ||
| 735 | stat() returns a temporary error. | ||
| 736 | 19960729 change: added RFCOWNER. | ||
| 737 | 19960729 change: added qmtpd setup question to FAQ. | ||
| 738 | 19960729 change: added qmail-qmtpd. | ||
| 739 | 19960728 change: revamped maildir2smtp error messages. | ||
| 740 | 19960728 change: revamped maildirwatch error messages. | ||
| 741 | 19960728 change: revamped maildir2mbox error messages. | ||
| 742 | 19960728 change: used strerr in maildir_scan(). | ||
| 743 | 19960728 change: used strerr in maildir_chdir(). | ||
| 744 | 19960728 change: introduced strerr. | ||
| 745 | 19960728 bug: the new tcp-env tried to read from an ndelay socket. | ||
| 746 | impact: TCPREMOTEINFO would always be empty. fix: unset ndelay | ||
| 747 | in remoteinfo.c. | ||
| 748 | 19960728 bug: if maildir2smtp saw a permanent failure after MAIL, it | ||
| 749 | failed to do RSET. impact: all further messages would be | ||
| 750 | rejected at the MAIL stage. fix: maildir2smtp now always does | ||
| 751 | RSET. tnx JW. | ||
| 752 | 19960728 cleanup: qmail-alias now applies lowercase and dot-to-colon | ||
| 753 | conversion directly to dashext, leaving everything else alone. | ||
| 754 | this works since all .qmail access is factored through dashext. | ||
| 755 | 19960727 portability problem: under NeXTStep, -posix is almost entirely | ||
| 756 | broken. impact: qmail daemons would dump core under NeXTStep. | ||
| 757 | fix: turn off -posix, except for loading qmail-setup, which | ||
| 758 | needs mkfifo(); NeXT, bless them, didn't put mkfifo() into the | ||
| 759 | C library where it belongs. this requires a new make command, | ||
| 760 | namely loadfifo. | ||
| 761 | 19960727 change: all characters 33-126 are now considered safe for logs. | ||
| 762 | tnx MD. | ||
| 763 | 19960727 cleanup: eliminated qp variable from mailforward(). | ||
| 764 | 19960727 cleanup: maildirwatch.c includes headerbody.h. | ||
| 765 | 19960727 cleanup: eliminated match from maildirwatch.c. | ||
| 766 | 19960727 cleanup: eliminated code variable from maildir2smtp.c:doit(). | ||
| 767 | 19960727 cleanup: maildir2smtp.c includes scan.h. | ||
| 768 | 19960727 cleanup: maildir.c includes str.h. | ||
| 769 | 19960727 cleanup: qmail-popup.c now includes exit.h. | ||
| 770 | 19960727 cleanup: qmail-pop3d.c now includes exit.h. | ||
| 771 | 19960727 cleanup: eliminated path from qmail-start.c. | ||
| 772 | 19960727 cleanup: eliminated birthplusnn from nextretry(). | ||
| 773 | 19960727 cleanup: eliminated r from timeoutconn(). | ||
| 774 | 19960727 cleanup: tcpto.c now includes byte.h. | ||
| 775 | 19960727 cleanup: spawn.c now declares initialize(). | ||
| 776 | 19960727 cleanup: qmail-lspawn.c now includes str.h, byte.h. | ||
| 777 | 19960727 cleanup: qmail-inject.c now includes quote.h. | ||
| 778 | 19960727 change: qmail-check now checks separately for group | ||
| 779 | readability and other readability. | ||
| 780 | 19960727 bug: maildir2smtp didn't check flagehlo in PIPELINING parsing. | ||
| 781 | impact: a server that said PIPELINING at any point, not just | ||
| 782 | EHLO, would receive pipelined data. fix: check flagehlo. | ||
| 783 | 19960727 bug: readsubdir was calling pause(). impact: if a subdirectory | ||
| 784 | was removed, qmail-send would hang. fix: use rs->pause(). | ||
| 785 | 19960727 change: used error_str in qmail-qread. | ||
| 786 | 19960727 change: qmail-qread now looks for local/remote open errors. | ||
| 787 | 19960727 cleanup: added warn() in qmail-qread.c. | ||
| 788 | 19960727 change: qmail-qread now exits 111 for temporary errors. | ||
| 789 | 19960727 change: used error_str in qmail-setup. | ||
| 790 | 19960727 change: introduced error_str. | ||
| 791 | 19960727 change: replaced qmail-check with make check in INSTALL. | ||
| 792 | 19960727 change: added check target to Makefile. | ||
| 793 | 19960727 change: replaced qmail-setup with make setup in INSTALL. | ||
| 794 | 19960727 change: indirected fake targets through do- targets. | ||
| 795 | 19960727 change: added setup target to Makefile. | ||
| 796 | 19960727 change: qmail-makectl now makes sure that defaultdomain has | ||
| 797 | at least one dot. e.g., enteract.com -> enteract.com, not com. | ||
| 798 | 19960726 bug: quote() failed to quote commas. impact: addresses | ||
| 799 | containing commas would not have been quoted correctly for | ||
| 800 | Return-Path or for SMTP MAIL FROM. fix: quote commas. | ||
| 801 | 19960726 change: sendmail now mentions qmail-qread, not qmail-mailq. | ||
| 802 | 19960726 change: qmail-alias now expects ext arg. this eliminates | ||
| 803 | LSPAWN_BREAK from qmail-alias and gives lspawn almost complete | ||
| 804 | control over the local -> ~user/.qmail-ext transformation. the | ||
| 805 | exception is that qmail-alias always uses ~user/.qmail, | ||
| 806 | ignoring ext, if local is the same as user. | ||
| 807 | 19960726 change: qmail-lspawn passes ext to qmail-alias. | ||
| 808 | 19960726 change: alloc() now uses up a 4K space before calling malloc(). | ||
| 809 | 19960726 change: ipalloc allocation base is now 10. 100 was silly. | ||
| 810 | 19960726 change: stralloc allocation base is now 30. | ||
| 811 | 19960726 change: injectbounce() now supports the owner hack. | ||
| 812 | 19960726 change: qmail-smtpd no longer requires HELO. tnx K1J. | ||
| 813 | 19960726 cleanup: replaced makereceived() with dohelo(). | ||
| 814 | 19960726 change: qmail-smtpd is back to 555 for syntax errors. | ||
| 815 | 19960725 change: qmail-alias now supports the owner hack. tnx to RN for | ||
| 816 | prodding me to look at this problem. | ||
| 817 | 19960725 change: senderadd() now supports the owner hack. | ||
| 818 | 19960725 cleanup: split off senderadd(). | ||
| 819 | 19960725 change: added pine-crashing note to FAQ. | ||
| 820 | 19960725 change: added procmail config.h note to INSTALL.mbox. | ||
| 821 | 19960725 change: added elm TMPDIR note to INSTALL.mbox. | ||
| 822 | 19960725 change: added pine.conf note to INSTALL.mbox. | ||
| 823 | 19960724 change: added fixup note to FAQ. | ||
| 824 | 19960724 change: qmail-inject now exits 111 for temporary errors. | ||
| 825 | 19960724 change: qmail-smtpd now appends RELAYCLIENT to incoming | ||
| 826 | recipient domain names. | ||
| 827 | 19960724 cleanup: moved relayclient out of qmail-smtpd's addrallowed() | ||
| 828 | into caller. | ||
| 829 | 19960724 change: added rcpthosts wildcards. | ||
| 830 | 19960724 change: added clean target to Makefile. | ||
| 831 | 19960723 change: added virtualdomains exceptions. | ||
| 832 | 19960722 change: added BLURB4. | ||
| 833 | 19960722 change: added BLURB3. | ||
| 834 | 19960722 change: eliminated smarthost and localnet. | ||
| 835 | 19960722 change: incorporated relaymap, contributed by LW. renamed it | ||
| 836 | as smtproutes. | ||
| 837 | 19960722 change: qmail-popup now supports APOP. suggested by BG, who | ||
| 838 | distributed similar changes. | ||
| 839 | 19960722 change: qmail-popup now sends APOP timestamp to checkpassword. | ||
| 840 | 19960722 cleanup: in qmail-popup, split off doanddie(). | ||
| 841 | 19960722 change: qmail-popup now prints APOP timestamp in banner. | ||
| 842 | 19960722 change: added hostname argument to qmail-popup. | ||
| 843 | 19960722 cleanup: in qmail-popup, split out() into out(), outflush(). | ||
| 844 | 19960722 cleanup: in qmail-popup, introduced pop3_greet(). | ||
| 845 | 19960721 portability problem: under Unisys SVR4, hostname is not in the | ||
| 846 | usual path. impact: qmail-makectl fails. fix: added hostname | ||
| 847 | command here, used it in qmail-makectl. | ||
| 848 | 19960721 portability problem: on some sysctl-based systems, apparently | ||
| 849 | gethostname() doesn't write anything if the output buffer is | ||
| 850 | too small. it should write a truncated name. impact: if anyone | ||
| 851 | has a hostname longer than 64 characters, maildirs could get up | ||
| 852 | to 64 characters of garbage, rather than a truncated hostname. | ||
| 853 | fix: qmail-alias now does *host = 0 before calling gethostname. | ||
| 854 | 19960721 change: updated FAQ examples from qsmhook to preline. | ||
| 855 | 19960721 change: added preline. | ||
| 856 | 19960721 change: qsmhook now uses signal_init, signal_uninit. | ||
| 857 | 19960721 change: qsmhook now checks specifically for empty args. | ||
| 858 | 19960721 change: documented mbox. | ||
| 859 | 19960721 change: added EXT, EXT2, EXT3, EXT4. | ||
| 860 | 19960721 change: added LAST response to qmail-pop3d, always returning | ||
| 861 | OK 0. tnx RN. | ||
| 862 | 19960721 change: added qmail home page to README. | ||
| 863 | 19960721 change: added HELP response to qmail-smtpd. tnx RN. | ||
| 864 | 19960720 change: expanded, vertically, the qmail-inject error message | ||
| 865 | for unparseable header fields. | ||
| 866 | 19960720 change: logo is now dolphin. tnx CEJ. | ||
| 867 | 19960719 qmail 0.76, beta. | ||
| 868 | 19960719 change: used LSPAWN_BREAK in qmail-alias for deciding how to | ||
| 869 | handle extensions. this should produce better behavior in the | ||
| 870 | (unsupported) case that LSPAWN_BREAK is not a hyphen. | ||
| 871 | 19960719 bug: qmail-smtpd didn't check for null arg on MAIL, RCPT. | ||
| 872 | impact: qmail-smtpd would deref 0 and crash. fix: qmail-smtpd | ||
| 873 | now gives syntax error on null arg. | ||
| 874 | 19960719 change: documented UFLINE in qmail-command.8. tnx TG. | ||
| 875 | 19960718 change: added maildir2smtp. | ||
| 876 | 19960718 cleanup: introduced maildir.c. used it in maildir2mbox.c, | ||
| 877 | maildirwatch.c. | ||
| 878 | 19960718 change: added maildirwatch. | ||
| 879 | 19960718 cleanup: maildir2mbox now sets up pq2 as it is deleting from | ||
| 880 | pq, rather than simultaneously with pq. | ||
| 881 | 19960718 change: added H_DELIVEREDTO. | ||
| 882 | 19960718 portability problem: Unisys requires -lsocket -lnsl. impact: | ||
| 883 | couldn't compile under Unisys. fix: added unix_sv section to | ||
| 884 | make-cmds.sh. tnx TVP. | ||
| 885 | 19960718 change: added unix_sv section in find-systype. tnx TVP. | ||
| 886 | 19960717 change: qmail-alias now appends newline if .qmail does not end | ||
| 887 | with a newline. tnx MC. | ||
| 888 | 19960717 change: qmail-alias now defers delivery for a blank line only | ||
| 889 | if it is the first line of the file. handles user behavior | ||
| 890 | described by MC of putting many newlines at end of file. | ||
| 891 | 19960717 bug: qmail-inject looked for dots in user part, not just host | ||
| 892 | part, when deciding whether to use defaultdomain. impact: the | ||
| 893 | address joe.bloggs@here didn't have defaultdomain added. fix: | ||
| 894 | qmail-inject now stops at the @. | ||
| 895 | 19960717 change: updated INSTALL.alias to mention qmsmac. | ||
| 896 | 19960717 change: syntax error code for SMTP is now 501. | ||
| 897 | 19960717 change: added -e option to sendmail. tnx TG. | ||
| 898 | 19960716 change: changed ~alias files to .qmail-local, not .qmaillocal. | ||
| 899 | suggested by many people. | ||
| 900 | 19960716 change: redid qmail-alias/qmail-lspawn interface. | ||
| 901 | 19960716 change: replaced EXTENSION, USEREXT with LOCAL. | ||
| 902 | 19960716 change: qmail-queue now removes intd, mess upon error, as long | ||
| 903 | as it doesn't time out. suggested by BB et al. | ||
| 904 | 19960716 change: added flagmademess, flagmadeintd to qmail-queue.c. | ||
| 905 | 19960716 cleanup: changed todofd to intdfd in qmail-queue.c. | ||
| 906 | 19960716 cleanup: added cleanup() to qmail-queue.c. | ||
| 907 | 19960716 change: added timeout to tcp-env.c, default 30 seconds. | ||
| 908 | 19960716 change: remoteinfo_get() now uses timeoutconn(). | ||
| 909 | 19960715 change: added procmail config.h note to FAQ. | ||
| 910 | 19960704 change: qmail-upgrade.7 now warns administrators that ~alias | ||
| 911 | generally doesn't apply to addresses starting with a user name. | ||
| 912 | 19960703 change: added echo \c note to FAQ. tnx PJG. | ||
| 913 | 19960702 change: qmail-smtpd now accepts HELO without an argument. | ||
| 914 | tnx K1J, J1B. | ||
| 915 | 19960627 change: qmail-lspawn.8 now mentions that qmail-lspawn doesn't | ||
| 916 | set up supplementary groups. tnx TG. | ||
| 917 | 19960625 portability problem: under Linux, read(,,0) doesn't do proper | ||
| 918 | error slippage. impact: timeoutconn() would always report | ||
| 919 | success; if a connection failed, qmail-remote would report a | ||
| 920 | greeting failure and skip all further MX records. tnx ME. fix: | ||
| 921 | timeoutconn() now uses getpeername() to check for success. | ||
| 922 | 19960625 change: qmail-smtpd now mentions disk full for QQT_WRITE. | ||
| 923 | 19960625 change: qmail-inject now mentions disk full for QQT_WRITE. | ||
| 924 | 19960622 change: if RELAYCLIENT is set, qmail-smtpd skips rcpthosts. | ||
| 925 | 19960609 change: updated INSTALL for current SMTP responses. | ||
| 926 | 19960607 change: clarified INSTALL.qsmhook examples. tnx S1R. | ||
| 927 | 19960607 change: added subject parsing to qlist.c. tnx RN. | ||
| 928 | 19960607 cleanup: used case_diffb in qlist.c. | ||
| 929 | 19960607 change: added extra log information to INSTALL examples. | ||
| 930 | 19960606 change: added -Pn to uucp line in FAQ. tnx DWS. | ||
| 931 | 19960605 portability problem: under Solaris, /usr/bin/groups incorrectly | ||
| 932 | reports your groups in /etc/group, rather than the results of | ||
| 933 | getgroups(). tnx MD, PJG. impact: test #19 in INSTALL fails. | ||
| 934 | fix: added special note to test #19 (sigh) about Solaris. | ||
| 935 | 19960605 change: improved maildir setup commands in INSTALL.mbox. | ||
| 936 | 19960605 change: on success, qmail-alias logs forwarding qp. 9 lines | ||
| 937 | extra code. | ||
| 938 | 19960605 change: qmail-send logs qp for bounce. 6 lines extra code. | ||
| 939 | 19960605 change: qmail-smtpd includes qp in its response when it accepts | ||
| 940 | a message. 7 lines extra code. requested by MD and others. | ||
| 941 | 19960605 change: added qqtalk_qp. | ||
| 942 | 19960605 change: qmail-send now logs uid and qp from todo file. 14 lines | ||
| 943 | extra code. | ||
| 944 | 19960605 change: qmail-queue now records uid and qp in u and p lines | ||
| 945 | in todo file. 7 lines extra code. | ||
| 946 | 19960605 change: improved qmail-alias x-bit error messages. | ||
| 947 | 19960605 change: newline in log is now converted to /, not underscore. | ||
| 948 | 19960604 change: when it accepts a message, qmail-smtpd includes the | ||
| 949 | local time in its 250 response. | ||
| 950 | 19960604 change: on success, qmail-alias prints delivery counts, | ||
| 951 | file+forward+program. | ||
| 952 | 19960603 change: qmail-remote now reports IP address on success. tnx MD. | ||
| 953 | 19960603 change: qmail-send now logs success and failure reports, not | ||
| 954 | just deferral reports. | ||
| 955 | 19960603 change: added netbsd section in find-systype, same as bsd.os | ||
| 956 | section. this will affect netbsd-* systypes. tnx MBS. | ||
| 957 | 19960530 qmail 0.75, beta. | ||
| 958 | 19960528 change: added qmail.7. tnx MD. | ||
| 959 | 19960525 change: added qmail-pop3d. tnx RN. | ||
| 960 | 19960525 change: added qmail-popup. tnx RN. | ||
| 961 | 19960525 change: added elm filter section to FAQ. tnx GB. | ||
| 962 | 19960502 portability problem: on many systems, select() on an | ||
| 963 | almost-full pipe incorrectly says writable. tnx ME for running | ||
| 964 | into this and helping track it down. impact: if qmail-send | ||
| 965 | writes a pipeful to qmail-lspawn or qmail-rspawn before they | ||
| 966 | can react (because of high concurrency, high load, or long | ||
| 967 | addresses), it will receive an incorrect -1/EAGAIN, and will | ||
| 968 | conclude that spawn died. sysadmin will have to restart qmail, | ||
| 969 | and messages will be duplicated. fix: in qmail-send.c, | ||
| 970 | busy-loop if write() to spawn returns any error other than | ||
| 971 | EPIPE. | ||
| 972 | 19960501 bug: qmail-alias treated NAMETOOLONG and NOTDIR as temporary | ||
| 973 | errors. impact: qmail-alias never looked for -default; even if | ||
| 974 | mail was destined to bounce, it would have to time out first. | ||
| 975 | fix: qmail-alias now uses error_temp(). | ||
| 976 | 19960430 bug: qmail-smtpd treated qq crash as permanent error. impact: | ||
| 977 | if somebody actively kills qq, mail will be incorrectly | ||
| 978 | bounced. tnx SS. fix: qmail-smtpd now treats only TOOLONG and | ||
| 979 | EXECHARD as permanent errors. | ||
| 980 | 19960430 cleanup: eliminated QQT_TTY from qqtalk.h. | ||
| 981 | 19960428 change: added ``warning: '' before trouble-marking message. | ||
| 982 | 19960428 change: added percenthack. requested by GB. | ||
| 983 | 19960428 cleanup: switched to auto-generated Makefile. | ||
| 984 | 19960428 cleanup: switched to auto-generated .o dependencies. | ||
| 985 | 19960428 cleanup: eliminated fmt.o, scan.o from Makefile. | ||
| 986 | 19960428 portability problem: under HP-UX 10, the rc pgrp is sent HUP | ||
| 987 | when rc finishes. tnx BG. impact: the qmail daemons are killed | ||
| 988 | when rc finishes. fix: added special note in INSTALL (sigh) to | ||
| 989 | use csh -cf. | ||
| 990 | 19960427 cleanup: added PORT_SMTP in qmail-remote.c. | ||
| 991 | 19960427 cleanup: introduced timeoutwrite.c. used it in qmail-remote.c. | ||
| 992 | 19960427 cleanup: introduced timeoutread.c. used it in qmail-remote.c. | ||
| 993 | 19960427 cleanup: introduced timeoutconn.c. used it in qmail-remote.c. | ||
| 994 | 19960427 change: added timeoutconnect. default: 60 seconds. | ||
| 995 | 19960427 change: added pop3d instructions to FAQ. tnx RN. | ||
| 996 | 19960427 change: eliminated env manipulation from qmail-start. tnx BG. | ||
| 997 | 19960427 change: headerbody now ends header, inserting blank line, if | ||
| 998 | first line of a header field doesn't pass hfield_valid. tnx TG. | ||
| 999 | 19960427 change: headerbody now prepends MBOX-Line: to any header line | ||
| 1000 | starting From_. this lets qmail-inject work with elm's bounce. | ||
| 1001 | tnx OR, K1J, et al. | ||
| 1002 | 19960426 change: added moreinfo arg to qlist and qlist2. | ||
| 1003 | 19960426 change: added signal_uncatchchild() to qmail-send.c. tnx BG. | ||
| 1004 | now, if sysadmin sets SIGCHLD to SIG_IGN before invoking | ||
| 1005 | qmail-send [sigh], qmail-send won't screw up bounce messages. | ||
| 1006 | 19960426 change: dns_cname now checks whether last character is ], | ||
| 1007 | rather than whether first character is [, for quick return. | ||
| 1008 | 19960426 cleanup: glue is now global in dns.c. | ||
| 1009 | 19960426 cleanup: qmail-remote no longer does stralloc_0 for host and | ||
| 1010 | canonhost. | ||
| 1011 | 19960426 change: dns_mxip no longer rejects [foo].bar. | ||
| 1012 | 19960426 change: dns_mxip no longer requires for bracket that input | ||
| 1013 | be 0-terminated. | ||
| 1014 | 19960426 change: qmail-start can now take logger as an argument. | ||
| 1015 | 19960426 change: qmail-start now invokes qmail-send in foreground (as | ||
| 1016 | parent of other processes). | ||
| 1017 | 19960426 change: added mailsubj. tnx GAW. | ||
| 1018 | 19960426 portability problem: under some systems, can't lock read-only | ||
| 1019 | file. impact: maildir2mbox would always fail on those systems. | ||
| 1020 | fix: maildir2mbox now opens a separate lock fd. tnx BG. | ||
| 1021 | 19960426 cleanup: removed unnecessary #!/bin/sh and # AUTO from mctl.sh. | ||
| 1022 | 19960426 change: added qmail-qstat. | ||
| 1023 | 19960426 change: added qmail-qread.8. | ||
| 1024 | 19960426 change: renamed qmail-mailq as qmail-qread. | ||
| 1025 | 19960419 change: qmail-alias now defers delivery rather than skipping | ||
| 1026 | blank lines in .qmail. | ||
| 1027 | 19960419 change: in qmail-lspawn.c, lowercased name before getpwnam(). | ||
| 1028 | really getpwnam() should do this, but oh well. | ||
| 1029 | 19960419 change: added username to qmail-lspawn.c, with LSPAWN_USERLEN | ||
| 1030 | in conf-unusual.h. names longer than LSPAWN_USERLEN will skip | ||
| 1031 | getpwnam(). | ||
| 1032 | 19960419 change: if qlist doesn't see any cmds, it presumes that you | ||
| 1033 | meant to subscribe. | ||
| 1034 | 19960419 change: reorganized qlist acknowledgment format. | ||
| 1035 | 19960415 change: reorganized and rewrote FAQ. | ||
| 1036 | 19960415 change: renamed HOWTO as FAQ. | ||
| 1037 | 19960414 change: in qmail-alias, converted extension to lowercase just | ||
| 1038 | before qmeopen(), qmeox() calls. thus EXTENSION and USEREXT and | ||
| 1039 | RECIPIENT will preserve case passed by qmail-lspawn, while | ||
| 1040 | .qmailext lookups will not. | ||
| 1041 | 19960414 change: removed case_lowers(r) from qmail-lspawn.c. tnx JLH. | ||
| 1042 | 19960414 change: moved extension . -> : conversion to just before | ||
| 1043 | qmeopen(), qmeox() calls in qmail-alias.c. thus EXTENSION and | ||
| 1044 | USEREXT and RECIPIENT will preserve dots. | ||
| 1045 | 19960414 change: qsmhook -x now does case-independent comparison. | ||
| 1046 | 19960413 change: added procmail instructions to HOWTO. | ||
| 1047 | 19960409 bug: qmail-alias does not check for newlines when it generates | ||
| 1048 | Return-Path. impact: resulting Return-Path header field will be | ||
| 1049 | illegal, if sender address contains newline followed by | ||
| 1050 | something other than whitespace. fix: qmail-alias now replaces | ||
| 1051 | newline with underscore in rpline. | ||
| 1052 | 19960409 change: added leaf UUCP description to HOWTO. tnx J2K. | ||
| 1053 | 19960409 change: added -B option to sendmail. tnx OR. | ||
| 1054 | 19960409 change: qlist now makes lists unwritable (after renaming from | ||
| 1055 | .qtemp to .qmail). tnx MLH. | ||
| 1056 | 19960409 change: added flagdtline to qsmhook.c, based on -l option. | ||
| 1057 | 19960409 change: added PIPELINING declaration to qmail-smtpd. tnx JGM. | ||
| 1058 | 19960409 change: qmail-smtpd now flushes output instantly after DATA, | ||
| 1059 | QUIT, HELO, EHLO, NOOP, VRFY, or any 502. | ||
| 1060 | 19960409 change: qmail-smtpd now flushes output upon read() and death. | ||
| 1061 | 19960409 change: qmail-smtpd no longer flushes output in out(). | ||
| 1062 | 19960409 change: increased qmail-smtpd outbuf size from 128 to 512. | ||
| 1063 | 19960409 cleanup: in qmail-smtpd, eliminated ssinit() in favor of FDBUF. | ||
| 1064 | 19960409 bug: qmail-alias produced aliasfoo-owner rather than foo-owner | ||
| 1065 | as envelope sender for ~alias/.qmailfoo. tnx DS. impact: wrong | ||
| 1066 | envelope sender whenever ~alias/.qmailfoo-owner existed. fix: | ||
| 1067 | qmail-alias now checks for hyphen at beginning of extension. | ||
| 1068 | 19960409 change: added _ESMTP to end of 220. tnx JLH. | ||
| 1069 | 19960409 change: moved out("\r\n") out of smtp_greet() into callers. | ||
| 1070 | this improves the flushing behavior on 221. | ||
| 1071 | 19960328 qmail 0.74, beta. | ||
| 1072 | 19960326 change: changed subdirectory split from 32 to 23. | ||
| 1073 | 19960326 portability problem: some versions of make don't understand | ||
| 1074 | that a line with just a tab is blank. impact: couldn't compile | ||
| 1075 | under those systems. fix: eliminated extra tab from Makefile. | ||
| 1076 | tnx TG. | ||
| 1077 | 19960325 change: added qmail-mailq. | ||
| 1078 | 19960325 change: introduced readsubdir. | ||
| 1079 | 19960325 change: qmail-setup makes split; qmail-check checks split. | ||
| 1080 | 19960325 change: used split in qmail-send, qmail-clean, qmail-queue | ||
| 1081 | for mess, info, local, remote. | ||
| 1082 | 19960325 change: fmtqfn now supports split queue subdirectories. | ||
| 1083 | 19960325 cleanup: eliminated cat2s(). | ||
| 1084 | 19960325 cleanup: introduced fmtqfn.c. used it in qmail-queue.c, | ||
| 1085 | qmail-send.c, qmail-clean.c. | ||
| 1086 | 19960325 change: in protocol between qmail-clean and qmail-send, now | ||
| 1087 | using intd/ instead of mess/. | ||
| 1088 | 19960325 change: qmail-queue.c and triggerpull.c now work inside queue | ||
| 1089 | subdirectory. | ||
| 1090 | 19960325 change: spawn.c now checks whether message is a regular file. | ||
| 1091 | 19960325 change: spawn.c now allows slashes in messid except at | ||
| 1092 | beginning. | ||
| 1093 | 19960325 cleanup: introduced fnmake_split in qmail-send.c. | ||
| 1094 | 19960325 cleanup: eliminated strnum in qmail-send.c in favor of | ||
| 1095 | fnmake_{info,todo,mess,chanaddr} and fnmake2_bounce. | ||
| 1096 | 19960325 cleanup: introduced strnum3 in qmail-send.c for the logging | ||
| 1097 | uses of strnum. | ||
| 1098 | 19960325 cleanup: in qmail-send.c, getinfo() now takes id argument. | ||
| 1099 | 19960325 cleanup: qmail-send.c now preallocates space for fn, fn2. | ||
| 1100 | 19960325 change: time zone is now -0000 instead of +0000. encouraging | ||
| 1101 | DRUMS to use this as an i-don't-know-the-local-time indicator. | ||
| 1102 | 19960324 change: qmail-rspawn.c now calls tcpto_clean(). | ||
| 1103 | 19960324 cleanup: spawn.c now calls initialize(). | ||
| 1104 | 19960324 change: qmail-setup makes lock/tcpto; qmail-check checks it. | ||
| 1105 | 19960324 change: qmail-remote now quickly skips connect() to a host that | ||
| 1106 | seems to be down. tnx BP for pressuring me to get this done. | ||
| 1107 | 19960323 change: in qmail-alias.8, renamed mboxg as mboxrd. tnx RD. | ||
| 1108 | idea was popularized by RD in June 1995. | ||
| 1109 | 19960322 cleanup: eliminated subfd_init(). | ||
| 1110 | 19960322 change: qbiff now removes the word Subject. | ||
| 1111 | 19960322 change: now /bin/true instead of /dev/null in the generic | ||
| 1112 | INSTALL.ids instructions. tnx JPR. | ||
| 1113 | 19960322 change: added hfield_skipname(). tnx RN. | ||
| 1114 | 19960322 bug: qmail-inject did not check whether USER needed quoting. | ||
| 1115 | impact: if USER had weird characters, the From address would | ||
| 1116 | generally be wrong, unless the user manually set up MAILUSER | ||
| 1117 | with proper quoting. fix: qmail-inject sets up a quoted-string | ||
| 1118 | if necessary. | ||
| 1119 | 19960322 cleanup: separated out quote_need() in quote.c. | ||
| 1120 | 19960322 cleanup: added stralloc_catb.c. used it in qmail-alias.c, | ||
| 1121 | qmail-send.c. | ||
| 1122 | 19960322 change: qmail-send now uses a quadratic retry schedule from | ||
| 1123 | birth of each message. this also eliminates clustering. | ||
| 1124 | 19960322 cleanup: separated out nextretry() in qmail-send.c. | ||
| 1125 | 19960322 change: qmail-remote now passes all non-@ addresses through | ||
| 1126 | without comment, not just <> and <#>. | ||
| 1127 | 19960322 change: replaced # test with anything@[] test in qmail-inject. | ||
| 1128 | 19960322 change: replaced # with #@[] in qlist.c, qmail-alias.c, | ||
| 1129 | qmail-send.c, qreceipt.c. | ||
| 1130 | 19960322 change: qmail-lspawn no longer discards messages to <#>. | ||
| 1131 | 19960322 cleanup: in qlist, used str_diff for <> and <#> tests. | ||
| 1132 | 19960322 change: qmail-alias is now back to testing envelope sender for | ||
| 1133 | <> and <#>, rather than things without an @. | ||
| 1134 | 19960321 change: added 8BITMIME support to qmail-smtpd. | ||
| 1135 | 19960321 change: added ESMTP support to qmail-smtpd. | ||
| 1136 | 19960318 change: used NEWSENDER in place of SENDER for |forward. | ||
| 1137 | 19960318 change: added NEWSENDER. | ||
| 1138 | 19960318 change: added HCMSSC support to qmail-alias.c. | ||
| 1139 | 19960318 change: added HCMSSC support to spawn.c. | ||
| 1140 | 19960318 change: added HCMSSC support to qmail-remote.c. | ||
| 1141 | 19960318 change: added HCMSSC support to qmail-smtpd.c. | ||
| 1142 | 19960317 portability problem: SCO requires -lsocket -lnsl. impact: | ||
| 1143 | couldn't compile under SCO. fix: added SCO section in | ||
| 1144 | make-cmds.sh. tnx JPR. note that this is for OSR 5; 3.2v4.2 | ||
| 1145 | will need more fixes, and old 3.2 is basically hopeless. | ||
| 1146 | 19960317 bug: newfield_datemake would leave newfield_date alone if it | ||
| 1147 | was already initialized, even though qmail-send calls | ||
| 1148 | newfield_datemake anew for each bounce. impact: bounce messages | ||
| 1149 | would usually have an incorrect Date field. fix: redid | ||
| 1150 | newfield_datemake to update newfield_date each time. | ||
| 1151 | 19960317 change: allowed . and @ in 822 phrases; 822 doesn't allow them, | ||
| 1152 | but they do show up. tnx to the DRUMS group. | ||
| 1153 | 19960317 change: replaced GMT with +0000 in date822fmt.c. this confuses | ||
| 1154 | a few versions of getdate(), but the DRUMS group is going to | ||
| 1155 | outlaw GMT, not just recommend against it as in 1123. | ||
| 1156 | 19960317 change: redefined ALIAS_EMPTY to take advantage of . for file | ||
| 1157 | deliveries. tnx RN. | ||
| 1158 | 19960317 change: qmail-alias now allows . as well as / to start file | ||
| 1159 | deliveries. tnx RN. | ||
| 1160 | 19960317 change: qmail-alias now dies (soft) if .qmail is writable to | ||
| 1161 | others, rather than silently ignoring it. | ||
| 1162 | 19960317 change: qmail-alias now dies (soft) if flagforwardonly is | ||
| 1163 | violated, rather than silently ignoring the bad instructions. | ||
| 1164 | 19960317 change: qmail-alias now ignores x bit on empty .qmail files. | ||
| 1165 | 19960317 bug: if RCPT gave 4xx and DATA gave 5xx, qmail-rspawn would | ||
| 1166 | incorrectly assign a permanent failure to that recipient. | ||
| 1167 | impact: in that case, mail would be incorrectly bounced. fix: | ||
| 1168 | remove orr > 0 test from qmail-rspawn.c. | ||
| 1169 | 19960310 change: tcp-env now uses signal_uninit(). [sigh] | ||
| 1170 | 19960310 change: tcp-env now specifically unsets HOST and INFO if they | ||
| 1171 | are not applicable. just trying to make it more widely usable. | ||
| 1172 | 19960310 cleanup: used byte_* in remoteinfo.c, ipme.c, tcp-env.c. | ||
| 1173 | 19960310 cleanup: added readwrite.h, eliminated sys.h. | ||
| 1174 | 19960310 cleanup: included byte.h in qmail-send.c. | ||
| 1175 | 19960310 cleanup: eliminated i and j from forward.c's main(). | ||
| 1176 | 19960310 cleanup: eliminated wstat from qlist.c. | ||
| 1177 | 19960310 cleanup: eliminated die_nomem() parameter in qmail-setup.c. | ||
| 1178 | 19960310 cleanup: eliminated i from qmail-remote's addrmangle(). | ||
| 1179 | 19960310 cleanup: added exit.h. | ||
| 1180 | 19960310 cleanup: split ipalloc.c off of ip.c. | ||
| 1181 | 19960310 cleanup: added fmt_strn.c, eliminated fmt_strncpy.c. | ||
| 1182 | 19960310 change: reorganized INSTALL to do some pre-upgrade tests. | ||
| 1183 | tnx RN. | ||
| 1184 | 19960310 change: reordered steps in upgrade procedure in INSTALL. | ||
| 1185 | 19960308 change: eliminated ownership test in qmail-alias.c. tnx DS. | ||
| 1186 | 19960304 change: in SECURITY, ``six most recent sendmail security | ||
| 1187 | holes'' -> ``seven most recent sendmail security holes.'' | ||
| 1188 | 19960303 qmail 0.73, beta. | ||
| 1189 | 19960303 change: added SYSDEPS. | ||
| 1190 | 19960303 cleanup: revamped select.h autoconfiguration. | ||
| 1191 | 19960303 cleanup: revamped fork.h autoconfiguration. | ||
| 1192 | 19960303 cleanup: revamped direntry.h autoconfiguration. target is now | ||
| 1193 | direntry.h; auto-hasdrent.h is gone. | ||
| 1194 | 19960303 change: tryflock.c now includes <sys/types.h>, for consistency | ||
| 1195 | with lock.c. may affect portability. | ||
| 1196 | 19960302 portability problem: under BSDI, can't set sticky on normal | ||
| 1197 | files. dorks. impact: the new qlist doesn't work under BSDI; | ||
| 1198 | be glad I test things before release. fix: qmail-alias and | ||
| 1199 | qlist now use executable instead of sticky. | ||
| 1200 | 19960302 change: gfrom now quotes >From and >>From etc. as well as From; | ||
| 1201 | in other words, I'm switching from mbox format to mboxg format. | ||
| 1202 | 19960302 cleanup: added gfrom.c. used it in qmail-alias.c, maildir2mbox.c. | ||
| 1203 | 19960302 change: addbounce() now substitutes \n\n -> \n/ in reports, | ||
| 1204 | and \n -> _ in recips. thus bounces can now be reliably parsed. | ||
| 1205 | 19960302 change: if qmail-send had trouble reading the original message | ||
| 1206 | or the list of addresses for a bounce, it used to give up and | ||
| 1207 | send a bounce with "Oh no! I had trouble reading the rest of | ||
| 1208 | your message" or some such. now it aborts the bounce attempt | ||
| 1209 | and tries again later. | ||
| 1210 | 19960302 cleanup: added qqtalk_fail(). used it in qmail-alias.c, | ||
| 1211 | qmail-smtpd.c. | ||
| 1212 | 19960302 bug: if mailforward() had trouble reading message (e.g., | ||
| 1213 | because of an I/O error), it marked an error but kept reading. | ||
| 1214 | impact: could loop forever. fix: upon error, break. | ||
| 1215 | 19960302 change: maildir2mbox now scans (restrictively) for return-path. | ||
| 1216 | 19960302 change: qbiff now prints subject and body, up to 74 chars. | ||
| 1217 | 19960302 change: added H_SUBJECT to hfield. | ||
| 1218 | 19960302 change: qbiff now puts TO before FROM. | ||
| 1219 | 19960301 cleanup: added fmt_str.c. used it in many places. | ||
| 1220 | 19960301 change: qmail-send now says something if you've told it to exit | ||
| 1221 | but it's waiting for some deliveries. tnx RN. | ||
| 1222 | 19960301 change: qmail-alias -n now continues (with warning) if home | ||
| 1223 | directory is sticky. tnx RN. | ||
| 1224 | 19960301 change: improved usage messages in qmail-alias.c. tnx RN. | ||
| 1225 | 19960301 change: put limit on length of addresses in qlist. | ||
| 1226 | 19960301 change: added exit 99 support to qmail-alias. tnx RN. | ||
| 1227 | 19960301 change: qmail-alias now exits immediately on temporary or | ||
| 1228 | permanent error. rewrote section in qmail-alias.8 accordingly. | ||
| 1229 | 19960301 cleanup: eliminated flagsuccesses from qmail-alias.c. | ||
| 1230 | 19960301 change: added usermap. | ||
| 1231 | 19960301 bug: failure to append to mbox was a permanent error. impact: | ||
| 1232 | if mbox was temporarily unopenable (e.g., because fds were | ||
| 1233 | low), mail would be incorrectly bounced. fix: failure is now | ||
| 1234 | temporary. tnx DS. | ||
| 1235 | 19960229 change: qmail-alias now preserves any envelope sender that | ||
| 1236 | doesn't contain an @, not just <> and <#>. | ||
| 1237 | 19960229 cleanup: revamped byte_* interface. | ||
| 1238 | 19960229 cleanup: renamed str_cpy as str_copy. | ||
| 1239 | 19960229 cleanup: added str_chr.c. used it in qbiff.c, qmail-smtpd.c. | ||
| 1240 | 19960229 cleanup: added str_rchr.c. used it in qmail-send.c, quote.c, | ||
| 1241 | qmail-remote.c. | ||
| 1242 | 19960229 cleanup: added byte_rchr.c. used it in qmail-smtpd.c, spawn.c. | ||
| 1243 | 19960229 cleanup: used USEREXT instead of RECIPIENT in qsmhook.c. | ||
| 1244 | 19960229 cleanup: used USEREXT instead of RECIPIENT in qbiff.c. | ||
| 1245 | 19960229 cleanup: removed j and k from rewrite() in qmail-send.c. | ||
| 1246 | 19960229 portability problem: under HP-UX 10 and Solaris 2.5, can't | ||
| 1247 | setgroups()/setgid() to the system's nogroup/nobody gid. dorks. | ||
| 1248 | impact: inetd chokes, so all SMTP connections are rejected; and | ||
| 1249 | ``alias'' mail, including postmaster, bounces. fix: in | ||
| 1250 | INSTALL.ids, set up a separate powerless gid (tentatively | ||
| 1251 | ``nofiles'') for qmaild and alias. tnx DS and PJG. | ||
| 1252 | 19960229 change: qreceipt now uses qqtalk rather than qmail-inject. | ||
| 1253 | 19960229 change: qlist now uses qqtalk rather than qmail-inject. | ||
| 1254 | 19960229 change: incorporated qmail-setup patch from RN for better | ||
| 1255 | error messages. | ||
| 1256 | 19960228 change: added LSPAWN_BREAK in conf-unusual.h; used it in | ||
| 1257 | lspawn.c. configurability requested by PJG. | ||
| 1258 | 19960228 portability problem: on several systems, including everything | ||
| 1259 | from DEC, select() on a pipe reader returns 1 if there aren't | ||
| 1260 | any writers yet. pointed out by DS. impact: qmail-send chewed | ||
| 1261 | up lots of CPU time. fix: trigger_set() now opens the pipe for | ||
| 1262 | writing after opening it for reading. also added trynpbg1; on | ||
| 1263 | working systems, no point in wasting the extra fd. | ||
| 1264 | 19960228 change: qmail-alias uses .qmail sticky bit for forwardonly. | ||
| 1265 | 19960228 change: qlist now sets sticky bit on .qmail file. | ||
| 1266 | 19960228 change: un-documented +list. | ||
| 1267 | 19960228 portability problem: on HP-UX and possibly other systems, the | ||
| 1268 | supplementary group list does not include the gid. pointed out | ||
| 1269 | by DS. impact: on those systems, tryshsgr could incorrectly set | ||
| 1270 | hasshsgr; this would prevent qmail-send from running. fix: if | ||
| 1271 | tryshsgr sees that getgroups() returns 0, now it actively sets | ||
| 1272 | up a supplementary group list. added chkshsgr to make sure the | ||
| 1273 | setgroups() will work. | ||
| 1274 | 19960227 cleanup: eliminated GETSHORT in dns.c in favor of getshort(). | ||
| 1275 | 19960227 cleanup: deleted h->len < 3 test from qlist.c:dobody. tnx RN. | ||
| 1276 | 19960227 change: replaced ~ with $HOME in INSTALL.mbox. | ||
| 1277 | 19960227 change: added note about setgid-mail bits to INSTALL.mbox. | ||
| 1278 | 19960227 change: added forward.1. | ||
| 1279 | 19960227 change: modified forward to allow multiple addresses. | ||
| 1280 | 19960227 change: modified forward to take an entire address, not just a | ||
| 1281 | hostname. | ||
| 1282 | 19960227 change: renamed qrelay as forward. | ||
| 1283 | 19960227 change: added USEREXT support to qmail-alias. | ||
| 1284 | 19960227 change: added -F to sendmail. the need for this was pointed | ||
| 1285 | out by RN. | ||
| 1286 | 19960227 change: added 2 bytes of slop in alloc(). | ||
| 1287 | 19960227 bug: received_setup() was not allowing space for the final \0. | ||
| 1288 | impact: none; the line length is always between 65 and 75 | ||
| 1289 | characters, which gives at least 45 characters of slop with | ||
| 1290 | existing malloc() implementations. fix: leave space. tnx NH. | ||
| 1291 | note that the bug here is really in fmt_strncpy, which was | ||
| 1292 | written before i was truly free of the curse of libc.a. | ||
| 1293 | 19960227 change: added ALIAS_EMPTY in conf-unusual.h; used it in | ||
| 1294 | qmail-alias.c. tnx PJG. | ||
| 1295 | 19960227 change: added SPAWN_NUMD in conf-unusual.h; used it in spawn.c. | ||
| 1296 | 19960227 change: added conf-unusual.h. | ||
| 1297 | 19960227 cleanup: replaced sizeof(short) with 2 in dns.c. | ||
| 1298 | 19960227 portability problem: on an Alpha, long is 64 bits. pointed out | ||
| 1299 | by DS. impact: address lookups produced incorrect results on an | ||
| 1300 | Alpha; qmail-makectl and qmail-remote failed. fix: replaced | ||
| 1301 | sizeof(long) with 4 in dns.c. | ||
| 1302 | 19960227 portability problem: on an Alpha, bzero() is declared properly | ||
| 1303 | via sys/time.h. impact: couldn't compile on an Alpha. fix: | ||
| 1304 | removed bzero() declaration from select.h. tnx DS. | ||
| 1305 | 19960227 portability problem: under SCO, sys/file.h is not protected. | ||
| 1306 | impact: couldn't compile under SCO. fix: include sys/types.h in | ||
| 1307 | lock.c. tnx RN. | ||
| 1308 | 19960219 change: added some .qmail-list hints to qlist.1. | ||
| 1309 | 19960219 change: added +list support to qmail-alias. | ||
| 1310 | 19960215 change: added THANKS. | ||
| 1311 | 19960212 bug: foo was not initialized in qrelay.c. impact: depends on | ||
| 1312 | the machine; on some machines, no effect; on other machines, | ||
| 1313 | guaranteed core dump. fix: initialized foo. tnx DS. | ||
| 1314 | 19960209 qmail 0.72, beta. | ||
| 1315 | 19960209 change: qmail-alias now replaces dot, not slash, with colon. | ||
| 1316 | also, qmeopen() makes sure that .qmail file is S_IFREG; I hope | ||
| 1317 | this doesn't cause portability problems. | ||
| 1318 | 19960209 change: added success-reporting procedure to INSTALL. | ||
| 1319 | 19960208 change: added VERSION. | ||
| 1320 | 19960208 change: added qlist2. | ||
| 1321 | 19960208 change: revamped qlist interface. tnx RN. | ||
| 1322 | 19960208 change: improved an error message in qlist.c. | ||
| 1323 | 19960208 change: added qrelay. added relay section to HOWTO. tnx DS. | ||
| 1324 | 19960208 cleanup: included substdio.h in qqtalk.h. | ||
| 1325 | 19960207 bug: prioq_delmin() wasn't guaranteeing heap structure on the | ||
| 1326 | last element. impact: scheduled passes could have been delayed, | ||
| 1327 | conceivably as long as half an hour. fix: prioq_delmin() now | ||
| 1328 | checks when it can safely move the last element. | ||
| 1329 | 19960207 change: added maildirmake.1, maildir2mbox.1. | ||
| 1330 | 19960206 change: revised logo paragraph in THOUGHTS. | ||
| 1331 | 19960206 change: replaced nowhere.org with nowhere.mil in examples. | ||
| 1332 | nowhere.org is a real domain... [sigh] | ||
| 1333 | 19960206 change: added qreceipt.1. | ||
| 1334 | 19960206 portability problem: IRIX doesn't have vfork. pointed out by | ||
| 1335 | DS. impact: couldn't compile under IRIX. fix: added fork.h, | ||
| 1336 | tryvfork.c. | ||
| 1337 | 19960206 portability problem: IRIX doesn't have ranlib. pointed out by | ||
| 1338 | DS. impact: couldn't compile under IRIX. fix: added IRIX | ||
| 1339 | section in make-cmds.sh. | ||
| 1340 | 19960205 cleanup: removed warning from substdio_copy() documentation; in | ||
| 1341 | fact, substdio_copy() can be used safely on a fed substdio. | ||
| 1342 | 19960205 change: added qbiff.1. | ||
| 1343 | 19960204 change: implemented localnet. removed relevant paragraph from | ||
| 1344 | THOUGHTS. tnx IS. | ||
| 1345 | 19960204 change: in qmail-remote.8, explained the dangers of smarthost. | ||
| 1346 | tnx IS. | ||
| 1347 | 19960204 change: implemented virtualdomains wildcards. tnx JLH. | ||
| 1348 | 19960203 change: qmail-send now handles virtualdomains _after_ locals. | ||
| 1349 | updated INSTALL.qsmhook appropriately. | ||
| 1350 | 19960203 change: added note to INSTALL.alias about ~ftp, ~www, ~uucp | ||
| 1351 | being owned by root. | ||
| 1352 | 19960130 cleanup: in qlist.c, renamed flagremoved as flagwasthere. | ||
| 1353 | 19960130 bug: qmail-send did not pay attention to flagexitasap in | ||
| 1354 | pass_dochan(). impact: qmail-send would happily start new | ||
| 1355 | deliveries even if it wanted to exit. fix: qmail-send now | ||
| 1356 | returns immediately in pass_selprep() and pass_dochan() if | ||
| 1357 | flagexitasap. | ||
| 1358 | 19960130 change: in qlist.c and qlist.1, renamed ext as list. | ||
| 1359 | 19960130 change: in qlist.c and qlist.1, renamed manager as owner. | ||
| 1360 | 19960129 qmail 0.71, beta. | ||
| 1361 | 19960129 change: mentioned djb-qmailbeta in README. tnx MWE. | ||
| 1362 | 19960129 change: added a note to INSTALL.mbox making clear that | ||
| 1363 | Mailbox is in mbox format. tnx MWE. | ||
| 1364 | 19960129 change: qlist now warns you if it didn't see any cmds. tnx RN. | ||
| 1365 | 19960129 change: incorporated qlist patch from RN to refuse double subs. | ||
| 1366 | 19960129 change: added qlist.1, contributed by RN. mangled it a bit. | ||
| 1367 | 19960129 bug: comment was not allowed in ``phrase (comment) <route>''; | ||
| 1368 | pointed out by RN. impact: some correct address lists could be | ||
| 1369 | mis-parsed by qmail-inject or qlist. fix: token.c now allows | ||
| 1370 | TOKEN_COMMENT in the appropriate scan. | ||
| 1371 | 19960128 change: added a logo paragraph to THOUGHTS. | ||
| 1372 | 19960127 change: implemented rcpthosts. | ||
| 1373 | 19960127 change: split up some uses of putflush in qmail-remote, | ||
| 1374 | qmail-smtpd, spawn.c. eliminated NODELAY and corresponding | ||
| 1375 | paragraph in THOUGHTS. | ||
| 1376 | 19960127 change: added quote2(). used it in qmail-alias, qmail-send, | ||
| 1377 | qreceipt. now addresses are properly quoted in the From, To, | ||
| 1378 | and internal Return-Path of bounces; the From and To of | ||
| 1379 | receipts; and the Return-Path/RPLINE of delivered messages. | ||
| 1380 | removed relevant paragraph from THOUGHTS. | ||
| 1381 | 19960127 change: in RFCLOOPS, documented fact that Delivered-To address | ||
| 1382 | is conventionally not quoted. | ||
| 1383 | 19960127 change: knocked default SMTP timeouts down to 20 minutes. | ||
| 1384 | 19960127 change: added INSTALL.ids. tnx RN. | ||
| 1385 | 19960127 change: in INSTALL, noted that nogroup should already exist. | ||
| 1386 | 19960127 bug: pass_selprep checked pqchan[c] even if pass[c].id. impact: | ||
| 1387 | qmail-send wasted CPU time whenever more than one message was | ||
| 1388 | waiting on a blocked channel. fix: pass_selprep now checks | ||
| 1389 | !pass[c].id. | ||
| 1390 | 19960127 bug: programs invoked from qmail-alias were immune to SIGPIPE. | ||
| 1391 | impact: a delivery pipeline such as |yes|head -1000 would loop | ||
| 1392 | forever, since yes does not check for write errors. fix: added | ||
| 1393 | signal_uninit(). used it before execvp in qmail-alias. [sigh] | ||
| 1394 | 19960127 cleanup: added date822fmt.c. used it in newfield.c, qmail-queue. | ||
| 1395 | 19960127 cleanup: added fmt_uint0.c. used it in myctime.c, newfield.c, | ||
| 1396 | qmail-queue. | ||
| 1397 | 19960127 cleanup: added dnsdoe.c. used it in dnscname, dnsfq, dnsip, | ||
| 1398 | dnsmxip, dnsptr. | ||
| 1399 | 19960127 cleanup: eliminated temp from dnsfq.c. | ||
| 1400 | 19960127 bug: gen_allocdefs was making assumptions incompatible with the | ||
| 1401 | alloc_re interface. impact: qmail-send would dump core if you | ||
| 1402 | ran out of memory. fix: changed alloc_re interface. | ||
| 1403 | 19960126 portability problem: some versions of Linux don't have | ||
| 1404 | net/route.h. pointed out by RN. impact: couldn't compile under | ||
| 1405 | those versions. fix: ipme.c no longer includes net/route.h; | ||
| 1406 | hopefully this won't cause new portability problems. | ||
| 1407 | 19960126 change: added chmod instructions to INSTALL and INSTALL.alias. | ||
| 1408 | tnx RN. | ||
| 1409 | 19960126 change: INSTALL now refers to the traditional sendmail spot | ||
| 1410 | (/usr/lib), not the BSD 4.4 spot (/usr/sbin). tnx RN. | ||
| 1411 | 19960126 change: make auto-uids.h now creates auto-uids.h.tmp first. | ||
| 1412 | thus, if someone disobeys the installation instructions, and | ||
| 1413 | his make fails to remove targets upon error, he'll still be | ||
| 1414 | okay. tnx RN. | ||
| 1415 | 19960126 change: added forgeries.7. | ||
| 1416 | 19960125 cleanup: eliminated flagverbose, flagmetoo in sendmail. | ||
| 1417 | 19960125 cleanup: added substdio_copy.c. used it at several spots. | ||
| 1418 | 19960125 cleanup: added constmap.c. qmail-send now uses constmap for | ||
| 1419 | locals and virtualdomains. this will speed things up: no | ||
| 1420 | problem now to have thousands of virtual domains. removed | ||
| 1421 | relevant paragraph from THOUGHTS. | ||
| 1422 | 19960125 change: added linux section in find-systype. this will affect | ||
| 1423 | linux-* systypes. tnx RN for relevant info. | ||
| 1424 | 19960124 change: added -od, -oe, -p, -f to sendmail. the need for | ||
| 1425 | these was pointed out by TN. | ||
| 1426 | 19960124 bug: qmail-smtpd was reading from descriptor 1. impact: none; | ||
| 1427 | in normal use, both 0 and 1 point to the network. fix: changed | ||
| 1428 | 1 to 0. | ||
| 1429 | 19960124 bug: qmail-alias treated any .qmail open failure as permanent. | ||
| 1430 | impact: if a .qmail file was temporarily unopenable (e.g., | ||
| 1431 | because of NFS), it was incorrectly ignored. fix: qmail-alias | ||
| 1432 | now dies QLX_SOFT on any open failure other than ENOENT. | ||
| 1433 | 19960124 change: added freebsd section in find-systype, same as bsd.os | ||
| 1434 | section. this will affect freebsd-* systypes. | ||
| 1435 | 19960124 cleanup: find-systype now immediately converts sys to lowercase. | ||
| 1436 | 19960124 change: qmail-setup now copies man pages into /var/qmail/man; | ||
| 1437 | qmail-check checks /var/qmail/man. using .0 style, which might | ||
| 1438 | cause trouble on various machines, but better than not trying. | ||
| 1439 | 19960124 change: in qmail-remote.c, changed perm_control to temp_control | ||
| 1440 | (and D to Z, thanks); thus failure to read control files (e.g., | ||
| 1441 | because of permissions) is now a temporary error. | ||
| 1442 | 19960124 bug: in qmail-remote.c, temp_chdir() used D, not Z. impact: if | ||
| 1443 | chdir() to CONF_HOME failed (e.g., because of NFS), message | ||
| 1444 | would be bounced. fix: changed D to Z. | ||
| 1445 | 19960124 change: reorganized README. | ||
| 1446 | 19960124 portability problem: Linux has the fifo kernel bug that I had | ||
| 1447 | hoped I'd never run into. impact: messages under Linux (and any | ||
| 1448 | other systems with this bug) were picked up only in sweeps, not | ||
| 1449 | instantly. fix: triggerpull.c now writes a byte (non-blocking) | ||
| 1450 | to the fifo. updated INTERNALS accordingly. | ||
| 1451 | 19960124 bug: in qmail-remote.c, if quit() saw a remote write error, it | ||
| 1452 | would call writeerr() even though a message report had already | ||
| 1453 | been produced. impact: the mess report would include an extra | ||
| 1454 | ``ZConnected but communications failed,'' which was confusing | ||
| 1455 | to humans. fix: quit() now simply skips the wait-for-QUIT | ||
| 1456 | smtpcode() upon write error. | ||
| 1457 | 19960124 portability problem: Linux does not have SIGSYS or SIGEMT. | ||
| 1458 | impact: couldn't compile under Linux. fix: added appropriate | ||
| 1459 | ifdefs in signal.c. | ||
| 1460 | 19960124 qmail 0.70, beta. | ||
| @@ -0,0 +1,706 @@ | |||
| 1 | 1. Controlling the appearance of outgoing messages | ||
| 2 | 1.1. How do I set up host masquerading? | ||
| 3 | 1.2. How do I set up user masquerading? | ||
| 4 | 1.3. How do I set up Mail-Followup-To automatically? | ||
| 5 | |||
| 6 | 2. Routing outgoing messages | ||
| 7 | 2.1. How do I send local messages to another host? | ||
| 8 | 2.2. How do I set up a null client? | ||
| 9 | 2.3. How do I send outgoing mail through UUCP? | ||
| 10 | 2.4. How do I set up a separate queue for a SLIP/PPP link? | ||
| 11 | 2.5. How do I deal with ``CNAME lookup failed temporarily''? | ||
| 12 | |||
| 13 | 3. Routing incoming messages by host | ||
| 14 | 3.1. How do I receive mail for another host name? | ||
| 15 | 3.2. How do I set up a virtual domain? | ||
| 16 | 3.3. How do I set up several virtual domains for one user? | ||
| 17 | |||
| 18 | 4. Routing incoming messages by user | ||
| 19 | 4.1. How do I forward unrecognized usernames to another host? | ||
| 20 | 4.2. How do I set up a mailing list? | ||
| 21 | 4.3. How do I use majordomo with qmail? | ||
| 22 | 4.4. How do I use procmail with qmail? | ||
| 23 | 4.5. How do I use elm's filter with qmail? | ||
| 24 | 4.6. How do I create aliases with dots? | ||
| 25 | 4.7. How do I use sendmail's .forward files with qmail? | ||
| 26 | 4.8. How do I use sendmail's /etc/aliases with qmail? | ||
| 27 | 4.9. How do I make qmail defer messages during NFS or NIS outages? | ||
| 28 | 4.10. How do I change which account controls an address? | ||
| 29 | |||
| 30 | 5. Setting up servers | ||
| 31 | 5.1. How do I run qmail-smtpd under tcpserver? | ||
| 32 | 5.2. How do I set up qmail-qmtpd? | ||
| 33 | 5.3. How do I set up qmail-pop3d? | ||
| 34 | 5.4. How do I allow selected clients to use this host as a relay? | ||
| 35 | 5.5. How do I fix up messages from broken SMTP clients? | ||
| 36 | 5.6. How do I set up qmail-qmqpd? | ||
| 37 | |||
| 38 | 6. Configuring MUAs to work with qmail | ||
| 39 | 6.1. How do I make BSD mail generate a Date with the local time zone? | ||
| 40 | 6.2. How do I make pine work with qmail? | ||
| 41 | 6.3. How do I make MH work with qmail? | ||
| 42 | 6.4. How do I stop Sun's dtcm from hanging? | ||
| 43 | |||
| 44 | 7. Managing the mail system | ||
| 45 | 7.1. How do I safely stop qmail-send? | ||
| 46 | 7.2. How do I manually run the queue? | ||
| 47 | 7.3. How do I rejuvenate a message? | ||
| 48 | 7.4. How do I organize a big network? | ||
| 49 | 7.5. How do I back up and restore the queue disk? | ||
| 50 | 7.6. How do I run a supervised copy of qmail? | ||
| 51 | 7.7. How do I avoid syslog? | ||
| 52 | |||
| 53 | 8. Miscellany | ||
| 54 | 8.1. How do I tell qmail to do more deliveries at once? | ||
| 55 | 8.2. How do I keep a copy of all incoming and outgoing mail messages? | ||
| 56 | 8.3. How do I switch slowly from sendmail to qmail? | ||
| 57 | |||
| 58 | |||
| 59 | |||
| 60 | 1. Controlling the appearance of outgoing messages | ||
| 61 | |||
| 62 | |||
| 63 | 1.1. How do I set up host masquerading? All the users on this host, | ||
| 64 | zippy.af.mil, are users on af.mil. When joe sends a message to fred, the | ||
| 65 | message should say ``From: joe@af.mil'' and ``To: fred@af.mil'', without | ||
| 66 | ``zippy'' anywhere. | ||
| 67 | |||
| 68 | Answer: echo af.mil > /var/qmail/control/defaulthost; chmod 644 | ||
| 69 | /var/qmail/control/defaulthost. | ||
| 70 | |||
| 71 | |||
| 72 | 1.2. How do I set up user masquerading? I'd like my own From lines to | ||
| 73 | show boss@af.mil rather than god@heaven.af.mil. | ||
| 74 | |||
| 75 | Answer: Add MAILHOST=af.mil and MAILUSER=boss to your environment. To | ||
| 76 | override From lines supplied by your MUA, add QMAILINJECT=f to your | ||
| 77 | environment. | ||
| 78 | |||
| 79 | |||
| 80 | 1.3. How do I set up Mail-Followup-To automatically? When I send a | ||
| 81 | message to the sos@heaven.af.mil mailing list, I'd like to include | ||
| 82 | ``Mail-Followup-To: sos@heaven.af.mil''. | ||
| 83 | |||
| 84 | Answer: Add QMAILMFTFILE=$HOME/.lists to your environment, and put | ||
| 85 | sos@heaven.af.mil into ~/.lists. | ||
| 86 | |||
| 87 | |||
| 88 | |||
| 89 | 2. Routing outgoing messages | ||
| 90 | |||
| 91 | |||
| 92 | 2.1. How do I send local messages to another host? All the mail for | ||
| 93 | af.mil should be delivered to our disk server, pokey.af.mil. I've set up | ||
| 94 | an MX from af.mil to pokey.af.mil, but when a user on the af.mil host | ||
| 95 | sends a message to boss@af.mil, af.mil tries to deliver it locally. How | ||
| 96 | do I stop that? | ||
| 97 | |||
| 98 | Answer: Remove af.mil from /var/qmail/control/locals. If qmail-send is | ||
| 99 | running, give it a HUP. Make sure the MX is set up properly before you | ||
| 100 | do this. Also make sure that pokey can receive mail for af.mil---see | ||
| 101 | question 3.1. | ||
| 102 | |||
| 103 | |||
| 104 | 2.2. How do I set up a null client? I'd like zippy.af.mil to | ||
| 105 | send all mail to bigbang.af.mil. | ||
| 106 | |||
| 107 | Answer: echo :bigbang.af.mil > /var/qmail/control/smtproutes; | ||
| 108 | chmod 644 /var/qmail/control/smtproutes. Disable local delivery as in | ||
| 109 | question 2.1. Turn off qmail-smtpd in /etc/inetd.conf. | ||
| 110 | |||
| 111 | |||
| 112 | 2.3. How do I send outgoing mail through UUCP? I need qmail to send all | ||
| 113 | outgoing mail via UUCP to my upstream UUCP site, gonzo. | ||
| 114 | |||
| 115 | Answer: Put | ||
| 116 | |||
| 117 | :alias-uucp | ||
| 118 | |||
| 119 | into control/virtualdomains and | ||
| 120 | |||
| 121 | |preline -df /usr/bin/uux - -r -gC | ||
| 122 | -a"${SENDER:-MAILER-DAEMON}" gonzo!rmail "($DEFAULT@$HOST)" | ||
| 123 | |||
| 124 | (all on one line) into ~alias/.qmail-uucp-default. (For some UUCP | ||
| 125 | software you will need to use -d instead of -df.) If qmail-send is | ||
| 126 | running, give it a HUP. | ||
| 127 | |||
| 128 | |||
| 129 | 2.4. How do I set up a separate queue for a SLIP/PPP link? | ||
| 130 | |||
| 131 | Answer: Use serialmail (http://pobox.com/~djb/serialmail.html). | ||
| 132 | |||
| 133 | |||
| 134 | 2.5. How do I deal with ``CNAME lookup failed temporarily''? The log | ||
| 135 | showed that a message was deferred for this reason. Why is qmail doing | ||
| 136 | CNAME lookups, anyway? | ||
| 137 | |||
| 138 | Answer: The SMTP standard does not permit aliased hostnames, so qmail | ||
| 139 | has to do a CNAME lookup in DNS for every recipient host. If the | ||
| 140 | relevant DNS server is down, qmail defers the message. It will try again | ||
| 141 | soon. | ||
| 142 | |||
| 143 | |||
| 144 | |||
| 145 | 3. Routing incoming messages by host | ||
| 146 | |||
| 147 | |||
| 148 | 3.1. How do I receive mail for another host name? I'd like our disk | ||
| 149 | server, pokey.af.mil, to receive mail addressed to af.mil. I've set up | ||
| 150 | an MX from af.mil to pokey.af.mil, but how do I get pokey to treat | ||
| 151 | af.mil as a name for the local host? | ||
| 152 | |||
| 153 | Answer: Add af.mil to /var/qmail/control/locals and to | ||
| 154 | /var/qmail/control/rcpthosts. If qmail-send is running, give it a HUP | ||
| 155 | (or do svc -h /var/run/qmail if qmail is supervised). | ||
| 156 | |||
| 157 | |||
| 158 | 3.2. How do I set up a virtual domain? I'd like any mail for | ||
| 159 | nowhere.mil, including root@nowhere.mil and postmaster@nowhere.mil and | ||
| 160 | so on, to be delivered to Bob. I've set up the MX already. | ||
| 161 | |||
| 162 | Answer: Put | ||
| 163 | |||
| 164 | nowhere.mil:bob | ||
| 165 | |||
| 166 | into control/virtualdomains. Add nowhere.mil to control/rcpthosts. If | ||
| 167 | qmail-send is running, give it a HUP (or do svc -h /var/run/qmail if | ||
| 168 | qmail is supervised). | ||
| 169 | |||
| 170 | Now mail for whatever@nowhere.mil will be delivered locally to | ||
| 171 | bob-whatever. Bob can set up ~bob/.qmail-default to catch all the | ||
| 172 | possible addresses, ~bob/.qmail-info to catch info@nowhere.mil, etc. | ||
| 173 | |||
| 174 | |||
| 175 | 3.3. How do I set up several virtual domains for one user? Bob wants | ||
| 176 | another virtual domain, everywhere.org, but he wants to handle | ||
| 177 | nowhere.mil users and everywhere.org users differently. How can we do | ||
| 178 | that without setting up a second account? | ||
| 179 | |||
| 180 | Answer: Put two lines into control/virtualdomains: | ||
| 181 | |||
| 182 | nowhere.mil:bob-nowhere | ||
| 183 | everywhere.org:bob-everywhere | ||
| 184 | |||
| 185 | Add nowhere.mil and everywhere.org to control/rcpthosts. If qmail-send | ||
| 186 | is running, give it a HUP (or do svc -h /var/run/qmail if qmail is | ||
| 187 | supervised). | ||
| 188 | |||
| 189 | Now Bob can set up separate .qmail-nowhere-* and everywhere-* files. He | ||
| 190 | can even set up .qmail-nowhere-default and .qmail-everywhere-default. | ||
| 191 | |||
| 192 | |||
| 193 | |||
| 194 | 4. Routing incoming messages by user | ||
| 195 | |||
| 196 | |||
| 197 | 4.1. How do I forward unrecognized usernames to another host? I'd like | ||
| 198 | to set up a LUSER_RELAY pointing at bigbang.af.mil. | ||
| 199 | |||
| 200 | Answer: Put | ||
| 201 | |||
| 202 | | forward "$LOCAL"@bigbang.af.mil | ||
| 203 | |||
| 204 | into ~alias/.qmail-default. | ||
| 205 | |||
| 206 | |||
| 207 | 4.2. How do I set up a mailing list? I'd like me-sos@my.host.name to be | ||
| 208 | forwarded to a bunch of people. | ||
| 209 | |||
| 210 | Answer: Put a list of addresses into ~me/.qmail-sos, one per line. Then | ||
| 211 | incoming mail for me-sos will be forwarded to each of those addresses. | ||
| 212 | You should also touch ~me/.qmail-sos-owner so that bounces come back to | ||
| 213 | you rather than the original sender. | ||
| 214 | |||
| 215 | Alternative: ezmlm (http://pobox.com/~djb/ezmlm.html) is a modern | ||
| 216 | mailing list manager, supporting automatic subscriptions, confirmations, | ||
| 217 | archives, fully automatic bounce handling (including warnings to | ||
| 218 | subscribers saying which messages they've missed), and more. | ||
| 219 | |||
| 220 | |||
| 221 | 4.3. How do I use majordomo with qmail? | ||
| 222 | |||
| 223 | Answer: See ftp://ftp.eyrie.org/pub/software/majordomo/mjqmail and | ||
| 224 | http://www.qmail.org for various methods. majordomo 2.0 is expected to | ||
| 225 | support qmail directly. | ||
| 226 | |||
| 227 | Beware that majordomo's lists are not crashproof. | ||
| 228 | |||
| 229 | |||
| 230 | |||
| 231 | 4.4. How do I use procmail with qmail? | ||
| 232 | |||
| 233 | Answer: Put | ||
| 234 | |||
| 235 | | preline procmail | ||
| 236 | |||
| 237 | into ~/.qmail. You'll have to use a full path for procmail unless | ||
| 238 | procmail is in the system's startup PATH. Note that procmail will try to | ||
| 239 | deliver to /var/spool/mail/$USER by default; to change this, see | ||
| 240 | INSTALL.mbox. | ||
| 241 | |||
| 242 | |||
| 243 | 4.5. How do I use elm's filter with qmail? | ||
| 244 | |||
| 245 | Answer: Put | ||
| 246 | |||
| 247 | | preline filter | ||
| 248 | |||
| 249 | into ~/.qmail. You'll have to use a full path for filter unless filter | ||
| 250 | is in the system's startup PATH. | ||
| 251 | |||
| 252 | |||
| 253 | 4.6. How do I create aliases with dots? I tried setting up | ||
| 254 | ~alias/.qmail-P.D.Q.Bach, but it doesn't do anything. | ||
| 255 | |||
| 256 | Answer: Use .qmail-p:d:q:bach. Dots are converted to colons, and | ||
| 257 | uppercase is converted to lowercase. | ||
| 258 | |||
| 259 | |||
| 260 | 4.7. How do I use sendmail's .forward files with qmail? | ||
| 261 | |||
| 262 | Answer: Install the dot-forward package | ||
| 263 | (http://pobox.com/~djb/dot-forward.html). | ||
| 264 | |||
| 265 | |||
| 266 | 4.8. How do I use sendmail's /etc/aliases with qmail? | ||
| 267 | |||
| 268 | Answer: Install the fastforward package | ||
| 269 | (http://pobox.com/~djb/fastforward.html). | ||
| 270 | |||
| 271 | |||
| 272 | 4.9. How do I make qmail defer messages during NFS or NIS outages? If | ||
| 273 | ~joe suddenly disappears, I'd like mail for joe to be deferred. | ||
| 274 | |||
| 275 | Answer: Build a qmail-users database, so that qmail no longer checks | ||
| 276 | home directories and the password database. This takes three steps. | ||
| 277 | First, put your complete user list (including local and NIS passwords) | ||
| 278 | into /var/qmail/users/passwd. Second, run | ||
| 279 | |||
| 280 | # qmail-pw2u -h < /var/qmail/users/passwd > /var/qmail/users/assign | ||
| 281 | |||
| 282 | Here -h means that every user must have a home directory; if you happen | ||
| 283 | to run qmail-pw2u during an NFS outage, it will print an error message | ||
| 284 | and stop. Third, run | ||
| 285 | |||
| 286 | # qmail-newu | ||
| 287 | |||
| 288 | Make sure to rebuild the database whenever you change your user list. | ||
| 289 | |||
| 290 | |||
| 291 | 4.10. How do I change which account controls an address? I set up | ||
| 292 | ~alias/.qmail-www, but qmail is looking at ~www/.qmail instead. | ||
| 293 | |||
| 294 | Answer: If you do | ||
| 295 | |||
| 296 | # chown root ~www | ||
| 297 | |||
| 298 | then qmail will no longer consider www to be a user; see qmail-getpw.0. | ||
| 299 | For more precise control over address assignments, see qmail-users.0. | ||
| 300 | |||
| 301 | |||
| 302 | |||
| 303 | 5. Setting up servers | ||
| 304 | |||
| 305 | |||
| 306 | 5.1. How do I run qmail-smtpd under tcpserver? inetd is barfing at high | ||
| 307 | loads, cutting off service for ten-minute stretches. I'd also like | ||
| 308 | better connection logging. | ||
| 309 | |||
| 310 | Answer: First, install the tcpserver program, part of the ucspi-tcp | ||
| 311 | package (http://pobox.com/~djb/ucspi-tcp.html). Second, remove the smtp | ||
| 312 | line from /etc/inetd.conf, and put the line | ||
| 313 | |||
| 314 | tcpserver -u 7770 -g 2108 0 smtp /var/qmail/bin/qmail-smtpd & | ||
| 315 | |||
| 316 | into your system startup files. Replace 7770 with your qmaild uid, and | ||
| 317 | replace 2108 with your nofiles gid. Don't forget the &. The change will | ||
| 318 | take effect at your next reboot. | ||
| 319 | |||
| 320 | By default, tcpserver allows at most 40 simultaneous qmail-smtpd | ||
| 321 | processes. To raise this limit to 400, use tcpserver -c 400. To keep | ||
| 322 | track of who's connecting and for how long, run (on two lines) | ||
| 323 | |||
| 324 | tcpserver -v -u 7770 -g 2108 0 smtp /var/qmail/bin/qmail-smtpd \ | ||
| 325 | 2>&1 | /var/qmail/bin/splogger smtpd 3 & | ||
| 326 | |||
| 327 | |||
| 328 | 5.2. How do I set up qmail-qmtpd? | ||
| 329 | |||
| 330 | Answer: Two steps. First, put a | ||
| 331 | |||
| 332 | qmtp 209/tcp | ||
| 333 | |||
| 334 | line into /etc/services. Second, put (all on one line) | ||
| 335 | |||
| 336 | qmtp stream tcp nowait qmaild | ||
| 337 | /var/qmail/bin/tcp-env tcp-env /var/qmail/bin/qmail-qmtpd | ||
| 338 | |||
| 339 | into /etc/inetd.conf, and give inetd a HUP. | ||
| 340 | |||
| 341 | If you have tcpserver installed, skip the inetd step, and set up | ||
| 342 | |||
| 343 | tcpserver -u 7770 -g 2108 0 qmtp /var/qmail/bin/qmail-qmtpd & | ||
| 344 | |||
| 345 | replacing 7770 and 2108 with the qmaild uid and nofiles gid. See | ||
| 346 | question 5.1 for more details on tcpserver. | ||
| 347 | |||
| 348 | |||
| 349 | 5.3. How do I set up qmail-pop3d? My old POP server works with mbox | ||
| 350 | delivery; I'd like to switch to maildir delivery. | ||
| 351 | |||
| 352 | Answer: Four steps. First, install the checkpassword program | ||
| 353 | (http://pobox.com/~djb/checkpwd.html). Second, make sure you have a | ||
| 354 | |||
| 355 | pop3 110/tcp | ||
| 356 | |||
| 357 | line in /etc/services. Third, put (all on one line, including | ||
| 358 | qmail-popup twice) | ||
| 359 | |||
| 360 | pop3 stream tcp nowait root | ||
| 361 | /var/qmail/bin/qmail-popup qmail-popup | ||
| 362 | YOURHOST /bin/checkpassword /var/qmail/bin/qmail-pop3d Maildir | ||
| 363 | |||
| 364 | into /etc/inetd.conf, and give inetd a HUP; replace YOURHOST with your | ||
| 365 | host's fully qualified domain name. Fourth, set up Maildir delivery for | ||
| 366 | any user who wants to read mail via POP. | ||
| 367 | |||
| 368 | If you have tcpserver installed, skip the inetd step, and set up (on two | ||
| 369 | lines) | ||
| 370 | |||
| 371 | tcpserver 0 pop3 /var/qmail/bin/qmail-popup YOURHOST \ | ||
| 372 | /bin/checkpassword /var/qmail/bin/qmail-pop3d Maildir & | ||
| 373 | |||
| 374 | replacing YOURHOST with your host's fully qualified domain name. See | ||
| 375 | question 5.1 for more details on tcpserver. | ||
| 376 | |||
| 377 | Security note: pop3d should be used only within a secure network; | ||
| 378 | otherwise an eavesdropper can steal passwords. | ||
| 379 | |||
| 380 | |||
| 381 | 5.4. How do I allow selected clients to use this host as a relay? I see | ||
| 382 | that qmail-smtpd rejects messages to any host not listed in | ||
| 383 | control/rcpthosts. | ||
| 384 | |||
| 385 | Answer: Three steps. First, install tcp-wrappers, available separately, | ||
| 386 | including hosts_options. Second, change your qmail-smtpd line in | ||
| 387 | inetd.conf to | ||
| 388 | |||
| 389 | smtp stream tcp nowait qmaild /usr/local/bin/tcpd | ||
| 390 | /var/qmail/bin/tcp-env /var/qmail/bin/qmail-smtpd | ||
| 391 | |||
| 392 | (all on one line) and give inetd a HUP. Third, in tcpd's hosts.allow, | ||
| 393 | make a line setting the environment variable RELAYCLIENT to the empty | ||
| 394 | string for the selected clients: | ||
| 395 | |||
| 396 | tcp-env: 1.2.3.4, 1.2.3.5: setenv = RELAYCLIENT | ||
| 397 | |||
| 398 | Here 1.2.3.4 and 1.2.3.5 are the clients' IP addresses. qmail-smtpd | ||
| 399 | ignores control/rcpthosts when RELAYCLIENT is set. (It also appends | ||
| 400 | RELAYCLIENT to each envelope recipient address. See question 5.5 for an | ||
| 401 | application.) | ||
| 402 | |||
| 403 | Alternative procedure, if you are using tcpserver 0.80 or above: Create | ||
| 404 | /etc/tcp.smtp containing | ||
| 405 | |||
| 406 | 1.2.3.6:allow,RELAYCLIENT="" | ||
| 407 | 127.:allow,RELAYCLIENT="" | ||
| 408 | |||
| 409 | to allow clients with IP addresses 1.2.3.6 and 127.*. Run | ||
| 410 | |||
| 411 | tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp | ||
| 412 | |||
| 413 | Finally, insert | ||
| 414 | |||
| 415 | -x /etc/tcp.smtp.cdb | ||
| 416 | |||
| 417 | after tcpserver in your qmail-smtpd invocation. | ||
| 418 | |||
| 419 | |||
| 420 | 5.5. How do I fix up messages from broken SMTP clients? | ||
| 421 | |||
| 422 | Answer: Three steps. First, put | ||
| 423 | |||
| 424 | | bouncesaying 'Permission denied' [ "@$HOST" != "@fixme" ] | ||
| 425 | | qmail-inject -f "$SENDER" -- "$DEFAULT" | ||
| 426 | |||
| 427 | into ~alias/.qmail-fixup-default. Second, put | ||
| 428 | |||
| 429 | fixme:fixup | ||
| 430 | |||
| 431 | into /var/qmail/control/virtualdomains, and give qmail-send a HUP. | ||
| 432 | Third, follow the procedure in question 5.4, but set RELAYCLIENT to the | ||
| 433 | string ``@fixme'': | ||
| 434 | |||
| 435 | tcp-env: 1.2.3.6, 1.2.3.7: setenv = RELAYCLIENT @fixme | ||
| 436 | |||
| 437 | Here 1.2.3.6 and 1.2.3.7 are the clients' IP addresses. If you are using | ||
| 438 | tcpserver instead of inetd and tcpd, put | ||
| 439 | |||
| 440 | 1.2.3.6:allow,RELAYCLIENT="@fixme" | ||
| 441 | 1.2.3.7:allow,RELAYCLIENT="@fixme" | ||
| 442 | |||
| 443 | into /etc/tcp.smtp, and run tcprules as in question 5.4. | ||
| 444 | |||
| 445 | |||
| 446 | 5.6. How do I set up qmail-qmqpd? I'd like to allow fast queueing of | ||
| 447 | outgoing mail from authorized clients. | ||
| 448 | |||
| 449 | Answer: Make sure you have installed tcpserver 0.80 or above. Create | ||
| 450 | /etc/qmqp.tcp in tcprules format to allow connections from authorized | ||
| 451 | hosts. For example, if queueing is allowed from 1.2.3.*: | ||
| 452 | |||
| 453 | 1.2.3.:allow | ||
| 454 | :deny | ||
| 455 | |||
| 456 | Convert /etc/qmqp.tcp to /etc/qmqp.cdb: | ||
| 457 | |||
| 458 | tcprules /etc/qmqp.cdb /etc/qmqp.tmp < /etc/qmqp.tcp | ||
| 459 | |||
| 460 | Finally, set up | ||
| 461 | |||
| 462 | tcpserver -x /etc/qmqp.cdb -u 7770 -g 2108 0 628 /var/qmail/bin/qmail-qmqpd & | ||
| 463 | |||
| 464 | replacing 7770 and 2108 with the qmaild uid and nofiles gid. See | ||
| 465 | question 5.1 for more details on tcpserver. | ||
| 466 | |||
| 467 | |||
| 468 | |||
| 469 | 6. Configuring MUAs to work with qmail | ||
| 470 | |||
| 471 | |||
| 472 | 6.1. How do I make BSD mail generate a Date with the local time zone? | ||
| 473 | When I send mail, I'd rather use the local time zone than GMT, since | ||
| 474 | some MUAs don't know how to display Date in the receiver's time zone. | ||
| 475 | |||
| 476 | Answer: Put | ||
| 477 | |||
| 478 | set sendmail=/var/qmail/bin/datemail | ||
| 479 | |||
| 480 | into your .mailrc or your system-wide Mail.rc. Beware that BSD mail is | ||
| 481 | neither secure nor reliable. | ||
| 482 | |||
| 483 | |||
| 484 | 6.2. How do I make pine work with qmail? | ||
| 485 | |||
| 486 | Answer: Put | ||
| 487 | |||
| 488 | sendmail-path=/usr/lib/sendmail -oem -oi -t | ||
| 489 | |||
| 490 | into /usr/local/lib/pine.conf. (This will work with sendmail too.) | ||
| 491 | Beware that pine is neither secure nor reliable. | ||
| 492 | |||
| 493 | |||
| 494 | 6.3. How do I make MH work with qmail? | ||
| 495 | |||
| 496 | Answer: Put | ||
| 497 | |||
| 498 | postproc: /usr/mh/lib/spost | ||
| 499 | |||
| 500 | into each user's .mh_profile. (This will work with sendmail too.) Beware | ||
| 501 | that MH is neither secure nor reliable. | ||
| 502 | |||
| 503 | |||
| 504 | 6.4. How do I stop Sun's dtcm from hanging? | ||
| 505 | |||
| 506 | Answer: There is a novice programming error in dtcm, known as ``failure | ||
| 507 | to close the output side of the pipe in the child.'' Sun has, at the | ||
| 508 | time of this writing, not yet provided a patch. Sorry. | ||
| 509 | |||
| 510 | |||
| 511 | |||
| 512 | 7. Managing the mail system | ||
| 513 | |||
| 514 | |||
| 515 | 7.1. How do I safely stop qmail-send? Back when we were running | ||
| 516 | sendmail, it was always tricky to kill sendmail without risking the loss | ||
| 517 | of current deliveries; what should I do with qmail-send? | ||
| 518 | |||
| 519 | Answer: Go ahead and kill the qmail-send process. It will shut down | ||
| 520 | cleanly. Wait for ``exiting'' to show up in the log. To restart qmail, | ||
| 521 | run /var/qmail/rc the same way it is run from your system boot scripts, | ||
| 522 | with the proper PATH, resource limits, etc. | ||
| 523 | |||
| 524 | Alternative, if qmail is supervised: svc -t /var/run/qmail. The | ||
| 525 | supervise process will kill qmail, wait for it to stop, and restart it. | ||
| 526 | Use -d instead of -t if you don't want qmail to restart automatically; | ||
| 527 | to manually restart it, use -u. | ||
| 528 | |||
| 529 | |||
| 530 | 7.2. How do I manually run the queue? I'd like qmail to try delivering | ||
| 531 | all the remote messages right now. | ||
| 532 | |||
| 533 | Answer: Give the qmail-send process an ALRM. (Do svc -a /var/run/qmail | ||
| 534 | if qmail is supervised.) | ||
| 535 | |||
| 536 | You may want to run qmail-tcpok first, to guarantee that qmail-remote | ||
| 537 | will try all addresses. Normally, if an address fails repeatedly, | ||
| 538 | qmail-remote leaves it alone for an hour. | ||
| 539 | |||
| 540 | |||
| 541 | 7.3. How do I rejuvenate a message? Somebody broke into Eric's computer | ||
| 542 | again; it's going to be down for at least another two days. I know Eric | ||
| 543 | has been expecting an important message---in fact, I see it sitting here | ||
| 544 | in /var/qmail/queue/mess/15/26902. It's been in the queue for six days; | ||
| 545 | how can I make sure it isn't bounced tomorrow? | ||
| 546 | |||
| 547 | Answer: Just touch /var/qmail/queue/info/15/26902. (This is the only | ||
| 548 | form of queue modification that's safe while qmail is running.) | ||
| 549 | |||
| 550 | |||
| 551 | 7.4. How do I organize a big network? I have a lot of machines, and I | ||
| 552 | don't know where to start. | ||
| 553 | |||
| 554 | Answer: First, choose the domain name where your users will receive | ||
| 555 | mail. This is normally the shortest domain name you control. If you are | ||
| 556 | in charge of *.movie.edu, you can use addresses like joe@movie.edu. | ||
| 557 | |||
| 558 | Second, choose the machine that will know what to do with different | ||
| 559 | users at movie.edu. Set up a host name in DNS for this machine: | ||
| 560 | |||
| 561 | mailhost.movie.edu IN A 1.2.3.4 | ||
| 562 | 4.3.2.1.in-addr.arpa IN PTR mailhost.movie.edu | ||
| 563 | |||
| 564 | Here 1.2.3.4 is the IP address of that machine. | ||
| 565 | |||
| 566 | Third, make a list of machines where mail should end up. For example, if | ||
| 567 | mail for Bob should end up on Bob's workstation, put Bob's workstation | ||
| 568 | onto the list. For each of these machines, set up a host name in DNS: | ||
| 569 | |||
| 570 | bobshost.movie.edu IN A 1.2.3.7 | ||
| 571 | 7.3.2.1.in-addr.arpa IN PTR bobshost.movie.edu | ||
| 572 | |||
| 573 | Fourth, install qmail on bobshost.movie.edu. qmail will automatically | ||
| 574 | configure itself to accept messages for bob@bobshost.movie.edu and | ||
| 575 | deliver them to ~bob/Mailbox on bobshost. Do the same for the other | ||
| 576 | machines where mail should end up. | ||
| 577 | |||
| 578 | Fifth, install qmail on mailhost.movie.edu. Put | ||
| 579 | |||
| 580 | movie.edu:alias-movie | ||
| 581 | |||
| 582 | into control/virtualdomains on mailhost. Then forward bob@movie.edu to | ||
| 583 | bob@bobshost.movie.edu, by putting | ||
| 584 | |||
| 585 | bob@bobshost.movie.edu | ||
| 586 | |||
| 587 | into ~alias/.qmail-movie-bob. Do the same for other users. | ||
| 588 | |||
| 589 | Sixth, put movie.edu into control/rcpthosts on mailhost.movie.edu, so | ||
| 590 | that mailhost.movie.edu will accept messages for users at movie.edu. | ||
| 591 | |||
| 592 | Seventh, set up an MX record in DNS to deliver movie.edu messages to | ||
| 593 | mailhost: | ||
| 594 | |||
| 595 | movie.edu IN MX 10 mailhost.movie.edu | ||
| 596 | |||
| 597 | Eighth, on all your machines, put movie.edu into control/defaulthost. | ||
| 598 | |||
| 599 | |||
| 600 | 7.5. How do I back up and restore the queue disk? | ||
| 601 | |||
| 602 | Answer: You can't. | ||
| 603 | |||
| 604 | One difficulty is that you can't get a consistent snapshot of the queue | ||
| 605 | while qmail-send is running. Another difficulty is that messages in the | ||
| 606 | queue must have filenames that match their inode numbers. | ||
| 607 | |||
| 608 | However, the big problem is that backups---even twice-daily backups--- | ||
| 609 | are far too unreliable for mail. If your disk dies, there will be very | ||
| 610 | little overlap between the messages saved in the last backup and the | ||
| 611 | messages that were lost. | ||
| 612 | |||
| 613 | There are several ways to add real reliability to a mail server. Battery | ||
| 614 | backups will keep your server alive, letting you park the disk to avoid | ||
| 615 | a head crash, when the power goes out. Solid-state disks have their own | ||
| 616 | battery backups. RAID boxes let you replace dead disks without losing | ||
| 617 | any data. | ||
| 618 | |||
| 619 | |||
| 620 | 7.6. How do I run a supervised copy of qmail? svc sounds useful. | ||
| 621 | |||
| 622 | Answer: Install daemontools (http://pobox.com/~djb/daemontools.html). | ||
| 623 | Create a /var/run/qmail directory. Change | ||
| 624 | |||
| 625 | /var/qmail/rc | ||
| 626 | |||
| 627 | to | ||
| 628 | |||
| 629 | supervise /var/run/qmail /var/qmail/rc | ||
| 630 | |||
| 631 | in your boot scripts. Make sure that supervise is in the startup PATH. | ||
| 632 | Now you can use svc to stop or restart qmail, and svstat to check | ||
| 633 | whether qmail is running. | ||
| 634 | |||
| 635 | |||
| 636 | 7.7. How do I avoid syslog? It chews up a lot of CPU time and isn't | ||
| 637 | reliable. | ||
| 638 | |||
| 639 | Answer: Install daemontools (http://pobox.com/~djb/daemontools.html). | ||
| 640 | Make a /var/log/qmail directory, owned by qmaill, mode 2700. Do | ||
| 641 | |||
| 642 | qmail-start ./Mailbox /usr/local/bin/accustamp \ | ||
| 643 | | setuser qmaill /usr/local/bin/cyclog /var/log/qmail & | ||
| 644 | |||
| 645 | in /var/qmail/rc. | ||
| 646 | |||
| 647 | If you are logging tcpserver connections, make a /var/log/smtpd | ||
| 648 | directory, and use cyclog /var/log/smtpd for tcpserver. You shouldn't | ||
| 649 | run several copies of cyclog with the same log directory. | ||
| 650 | |||
| 651 | By default, cyclog keeps 10 automatically rotated log files, each | ||
| 652 | containing up to 100KB of log data. To keep 20 files with 1MB each, use | ||
| 653 | cyclog -s 1000000 -n 20. | ||
| 654 | |||
| 655 | |||
| 656 | |||
| 657 | 8. Miscellany | ||
| 658 | |||
| 659 | |||
| 660 | 8.1. How do I tell qmail to do more deliveries at once? It's running | ||
| 661 | only 20 parallel qmail-remote processes. | ||
| 662 | |||
| 663 | Answer: Decide how many deliveries you want to allow at once. Put that | ||
| 664 | number into control/concurrencyremote. Restart qmail-send as in question | ||
| 665 | 7.1. If your system has resource limits, make sure you set the | ||
| 666 | descriptors limit to at least double the concurrency plus 5; otherwise | ||
| 667 | you'll get lots of unnecessary deferrals whenever a big burst of mail | ||
| 668 | shows up. Note that qmail also imposes a compile-time concurrency limit, | ||
| 669 | 120 by default; this is set in conf-spawn. | ||
| 670 | |||
| 671 | |||
| 672 | 8.2. How do I keep a copy of all incoming and outgoing mail messages? | ||
| 673 | |||
| 674 | Answer: Set QUEUE_EXTRA to "Tlog\0" and QUEUE_EXTRALEN to 5 in extra.h. | ||
| 675 | Recompile qmail. Put ./msg-log into ~alias/.qmail-log. | ||
| 676 | |||
| 677 | You can also use QUEUE_EXTRA to, e.g., record the Message-ID of every | ||
| 678 | message: run | ||
| 679 | |||
| 680 | | awk '/^$/ { exit } /^[mM][eE][sS][sS][aA][gG][eE]-/ { print }' | ||
| 681 | |||
| 682 | from ~alias/.qmail-log. | ||
| 683 | |||
| 684 | |||
| 685 | 8.3. How do I switch slowly from sendmail to qmail? I'm thinking of | ||
| 686 | moving the heaven.af.mil network over to qmail, but first I'd like to | ||
| 687 | give my users a chance to try out qmail without affecting current | ||
| 688 | sendmail deliveries. We're using NFS. | ||
| 689 | |||
| 690 | Answer: Find a host in your network, say pc.heaven.af.mil, that isn't | ||
| 691 | running an SMTP server. (If addresses at pc.heaven.af.mil are used, you | ||
| 692 | should already have an MX pointing pc.heaven.af.mil to your mail hub.) | ||
| 693 | |||
| 694 | Set up a new MX record pointing lists.heaven.af.mil to pc.heaven.af.mil. | ||
| 695 | Install qmail on pc.heaven.af.mil. Replace pc with lists in the control | ||
| 696 | files. Make the qmail man pages available on all your machines. | ||
| 697 | |||
| 698 | Now tell your users about qmail. A user can forward joe@heaven.af.mil to | ||
| 699 | joe@lists.heaven.af.mil to get ~/Mailbox delivery; he can set up .qmail | ||
| 700 | files; he can start running his own mailing lists @lists.heaven.af.mil. | ||
| 701 | |||
| 702 | When you're ready to turn sendmail off, you can set up pc.heaven.af.mil | ||
| 703 | as your new mail hub. Add heaven.af.mil to control/locals, and change | ||
| 704 | the heaven.af.mil MX to point to pc.heaven.af.mil. Make sure you leave | ||
| 705 | lists.heaven.af.mil in control/locals so that transition addresses will | ||
| 706 | continue to work. | ||
| @@ -0,0 +1,433 @@ | |||
| 1 | BLURB | ||
| 2 | BLURB2 | ||
| 3 | BLURB3 | ||
| 4 | BLURB4 | ||
| 5 | README | ||
| 6 | FAQ | ||
| 7 | INSTALL | ||
| 8 | INSTALL.alias | ||
| 9 | INSTALL.ctl | ||
| 10 | INSTALL.ids | ||
| 11 | INSTALL.maildir | ||
| 12 | INSTALL.mbox | ||
| 13 | INSTALL.vsm | ||
| 14 | REMOVE.sendmail | ||
| 15 | REMOVE.binmail | ||
| 16 | TEST.deliver | ||
| 17 | TEST.receive | ||
| 18 | UPGRADE | ||
| 19 | THOUGHTS | ||
| 20 | TODO | ||
| 21 | THANKS | ||
| 22 | CHANGES | ||
| 23 | SECURITY | ||
| 24 | INTERNALS | ||
| 25 | SENDMAIL | ||
| 26 | PIC.local2alias | ||
| 27 | PIC.local2ext | ||
| 28 | PIC.local2local | ||
| 29 | PIC.local2rem | ||
| 30 | PIC.local2virt | ||
| 31 | PIC.nullclient | ||
| 32 | PIC.relaybad | ||
| 33 | PIC.relaygood | ||
| 34 | PIC.rem2local | ||
| 35 | FILES | ||
| 36 | VERSION | ||
| 37 | SYSDEPS | ||
| 38 | TARGETS | ||
| 39 | Makefile | ||
| 40 | BIN.README | ||
| 41 | BIN.Makefile | ||
| 42 | idedit.c | ||
| 43 | conf-break | ||
| 44 | auto_break.h | ||
| 45 | conf-spawn | ||
| 46 | auto_spawn.h | ||
| 47 | chkspawn.c | ||
| 48 | conf-split | ||
| 49 | auto_split.h | ||
| 50 | conf-patrn | ||
| 51 | auto_patrn.h | ||
| 52 | conf-users | ||
| 53 | conf-groups | ||
| 54 | auto_uids.h | ||
| 55 | auto_usera.h | ||
| 56 | extra.h | ||
| 57 | addresses.5 | ||
| 58 | except.1 | ||
| 59 | bouncesaying.1 | ||
| 60 | condredirect.1 | ||
| 61 | dot-qmail.9 | ||
| 62 | envelopes.5 | ||
| 63 | forgeries.7 | ||
| 64 | forward.1 | ||
| 65 | maildir2mbox.1 | ||
| 66 | maildirmake.1 | ||
| 67 | maildirwatch.1 | ||
| 68 | mailsubj.1 | ||
| 69 | mbox.5 | ||
| 70 | preline.1 | ||
| 71 | qbiff.1 | ||
| 72 | qmail-clean.8 | ||
| 73 | qmail-command.8 | ||
| 74 | qmail-control.9 | ||
| 75 | qmail-getpw.9 | ||
| 76 | qmail-header.5 | ||
| 77 | qmail-inject.8 | ||
| 78 | qmail-limits.9 | ||
| 79 | qmail-local.8 | ||
| 80 | qmail-log.5 | ||
| 81 | qmail-lspawn.8 | ||
| 82 | qmail-newmrh.9 | ||
| 83 | qmail-newu.9 | ||
| 84 | qmail-pop3d.8 | ||
| 85 | qmail-popup.8 | ||
| 86 | qmail-pw2u.9 | ||
| 87 | qmail-qmqpc.8 | ||
| 88 | qmail-qmqpd.8 | ||
| 89 | qmail-qmtpd.8 | ||
| 90 | qmail-qread.8 | ||
| 91 | qmail-qstat.8 | ||
| 92 | qmail-queue.8 | ||
| 93 | qmail-remote.8 | ||
| 94 | qmail-rspawn.8 | ||
| 95 | qmail-send.9 | ||
| 96 | qmail-showctl.8 | ||
| 97 | qmail-smtpd.8 | ||
| 98 | qmail-start.9 | ||
| 99 | qmail-tcpok.8 | ||
| 100 | qmail-tcpto.8 | ||
| 101 | qmail-users.9 | ||
| 102 | qmail.7 | ||
| 103 | qreceipt.1 | ||
| 104 | splogger.8 | ||
| 105 | tcp-env.1 | ||
| 106 | config.sh | ||
| 107 | config-fast.sh | ||
| 108 | qmail-clean.c | ||
| 109 | qmail-getpw.c | ||
| 110 | qmail-inject.c | ||
| 111 | qmail-local.c | ||
| 112 | qmail-lspawn.c | ||
| 113 | qmail-newmrh.c | ||
| 114 | qmail-newu.c | ||
| 115 | qmail-pop3d.c | ||
| 116 | qmail-popup.c | ||
| 117 | qmail-pw2u.c | ||
| 118 | qmail-qmqpc.c | ||
| 119 | qmail-qmqpd.c | ||
| 120 | qmail-qmtpd.c | ||
| 121 | qmail-qread.c | ||
| 122 | qmail-qstat.sh | ||
| 123 | qmail-queue.c | ||
| 124 | qmail-remote.c | ||
| 125 | qmail-rspawn.c | ||
| 126 | qmail-send.c | ||
| 127 | qmail-showctl.c | ||
| 128 | qmail-smtpd.c | ||
| 129 | qmail-start.c | ||
| 130 | qmail-tcpok.c | ||
| 131 | qmail-tcpto.c | ||
| 132 | spawn.c | ||
| 133 | dnscname.c | ||
| 134 | dnsfq.c | ||
| 135 | dnsip.c | ||
| 136 | dnsmxip.c | ||
| 137 | dnsptr.c | ||
| 138 | hostname.c | ||
| 139 | ipmeprint.c | ||
| 140 | tcp-env.c | ||
| 141 | sendmail.c | ||
| 142 | qreceipt.c | ||
| 143 | qsmhook.c | ||
| 144 | qbiff.c | ||
| 145 | forward.c | ||
| 146 | preline.c | ||
| 147 | predate.c | ||
| 148 | except.c | ||
| 149 | bouncesaying.c | ||
| 150 | condredirect.c | ||
| 151 | maildirmake.c | ||
| 152 | maildir2mbox.c | ||
| 153 | maildirwatch.c | ||
| 154 | splogger.c | ||
| 155 | qail.sh | ||
| 156 | elq.sh | ||
| 157 | pinq.sh | ||
| 158 | qmail-upq.sh | ||
| 159 | datemail.sh | ||
| 160 | mailsubj.sh | ||
| 161 | qlx.h | ||
| 162 | rcpthosts.h | ||
| 163 | rcpthosts.c | ||
| 164 | commands.h | ||
| 165 | commands.c | ||
| 166 | dnsdoe.h | ||
| 167 | dnsdoe.c | ||
| 168 | fmtqfn.h | ||
| 169 | fmtqfn.c | ||
| 170 | gfrom.h | ||
| 171 | gfrom.c | ||
| 172 | myctime.h | ||
| 173 | myctime.c | ||
| 174 | newfield.h | ||
| 175 | newfield.c | ||
| 176 | qsutil.h | ||
| 177 | qsutil.c | ||
| 178 | readsubdir.h | ||
| 179 | readsubdir.c | ||
| 180 | received.h | ||
| 181 | received.c | ||
| 182 | tcpto.h | ||
| 183 | tcpto.c | ||
| 184 | tcpto_clean.c | ||
| 185 | trigger.h | ||
| 186 | trigger.c | ||
| 187 | triggerpull.h | ||
| 188 | triggerpull.c | ||
| 189 | trynpbg1.c | ||
| 190 | trysyslog.c | ||
| 191 | conf-cc | ||
| 192 | conf-ld | ||
| 193 | home.sh | ||
| 194 | home+df.sh | ||
| 195 | proc.sh | ||
| 196 | proc+df.sh | ||
| 197 | binm1.sh | ||
| 198 | binm2.sh | ||
| 199 | binm3.sh | ||
| 200 | binm1+df.sh | ||
| 201 | binm2+df.sh | ||
| 202 | binm3+df.sh | ||
| 203 | find-systype.sh | ||
| 204 | make-compile.sh | ||
| 205 | make-load.sh | ||
| 206 | make-makelib.sh | ||
| 207 | trycpp.c | ||
| 208 | warn-auto.sh | ||
| 209 | auto-str.c | ||
| 210 | auto-int.c | ||
| 211 | auto-int8.c | ||
| 212 | auto-gid.c | ||
| 213 | auto-uid.c | ||
| 214 | hier.c | ||
| 215 | install.c | ||
| 216 | instcheck.c | ||
| 217 | install-big.c | ||
| 218 | alloc.3 | ||
| 219 | alloc.h | ||
| 220 | alloc.c | ||
| 221 | alloc_re.c | ||
| 222 | case.3 | ||
| 223 | case.h | ||
| 224 | case_diffb.c | ||
| 225 | case_diffs.c | ||
| 226 | case_lowerb.c | ||
| 227 | case_lowers.c | ||
| 228 | case_starts.c | ||
| 229 | cdb.3 | ||
| 230 | cdb.h | ||
| 231 | cdb_hash.c | ||
| 232 | cdb_seek.c | ||
| 233 | cdb_unpack.c | ||
| 234 | cdbmake.h | ||
| 235 | cdbmake_add.c | ||
| 236 | cdbmake_hash.c | ||
| 237 | cdbmake_pack.c | ||
| 238 | cdbmss.h | ||
| 239 | cdbmss.c | ||
| 240 | coe.3 | ||
| 241 | coe.h | ||
| 242 | coe.c | ||
| 243 | fd.h | ||
| 244 | fd_copy.3 | ||
| 245 | fd_copy.c | ||
| 246 | fd_move.3 | ||
| 247 | fd_move.c | ||
| 248 | fifo_make.3 | ||
| 249 | fifo.h | ||
| 250 | fifo.c | ||
| 251 | trymkffo.c | ||
| 252 | fork.h1 | ||
| 253 | fork.h2 | ||
| 254 | tryvfork.c | ||
| 255 | now.3 | ||
| 256 | now.h | ||
| 257 | now.c | ||
| 258 | open.h | ||
| 259 | open_append.c | ||
| 260 | open_excl.c | ||
| 261 | open_read.c | ||
| 262 | open_trunc.c | ||
| 263 | open_write.c | ||
| 264 | seek.h | ||
| 265 | seek_cur.c | ||
| 266 | seek_end.c | ||
| 267 | seek_set.c | ||
| 268 | seek_trunc.c | ||
| 269 | conf-qmail | ||
| 270 | auto_qmail.h | ||
| 271 | qmail.h | ||
| 272 | qmail.c | ||
| 273 | gen_alloc.h | ||
| 274 | gen_allocdefs.h | ||
| 275 | stralloc.3 | ||
| 276 | stralloc.h | ||
| 277 | stralloc_eady.c | ||
| 278 | stralloc_pend.c | ||
| 279 | stralloc_copy.c | ||
| 280 | stralloc_opyb.c | ||
| 281 | stralloc_opys.c | ||
| 282 | stralloc_cat.c | ||
| 283 | stralloc_catb.c | ||
| 284 | stralloc_cats.c | ||
| 285 | stralloc_arts.c | ||
| 286 | strerr.h | ||
| 287 | strerr_sys.c | ||
| 288 | strerr_die.c | ||
| 289 | substdio.h | ||
| 290 | substdio.c | ||
| 291 | substdi.c | ||
| 292 | substdo.c | ||
| 293 | substdio_copy.c | ||
| 294 | subfd.h | ||
| 295 | subfderr.c | ||
| 296 | subfdouts.c | ||
| 297 | subfdout.c | ||
| 298 | subfdins.c | ||
| 299 | subfdin.c | ||
| 300 | readwrite.h | ||
| 301 | exit.h | ||
| 302 | timeoutconn.h | ||
| 303 | timeoutconn.c | ||
| 304 | timeoutread.h | ||
| 305 | timeoutread.c | ||
| 306 | timeoutwrite.h | ||
| 307 | timeoutwrite.c | ||
| 308 | remoteinfo.h | ||
| 309 | remoteinfo.c | ||
| 310 | uint32.h1 | ||
| 311 | uint32.h2 | ||
| 312 | tryulong32.c | ||
| 313 | wait.3 | ||
| 314 | wait.h | ||
| 315 | wait_pid.c | ||
| 316 | wait_nohang.c | ||
| 317 | trywaitp.c | ||
| 318 | sig.h | ||
| 319 | sig_alarm.c | ||
| 320 | sig_block.c | ||
| 321 | sig_catch.c | ||
| 322 | sig_pause.c | ||
| 323 | sig_pipe.c | ||
| 324 | sig_child.c | ||
| 325 | sig_term.c | ||
| 326 | sig_hup.c | ||
| 327 | sig_misc.c | ||
| 328 | sig_bug.c | ||
| 329 | trysgact.c | ||
| 330 | trysgprm.c | ||
| 331 | env.3 | ||
| 332 | env.h | ||
| 333 | env.c | ||
| 334 | envread.c | ||
| 335 | byte.h | ||
| 336 | byte_chr.c | ||
| 337 | byte_copy.c | ||
| 338 | byte_cr.c | ||
| 339 | byte_diff.c | ||
| 340 | byte_rchr.c | ||
| 341 | byte_zero.c | ||
| 342 | str.h | ||
| 343 | str_chr.c | ||
| 344 | str_cpy.c | ||
| 345 | str_diff.c | ||
| 346 | str_diffn.c | ||
| 347 | str_len.c | ||
| 348 | str_rchr.c | ||
| 349 | str_start.c | ||
| 350 | lock.h | ||
| 351 | lock_ex.c | ||
| 352 | lock_exnb.c | ||
| 353 | lock_un.c | ||
| 354 | tryflock.c | ||
| 355 | getln.3 | ||
| 356 | getln.h | ||
| 357 | getln.c | ||
| 358 | getln2.3 | ||
| 359 | getln2.c | ||
| 360 | sgetopt.3 | ||
| 361 | sgetopt.h | ||
| 362 | sgetopt.c | ||
| 363 | subgetopt.3 | ||
| 364 | subgetopt.h | ||
| 365 | subgetopt.c | ||
| 366 | error.3 | ||
| 367 | error_str.3 | ||
| 368 | error_temp.3 | ||
| 369 | error.h | ||
| 370 | error.c | ||
| 371 | error_str.c | ||
| 372 | error_temp.c | ||
| 373 | fmt.h | ||
| 374 | fmt_str.c | ||
| 375 | fmt_strn.c | ||
| 376 | fmt_uint.c | ||
| 377 | fmt_uint0.c | ||
| 378 | fmt_ulong.c | ||
| 379 | scan.h | ||
| 380 | scan_ulong.c | ||
| 381 | scan_8long.c | ||
| 382 | slurpclose.h | ||
| 383 | slurpclose.c | ||
| 384 | quote.h | ||
| 385 | quote.c | ||
| 386 | hfield.h | ||
| 387 | hfield.c | ||
| 388 | headerbody.h | ||
| 389 | headerbody.c | ||
| 390 | token822.h | ||
| 391 | token822.c | ||
| 392 | control.h | ||
| 393 | control.c | ||
| 394 | datetime.3 | ||
| 395 | datetime.h | ||
| 396 | datetime.c | ||
| 397 | datetime_un.c | ||
| 398 | prioq.h | ||
| 399 | prioq.c | ||
| 400 | date822fmt.h | ||
| 401 | date822fmt.c | ||
| 402 | dns.h | ||
| 403 | dns.c | ||
| 404 | trylsock.c | ||
| 405 | tryrsolv.c | ||
| 406 | ip.h | ||
| 407 | ip.c | ||
| 408 | ipalloc.h | ||
| 409 | ipalloc.c | ||
| 410 | select.h1 | ||
| 411 | select.h2 | ||
| 412 | trysysel.c | ||
| 413 | ndelay.h | ||
| 414 | ndelay.c | ||
| 415 | ndelay_off.c | ||
| 416 | direntry.3 | ||
| 417 | direntry.h1 | ||
| 418 | direntry.h2 | ||
| 419 | trydrent.c | ||
| 420 | prot.h | ||
| 421 | prot.c | ||
| 422 | chkshsgr.c | ||
| 423 | warn-shsgr | ||
| 424 | tryshsgr.c | ||
| 425 | ipme.h | ||
| 426 | ipme.c | ||
| 427 | trysalen.c | ||
| 428 | maildir.5 | ||
| 429 | maildir.h | ||
| 430 | maildir.c | ||
| 431 | tcp-environ.5 | ||
| 432 | constmap.h | ||
| 433 | constmap.c | ||
| @@ -0,0 +1,84 @@ | |||
| 1 | SAVE COPIES OF YOUR OUTGOING MAIL! Like any other piece of software (and | ||
| 2 | information generally), the qmail system comes with NO WARRANTY. It's | ||
| 3 | much more secure and reliable than sendmail, but that's not saying much. | ||
| 4 | |||
| 5 | |||
| 6 | Things you have to decide before starting: | ||
| 7 | |||
| 8 | * The qmail home directory, normally /var/qmail. To change this | ||
| 9 | directory, edit conf-qmail now. | ||
| 10 | |||
| 11 | * The names of the qmail users and the qmail groups. To change these | ||
| 12 | names, edit conf-users and conf-groups now. | ||
| 13 | |||
| 14 | |||
| 15 | To create /var/qmail and configure qmail (won't interfere with sendmail): | ||
| 16 | |||
| 17 | 1. Create the qmail home directory: | ||
| 18 | # mkdir /var/qmail | ||
| 19 | |||
| 20 | 2. Read INSTALL.ids. You must set up the qmail group and the qmail | ||
| 21 | users before compiling the programs. | ||
| 22 | |||
| 23 | 3. Compile the programs and create the qmail directory tree: | ||
| 24 | # make setup check | ||
| 25 | |||
| 26 | 4. Read INSTALL.ctl and FAQ. Minimal survival command: | ||
| 27 | # ./config | ||
| 28 | |||
| 29 | 5. Read INSTALL.alias. Minimal survival command: | ||
| 30 | # (cd ~alias; touch .qmail-postmaster .qmail-mailer-daemon .qmail-root) | ||
| 31 | # chmod 644 ~alias/.qmail* | ||
| 32 | |||
| 33 | 6. Read INSTALL.mbox and INSTALL.vsm. | ||
| 34 | |||
| 35 | 7. Read INSTALL.maildir. | ||
| 36 | |||
| 37 | 8. Copy /var/qmail/boot/home (or proc) to /var/qmail/rc. | ||
| 38 | |||
| 39 | |||
| 40 | To test qmail deliveries (won't interfere with sendmail): | ||
| 41 | |||
| 42 | 9. Enable deliveries of messages injected into qmail: | ||
| 43 | # csh -cf '/var/qmail/rc &' | ||
| 44 | |||
| 45 | 10. Read TEST.deliver. | ||
| 46 | |||
| 47 | |||
| 48 | To upgrade from sendmail to qmail: | ||
| 49 | |||
| 50 | 11. Read SENDMAIL. This is what your users will want to know about the | ||
| 51 | switch from sendmail to qmail. | ||
| 52 | |||
| 53 | 12. Read REMOVE.sendmail. You must remove sendmail before installing | ||
| 54 | qmail. | ||
| 55 | |||
| 56 | 13. Read REMOVE.binmail. | ||
| 57 | |||
| 58 | 14. Add | ||
| 59 | csh -cf '/var/qmail/rc &' | ||
| 60 | to your boot scripts, so that the qmail daemons are restarted | ||
| 61 | whenever your system reboots. Make sure you include the &. | ||
| 62 | |||
| 63 | 15. Make qmail's ``sendmail'' wrapper available to MUAs: | ||
| 64 | # ln -s /var/qmail/bin/sendmail /usr/lib/sendmail | ||
| 65 | # ln -s /var/qmail/bin/sendmail /usr/sbin/sendmail | ||
| 66 | /usr/sbin might not exist on your system. | ||
| 67 | |||
| 68 | 16. Set up qmail-smtpd in /etc/inetd.conf (all on one line): | ||
| 69 | smtp stream tcp nowait qmaild /var/qmail/bin/tcp-env | ||
| 70 | tcp-env /var/qmail/bin/qmail-smtpd | ||
| 71 | |||
| 72 | 17. Reboot. (Or kill -HUP your inetd and make sure the qmail daemons | ||
| 73 | are running.) | ||
| 74 | |||
| 75 | 18. Read TEST.receive. | ||
| 76 | |||
| 77 | |||
| 78 | |||
| 79 | That's it! To report success: | ||
| 80 | % ( echo 'First M. Last'; cat `cat SYSDEPS` ) | mail djb-qst@cr.yp.to | ||
| 81 | Replace First M. Last with your name. | ||
| 82 | |||
| 83 | If you have questions about qmail, join the qmail mailing list; see | ||
| 84 | http://pobox.com/~djb/qmail.html. | ||
diff --git a/INSTALL.alias b/INSTALL.alias new file mode 100644 index 0000000..672365a --- /dev/null +++ b/INSTALL.alias | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | qmail lets each user control all addresses of the form user-anything. | ||
| 2 | Addresses that don't start with a username are controlled by a special | ||
| 3 | user, alias. Delivery instructions for foo go into ~alias/.qmail-foo; | ||
| 4 | delivery instructions for user-foo go into ~user/.qmail-foo. See | ||
| 5 | dot-qmail.0 for the full story. | ||
| 6 | |||
| 7 | qmail doesn't have any built-in support for /etc/aliases. If you have a | ||
| 8 | big /etc/aliases and you'd like to keep it, install the fastforward | ||
| 9 | package, available separately. /etc/aliases should already include the | ||
| 10 | aliases discussed below---Postmaster, MAILER-DAEMON, and root. | ||
| 11 | |||
| 12 | If you don't have a big /etc/aliases, you'll find it easier to use | ||
| 13 | qmail's native alias mechanism. Here's a checklist of aliases you should | ||
| 14 | set up right now. | ||
| 15 | |||
| 16 | * Postmaster. You're not an Internet citizen if this address doesn't | ||
| 17 | work. Simply touch (and chmod 644) ~alias/.qmail-postmaster; any mail | ||
| 18 | for Postmaster will be delivered to ~alias/Mailbox. | ||
| 19 | |||
| 20 | * MAILER-DAEMON. Not required, but users sometimes respond to bounce | ||
| 21 | messages. Touch (and chmod 644) ~alias/.qmail-mailer-daemon. | ||
| 22 | |||
| 23 | * root. Under qmail, root never receives mail. Your system may generate | ||
| 24 | mail messages to root every night; if you don't have an alias for root, | ||
| 25 | those messages will bounce. (They'll end up double-bouncing to the | ||
| 26 | postmaster.) Set up an alias for root in ~alias/.qmail-root. .qmail | ||
| 27 | files are similar to .forward files, but beware that they are strictly | ||
| 28 | line-oriented---see dot-qmail.0 for details. | ||
| 29 | |||
| 30 | * Other non-user accounts. Under qmail, non-user accounts don't get | ||
| 31 | mail; ``user'' means a non-root account that owns ~account. Set up | ||
| 32 | aliases for any non-user accounts that normally receive mail. | ||
| 33 | |||
| 34 | Note that special accounts such as ftp, www, and uucp should always have | ||
| 35 | home directories owned by root. | ||
| 36 | |||
| 37 | * Default. If you want, you can touch ~alias/.qmail-default to catch | ||
| 38 | everything else. Beware: this will also catch typos and other addresses | ||
| 39 | that should probably be bounced instead. It won't catch addresses that | ||
| 40 | start with a user name---the user can set up his own ~/.qmail-default. | ||
diff --git a/INSTALL.ctl b/INSTALL.ctl new file mode 100644 index 0000000..00ce689 --- /dev/null +++ b/INSTALL.ctl | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | As you've seen, qmail has essentially no pre-compilation configuration. | ||
| 2 | You should never have to recompile it unless you want to change the | ||
| 3 | qmail home directory, usernames, or uids. | ||
| 4 | |||
| 5 | qmail does allow quite a bit of easy post-installation configuration. If | ||
| 6 | you care how your machine greets other machines via SMTP, for example, | ||
| 7 | you can put an appropriate line into /var/qmail/control/smtpgreeting. | ||
| 8 | |||
| 9 | But this is all optional---if control/smtpgreeting doesn't exist, qmail | ||
| 10 | will do something reasonable by default. You shouldn't worry much about | ||
| 11 | configuration right now. You can always come back and tune things later. | ||
| 12 | |||
| 13 | There's one big exception. You MUST tell qmail your hostname. Just run | ||
| 14 | the config-fast script: | ||
| 15 | |||
| 16 | # ./config-fast your.full.host.name | ||
| 17 | |||
| 18 | config-fast puts your.full.host.name into control/me. It also puts it | ||
| 19 | into control/locals and control/rcpthosts, so that qmail will accept | ||
| 20 | mail for your.full.host.name. | ||
| 21 | |||
| 22 | You can instead use the config script, which looks up your host name in | ||
| 23 | DNS: | ||
| 24 | |||
| 25 | # ./config | ||
| 26 | |||
| 27 | config also looks up your local IP addresses in DNS to decide which | ||
| 28 | hosts to accept mail for. | ||
| 29 | |||
| 30 | (Why doesn't qmail do these lookups on the fly? This was a deliberate | ||
| 31 | design decision. qmail does all its local functions---header rewriting, | ||
| 32 | checking if a recipient is local, etc.---without talking to the network. | ||
| 33 | The point is that qmail can continue accepting and delivering local mail | ||
| 34 | even if your network connection goes down.) | ||
| 35 | |||
| 36 | Next, read through FAQ for information on setting up optional features | ||
| 37 | like masquerading. If you really want to learn right now what all the | ||
| 38 | configuration possibilities are, see qmail-control.0. | ||
diff --git a/INSTALL.ids b/INSTALL.ids new file mode 100644 index 0000000..a50e10d --- /dev/null +++ b/INSTALL.ids | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | Here's how to set up the qmail groups and the qmail users. | ||
| 2 | |||
| 3 | On some systems there are commands that make this easy. Solaris and | ||
| 4 | Linux: | ||
| 5 | |||
| 6 | # groupadd nofiles | ||
| 7 | # useradd -g nofiles -d /var/qmail/alias alias | ||
| 8 | # useradd -g nofiles -d /var/qmail qmaild | ||
| 9 | # useradd -g nofiles -d /var/qmail qmaill | ||
| 10 | # useradd -g nofiles -d /var/qmail qmailp | ||
| 11 | # groupadd qmail | ||
| 12 | # useradd -g qmail -d /var/qmail qmailq | ||
| 13 | # useradd -g qmail -d /var/qmail qmailr | ||
| 14 | # useradd -g qmail -d /var/qmail qmails | ||
| 15 | |||
| 16 | FreeBSD 2.2: | ||
| 17 | |||
| 18 | # pw groupadd nofiles | ||
| 19 | # pw useradd alias -g nofiles -d /var/qmail/alias -s /nonexistent | ||
| 20 | # pw useradd qmaild -g nofiles -d /var/qmail -s /nonexistent | ||
| 21 | # pw useradd qmaill -g nofiles -d /var/qmail -s /nonexistent | ||
| 22 | # pw useradd qmailp -g nofiles -d /var/qmail -s /nonexistent | ||
| 23 | # pw groupadd qmail | ||
| 24 | # pw useradd qmailq -g qmail -d /var/qmail -s /nonexistent | ||
| 25 | # pw useradd qmailr -g qmail -d /var/qmail -s /nonexistent | ||
| 26 | # pw useradd qmails -g qmail -d /var/qmail -s /nonexistent | ||
| 27 | |||
| 28 | BSDI 2.0: | ||
| 29 | |||
| 30 | # addgroup nofiles | ||
| 31 | # adduser -g nofiles -H/var/qmail/alias -G,,, -s/dev/null -P'*' alias | ||
| 32 | # adduser -g nofiles -H/var/qmail -G,,, -s/dev/null -P'*' qmaild | ||
| 33 | # adduser -g nofiles -H/var/qmail -G,,, -s/dev/null -P'*' qmaill | ||
| 34 | # adduser -g nofiles -H/var/qmail -G,,, -s/dev/null -P'*' qmailp | ||
| 35 | # addgroup qmail | ||
| 36 | # adduser -g qmail -H/var/qmail -G,,, -s/dev/null -P'*' qmailq | ||
| 37 | # adduser -g qmail -H/var/qmail -G,,, -s/dev/null -P'*' qmailr | ||
| 38 | # adduser -g qmail -H/var/qmail -G,,, -s/dev/null -P'*' qmails | ||
| 39 | |||
| 40 | AIX: | ||
| 41 | |||
| 42 | # mkgroup -A nofiles | ||
| 43 | # mkuser pgrp=nofiles home=/var/qmail/alias shell=/bin/true alias | ||
| 44 | # mkuser pgrp=nofiles home=/var/qmail shell=/bin/true qmaild | ||
| 45 | # mkuser pgrp=nofiles home=/var/qmail shell=/bin/true qmaill | ||
| 46 | # mkuser pgrp=nofiles home=/var/qmail shell=/bin/true qmailp | ||
| 47 | # mkgroup -A qmail | ||
| 48 | # mkuser pgrp=qmail home=/var/qmail shell=/bin/true qmailq | ||
| 49 | # mkuser pgrp=qmail home=/var/qmail shell=/bin/true qmailr | ||
| 50 | # mkuser pgrp=qmail home=/var/qmail shell=/bin/true qmails | ||
| 51 | |||
| 52 | On other systems, you will have to edit /etc/group and /etc/passwd | ||
| 53 | manually. First add two new lines to /etc/group, something like | ||
| 54 | |||
| 55 | qmail:*:2107: | ||
| 56 | nofiles:*:2108: | ||
| 57 | |||
| 58 | where 2107 and 2108 are different from the other gids in /etc/group. | ||
| 59 | Next (using vipw) add six new lines to /etc/passwd, something like | ||
| 60 | |||
| 61 | alias:*:7790:2108::/var/qmail/alias:/bin/true | ||
| 62 | qmaild:*:7791:2108::/var/qmail:/bin/true | ||
| 63 | qmaill:*:7792:2108::/var/qmail:/bin/true | ||
| 64 | qmailp:*:7793:2108::/var/qmail:/bin/true | ||
| 65 | qmailq:*:7794:2107::/var/qmail:/bin/true | ||
| 66 | qmailr:*:7795:2107::/var/qmail:/bin/true | ||
| 67 | qmails:*:7796:2107::/var/qmail:/bin/true | ||
| 68 | |||
| 69 | where 7790 through 7796 are _new_ uids, 2107 is the qmail gid, and 2108 | ||
| 70 | is the nofiles gid. Make sure you use the nofiles gid for qmaild, | ||
| 71 | qmaill, qmailp, and alias, and the qmail gid for qmailq, qmailr, and | ||
| 72 | qmails. | ||
diff --git a/INSTALL.maildir b/INSTALL.maildir new file mode 100644 index 0000000..72373aa --- /dev/null +++ b/INSTALL.maildir | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | This file points out some reasons that you might want to switch from | ||
| 2 | mbox format to a new format, maildir. | ||
| 3 | |||
| 4 | |||
| 5 | 1. The trouble with mbox | ||
| 6 | |||
| 7 | The mbox format---the format of ~user/Mailbox, understood by BSD Mail | ||
| 8 | and lots of other MUAs---is inherently unreliable. | ||
| 9 | |||
| 10 | Think about it: what happens if the system crashes while a program is | ||
| 11 | appending a new message to ~user/Mailbox? The message will be truncated. | ||
| 12 | Even worse, if it was truncated in the middle of a line, it will end up | ||
| 13 | being merged with the next message! Sure, the mailer understands that it | ||
| 14 | wasn't successful, so it'll try delivering the message again later, but | ||
| 15 | it can't fix your corrupted mbox. | ||
| 16 | |||
| 17 | Other formats, such as mh folders, are just as unreliable. | ||
| 18 | |||
| 19 | qmail supports maildir, a crashproof format for incoming mail messages. | ||
| 20 | maildir is fast and easy for MUAs to use. Even better, maildir works | ||
| 21 | wonders over NFS---see below. | ||
| 22 | |||
| 23 | I don't want to cram maildir down people's throats, so it's not the | ||
| 24 | default. Nevertheless, I encourage you to start asking for maildir | ||
| 25 | versions of your favorite MUAs, and to switch over to maildir as soon as | ||
| 26 | you can. | ||
| 27 | |||
| 28 | |||
| 29 | 2. Sun's Network F_ail_u_re System | ||
| 30 | |||
| 31 | Anyone who tells you that mail can be safely delivered in mbox format | ||
| 32 | over NFS is pulling your leg---as explained above, mbox format is | ||
| 33 | inherently unreliable even on a single machine. | ||
| 34 | |||
| 35 | Anyway, NFS is the most unreliable computing environment ever invented, | ||
| 36 | and qmail doesn't even pretend to support mbox over NFS. | ||
| 37 | |||
| 38 | You should switch to maildir, which works fine over NFS without any | ||
| 39 | locking. You can safely read your mail over NFS if it's in maildir | ||
| 40 | format. Any number of machines can deliver mail to you at the same time. | ||
| 41 | (On the other hand, for efficiency, it's better to get NFS out of the | ||
| 42 | picture---your mail should be delivered on the server that contains your | ||
| 43 | home directory.) | ||
| 44 | |||
| 45 | Here's how to set up qmail to use maildir for your incoming mail: | ||
| 46 | |||
| 47 | % maildirmake $HOME/Maildir | ||
| 48 | % echo ./Maildir/ > ~/.qmail | ||
| 49 | |||
| 50 | Make sure you include the trailing slash on Maildir/. | ||
| 51 | |||
| 52 | The system administrator can set up Maildir as the default for everybody | ||
| 53 | by creating a maildir in the new-user template directory and replacing | ||
| 54 | ./Mailbox with ./Maildir/ in /var/qmail/rc. | ||
| 55 | |||
| 56 | Until your MUA supports maildir, you'll probably want to convert maildir | ||
| 57 | format to (gaaack) mbox format. I've supplied a maildir2mbox utility | ||
| 58 | that does the trick, along with some tiny qail and elq and pinq wrappers | ||
| 59 | that call maildir2mbox before calling Mail or elm or pine. | ||
diff --git a/INSTALL.mbox b/INSTALL.mbox new file mode 100644 index 0000000..93ca16c --- /dev/null +++ b/INSTALL.mbox | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | The qmail package includes a local delivery agent, qmail-local, which | ||
| 2 | provides user-controlled mailing lists, cross-host alias loop detection, | ||
| 3 | and many other important qmail features. | ||
| 4 | |||
| 5 | There's one important difference between qmail-local and binmail: | ||
| 6 | qmail-local delivers mail by default into ~user/Mailbox, rather than | ||
| 7 | /var/spool/mail/user. It uses mbox format, with lockf locking on systems | ||
| 8 | that don't have flock (HP/UX, Solaris), and flock locking otherwise. | ||
| 9 | |||
| 10 | This file explains how to switch your system to ~user/Mailbox. You | ||
| 11 | aren't required to do this; for further discussion of /var/spool/mail, | ||
| 12 | and an explanation of how to continue using binmail for local | ||
| 13 | deliveries, see INSTALL.vsm. | ||
| 14 | |||
| 15 | The basic procedure for switching to ~user/Mailbox is simple: | ||
| 16 | |||
| 17 | * Move each /var/spool/mail/user to ~user/Mailbox. For safety, do | ||
| 18 | this in single-user mode. | ||
| 19 | |||
| 20 | * As root, set up a symbolic link from /var/spool/mail/user to | ||
| 21 | ~user/Mailbox for each user. /var/spool/mail should be mode 1777, | ||
| 22 | so users will not be able to accidentally remove these links. | ||
| 23 | |||
| 24 | A few mail programs are unable to handle symbolic links, so you will | ||
| 25 | have to configure them to look at ~user/Mailbox directly: | ||
| 26 | |||
| 27 | * procmail: Change SYSTEM_MBOX in config.h and recompile; or, with | ||
| 28 | recent versions, define MAILSPOOLHOME in src/authenticate.c. | ||
| 29 | |||
| 30 | An alternative to symbolic links is hlfsd. Consult the documentation for | ||
| 31 | hlfsd if it is included in your operating system. | ||
| 32 | |||
| 33 | If /var/spool/mail is large, you can gain extra speed by configuring | ||
| 34 | all your mail software to look at ~user/Mailbox directly: | ||
| 35 | |||
| 36 | * Most MUAs: Put ``setenv MAIL $HOME/Mailbox'' in your system-wide | ||
| 37 | .cshrc and ``MAIL=$HOME/Mailbox; export MAIL'' in your system-wide | ||
| 38 | .profile. | ||
| 39 | |||
| 40 | * elm: Change "mailbox" to "Mailbox" around line 388 of newmbox.c and | ||
| 41 | recompile. (elm looks at $MAIL, but without this change elm will | ||
| 42 | fail if two users try to read mail simultaneously.) | ||
| 43 | |||
| 44 | * pine: Put ``inbox-path=Mailbox'' in your system-wide pine.conf. | ||
| 45 | (For pine versions more recent than 3.91, see also FAQ 6.2.) | ||
| 46 | |||
| 47 | * qpopper 2.2: Change /.mail to /Mailbox in pop_dropcopy.c and | ||
| 48 | recompile with -DHOMEDIRMAIL in CFLAGS. | ||
| 49 | |||
| 50 | Some vendors, in a misguided attempt to solve the security problems of | ||
| 51 | /var/spool/mail, have made all their mail software setgid mail. After | ||
| 52 | you move the mailboxes, you can---and, for security, should---remove | ||
| 53 | those setgid-mail bits. | ||
diff --git a/INSTALL.vsm b/INSTALL.vsm new file mode 100644 index 0000000..cf6a6cc --- /dev/null +++ b/INSTALL.vsm | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | UNIX has traditionally delivered mail into a central spool directory, | ||
| 2 | /var/spool/mail. (The original name was /usr/spool/mail; some systems | ||
| 3 | now use /var/mail.) There are two basic problems with /var/spool/mail: | ||
| 4 | |||
| 5 | * It's slow. On systems with thousands of users, /var/spool/mail has | ||
| 6 | thousands of entries. A few UNIX systems support fast operations on | ||
| 7 | large directories, but most don't. | ||
| 8 | |||
| 9 | * It's insecure. Writing code that works safely in a world-writable | ||
| 10 | directory is not easy. See, for example, CERT advisory 95:02. | ||
| 11 | |||
| 12 | These may not be problems at your site, so you may want to leave your | ||
| 13 | mailboxes in /var/spool/mail. | ||
| 14 | |||
| 15 | This file explains several ways that you can configure qmail to use | ||
| 16 | existing /var/spool/mail delivery tools. Please note that I do not vouch | ||
| 17 | for the security or reliability of any of those tools. | ||
| 18 | |||
| 19 | |||
| 20 | 1. What to configure | ||
| 21 | |||
| 22 | The qmail system is started from /var/qmail/rc with | ||
| 23 | |||
| 24 | qmail-start ./Mailbox splogger qmail | ||
| 25 | |||
| 26 | The first argument to qmail-start, ./Mailbox, is the default delivery | ||
| 27 | instruction. You can change it to run a program such as binmail or | ||
| 28 | procmail. (See dot-qmail.0 for the format of delivery instructions.) | ||
| 29 | |||
| 30 | |||
| 31 | 2. Using procmail | ||
| 32 | |||
| 33 | You may already have installed procmail for mail filtering. procmail | ||
| 34 | delivers to /var/spool/mail by default. | ||
| 35 | |||
| 36 | To set up qmail to use procmail, simply copy /var/qmail/boot/proc to | ||
| 37 | /var/qmail/rc. | ||
| 38 | |||
| 39 | Note that procmail must be in your system's boot PATH; if it isn't, you | ||
| 40 | will have edit /var/qmail/rc to include the full path. | ||
| 41 | |||
| 42 | |||
| 43 | 3. Using sendmail's delivery agent | ||
| 44 | |||
| 45 | sendmail uses binmail to deliver to /var/spool/mail. binmail is shipped | ||
| 46 | with the operating system as /bin/mail or /usr/libexec/mail.local. | ||
| 47 | |||
| 48 | There is some variation in binmail syntax among systems. The most common | ||
| 49 | interfaces are shown in /var/qmail/boot/binm1, /var/qmail/boot/binm2, | ||
| 50 | and /var/qmail/boot/binm3. | ||
diff --git a/INTERNALS b/INTERNALS new file mode 100644 index 0000000..e668ae8 --- /dev/null +++ b/INTERNALS | |||
| @@ -0,0 +1,156 @@ | |||
| 1 | 1. Overview | ||
| 2 | |||
| 3 | Here's the data flow in the qmail suite: | ||
| 4 | |||
| 5 | qmail-smtpd --- qmail-queue --- qmail-send --- qmail-rspawn --- qmail-remote | ||
| 6 | / | \ | ||
| 7 | qmail-inject _/ qmail-clean \_ qmail-lspawn --- qmail-local | ||
| 8 | |||
| 9 | Every message is added to a central queue directory by qmail-queue. | ||
| 10 | qmail-queue is invoked as needed, usually by qmail-inject for locally | ||
| 11 | generated messages, qmail-smtpd for messages received through SMTP, | ||
| 12 | qmail-local for forwarded messages, or qmail-send for bounce messages. | ||
| 13 | |||
| 14 | Every message is then delivered by qmail-send, in cooperation with | ||
| 15 | qmail-lspawn and qmail-rspawn, and cleaned up by qmail-clean. These four | ||
| 16 | programs are long-running daemons. | ||
| 17 | |||
| 18 | The queue is designed to be crashproof, provided that the underlying | ||
| 19 | filesystem is crashproof. All cleanups are handled by qmail-send and | ||
| 20 | qmail-clean without human intervention. See section 6 for more details. | ||
| 21 | |||
| 22 | |||
| 23 | 2. Queue structure | ||
| 24 | |||
| 25 | Each message in the queue is identified by a unique number, let's say | ||
| 26 | 457. The queue is organized into several directories, each of which may | ||
| 27 | contain files related to message 457: | ||
| 28 | |||
| 29 | mess/457: the message | ||
| 30 | todo/457: the envelope: where the message came from, where it's going | ||
| 31 | intd/457: the envelope, under construction by qmail-queue | ||
| 32 | info/457: the envelope sender address, after preprocessing | ||
| 33 | local/457: local envelope recipient addresses, after preprocessing | ||
| 34 | remote/457: remote envelope recipient addresses, after preprocessing | ||
| 35 | bounce/457: permanent delivery errors | ||
| 36 | |||
| 37 | Here are all possible states for a message. + means a file exists; - | ||
| 38 | means it does not exist; ? means it may or may not exist. | ||
| 39 | |||
| 40 | S1. -mess -intd -todo -info -local -remote -bounce | ||
| 41 | S2. +mess -intd -todo -info -local -remote -bounce | ||
| 42 | S3. +mess +intd -todo -info -local -remote -bounce | ||
| 43 | S4. +mess ?intd +todo ?info ?local ?remote -bounce (queued) | ||
| 44 | S5. +mess -intd -todo +info ?local ?remote ?bounce (preprocessed) | ||
| 45 | |||
| 46 | Guarantee: If mess/457 exists, it has inode number 457. | ||
| 47 | |||
| 48 | |||
| 49 | 3. How messages enter the queue | ||
| 50 | |||
| 51 | To add a message to the queue, qmail-queue first creates a file in a | ||
| 52 | separate directory, pid/, with a unique name. The filesystem assigns | ||
| 53 | that file a unique inode number. qmail-queue looks at that number, say | ||
| 54 | 457. By the guarantee above, message 457 must be in state S1. | ||
| 55 | |||
| 56 | qmail-queue renames pid/whatever as mess/457, moving to S2. It writes | ||
| 57 | the message to mess/457. It then creates intd/457, moving to S3, and | ||
| 58 | writes the envelope information to intd/457. | ||
| 59 | |||
| 60 | Finally qmail-queue creates a new link, todo/457, for intd/457, moving | ||
| 61 | to S4. At that instant the message has been successfully queued, and | ||
| 62 | qmail-queue leaves it for further handling by qmail-send. | ||
| 63 | |||
| 64 | qmail-queue starts a 24-hour timer before touching any files, and | ||
| 65 | commits suicide if the timer expires. | ||
| 66 | |||
| 67 | |||
| 68 | 4. How queued messages are preprocessed | ||
| 69 | |||
| 70 | Once a message has been queued, qmail-send must decide which recipients | ||
| 71 | are local and which recipients are remote. It may also rewrite some | ||
| 72 | recipient addresses. | ||
| 73 | |||
| 74 | When qmail-send notices todo/457, it knows that message 457 is in S4. It | ||
| 75 | removes info/457, local/457, and remote/457 if they exist. Then it reads | ||
| 76 | through todo/457. It creates info/457, possibly local/457, and possibly | ||
| 77 | remote/457. When it is done, it removes intd/457. The message is still | ||
| 78 | in S4 at this point. Finally qmail-send removes todo/457, moving to S5. | ||
| 79 | At that instant the message has been successfully preprocessed. | ||
| 80 | |||
| 81 | |||
| 82 | 5. How preprocessed messages are delivered | ||
| 83 | |||
| 84 | Messages at S5 are handled as follows. Each address in local/457 and | ||
| 85 | remote/457 is marked either NOT DONE or DONE. | ||
| 86 | |||
| 87 | DONE: The message was successfully delivered, or the last delivery | ||
| 88 | attempt met with permanent failure. Either way, qmail-send | ||
| 89 | should not attempt further delivery to this address. | ||
| 90 | |||
| 91 | NOT DONE: If there have been any delivery attempts, they have all | ||
| 92 | met with temporary failure. Either way, qmail-send should | ||
| 93 | try delivery in the future. | ||
| 94 | |||
| 95 | qmail-send may at its leisure try to deliver a message to a NOT DONE | ||
| 96 | address. If the message is successfully delivered, qmail-send marks the | ||
| 97 | address as DONE. If the delivery attempt meets with permanent failure, | ||
| 98 | qmail-send first appends a note to bounce/457, creating bounce/457 if | ||
| 99 | necessary; then it marks the address as DONE. Note that bounce/457 is | ||
| 100 | not crashproof. | ||
| 101 | |||
| 102 | qmail-send may handle bounce/457 at any time, as follows: it (1) injects | ||
| 103 | a new bounce message, created from bounce/457 and mess/457; (2) deletes | ||
| 104 | bounce/457. | ||
| 105 | |||
| 106 | When all addresses in local/457 are DONE, qmail-send deletes local/457. | ||
| 107 | Same for remote/457. | ||
| 108 | |||
| 109 | When local/457 and remote/457 are gone, qmail-send eliminates the | ||
| 110 | message, as follows. First, if bounce/457 exists, qmail-send handles it | ||
| 111 | as described above. Once bounce/457 is definitely gone, qmail-send | ||
| 112 | deletes info/457, moving to S2, and finally mess/457, moving to S1. | ||
| 113 | |||
| 114 | |||
| 115 | 6. Cleanups | ||
| 116 | |||
| 117 | If the computer crashes while qmail-queue is trying to queue a message, | ||
| 118 | or while qmail-send is eliminating a message, the message may be left in | ||
| 119 | state S2 or S3. | ||
| 120 | |||
| 121 | When qmail-send sees a message in state S2 or S3---other than one | ||
| 122 | it is currently eliminating!---where mess/457 is more than 36 hours old, | ||
| 123 | it deletes intd/457 if that exists, then deletes mess/457. Note that any | ||
| 124 | qmail-queue handling the message must be dead. | ||
| 125 | |||
| 126 | Similarly, when qmail-send sees a file in the pid/ directory that is | ||
| 127 | more than 36 hours old, it deletes it. | ||
| 128 | |||
| 129 | Cleanups are not necessary if the computer crashes while qmail-send is | ||
| 130 | delivering a message. At worst a message may be delivered twice. (There | ||
| 131 | is no way for a distributed mail system to eliminate the possibility of | ||
| 132 | duplication. What if an SMTP connection is broken just before the server | ||
| 133 | acknowledges successful receipt of the message? The client must assume | ||
| 134 | the worst and send the message again. Similarly, if the computer crashes | ||
| 135 | just before qmail-send marks a message as DONE, the new qmail-send must | ||
| 136 | assume the worst and send the message again. The usual solutions in the | ||
| 137 | database literature---e.g., keeping log files---amount to saying that | ||
| 138 | it's the recipient's computer's job to discard duplicate messages.) | ||
| 139 | |||
| 140 | |||
| 141 | 7. Further notes | ||
| 142 | |||
| 143 | Currently info/457 serves two purposes: first, it records the envelope | ||
| 144 | sender; second, its modification time is used to decide when a message | ||
| 145 | has been in the queue too long. In the future info/457 may store more | ||
| 146 | information. Any non-backwards-compatible changes will be identified by | ||
| 147 | version numbers. | ||
| 148 | |||
| 149 | When qmail-queue has successfully placed a message into the queue, it | ||
| 150 | pulls a trigger offered by qmail-send. Here is the current triggering | ||
| 151 | mechanism: lock/trigger is a named pipe. Before scanning todo/, | ||
| 152 | qmail-send opens lock/trigger O_NDELAY for reading. It then selects for | ||
| 153 | readability on lock/trigger. qmail-queue pulls the trigger by writing a | ||
| 154 | byte O_NDELAY to lock/trigger. This makes lock/trigger readable and | ||
| 155 | wakes up qmail-send. Before scanning todo/ again, qmail-send closes and | ||
| 156 | reopens lock/trigger. | ||
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9230887 --- /dev/null +++ b/Makefile | |||
| @@ -0,0 +1,2141 @@ | |||
| 1 | # Don't edit Makefile! Use conf-* for configuration. | ||
| 2 | |||
| 3 | SHELL=/bin/sh | ||
| 4 | |||
| 5 | default: it | ||
| 6 | |||
| 7 | addresses.0: \ | ||
| 8 | addresses.5 | ||
| 9 | nroff -man addresses.5 > addresses.0 | ||
| 10 | |||
| 11 | alloc.a: \ | ||
| 12 | makelib alloc.o alloc_re.o | ||
| 13 | ./makelib alloc.a alloc.o alloc_re.o | ||
| 14 | |||
| 15 | alloc.o: \ | ||
| 16 | compile alloc.c alloc.h error.h | ||
| 17 | ./compile alloc.c | ||
| 18 | |||
| 19 | alloc_re.o: \ | ||
| 20 | compile alloc_re.c alloc.h byte.h | ||
| 21 | ./compile alloc_re.c | ||
| 22 | |||
| 23 | auto-ccld.sh: \ | ||
| 24 | conf-cc conf-ld warn-auto.sh | ||
| 25 | ( cat warn-auto.sh; \ | ||
| 26 | echo CC=\'`head -1 conf-cc`\'; \ | ||
| 27 | echo LD=\'`head -1 conf-ld`\' \ | ||
| 28 | ) > auto-ccld.sh | ||
| 29 | |||
| 30 | auto-gid: \ | ||
| 31 | load auto-gid.o substdio.a error.a str.a fs.a | ||
| 32 | ./load auto-gid substdio.a error.a str.a fs.a | ||
| 33 | |||
| 34 | auto-gid.o: \ | ||
| 35 | compile auto-gid.c subfd.h substdio.h substdio.h readwrite.h exit.h \ | ||
| 36 | scan.h fmt.h | ||
| 37 | ./compile auto-gid.c | ||
| 38 | |||
| 39 | auto-int: \ | ||
| 40 | load auto-int.o substdio.a error.a str.a fs.a | ||
| 41 | ./load auto-int substdio.a error.a str.a fs.a | ||
| 42 | |||
| 43 | auto-int.o: \ | ||
| 44 | compile auto-int.c substdio.h readwrite.h exit.h scan.h fmt.h | ||
| 45 | ./compile auto-int.c | ||
| 46 | |||
| 47 | auto-int8: \ | ||
| 48 | load auto-int8.o substdio.a error.a str.a fs.a | ||
| 49 | ./load auto-int8 substdio.a error.a str.a fs.a | ||
| 50 | |||
| 51 | auto-int8.o: \ | ||
| 52 | compile auto-int8.c substdio.h readwrite.h exit.h scan.h fmt.h | ||
| 53 | ./compile auto-int8.c | ||
| 54 | |||
| 55 | auto-str: \ | ||
| 56 | load auto-str.o substdio.a error.a str.a | ||
| 57 | ./load auto-str substdio.a error.a str.a | ||
| 58 | |||
| 59 | auto-str.o: \ | ||
| 60 | compile auto-str.c substdio.h readwrite.h exit.h | ||
| 61 | ./compile auto-str.c | ||
| 62 | |||
| 63 | auto-uid: \ | ||
| 64 | load auto-uid.o substdio.a error.a str.a fs.a | ||
| 65 | ./load auto-uid substdio.a error.a str.a fs.a | ||
| 66 | |||
| 67 | auto-uid.o: \ | ||
| 68 | compile auto-uid.c subfd.h substdio.h substdio.h readwrite.h exit.h \ | ||
| 69 | scan.h fmt.h | ||
| 70 | ./compile auto-uid.c | ||
| 71 | |||
| 72 | auto_break.c: \ | ||
| 73 | auto-str conf-break | ||
| 74 | ./auto-str auto_break \ | ||
| 75 | "`head -1 conf-break`" > auto_break.c | ||
| 76 | |||
| 77 | auto_break.o: \ | ||
| 78 | compile auto_break.c | ||
| 79 | ./compile auto_break.c | ||
| 80 | |||
| 81 | auto_patrn.c: \ | ||
| 82 | auto-int8 conf-patrn | ||
| 83 | ./auto-int8 auto_patrn `head -1 conf-patrn` > auto_patrn.c | ||
| 84 | |||
| 85 | auto_patrn.o: \ | ||
| 86 | compile auto_patrn.c | ||
| 87 | ./compile auto_patrn.c | ||
| 88 | |||
| 89 | auto_qmail.c: \ | ||
| 90 | auto-str conf-qmail | ||
| 91 | ./auto-str auto_qmail `head -1 conf-qmail` > auto_qmail.c | ||
| 92 | |||
| 93 | auto_qmail.o: \ | ||
| 94 | compile auto_qmail.c | ||
| 95 | ./compile auto_qmail.c | ||
| 96 | |||
| 97 | auto_spawn.c: \ | ||
| 98 | auto-int conf-spawn | ||
| 99 | ./auto-int auto_spawn `head -1 conf-spawn` > auto_spawn.c | ||
| 100 | |||
| 101 | auto_spawn.o: \ | ||
| 102 | compile auto_spawn.c | ||
| 103 | ./compile auto_spawn.c | ||
| 104 | |||
| 105 | auto_split.c: \ | ||
| 106 | auto-int conf-split | ||
| 107 | ./auto-int auto_split `head -1 conf-split` > auto_split.c | ||
| 108 | |||
| 109 | auto_split.o: \ | ||
| 110 | compile auto_split.c | ||
| 111 | ./compile auto_split.c | ||
| 112 | |||
| 113 | auto_uids.c: \ | ||
| 114 | auto-uid auto-gid conf-users conf-groups | ||
| 115 | ( ./auto-uid auto_uida `head -1 conf-users` \ | ||
| 116 | &&./auto-uid auto_uidd `head -2 conf-users | tail -1` \ | ||
| 117 | &&./auto-uid auto_uidl `head -3 conf-users | tail -1` \ | ||
| 118 | &&./auto-uid auto_uido `head -4 conf-users | tail -1` \ | ||
| 119 | &&./auto-uid auto_uidp `head -5 conf-users | tail -1` \ | ||
| 120 | &&./auto-uid auto_uidq `head -6 conf-users | tail -1` \ | ||
| 121 | &&./auto-uid auto_uidr `head -7 conf-users | tail -1` \ | ||
| 122 | &&./auto-uid auto_uids `head -8 conf-users | tail -1` \ | ||
| 123 | &&./auto-gid auto_gidq `head -1 conf-groups` \ | ||
| 124 | &&./auto-gid auto_gidn `head -2 conf-groups | tail -1` \ | ||
| 125 | ) > auto_uids.c.tmp && mv auto_uids.c.tmp auto_uids.c | ||
| 126 | |||
| 127 | auto_uids.o: \ | ||
| 128 | compile auto_uids.c | ||
| 129 | ./compile auto_uids.c | ||
| 130 | |||
| 131 | auto_usera.c: \ | ||
| 132 | auto-str conf-users | ||
| 133 | ./auto-str auto_usera `head -1 conf-users` > auto_usera.c | ||
| 134 | |||
| 135 | auto_usera.o: \ | ||
| 136 | compile auto_usera.c | ||
| 137 | ./compile auto_usera.c | ||
| 138 | |||
| 139 | binm1: \ | ||
| 140 | binm1.sh conf-qmail | ||
| 141 | cat binm1.sh \ | ||
| 142 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 143 | > binm1 | ||
| 144 | chmod 755 binm1 | ||
| 145 | |||
| 146 | binm1+df: \ | ||
| 147 | binm1+df.sh conf-qmail | ||
| 148 | cat binm1+df.sh \ | ||
| 149 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 150 | > binm1+df | ||
| 151 | chmod 755 binm1+df | ||
| 152 | |||
| 153 | binm2: \ | ||
| 154 | binm2.sh conf-qmail | ||
| 155 | cat binm2.sh \ | ||
| 156 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 157 | > binm2 | ||
| 158 | chmod 755 binm2 | ||
| 159 | |||
| 160 | binm2+df: \ | ||
| 161 | binm2+df.sh conf-qmail | ||
| 162 | cat binm2+df.sh \ | ||
| 163 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 164 | > binm2+df | ||
| 165 | chmod 755 binm2+df | ||
| 166 | |||
| 167 | binm3: \ | ||
| 168 | binm3.sh conf-qmail | ||
| 169 | cat binm3.sh \ | ||
| 170 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 171 | > binm3 | ||
| 172 | chmod 755 binm3 | ||
| 173 | |||
| 174 | binm3+df: \ | ||
| 175 | binm3+df.sh conf-qmail | ||
| 176 | cat binm3+df.sh \ | ||
| 177 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 178 | > binm3+df | ||
| 179 | chmod 755 binm3+df | ||
| 180 | |||
| 181 | bouncesaying: \ | ||
| 182 | load bouncesaying.o strerr.a error.a substdio.a str.a wait.a | ||
| 183 | ./load bouncesaying strerr.a error.a substdio.a str.a \ | ||
| 184 | wait.a | ||
| 185 | |||
| 186 | bouncesaying.0: \ | ||
| 187 | bouncesaying.1 | ||
| 188 | nroff -man bouncesaying.1 > bouncesaying.0 | ||
| 189 | |||
| 190 | bouncesaying.o: \ | ||
| 191 | compile bouncesaying.c fork.h strerr.h error.h wait.h sig.h exit.h | ||
| 192 | ./compile bouncesaying.c | ||
| 193 | |||
| 194 | byte_chr.o: \ | ||
| 195 | compile byte_chr.c byte.h | ||
| 196 | ./compile byte_chr.c | ||
| 197 | |||
| 198 | byte_copy.o: \ | ||
| 199 | compile byte_copy.c byte.h | ||
| 200 | ./compile byte_copy.c | ||
| 201 | |||
| 202 | byte_cr.o: \ | ||
| 203 | compile byte_cr.c byte.h | ||
| 204 | ./compile byte_cr.c | ||
| 205 | |||
| 206 | byte_diff.o: \ | ||
| 207 | compile byte_diff.c byte.h | ||
| 208 | ./compile byte_diff.c | ||
| 209 | |||
| 210 | byte_rchr.o: \ | ||
| 211 | compile byte_rchr.c byte.h | ||
| 212 | ./compile byte_rchr.c | ||
| 213 | |||
| 214 | byte_zero.o: \ | ||
| 215 | compile byte_zero.c byte.h | ||
| 216 | ./compile byte_zero.c | ||
| 217 | |||
| 218 | case.a: \ | ||
| 219 | makelib case_diffb.o case_diffs.o case_lowerb.o case_lowers.o \ | ||
| 220 | case_starts.o | ||
| 221 | ./makelib case.a case_diffb.o case_diffs.o case_lowerb.o \ | ||
| 222 | case_lowers.o case_starts.o | ||
| 223 | |||
| 224 | case_diffb.o: \ | ||
| 225 | compile case_diffb.c case.h | ||
| 226 | ./compile case_diffb.c | ||
| 227 | |||
| 228 | case_diffs.o: \ | ||
| 229 | compile case_diffs.c case.h | ||
| 230 | ./compile case_diffs.c | ||
| 231 | |||
| 232 | case_lowerb.o: \ | ||
| 233 | compile case_lowerb.c case.h | ||
| 234 | ./compile case_lowerb.c | ||
| 235 | |||
| 236 | case_lowers.o: \ | ||
| 237 | compile case_lowers.c case.h | ||
| 238 | ./compile case_lowers.c | ||
| 239 | |||
| 240 | case_starts.o: \ | ||
| 241 | compile case_starts.c case.h | ||
| 242 | ./compile case_starts.c | ||
| 243 | |||
| 244 | cdb.a: \ | ||
| 245 | makelib cdb_hash.o cdb_unpack.o cdb_seek.o | ||
| 246 | ./makelib cdb.a cdb_hash.o cdb_unpack.o cdb_seek.o | ||
| 247 | |||
| 248 | cdb_hash.o: \ | ||
| 249 | compile cdb_hash.c cdb.h uint32.h | ||
| 250 | ./compile cdb_hash.c | ||
| 251 | |||
| 252 | cdb_seek.o: \ | ||
| 253 | compile cdb_seek.c cdb.h uint32.h | ||
| 254 | ./compile cdb_seek.c | ||
| 255 | |||
| 256 | cdb_unpack.o: \ | ||
| 257 | compile cdb_unpack.c cdb.h uint32.h | ||
| 258 | ./compile cdb_unpack.c | ||
| 259 | |||
| 260 | cdbmake.a: \ | ||
| 261 | makelib cdbmake_pack.o cdbmake_hash.o cdbmake_add.o | ||
| 262 | ./makelib cdbmake.a cdbmake_pack.o cdbmake_hash.o \ | ||
| 263 | cdbmake_add.o | ||
| 264 | |||
| 265 | cdbmake_add.o: \ | ||
| 266 | compile cdbmake_add.c cdbmake.h uint32.h | ||
| 267 | ./compile cdbmake_add.c | ||
| 268 | |||
| 269 | cdbmake_hash.o: \ | ||
| 270 | compile cdbmake_hash.c cdbmake.h uint32.h | ||
| 271 | ./compile cdbmake_hash.c | ||
| 272 | |||
| 273 | cdbmake_pack.o: \ | ||
| 274 | compile cdbmake_pack.c cdbmake.h uint32.h | ||
| 275 | ./compile cdbmake_pack.c | ||
| 276 | |||
| 277 | cdbmss.o: \ | ||
| 278 | compile cdbmss.c readwrite.h seek.h alloc.h cdbmss.h cdbmake.h \ | ||
| 279 | uint32.h substdio.h | ||
| 280 | ./compile cdbmss.c | ||
| 281 | |||
| 282 | check: \ | ||
| 283 | it man | ||
| 284 | ./instcheck | ||
| 285 | |||
| 286 | chkshsgr: \ | ||
| 287 | load chkshsgr.o | ||
| 288 | ./load chkshsgr | ||
| 289 | |||
| 290 | chkshsgr.o: \ | ||
| 291 | compile chkshsgr.c exit.h | ||
| 292 | ./compile chkshsgr.c | ||
| 293 | |||
| 294 | chkspawn: \ | ||
| 295 | load chkspawn.o substdio.a error.a str.a fs.a auto_spawn.o | ||
| 296 | ./load chkspawn substdio.a error.a str.a fs.a auto_spawn.o | ||
| 297 | |||
| 298 | chkspawn.o: \ | ||
| 299 | compile chkspawn.c substdio.h subfd.h substdio.h fmt.h select.h \ | ||
| 300 | exit.h auto_spawn.h | ||
| 301 | ./compile chkspawn.c | ||
| 302 | |||
| 303 | clean: \ | ||
| 304 | TARGETS | ||
| 305 | rm -f `cat TARGETS` | ||
| 306 | |||
| 307 | coe.o: \ | ||
| 308 | compile coe.c coe.h | ||
| 309 | ./compile coe.c | ||
| 310 | |||
| 311 | commands.o: \ | ||
| 312 | compile commands.c commands.h substdio.h stralloc.h gen_alloc.h str.h \ | ||
| 313 | case.h | ||
| 314 | ./compile commands.c | ||
| 315 | |||
| 316 | compile: \ | ||
| 317 | make-compile warn-auto.sh systype | ||
| 318 | ( cat warn-auto.sh; ./make-compile "`cat systype`" ) > \ | ||
| 319 | compile | ||
| 320 | chmod 755 compile | ||
| 321 | |||
| 322 | condredirect: \ | ||
| 323 | load condredirect.o qmail.o strerr.a fd.a sig.a wait.a seek.a env.a \ | ||
| 324 | substdio.a error.a str.a fs.a auto_qmail.o | ||
| 325 | ./load condredirect qmail.o strerr.a fd.a sig.a wait.a \ | ||
| 326 | seek.a env.a substdio.a error.a str.a fs.a auto_qmail.o | ||
| 327 | |||
| 328 | condredirect.0: \ | ||
| 329 | condredirect.1 | ||
| 330 | nroff -man condredirect.1 > condredirect.0 | ||
| 331 | |||
| 332 | condredirect.o: \ | ||
| 333 | compile condredirect.c sig.h readwrite.h exit.h env.h error.h fork.h \ | ||
| 334 | wait.h seek.h qmail.h substdio.h strerr.h substdio.h fmt.h | ||
| 335 | ./compile condredirect.c | ||
| 336 | |||
| 337 | config: \ | ||
| 338 | warn-auto.sh config.sh conf-qmail conf-break conf-split | ||
| 339 | cat warn-auto.sh config.sh \ | ||
| 340 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 341 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 342 | | sed s}SPLIT}"`head -1 conf-split`"}g \ | ||
| 343 | > config | ||
| 344 | chmod 755 config | ||
| 345 | |||
| 346 | config-fast: \ | ||
| 347 | warn-auto.sh config-fast.sh conf-qmail conf-break conf-split | ||
| 348 | cat warn-auto.sh config-fast.sh \ | ||
| 349 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 350 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 351 | | sed s}SPLIT}"`head -1 conf-split`"}g \ | ||
| 352 | > config-fast | ||
| 353 | chmod 755 config-fast | ||
| 354 | |||
| 355 | constmap.o: \ | ||
| 356 | compile constmap.c constmap.h alloc.h case.h | ||
| 357 | ./compile constmap.c | ||
| 358 | |||
| 359 | control.o: \ | ||
| 360 | compile control.c readwrite.h open.h getln.h stralloc.h gen_alloc.h \ | ||
| 361 | substdio.h error.h control.h alloc.h scan.h | ||
| 362 | ./compile control.c | ||
| 363 | |||
| 364 | date822fmt.o: \ | ||
| 365 | compile date822fmt.c datetime.h fmt.h date822fmt.h | ||
| 366 | ./compile date822fmt.c | ||
| 367 | |||
| 368 | datemail: \ | ||
| 369 | warn-auto.sh datemail.sh conf-qmail conf-break conf-split | ||
| 370 | cat warn-auto.sh datemail.sh \ | ||
| 371 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 372 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 373 | | sed s}SPLIT}"`head -1 conf-split`"}g \ | ||
| 374 | > datemail | ||
| 375 | chmod 755 datemail | ||
| 376 | |||
| 377 | datetime.a: \ | ||
| 378 | makelib datetime.o datetime_un.o | ||
| 379 | ./makelib datetime.a datetime.o datetime_un.o | ||
| 380 | |||
| 381 | datetime.o: \ | ||
| 382 | compile datetime.c datetime.h | ||
| 383 | ./compile datetime.c | ||
| 384 | |||
| 385 | datetime_un.o: \ | ||
| 386 | compile datetime_un.c datetime.h | ||
| 387 | ./compile datetime_un.c | ||
| 388 | |||
| 389 | direntry.h: \ | ||
| 390 | compile trydrent.c direntry.h1 direntry.h2 | ||
| 391 | ( ./compile trydrent.c >/dev/null 2>&1 \ | ||
| 392 | && cat direntry.h2 || cat direntry.h1 ) > direntry.h | ||
| 393 | rm -f trydrent.o | ||
| 394 | |||
| 395 | dns.lib: \ | ||
| 396 | tryrsolv.c compile load socket.lib dns.o ipalloc.o ip.o stralloc.a \ | ||
| 397 | alloc.a error.a fs.a str.a | ||
| 398 | ( ( ./compile tryrsolv.c && ./load tryrsolv dns.o \ | ||
| 399 | ipalloc.o ip.o stralloc.a alloc.a error.a fs.a str.a \ | ||
| 400 | -lresolv `cat socket.lib` ) >/dev/null 2>&1 \ | ||
| 401 | && echo -lresolv || exit 0 ) > dns.lib | ||
| 402 | rm -f tryrsolv.o tryrsolv | ||
| 403 | |||
| 404 | dns.o: \ | ||
| 405 | compile dns.c ip.h ipalloc.h ip.h gen_alloc.h fmt.h alloc.h str.h \ | ||
| 406 | stralloc.h gen_alloc.h dns.h case.h | ||
| 407 | ./compile dns.c | ||
| 408 | |||
| 409 | dnscname: \ | ||
| 410 | load dnscname.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ | ||
| 411 | substdio.a error.a str.a fs.a dns.lib socket.lib | ||
| 412 | ./load dnscname dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \ | ||
| 413 | alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \ | ||
| 414 | socket.lib` | ||
| 415 | |||
| 416 | dnscname.o: \ | ||
| 417 | compile dnscname.c substdio.h subfd.h substdio.h stralloc.h \ | ||
| 418 | gen_alloc.h dns.h dnsdoe.h readwrite.h exit.h | ||
| 419 | ./compile dnscname.c | ||
| 420 | |||
| 421 | dnsdoe.o: \ | ||
| 422 | compile dnsdoe.c substdio.h subfd.h substdio.h exit.h dns.h dnsdoe.h | ||
| 423 | ./compile dnsdoe.c | ||
| 424 | |||
| 425 | dnsfq: \ | ||
| 426 | load dnsfq.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ | ||
| 427 | substdio.a error.a str.a fs.a dns.lib socket.lib | ||
| 428 | ./load dnsfq dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \ | ||
| 429 | alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \ | ||
| 430 | socket.lib` | ||
| 431 | |||
| 432 | dnsfq.o: \ | ||
| 433 | compile dnsfq.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \ | ||
| 434 | dns.h dnsdoe.h ip.h ipalloc.h ip.h gen_alloc.h exit.h | ||
| 435 | ./compile dnsfq.c | ||
| 436 | |||
| 437 | dnsip: \ | ||
| 438 | load dnsip.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ | ||
| 439 | substdio.a error.a str.a fs.a dns.lib socket.lib | ||
| 440 | ./load dnsip dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \ | ||
| 441 | alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \ | ||
| 442 | socket.lib` | ||
| 443 | |||
| 444 | dnsip.o: \ | ||
| 445 | compile dnsip.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \ | ||
| 446 | dns.h dnsdoe.h ip.h ipalloc.h ip.h gen_alloc.h exit.h | ||
| 447 | ./compile dnsip.c | ||
| 448 | |||
| 449 | dnsmxip: \ | ||
| 450 | load dnsmxip.o dns.o dnsdoe.o ip.o ipalloc.o now.o stralloc.a alloc.a \ | ||
| 451 | substdio.a error.a str.a fs.a dns.lib socket.lib | ||
| 452 | ./load dnsmxip dns.o dnsdoe.o ip.o ipalloc.o now.o \ | ||
| 453 | stralloc.a alloc.a substdio.a error.a str.a fs.a `cat \ | ||
| 454 | dns.lib` `cat socket.lib` | ||
| 455 | |||
| 456 | dnsmxip.o: \ | ||
| 457 | compile dnsmxip.c substdio.h subfd.h substdio.h stralloc.h \ | ||
| 458 | gen_alloc.h fmt.h dns.h dnsdoe.h ip.h ipalloc.h ip.h gen_alloc.h \ | ||
| 459 | now.h datetime.h exit.h | ||
| 460 | ./compile dnsmxip.c | ||
| 461 | |||
| 462 | dnsptr: \ | ||
| 463 | load dnsptr.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ | ||
| 464 | substdio.a error.a str.a fs.a dns.lib socket.lib | ||
| 465 | ./load dnsptr dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \ | ||
| 466 | alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \ | ||
| 467 | socket.lib` | ||
| 468 | |||
| 469 | dnsptr.o: \ | ||
| 470 | compile dnsptr.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \ | ||
| 471 | str.h scan.h dns.h dnsdoe.h ip.h exit.h | ||
| 472 | ./compile dnsptr.c | ||
| 473 | |||
| 474 | dot-qmail.0: \ | ||
| 475 | dot-qmail.5 | ||
| 476 | nroff -man dot-qmail.5 > dot-qmail.0 | ||
| 477 | |||
| 478 | dot-qmail.5: \ | ||
| 479 | dot-qmail.9 conf-break conf-spawn | ||
| 480 | cat dot-qmail.9 \ | ||
| 481 | | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ | ||
| 482 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 483 | | sed s}SPAWN}"`head -1 conf-spawn`"}g \ | ||
| 484 | > dot-qmail.5 | ||
| 485 | |||
| 486 | elq: \ | ||
| 487 | warn-auto.sh elq.sh conf-qmail conf-break conf-split | ||
| 488 | cat warn-auto.sh elq.sh \ | ||
| 489 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 490 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 491 | | sed s}SPLIT}"`head -1 conf-split`"}g \ | ||
| 492 | > elq | ||
| 493 | chmod 755 elq | ||
| 494 | |||
| 495 | env.a: \ | ||
| 496 | makelib env.o envread.o | ||
| 497 | ./makelib env.a env.o envread.o | ||
| 498 | |||
| 499 | env.o: \ | ||
| 500 | compile env.c str.h alloc.h env.h | ||
| 501 | ./compile env.c | ||
| 502 | |||
| 503 | envelopes.0: \ | ||
| 504 | envelopes.5 | ||
| 505 | nroff -man envelopes.5 > envelopes.0 | ||
| 506 | |||
| 507 | envread.o: \ | ||
| 508 | compile envread.c env.h str.h | ||
| 509 | ./compile envread.c | ||
| 510 | |||
| 511 | error.a: \ | ||
| 512 | makelib error.o error_str.o error_temp.o | ||
| 513 | ./makelib error.a error.o error_str.o error_temp.o | ||
| 514 | |||
| 515 | error.o: \ | ||
| 516 | compile error.c error.h | ||
| 517 | ./compile error.c | ||
| 518 | |||
| 519 | error_str.o: \ | ||
| 520 | compile error_str.c error.h | ||
| 521 | ./compile error_str.c | ||
| 522 | |||
| 523 | error_temp.o: \ | ||
| 524 | compile error_temp.c error.h | ||
| 525 | ./compile error_temp.c | ||
| 526 | |||
| 527 | except: \ | ||
| 528 | load except.o strerr.a error.a substdio.a str.a wait.a | ||
| 529 | ./load except strerr.a error.a substdio.a str.a wait.a | ||
| 530 | |||
| 531 | except.0: \ | ||
| 532 | except.1 | ||
| 533 | nroff -man except.1 > except.0 | ||
| 534 | |||
| 535 | except.o: \ | ||
| 536 | compile except.c fork.h strerr.h wait.h error.h exit.h | ||
| 537 | ./compile except.c | ||
| 538 | |||
| 539 | fd.a: \ | ||
| 540 | makelib fd_copy.o fd_move.o | ||
| 541 | ./makelib fd.a fd_copy.o fd_move.o | ||
| 542 | |||
| 543 | fd_copy.o: \ | ||
| 544 | compile fd_copy.c fd.h | ||
| 545 | ./compile fd_copy.c | ||
| 546 | |||
| 547 | fd_move.o: \ | ||
| 548 | compile fd_move.c fd.h | ||
| 549 | ./compile fd_move.c | ||
| 550 | |||
| 551 | fifo.o: \ | ||
| 552 | compile fifo.c hasmkffo.h fifo.h | ||
| 553 | ./compile fifo.c | ||
| 554 | |||
| 555 | find-systype: \ | ||
| 556 | find-systype.sh auto-ccld.sh | ||
| 557 | cat auto-ccld.sh find-systype.sh > find-systype | ||
| 558 | chmod 755 find-systype | ||
| 559 | |||
| 560 | fmt_str.o: \ | ||
| 561 | compile fmt_str.c fmt.h | ||
| 562 | ./compile fmt_str.c | ||
| 563 | |||
| 564 | fmt_strn.o: \ | ||
| 565 | compile fmt_strn.c fmt.h | ||
| 566 | ./compile fmt_strn.c | ||
| 567 | |||
| 568 | fmt_uint.o: \ | ||
| 569 | compile fmt_uint.c fmt.h | ||
| 570 | ./compile fmt_uint.c | ||
| 571 | |||
| 572 | fmt_uint0.o: \ | ||
| 573 | compile fmt_uint0.c fmt.h | ||
| 574 | ./compile fmt_uint0.c | ||
| 575 | |||
| 576 | fmt_ulong.o: \ | ||
| 577 | compile fmt_ulong.c fmt.h | ||
| 578 | ./compile fmt_ulong.c | ||
| 579 | |||
| 580 | fmtqfn.o: \ | ||
| 581 | compile fmtqfn.c fmtqfn.h fmt.h auto_split.h | ||
| 582 | ./compile fmtqfn.c | ||
| 583 | |||
| 584 | forgeries.0: \ | ||
| 585 | forgeries.7 | ||
| 586 | nroff -man forgeries.7 > forgeries.0 | ||
| 587 | |||
| 588 | fork.h: \ | ||
| 589 | compile load tryvfork.c fork.h1 fork.h2 | ||
| 590 | ( ( ./compile tryvfork.c && ./load tryvfork ) >/dev/null \ | ||
| 591 | 2>&1 \ | ||
| 592 | && cat fork.h2 || cat fork.h1 ) > fork.h | ||
| 593 | rm -f tryvfork.o tryvfork | ||
| 594 | |||
| 595 | forward: \ | ||
| 596 | load forward.o qmail.o strerr.a alloc.a fd.a wait.a sig.a env.a \ | ||
| 597 | substdio.a error.a str.a fs.a auto_qmail.o | ||
| 598 | ./load forward qmail.o strerr.a alloc.a fd.a wait.a sig.a \ | ||
| 599 | env.a substdio.a error.a str.a fs.a auto_qmail.o | ||
| 600 | |||
| 601 | forward.0: \ | ||
| 602 | forward.1 | ||
| 603 | nroff -man forward.1 > forward.0 | ||
| 604 | |||
| 605 | forward.o: \ | ||
| 606 | compile forward.c sig.h readwrite.h exit.h env.h qmail.h substdio.h \ | ||
| 607 | strerr.h substdio.h fmt.h | ||
| 608 | ./compile forward.c | ||
| 609 | |||
| 610 | fs.a: \ | ||
| 611 | makelib fmt_str.o fmt_strn.o fmt_uint.o fmt_uint0.o fmt_ulong.o \ | ||
| 612 | scan_ulong.o scan_8long.o | ||
| 613 | ./makelib fs.a fmt_str.o fmt_strn.o fmt_uint.o fmt_uint0.o \ | ||
| 614 | fmt_ulong.o scan_ulong.o scan_8long.o | ||
| 615 | |||
| 616 | getln.a: \ | ||
| 617 | makelib getln.o getln2.o | ||
| 618 | ./makelib getln.a getln.o getln2.o | ||
| 619 | |||
| 620 | getln.o: \ | ||
| 621 | compile getln.c substdio.h byte.h stralloc.h gen_alloc.h getln.h | ||
| 622 | ./compile getln.c | ||
| 623 | |||
| 624 | getln2.o: \ | ||
| 625 | compile getln2.c substdio.h stralloc.h gen_alloc.h byte.h getln.h | ||
| 626 | ./compile getln2.c | ||
| 627 | |||
| 628 | getopt.a: \ | ||
| 629 | makelib subgetopt.o sgetopt.o | ||
| 630 | ./makelib getopt.a subgetopt.o sgetopt.o | ||
| 631 | |||
| 632 | gfrom.o: \ | ||
| 633 | compile gfrom.c str.h gfrom.h | ||
| 634 | ./compile gfrom.c | ||
| 635 | |||
| 636 | hasflock.h: \ | ||
| 637 | tryflock.c compile load | ||
| 638 | ( ( ./compile tryflock.c && ./load tryflock ) >/dev/null \ | ||
| 639 | 2>&1 \ | ||
| 640 | && echo \#define HASFLOCK 1 || exit 0 ) > hasflock.h | ||
| 641 | rm -f tryflock.o tryflock | ||
| 642 | |||
| 643 | hasmkffo.h: \ | ||
| 644 | trymkffo.c compile load | ||
| 645 | ( ( ./compile trymkffo.c && ./load trymkffo ) >/dev/null \ | ||
| 646 | 2>&1 \ | ||
| 647 | && echo \#define HASMKFIFO 1 || exit 0 ) > hasmkffo.h | ||
| 648 | rm -f trymkffo.o trymkffo | ||
| 649 | |||
| 650 | hasnpbg1.h: \ | ||
| 651 | trynpbg1.c compile load open.h open.a fifo.h fifo.o select.h | ||
| 652 | ( ( ./compile trynpbg1.c \ | ||
| 653 | && ./load trynpbg1 fifo.o open.a && ./trynpbg1 ) \ | ||
| 654 | >/dev/null 2>&1 \ | ||
| 655 | && echo \#define HASNAMEDPIPEBUG1 1 || exit 0 ) > \ | ||
| 656 | hasnpbg1.h | ||
| 657 | rm -f trynpbg1.o trynpbg1 | ||
| 658 | |||
| 659 | hassalen.h: \ | ||
| 660 | trysalen.c compile | ||
| 661 | ( ./compile trysalen.c >/dev/null 2>&1 \ | ||
| 662 | && echo \#define HASSALEN 1 || exit 0 ) > hassalen.h | ||
| 663 | rm -f trysalen.o | ||
| 664 | |||
| 665 | hassgact.h: \ | ||
| 666 | trysgact.c compile load | ||
| 667 | ( ( ./compile trysgact.c && ./load trysgact ) >/dev/null \ | ||
| 668 | 2>&1 \ | ||
| 669 | && echo \#define HASSIGACTION 1 || exit 0 ) > hassgact.h | ||
| 670 | rm -f trysgact.o trysgact | ||
| 671 | |||
| 672 | hassgprm.h: \ | ||
| 673 | trysgprm.c compile load | ||
| 674 | ( ( ./compile trysgprm.c && ./load trysgprm ) >/dev/null \ | ||
| 675 | 2>&1 \ | ||
| 676 | && echo \#define HASSIGPROCMASK 1 || exit 0 ) > hassgprm.h | ||
| 677 | rm -f trysgprm.o trysgprm | ||
| 678 | |||
| 679 | hasshsgr.h: \ | ||
| 680 | chkshsgr warn-shsgr tryshsgr.c compile load | ||
| 681 | ./chkshsgr || ( cat warn-shsgr; exit 1 ) | ||
| 682 | ( ( ./compile tryshsgr.c \ | ||
| 683 | && ./load tryshsgr && ./tryshsgr ) >/dev/null 2>&1 \ | ||
| 684 | && echo \#define HASSHORTSETGROUPS 1 || exit 0 ) > \ | ||
| 685 | hasshsgr.h | ||
| 686 | rm -f tryshsgr.o tryshsgr | ||
| 687 | |||
| 688 | haswaitp.h: \ | ||
| 689 | trywaitp.c compile load | ||
| 690 | ( ( ./compile trywaitp.c && ./load trywaitp ) >/dev/null \ | ||
| 691 | 2>&1 \ | ||
| 692 | && echo \#define HASWAITPID 1 || exit 0 ) > haswaitp.h | ||
| 693 | rm -f trywaitp.o trywaitp | ||
| 694 | |||
| 695 | headerbody.o: \ | ||
| 696 | compile headerbody.c stralloc.h gen_alloc.h substdio.h getln.h \ | ||
| 697 | hfield.h headerbody.h | ||
| 698 | ./compile headerbody.c | ||
| 699 | |||
| 700 | hfield.o: \ | ||
| 701 | compile hfield.c hfield.h | ||
| 702 | ./compile hfield.c | ||
| 703 | |||
| 704 | hier.o: \ | ||
| 705 | compile hier.c auto_qmail.h auto_split.h auto_uids.h fmt.h fifo.h | ||
| 706 | ./compile hier.c | ||
| 707 | |||
| 708 | home: \ | ||
| 709 | home.sh conf-qmail | ||
| 710 | cat home.sh \ | ||
| 711 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 712 | > home | ||
| 713 | chmod 755 home | ||
| 714 | |||
| 715 | home+df: \ | ||
| 716 | home+df.sh conf-qmail | ||
| 717 | cat home+df.sh \ | ||
| 718 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 719 | > home+df | ||
| 720 | chmod 755 home+df | ||
| 721 | |||
| 722 | hostname: \ | ||
| 723 | load hostname.o substdio.a error.a str.a dns.lib socket.lib | ||
| 724 | ./load hostname substdio.a error.a str.a `cat dns.lib` \ | ||
| 725 | `cat socket.lib` | ||
| 726 | |||
| 727 | hostname.o: \ | ||
| 728 | compile hostname.c substdio.h subfd.h substdio.h readwrite.h exit.h | ||
| 729 | ./compile hostname.c | ||
| 730 | |||
| 731 | idedit: \ | ||
| 732 | load idedit.o strerr.a substdio.a error.a str.a fs.a wait.a open.a \ | ||
| 733 | seek.a | ||
| 734 | ./load idedit strerr.a substdio.a error.a str.a fs.a \ | ||
| 735 | wait.a open.a seek.a | ||
| 736 | |||
| 737 | idedit.o: \ | ||
| 738 | compile idedit.c readwrite.h exit.h scan.h fmt.h strerr.h open.h \ | ||
| 739 | seek.h fork.h | ||
| 740 | ./compile idedit.c | ||
| 741 | |||
| 742 | install: \ | ||
| 743 | load install.o fifo.o hier.o auto_qmail.o auto_split.o auto_uids.o \ | ||
| 744 | strerr.a substdio.a open.a error.a str.a fs.a | ||
| 745 | ./load install fifo.o hier.o auto_qmail.o auto_split.o \ | ||
| 746 | auto_uids.o strerr.a substdio.a open.a error.a str.a fs.a | ||
| 747 | |||
| 748 | install-big: \ | ||
| 749 | load install-big.o fifo.o install.o auto_qmail.o auto_split.o \ | ||
| 750 | auto_uids.o strerr.a substdio.a open.a error.a str.a fs.a | ||
| 751 | ./load install-big fifo.o install.o auto_qmail.o \ | ||
| 752 | auto_split.o auto_uids.o strerr.a substdio.a open.a error.a \ | ||
| 753 | str.a fs.a | ||
| 754 | |||
| 755 | install-big.o: \ | ||
| 756 | compile install-big.c auto_qmail.h auto_split.h auto_uids.h fmt.h \ | ||
| 757 | fifo.h | ||
| 758 | ./compile install-big.c | ||
| 759 | |||
| 760 | install.o: \ | ||
| 761 | compile install.c substdio.h strerr.h error.h open.h readwrite.h \ | ||
| 762 | exit.h | ||
| 763 | ./compile install.c | ||
| 764 | |||
| 765 | instcheck: \ | ||
| 766 | load instcheck.o fifo.o hier.o auto_qmail.o auto_split.o auto_uids.o \ | ||
| 767 | strerr.a substdio.a error.a str.a fs.a | ||
| 768 | ./load instcheck fifo.o hier.o auto_qmail.o auto_split.o \ | ||
| 769 | auto_uids.o strerr.a substdio.a error.a str.a fs.a | ||
| 770 | |||
| 771 | instcheck.o: \ | ||
| 772 | compile instcheck.c strerr.h error.h readwrite.h exit.h | ||
| 773 | ./compile instcheck.c | ||
| 774 | |||
| 775 | ip.o: \ | ||
| 776 | compile ip.c fmt.h scan.h ip.h | ||
| 777 | ./compile ip.c | ||
| 778 | |||
| 779 | ipalloc.o: \ | ||
| 780 | compile ipalloc.c alloc.h gen_allocdefs.h ip.h ipalloc.h ip.h \ | ||
| 781 | gen_alloc.h | ||
| 782 | ./compile ipalloc.c | ||
| 783 | |||
| 784 | ipme.o: \ | ||
| 785 | compile ipme.c hassalen.h byte.h ip.h ipalloc.h ip.h gen_alloc.h \ | ||
| 786 | stralloc.h gen_alloc.h ipme.h ip.h ipalloc.h | ||
| 787 | ./compile ipme.c | ||
| 788 | |||
| 789 | ipmeprint: \ | ||
| 790 | load ipmeprint.o ipme.o ip.o ipalloc.o stralloc.a alloc.a substdio.a \ | ||
| 791 | error.a str.a fs.a socket.lib | ||
| 792 | ./load ipmeprint ipme.o ip.o ipalloc.o stralloc.a alloc.a \ | ||
| 793 | substdio.a error.a str.a fs.a `cat socket.lib` | ||
| 794 | |||
| 795 | ipmeprint.o: \ | ||
| 796 | compile ipmeprint.c subfd.h substdio.h substdio.h ip.h ipme.h ip.h \ | ||
| 797 | ipalloc.h ip.h gen_alloc.h exit.h | ||
| 798 | ./compile ipmeprint.c | ||
| 799 | |||
| 800 | it: \ | ||
| 801 | qmail-local qmail-lspawn qmail-getpw qmail-remote qmail-rspawn \ | ||
| 802 | qmail-clean qmail-send qmail-start splogger qmail-queue qmail-inject \ | ||
| 803 | predate datemail mailsubj qmail-upq qmail-showctl qmail-newu \ | ||
| 804 | qmail-pw2u qmail-qread qmail-qstat qmail-tcpto qmail-tcpok \ | ||
| 805 | qmail-pop3d qmail-popup qmail-qmqpc qmail-qmqpd qmail-qmtpd \ | ||
| 806 | qmail-smtpd sendmail tcp-env qmail-newmrh config config-fast dnscname \ | ||
| 807 | dnsptr dnsip dnsmxip dnsfq hostname ipmeprint qreceipt qsmhook qbiff \ | ||
| 808 | forward preline condredirect bouncesaying except maildirmake \ | ||
| 809 | maildir2mbox maildirwatch qail elq pinq idedit install-big install \ | ||
| 810 | instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \ | ||
| 811 | binm3 binm3+df | ||
| 812 | |||
| 813 | load: \ | ||
| 814 | make-load warn-auto.sh systype | ||
| 815 | ( cat warn-auto.sh; ./make-load "`cat systype`" ) > load | ||
| 816 | chmod 755 load | ||
| 817 | |||
| 818 | lock.a: \ | ||
| 819 | makelib lock_ex.o lock_exnb.o lock_un.o | ||
| 820 | ./makelib lock.a lock_ex.o lock_exnb.o lock_un.o | ||
| 821 | |||
| 822 | lock_ex.o: \ | ||
| 823 | compile lock_ex.c hasflock.h lock.h | ||
| 824 | ./compile lock_ex.c | ||
| 825 | |||
| 826 | lock_exnb.o: \ | ||
| 827 | compile lock_exnb.c hasflock.h lock.h | ||
| 828 | ./compile lock_exnb.c | ||
| 829 | |||
| 830 | lock_un.o: \ | ||
| 831 | compile lock_un.c hasflock.h lock.h | ||
| 832 | ./compile lock_un.c | ||
| 833 | |||
| 834 | maildir.0: \ | ||
| 835 | maildir.5 | ||
| 836 | nroff -man maildir.5 > maildir.0 | ||
| 837 | |||
| 838 | maildir.o: \ | ||
| 839 | compile maildir.c prioq.h datetime.h gen_alloc.h env.h stralloc.h \ | ||
| 840 | gen_alloc.h direntry.h datetime.h now.h datetime.h str.h maildir.h \ | ||
| 841 | strerr.h | ||
| 842 | ./compile maildir.c | ||
| 843 | |||
| 844 | maildir2mbox: \ | ||
| 845 | load maildir2mbox.o maildir.o prioq.o now.o myctime.o gfrom.o lock.a \ | ||
| 846 | getln.a env.a open.a strerr.a stralloc.a alloc.a substdio.a error.a \ | ||
| 847 | str.a fs.a datetime.a | ||
| 848 | ./load maildir2mbox maildir.o prioq.o now.o myctime.o \ | ||
| 849 | gfrom.o lock.a getln.a env.a open.a strerr.a stralloc.a \ | ||
| 850 | alloc.a substdio.a error.a str.a fs.a datetime.a | ||
| 851 | |||
| 852 | maildir2mbox.0: \ | ||
| 853 | maildir2mbox.1 | ||
| 854 | nroff -man maildir2mbox.1 > maildir2mbox.0 | ||
| 855 | |||
| 856 | maildir2mbox.o: \ | ||
| 857 | compile maildir2mbox.c readwrite.h prioq.h datetime.h gen_alloc.h \ | ||
| 858 | env.h stralloc.h gen_alloc.h subfd.h substdio.h substdio.h getln.h \ | ||
| 859 | error.h open.h lock.h gfrom.h str.h exit.h myctime.h maildir.h \ | ||
| 860 | strerr.h | ||
| 861 | ./compile maildir2mbox.c | ||
| 862 | |||
| 863 | maildirmake: \ | ||
| 864 | load maildirmake.o strerr.a substdio.a error.a str.a | ||
| 865 | ./load maildirmake strerr.a substdio.a error.a str.a | ||
| 866 | |||
| 867 | maildirmake.0: \ | ||
| 868 | maildirmake.1 | ||
| 869 | nroff -man maildirmake.1 > maildirmake.0 | ||
| 870 | |||
| 871 | maildirmake.o: \ | ||
| 872 | compile maildirmake.c strerr.h exit.h | ||
| 873 | ./compile maildirmake.c | ||
| 874 | |||
| 875 | maildirwatch: \ | ||
| 876 | load maildirwatch.o hfield.o headerbody.o maildir.o prioq.o now.o \ | ||
| 877 | getln.a env.a open.a strerr.a stralloc.a alloc.a substdio.a error.a \ | ||
| 878 | str.a | ||
| 879 | ./load maildirwatch hfield.o headerbody.o maildir.o \ | ||
| 880 | prioq.o now.o getln.a env.a open.a strerr.a stralloc.a \ | ||
| 881 | alloc.a substdio.a error.a str.a | ||
| 882 | |||
| 883 | maildirwatch.0: \ | ||
| 884 | maildirwatch.1 | ||
| 885 | nroff -man maildirwatch.1 > maildirwatch.0 | ||
| 886 | |||
| 887 | maildirwatch.o: \ | ||
| 888 | compile maildirwatch.c getln.h substdio.h subfd.h substdio.h prioq.h \ | ||
| 889 | datetime.h gen_alloc.h stralloc.h gen_alloc.h str.h exit.h hfield.h \ | ||
| 890 | readwrite.h open.h headerbody.h maildir.h strerr.h | ||
| 891 | ./compile maildirwatch.c | ||
| 892 | |||
| 893 | mailsubj: \ | ||
| 894 | warn-auto.sh mailsubj.sh conf-qmail conf-break conf-split | ||
| 895 | cat warn-auto.sh mailsubj.sh \ | ||
| 896 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 897 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 898 | | sed s}SPLIT}"`head -1 conf-split`"}g \ | ||
| 899 | > mailsubj | ||
| 900 | chmod 755 mailsubj | ||
| 901 | |||
| 902 | mailsubj.0: \ | ||
| 903 | mailsubj.1 | ||
| 904 | nroff -man mailsubj.1 > mailsubj.0 | ||
| 905 | |||
| 906 | make-compile: \ | ||
| 907 | make-compile.sh auto-ccld.sh | ||
| 908 | cat auto-ccld.sh make-compile.sh > make-compile | ||
| 909 | chmod 755 make-compile | ||
| 910 | |||
| 911 | make-load: \ | ||
| 912 | make-load.sh auto-ccld.sh | ||
| 913 | cat auto-ccld.sh make-load.sh > make-load | ||
| 914 | chmod 755 make-load | ||
| 915 | |||
| 916 | make-makelib: \ | ||
| 917 | make-makelib.sh auto-ccld.sh | ||
| 918 | cat auto-ccld.sh make-makelib.sh > make-makelib | ||
| 919 | chmod 755 make-makelib | ||
| 920 | |||
| 921 | makelib: \ | ||
| 922 | make-makelib warn-auto.sh systype | ||
| 923 | ( cat warn-auto.sh; ./make-makelib "`cat systype`" ) > \ | ||
| 924 | makelib | ||
| 925 | chmod 755 makelib | ||
| 926 | |||
| 927 | man: \ | ||
| 928 | qmail-local.0 qmail-lspawn.0 qmail-getpw.0 qmail-remote.0 \ | ||
| 929 | qmail-rspawn.0 qmail-clean.0 qmail-send.0 qmail-start.0 splogger.0 \ | ||
| 930 | qmail-queue.0 qmail-inject.0 mailsubj.0 qmail-showctl.0 qmail-newu.0 \ | ||
| 931 | qmail-pw2u.0 qmail-qread.0 qmail-qstat.0 qmail-tcpto.0 qmail-tcpok.0 \ | ||
| 932 | qmail-pop3d.0 qmail-popup.0 qmail-qmqpc.0 qmail-qmqpd.0 qmail-qmtpd.0 \ | ||
| 933 | qmail-smtpd.0 tcp-env.0 qmail-newmrh.0 qreceipt.0 qbiff.0 forward.0 \ | ||
| 934 | preline.0 condredirect.0 bouncesaying.0 except.0 maildirmake.0 \ | ||
| 935 | maildir2mbox.0 maildirwatch.0 qmail.0 qmail-limits.0 qmail-log.0 \ | ||
| 936 | qmail-control.0 qmail-header.0 qmail-users.0 dot-qmail.0 \ | ||
| 937 | qmail-command.0 tcp-environ.0 maildir.0 mbox.0 addresses.0 \ | ||
| 938 | envelopes.0 forgeries.0 | ||
| 939 | |||
| 940 | mbox.0: \ | ||
| 941 | mbox.5 | ||
| 942 | nroff -man mbox.5 > mbox.0 | ||
| 943 | |||
| 944 | myctime.o: \ | ||
| 945 | compile myctime.c datetime.h fmt.h myctime.h | ||
| 946 | ./compile myctime.c | ||
| 947 | |||
| 948 | ndelay.a: \ | ||
| 949 | makelib ndelay.o ndelay_off.o | ||
| 950 | ./makelib ndelay.a ndelay.o ndelay_off.o | ||
| 951 | |||
| 952 | ndelay.o: \ | ||
| 953 | compile ndelay.c ndelay.h | ||
| 954 | ./compile ndelay.c | ||
| 955 | |||
| 956 | ndelay_off.o: \ | ||
| 957 | compile ndelay_off.c ndelay.h | ||
| 958 | ./compile ndelay_off.c | ||
| 959 | |||
| 960 | newfield.o: \ | ||
| 961 | compile newfield.c fmt.h datetime.h stralloc.h gen_alloc.h \ | ||
| 962 | date822fmt.h newfield.h stralloc.h | ||
| 963 | ./compile newfield.c | ||
| 964 | |||
| 965 | now.o: \ | ||
| 966 | compile now.c datetime.h now.h datetime.h | ||
| 967 | ./compile now.c | ||
| 968 | |||
| 969 | open.a: \ | ||
| 970 | makelib open_append.o open_excl.o open_read.o open_trunc.o \ | ||
| 971 | open_write.o | ||
| 972 | ./makelib open.a open_append.o open_excl.o open_read.o \ | ||
| 973 | open_trunc.o open_write.o | ||
| 974 | |||
| 975 | open_append.o: \ | ||
| 976 | compile open_append.c open.h | ||
| 977 | ./compile open_append.c | ||
| 978 | |||
| 979 | open_excl.o: \ | ||
| 980 | compile open_excl.c open.h | ||
| 981 | ./compile open_excl.c | ||
| 982 | |||
| 983 | open_read.o: \ | ||
| 984 | compile open_read.c open.h | ||
| 985 | ./compile open_read.c | ||
| 986 | |||
| 987 | open_trunc.o: \ | ||
| 988 | compile open_trunc.c open.h | ||
| 989 | ./compile open_trunc.c | ||
| 990 | |||
| 991 | open_write.o: \ | ||
| 992 | compile open_write.c open.h | ||
| 993 | ./compile open_write.c | ||
| 994 | |||
| 995 | pinq: \ | ||
| 996 | warn-auto.sh pinq.sh conf-qmail conf-break conf-split | ||
| 997 | cat warn-auto.sh pinq.sh \ | ||
| 998 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 999 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 1000 | | sed s}SPLIT}"`head -1 conf-split`"}g \ | ||
| 1001 | > pinq | ||
| 1002 | chmod 755 pinq | ||
| 1003 | |||
| 1004 | predate: \ | ||
| 1005 | load predate.o datetime.a strerr.a sig.a fd.a wait.a substdio.a \ | ||
| 1006 | error.a str.a fs.a | ||
| 1007 | ./load predate datetime.a strerr.a sig.a fd.a wait.a \ | ||
| 1008 | substdio.a error.a str.a fs.a | ||
| 1009 | |||
| 1010 | predate.o: \ | ||
| 1011 | compile predate.c datetime.h fork.h wait.h fd.h fmt.h strerr.h \ | ||
| 1012 | substdio.h subfd.h substdio.h readwrite.h exit.h | ||
| 1013 | ./compile predate.c | ||
| 1014 | |||
| 1015 | preline: \ | ||
| 1016 | load preline.o strerr.a fd.a wait.a sig.a env.a getopt.a substdio.a \ | ||
| 1017 | error.a str.a | ||
| 1018 | ./load preline strerr.a fd.a wait.a sig.a env.a getopt.a \ | ||
| 1019 | substdio.a error.a str.a | ||
| 1020 | |||
| 1021 | preline.0: \ | ||
| 1022 | preline.1 | ||
| 1023 | nroff -man preline.1 > preline.0 | ||
| 1024 | |||
| 1025 | preline.o: \ | ||
| 1026 | compile preline.c fd.h sgetopt.h subgetopt.h readwrite.h strerr.h \ | ||
| 1027 | substdio.h exit.h fork.h wait.h env.h sig.h error.h | ||
| 1028 | ./compile preline.c | ||
| 1029 | |||
| 1030 | prioq.o: \ | ||
| 1031 | compile prioq.c alloc.h gen_allocdefs.h prioq.h datetime.h \ | ||
| 1032 | gen_alloc.h | ||
| 1033 | ./compile prioq.c | ||
| 1034 | |||
| 1035 | proc: \ | ||
| 1036 | proc.sh conf-qmail | ||
| 1037 | cat proc.sh \ | ||
| 1038 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 1039 | > proc | ||
| 1040 | chmod 755 proc | ||
| 1041 | |||
| 1042 | proc+df: \ | ||
| 1043 | proc+df.sh conf-qmail | ||
| 1044 | cat proc+df.sh \ | ||
| 1045 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 1046 | > proc+df | ||
| 1047 | chmod 755 proc+df | ||
| 1048 | |||
| 1049 | prot.o: \ | ||
| 1050 | compile prot.c hasshsgr.h prot.h | ||
| 1051 | ./compile prot.c | ||
| 1052 | |||
| 1053 | qail: \ | ||
| 1054 | warn-auto.sh qail.sh conf-qmail conf-break conf-split | ||
| 1055 | cat warn-auto.sh qail.sh \ | ||
| 1056 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 1057 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 1058 | | sed s}SPLIT}"`head -1 conf-split`"}g \ | ||
| 1059 | > qail | ||
| 1060 | chmod 755 qail | ||
| 1061 | |||
| 1062 | qbiff: \ | ||
| 1063 | load qbiff.o headerbody.o hfield.o getln.a env.a open.a stralloc.a \ | ||
| 1064 | alloc.a substdio.a error.a str.a | ||
| 1065 | ./load qbiff headerbody.o hfield.o getln.a env.a open.a \ | ||
| 1066 | stralloc.a alloc.a substdio.a error.a str.a | ||
| 1067 | |||
| 1068 | qbiff.0: \ | ||
| 1069 | qbiff.1 | ||
| 1070 | nroff -man qbiff.1 > qbiff.0 | ||
| 1071 | |||
| 1072 | qbiff.o: \ | ||
| 1073 | compile qbiff.c readwrite.h stralloc.h gen_alloc.h substdio.h subfd.h \ | ||
| 1074 | substdio.h open.h byte.h str.h headerbody.h hfield.h env.h exit.h | ||
| 1075 | ./compile qbiff.c | ||
| 1076 | |||
| 1077 | qmail-clean: \ | ||
| 1078 | load qmail-clean.o fmtqfn.o now.o getln.a sig.a stralloc.a alloc.a \ | ||
| 1079 | substdio.a error.a str.a fs.a auto_qmail.o auto_split.o | ||
| 1080 | ./load qmail-clean fmtqfn.o now.o getln.a sig.a stralloc.a \ | ||
| 1081 | alloc.a substdio.a error.a str.a fs.a auto_qmail.o \ | ||
| 1082 | auto_split.o | ||
| 1083 | |||
| 1084 | qmail-clean.0: \ | ||
| 1085 | qmail-clean.8 | ||
| 1086 | nroff -man qmail-clean.8 > qmail-clean.0 | ||
| 1087 | |||
| 1088 | qmail-clean.o: \ | ||
| 1089 | compile qmail-clean.c readwrite.h sig.h now.h datetime.h str.h \ | ||
| 1090 | direntry.h getln.h stralloc.h gen_alloc.h substdio.h subfd.h \ | ||
| 1091 | substdio.h byte.h scan.h fmt.h error.h exit.h fmtqfn.h auto_qmail.h | ||
| 1092 | ./compile qmail-clean.c | ||
| 1093 | |||
| 1094 | qmail-command.0: \ | ||
| 1095 | qmail-command.8 | ||
| 1096 | nroff -man qmail-command.8 > qmail-command.0 | ||
| 1097 | |||
| 1098 | qmail-control.0: \ | ||
| 1099 | qmail-control.5 | ||
| 1100 | nroff -man qmail-control.5 > qmail-control.0 | ||
| 1101 | |||
| 1102 | qmail-control.5: \ | ||
| 1103 | qmail-control.9 conf-break conf-spawn | ||
| 1104 | cat qmail-control.9 \ | ||
| 1105 | | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ | ||
| 1106 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 1107 | | sed s}SPAWN}"`head -1 conf-spawn`"}g \ | ||
| 1108 | > qmail-control.5 | ||
| 1109 | |||
| 1110 | qmail-getpw: \ | ||
| 1111 | load qmail-getpw.o case.a substdio.a error.a str.a fs.a auto_break.o \ | ||
| 1112 | auto_usera.o | ||
| 1113 | ./load qmail-getpw case.a substdio.a error.a str.a fs.a \ | ||
| 1114 | auto_break.o auto_usera.o | ||
| 1115 | |||
| 1116 | qmail-getpw.0: \ | ||
| 1117 | qmail-getpw.8 | ||
| 1118 | nroff -man qmail-getpw.8 > qmail-getpw.0 | ||
| 1119 | |||
| 1120 | qmail-getpw.8: \ | ||
| 1121 | qmail-getpw.9 conf-break conf-spawn | ||
| 1122 | cat qmail-getpw.9 \ | ||
| 1123 | | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ | ||
| 1124 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 1125 | | sed s}SPAWN}"`head -1 conf-spawn`"}g \ | ||
| 1126 | > qmail-getpw.8 | ||
| 1127 | |||
| 1128 | qmail-getpw.o: \ | ||
| 1129 | compile qmail-getpw.c readwrite.h substdio.h subfd.h substdio.h \ | ||
| 1130 | error.h exit.h byte.h str.h case.h fmt.h auto_usera.h auto_break.h \ | ||
| 1131 | qlx.h | ||
| 1132 | ./compile qmail-getpw.c | ||
| 1133 | |||
| 1134 | qmail-header.0: \ | ||
| 1135 | qmail-header.5 | ||
| 1136 | nroff -man qmail-header.5 > qmail-header.0 | ||
| 1137 | |||
| 1138 | qmail-inject: \ | ||
| 1139 | load qmail-inject.o headerbody.o hfield.o newfield.o quote.o now.o \ | ||
| 1140 | control.o date822fmt.o constmap.o qmail.o case.a fd.a wait.a open.a \ | ||
| 1141 | getln.a sig.a getopt.a datetime.a token822.o env.a stralloc.a alloc.a \ | ||
| 1142 | substdio.a error.a str.a fs.a auto_qmail.o | ||
| 1143 | ./load qmail-inject headerbody.o hfield.o newfield.o \ | ||
| 1144 | quote.o now.o control.o date822fmt.o constmap.o qmail.o \ | ||
| 1145 | case.a fd.a wait.a open.a getln.a sig.a getopt.a datetime.a \ | ||
| 1146 | token822.o env.a stralloc.a alloc.a substdio.a error.a \ | ||
| 1147 | str.a fs.a auto_qmail.o | ||
| 1148 | |||
| 1149 | qmail-inject.0: \ | ||
| 1150 | qmail-inject.8 | ||
| 1151 | nroff -man qmail-inject.8 > qmail-inject.0 | ||
| 1152 | |||
| 1153 | qmail-inject.o: \ | ||
| 1154 | compile qmail-inject.c sig.h substdio.h stralloc.h gen_alloc.h \ | ||
| 1155 | subfd.h substdio.h sgetopt.h subgetopt.h getln.h alloc.h str.h fmt.h \ | ||
| 1156 | hfield.h token822.h gen_alloc.h control.h env.h gen_alloc.h \ | ||
| 1157 | gen_allocdefs.h error.h qmail.h substdio.h now.h datetime.h exit.h \ | ||
| 1158 | quote.h headerbody.h auto_qmail.h newfield.h stralloc.h constmap.h | ||
| 1159 | ./compile qmail-inject.c | ||
| 1160 | |||
| 1161 | qmail-limits.0: \ | ||
| 1162 | qmail-limits.7 | ||
| 1163 | nroff -man qmail-limits.7 > qmail-limits.0 | ||
| 1164 | |||
| 1165 | qmail-limits.7: \ | ||
| 1166 | qmail-limits.9 conf-break conf-spawn | ||
| 1167 | cat qmail-limits.9 \ | ||
| 1168 | | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ | ||
| 1169 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 1170 | | sed s}SPAWN}"`head -1 conf-spawn`"}g \ | ||
| 1171 | > qmail-limits.7 | ||
| 1172 | |||
| 1173 | qmail-local: \ | ||
| 1174 | load qmail-local.o qmail.o quote.o now.o gfrom.o myctime.o \ | ||
| 1175 | slurpclose.o case.a getln.a getopt.a sig.a open.a seek.a lock.a fd.a \ | ||
| 1176 | wait.a env.a stralloc.a alloc.a strerr.a substdio.a error.a str.a \ | ||
| 1177 | fs.a datetime.a auto_qmail.o auto_patrn.o socket.lib | ||
| 1178 | ./load qmail-local qmail.o quote.o now.o gfrom.o myctime.o \ | ||
| 1179 | slurpclose.o case.a getln.a getopt.a sig.a open.a seek.a \ | ||
| 1180 | lock.a fd.a wait.a env.a stralloc.a alloc.a strerr.a \ | ||
| 1181 | substdio.a error.a str.a fs.a datetime.a auto_qmail.o \ | ||
| 1182 | auto_patrn.o `cat socket.lib` | ||
| 1183 | |||
| 1184 | qmail-local.0: \ | ||
| 1185 | qmail-local.8 | ||
| 1186 | nroff -man qmail-local.8 > qmail-local.0 | ||
| 1187 | |||
| 1188 | qmail-local.o: \ | ||
| 1189 | compile qmail-local.c readwrite.h sig.h env.h byte.h exit.h fork.h \ | ||
| 1190 | open.h wait.h lock.h seek.h substdio.h getln.h strerr.h subfd.h \ | ||
| 1191 | substdio.h sgetopt.h subgetopt.h alloc.h error.h stralloc.h \ | ||
| 1192 | gen_alloc.h fmt.h str.h now.h datetime.h case.h quote.h qmail.h \ | ||
| 1193 | substdio.h slurpclose.h myctime.h gfrom.h auto_patrn.h | ||
| 1194 | ./compile qmail-local.c | ||
| 1195 | |||
| 1196 | qmail-log.0: \ | ||
| 1197 | qmail-log.5 | ||
| 1198 | nroff -man qmail-log.5 > qmail-log.0 | ||
| 1199 | |||
| 1200 | qmail-lspawn: \ | ||
| 1201 | load qmail-lspawn.o spawn.o prot.o slurpclose.o coe.o sig.a wait.a \ | ||
| 1202 | case.a cdb.a fd.a open.a stralloc.a alloc.a substdio.a error.a str.a \ | ||
| 1203 | fs.a auto_qmail.o auto_uids.o auto_spawn.o | ||
| 1204 | ./load qmail-lspawn spawn.o prot.o slurpclose.o coe.o \ | ||
| 1205 | sig.a wait.a case.a cdb.a fd.a open.a stralloc.a alloc.a \ | ||
| 1206 | substdio.a error.a str.a fs.a auto_qmail.o auto_uids.o \ | ||
| 1207 | auto_spawn.o | ||
| 1208 | |||
| 1209 | qmail-lspawn.0: \ | ||
| 1210 | qmail-lspawn.8 | ||
| 1211 | nroff -man qmail-lspawn.8 > qmail-lspawn.0 | ||
| 1212 | |||
| 1213 | qmail-lspawn.o: \ | ||
| 1214 | compile qmail-lspawn.c fd.h wait.h prot.h substdio.h stralloc.h \ | ||
| 1215 | gen_alloc.h scan.h exit.h fork.h error.h cdb.h uint32.h case.h \ | ||
| 1216 | slurpclose.h auto_qmail.h auto_uids.h qlx.h | ||
| 1217 | ./compile qmail-lspawn.c | ||
| 1218 | |||
| 1219 | qmail-newmrh: \ | ||
| 1220 | load qmail-newmrh.o cdbmss.o getln.a open.a cdbmake.a seek.a case.a \ | ||
| 1221 | stralloc.a alloc.a strerr.a substdio.a error.a str.a auto_qmail.o | ||
| 1222 | ./load qmail-newmrh cdbmss.o getln.a open.a cdbmake.a \ | ||
| 1223 | seek.a case.a stralloc.a alloc.a strerr.a substdio.a \ | ||
| 1224 | error.a str.a auto_qmail.o | ||
| 1225 | |||
| 1226 | qmail-newmrh.0: \ | ||
| 1227 | qmail-newmrh.8 | ||
| 1228 | nroff -man qmail-newmrh.8 > qmail-newmrh.0 | ||
| 1229 | |||
| 1230 | qmail-newmrh.8: \ | ||
| 1231 | qmail-newmrh.9 conf-break conf-spawn | ||
| 1232 | cat qmail-newmrh.9 \ | ||
| 1233 | | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ | ||
| 1234 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 1235 | | sed s}SPAWN}"`head -1 conf-spawn`"}g \ | ||
| 1236 | > qmail-newmrh.8 | ||
| 1237 | |||
| 1238 | qmail-newmrh.o: \ | ||
| 1239 | compile qmail-newmrh.c strerr.h stralloc.h gen_alloc.h substdio.h \ | ||
| 1240 | getln.h exit.h readwrite.h open.h auto_qmail.h cdbmss.h cdbmake.h \ | ||
| 1241 | uint32.h substdio.h | ||
| 1242 | ./compile qmail-newmrh.c | ||
| 1243 | |||
| 1244 | qmail-newu: \ | ||
| 1245 | load qmail-newu.o cdbmss.o getln.a open.a seek.a cdbmake.a case.a \ | ||
| 1246 | stralloc.a alloc.a substdio.a error.a str.a auto_qmail.o | ||
| 1247 | ./load qmail-newu cdbmss.o getln.a open.a seek.a cdbmake.a \ | ||
| 1248 | case.a stralloc.a alloc.a substdio.a error.a str.a \ | ||
| 1249 | auto_qmail.o | ||
| 1250 | |||
| 1251 | qmail-newu.0: \ | ||
| 1252 | qmail-newu.8 | ||
| 1253 | nroff -man qmail-newu.8 > qmail-newu.0 | ||
| 1254 | |||
| 1255 | qmail-newu.8: \ | ||
| 1256 | qmail-newu.9 conf-break conf-spawn | ||
| 1257 | cat qmail-newu.9 \ | ||
| 1258 | | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ | ||
| 1259 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 1260 | | sed s}SPAWN}"`head -1 conf-spawn`"}g \ | ||
| 1261 | > qmail-newu.8 | ||
| 1262 | |||
| 1263 | qmail-newu.o: \ | ||
| 1264 | compile qmail-newu.c stralloc.h gen_alloc.h subfd.h substdio.h \ | ||
| 1265 | getln.h substdio.h cdbmss.h cdbmake.h uint32.h substdio.h exit.h \ | ||
| 1266 | readwrite.h open.h error.h case.h auto_qmail.h | ||
| 1267 | ./compile qmail-newu.c | ||
| 1268 | |||
| 1269 | qmail-pop3d: \ | ||
| 1270 | load qmail-pop3d.o commands.o case.a timeoutread.o timeoutwrite.o \ | ||
| 1271 | maildir.o prioq.o now.o env.a strerr.a sig.a open.a getln.a \ | ||
| 1272 | stralloc.a alloc.a substdio.a error.a str.a fs.a socket.lib | ||
| 1273 | ./load qmail-pop3d commands.o case.a timeoutread.o \ | ||
| 1274 | timeoutwrite.o maildir.o prioq.o now.o env.a strerr.a sig.a \ | ||
| 1275 | open.a getln.a stralloc.a alloc.a substdio.a error.a str.a \ | ||
| 1276 | fs.a `cat socket.lib` | ||
| 1277 | |||
| 1278 | qmail-pop3d.0: \ | ||
| 1279 | qmail-pop3d.8 | ||
| 1280 | nroff -man qmail-pop3d.8 > qmail-pop3d.0 | ||
| 1281 | |||
| 1282 | qmail-pop3d.o: \ | ||
| 1283 | compile qmail-pop3d.c commands.h sig.h getln.h stralloc.h gen_alloc.h \ | ||
| 1284 | substdio.h alloc.h open.h prioq.h datetime.h gen_alloc.h scan.h fmt.h \ | ||
| 1285 | str.h exit.h maildir.h strerr.h readwrite.h timeoutread.h \ | ||
| 1286 | timeoutwrite.h | ||
| 1287 | ./compile qmail-pop3d.c | ||
| 1288 | |||
| 1289 | qmail-popup: \ | ||
| 1290 | load qmail-popup.o commands.o timeoutread.o timeoutwrite.o now.o \ | ||
| 1291 | case.a fd.a sig.a wait.a stralloc.a alloc.a substdio.a error.a str.a \ | ||
| 1292 | fs.a socket.lib | ||
| 1293 | ./load qmail-popup commands.o timeoutread.o timeoutwrite.o \ | ||
| 1294 | now.o case.a fd.a sig.a wait.a stralloc.a alloc.a \ | ||
| 1295 | substdio.a error.a str.a fs.a `cat socket.lib` | ||
| 1296 | |||
| 1297 | qmail-popup.0: \ | ||
| 1298 | qmail-popup.8 | ||
| 1299 | nroff -man qmail-popup.8 > qmail-popup.0 | ||
| 1300 | |||
| 1301 | qmail-popup.o: \ | ||
| 1302 | compile qmail-popup.c commands.h fd.h sig.h stralloc.h gen_alloc.h \ | ||
| 1303 | substdio.h alloc.h wait.h str.h byte.h now.h datetime.h fmt.h exit.h \ | ||
| 1304 | readwrite.h timeoutread.h timeoutwrite.h | ||
| 1305 | ./compile qmail-popup.c | ||
| 1306 | |||
| 1307 | qmail-pw2u: \ | ||
| 1308 | load qmail-pw2u.o constmap.o control.o open.a getln.a case.a getopt.a \ | ||
| 1309 | stralloc.a alloc.a substdio.a error.a str.a fs.a auto_usera.o \ | ||
| 1310 | auto_break.o auto_qmail.o | ||
| 1311 | ./load qmail-pw2u constmap.o control.o open.a getln.a \ | ||
| 1312 | case.a getopt.a stralloc.a alloc.a substdio.a error.a str.a \ | ||
| 1313 | fs.a auto_usera.o auto_break.o auto_qmail.o | ||
| 1314 | |||
| 1315 | qmail-pw2u.0: \ | ||
| 1316 | qmail-pw2u.8 | ||
| 1317 | nroff -man qmail-pw2u.8 > qmail-pw2u.0 | ||
| 1318 | |||
| 1319 | qmail-pw2u.8: \ | ||
| 1320 | qmail-pw2u.9 conf-break conf-spawn | ||
| 1321 | cat qmail-pw2u.9 \ | ||
| 1322 | | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ | ||
| 1323 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 1324 | | sed s}SPAWN}"`head -1 conf-spawn`"}g \ | ||
| 1325 | > qmail-pw2u.8 | ||
| 1326 | |||
| 1327 | qmail-pw2u.o: \ | ||
| 1328 | compile qmail-pw2u.c substdio.h readwrite.h subfd.h substdio.h \ | ||
| 1329 | sgetopt.h subgetopt.h control.h constmap.h stralloc.h gen_alloc.h \ | ||
| 1330 | fmt.h str.h scan.h open.h error.h getln.h auto_break.h auto_qmail.h \ | ||
| 1331 | auto_usera.h | ||
| 1332 | ./compile qmail-pw2u.c | ||
| 1333 | |||
| 1334 | qmail-qmqpc: \ | ||
| 1335 | load qmail-qmqpc.o slurpclose.o timeoutread.o timeoutwrite.o \ | ||
| 1336 | timeoutconn.o ip.o control.o auto_qmail.o sig.a ndelay.a open.a \ | ||
| 1337 | getln.a substdio.a stralloc.a alloc.a error.a str.a fs.a socket.lib | ||
| 1338 | ./load qmail-qmqpc slurpclose.o timeoutread.o \ | ||
| 1339 | timeoutwrite.o timeoutconn.o ip.o control.o auto_qmail.o \ | ||
| 1340 | sig.a ndelay.a open.a getln.a substdio.a stralloc.a alloc.a \ | ||
| 1341 | error.a str.a fs.a `cat socket.lib` | ||
| 1342 | |||
| 1343 | qmail-qmqpc.0: \ | ||
| 1344 | qmail-qmqpc.8 | ||
| 1345 | nroff -man qmail-qmqpc.8 > qmail-qmqpc.0 | ||
| 1346 | |||
| 1347 | qmail-qmqpc.o: \ | ||
| 1348 | compile qmail-qmqpc.c substdio.h getln.h readwrite.h exit.h \ | ||
| 1349 | stralloc.h gen_alloc.h slurpclose.h error.h sig.h ip.h timeoutconn.h \ | ||
| 1350 | timeoutread.h timeoutwrite.h auto_qmail.h control.h fmt.h | ||
| 1351 | ./compile qmail-qmqpc.c | ||
| 1352 | |||
| 1353 | qmail-qmqpd: \ | ||
| 1354 | load qmail-qmqpd.o received.o now.o date822fmt.o qmail.o auto_qmail.o \ | ||
| 1355 | env.a substdio.a sig.a error.a wait.a fd.a str.a datetime.a fs.a | ||
| 1356 | ./load qmail-qmqpd received.o now.o date822fmt.o qmail.o \ | ||
| 1357 | auto_qmail.o env.a substdio.a sig.a error.a wait.a fd.a \ | ||
| 1358 | str.a datetime.a fs.a | ||
| 1359 | |||
| 1360 | qmail-qmqpd.0: \ | ||
| 1361 | qmail-qmqpd.8 | ||
| 1362 | nroff -man qmail-qmqpd.8 > qmail-qmqpd.0 | ||
| 1363 | |||
| 1364 | qmail-qmqpd.o: \ | ||
| 1365 | compile qmail-qmqpd.c auto_qmail.h qmail.h substdio.h received.h \ | ||
| 1366 | sig.h substdio.h readwrite.h exit.h now.h datetime.h fmt.h env.h | ||
| 1367 | ./compile qmail-qmqpd.c | ||
| 1368 | |||
| 1369 | qmail-qmtpd: \ | ||
| 1370 | load qmail-qmtpd.o rcpthosts.o control.o constmap.o received.o \ | ||
| 1371 | date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a open.a \ | ||
| 1372 | getln.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a \ | ||
| 1373 | str.a fs.a auto_qmail.o | ||
| 1374 | ./load qmail-qmtpd rcpthosts.o control.o constmap.o \ | ||
| 1375 | received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \ | ||
| 1376 | datetime.a open.a getln.a sig.a case.a env.a stralloc.a \ | ||
| 1377 | alloc.a substdio.a error.a str.a fs.a auto_qmail.o | ||
| 1378 | |||
| 1379 | qmail-qmtpd.0: \ | ||
| 1380 | qmail-qmtpd.8 | ||
| 1381 | nroff -man qmail-qmtpd.8 > qmail-qmtpd.0 | ||
| 1382 | |||
| 1383 | qmail-qmtpd.o: \ | ||
| 1384 | compile qmail-qmtpd.c stralloc.h gen_alloc.h substdio.h qmail.h \ | ||
| 1385 | substdio.h now.h datetime.h str.h fmt.h env.h sig.h rcpthosts.h \ | ||
| 1386 | auto_qmail.h readwrite.h control.h received.h | ||
| 1387 | ./compile qmail-qmtpd.c | ||
| 1388 | |||
| 1389 | qmail-qread: \ | ||
| 1390 | load qmail-qread.o fmtqfn.o readsubdir.o date822fmt.o datetime.a \ | ||
| 1391 | open.a getln.a stralloc.a alloc.a substdio.a error.a str.a fs.a \ | ||
| 1392 | auto_qmail.o auto_split.o | ||
| 1393 | ./load qmail-qread fmtqfn.o readsubdir.o date822fmt.o \ | ||
| 1394 | datetime.a open.a getln.a stralloc.a alloc.a substdio.a \ | ||
| 1395 | error.a str.a fs.a auto_qmail.o auto_split.o | ||
| 1396 | |||
| 1397 | qmail-qread.0: \ | ||
| 1398 | qmail-qread.8 | ||
| 1399 | nroff -man qmail-qread.8 > qmail-qread.0 | ||
| 1400 | |||
| 1401 | qmail-qread.o: \ | ||
| 1402 | compile qmail-qread.c stralloc.h gen_alloc.h substdio.h subfd.h \ | ||
| 1403 | substdio.h fmt.h str.h getln.h fmtqfn.h readsubdir.h direntry.h \ | ||
| 1404 | auto_qmail.h open.h datetime.h date822fmt.h readwrite.h error.h \ | ||
| 1405 | exit.h | ||
| 1406 | ./compile qmail-qread.c | ||
| 1407 | |||
| 1408 | qmail-qstat: \ | ||
| 1409 | warn-auto.sh qmail-qstat.sh conf-qmail conf-break conf-split | ||
| 1410 | cat warn-auto.sh qmail-qstat.sh \ | ||
| 1411 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 1412 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 1413 | | sed s}SPLIT}"`head -1 conf-split`"}g \ | ||
| 1414 | > qmail-qstat | ||
| 1415 | chmod 755 qmail-qstat | ||
| 1416 | |||
| 1417 | qmail-qstat.0: \ | ||
| 1418 | qmail-qstat.8 | ||
| 1419 | nroff -man qmail-qstat.8 > qmail-qstat.0 | ||
| 1420 | |||
| 1421 | qmail-queue: \ | ||
| 1422 | load qmail-queue.o triggerpull.o fmtqfn.o now.o date822fmt.o \ | ||
| 1423 | datetime.a seek.a ndelay.a open.a sig.a alloc.a substdio.a error.a \ | ||
| 1424 | str.a fs.a auto_qmail.o auto_split.o auto_uids.o | ||
| 1425 | ./load qmail-queue triggerpull.o fmtqfn.o now.o \ | ||
| 1426 | date822fmt.o datetime.a seek.a ndelay.a open.a sig.a \ | ||
| 1427 | alloc.a substdio.a error.a str.a fs.a auto_qmail.o \ | ||
| 1428 | auto_split.o auto_uids.o | ||
| 1429 | |||
| 1430 | qmail-queue.0: \ | ||
| 1431 | qmail-queue.8 | ||
| 1432 | nroff -man qmail-queue.8 > qmail-queue.0 | ||
| 1433 | |||
| 1434 | qmail-queue.o: \ | ||
| 1435 | compile qmail-queue.c readwrite.h sig.h exit.h open.h seek.h fmt.h \ | ||
| 1436 | alloc.h substdio.h datetime.h now.h datetime.h triggerpull.h extra.h \ | ||
| 1437 | auto_qmail.h auto_uids.h date822fmt.h fmtqfn.h | ||
| 1438 | ./compile qmail-queue.c | ||
| 1439 | |||
| 1440 | qmail-remote: \ | ||
| 1441 | load qmail-remote.o control.o constmap.o timeoutread.o timeoutwrite.o \ | ||
| 1442 | timeoutconn.o tcpto.o now.o dns.o ip.o ipalloc.o ipme.o quote.o \ | ||
| 1443 | ndelay.a case.a sig.a open.a lock.a seek.a getln.a stralloc.a alloc.a \ | ||
| 1444 | substdio.a error.a str.a fs.a auto_qmail.o dns.lib socket.lib | ||
| 1445 | ./load qmail-remote control.o constmap.o timeoutread.o \ | ||
| 1446 | timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \ | ||
| 1447 | ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \ | ||
| 1448 | lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \ | ||
| 1449 | str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib` | ||
| 1450 | |||
| 1451 | qmail-remote.0: \ | ||
| 1452 | qmail-remote.8 | ||
| 1453 | nroff -man qmail-remote.8 > qmail-remote.0 | ||
| 1454 | |||
| 1455 | qmail-remote.o: \ | ||
| 1456 | compile qmail-remote.c sig.h stralloc.h gen_alloc.h substdio.h \ | ||
| 1457 | subfd.h substdio.h scan.h case.h error.h auto_qmail.h control.h dns.h \ | ||
| 1458 | alloc.h quote.h ip.h ipalloc.h ip.h gen_alloc.h ipme.h ip.h ipalloc.h \ | ||
| 1459 | gen_alloc.h gen_allocdefs.h str.h now.h datetime.h exit.h constmap.h \ | ||
| 1460 | tcpto.h readwrite.h timeoutconn.h timeoutread.h timeoutwrite.h | ||
| 1461 | ./compile qmail-remote.c | ||
| 1462 | |||
| 1463 | qmail-rspawn: \ | ||
| 1464 | load qmail-rspawn.o spawn.o tcpto_clean.o now.o coe.o sig.a open.a \ | ||
| 1465 | seek.a lock.a wait.a fd.a stralloc.a alloc.a substdio.a error.a str.a \ | ||
| 1466 | auto_qmail.o auto_uids.o auto_spawn.o | ||
| 1467 | ./load qmail-rspawn spawn.o tcpto_clean.o now.o coe.o \ | ||
| 1468 | sig.a open.a seek.a lock.a wait.a fd.a stralloc.a alloc.a \ | ||
| 1469 | substdio.a error.a str.a auto_qmail.o auto_uids.o \ | ||
| 1470 | auto_spawn.o | ||
| 1471 | |||
| 1472 | qmail-rspawn.0: \ | ||
| 1473 | qmail-rspawn.8 | ||
| 1474 | nroff -man qmail-rspawn.8 > qmail-rspawn.0 | ||
| 1475 | |||
| 1476 | qmail-rspawn.o: \ | ||
| 1477 | compile qmail-rspawn.c fd.h wait.h substdio.h exit.h fork.h error.h \ | ||
| 1478 | tcpto.h | ||
| 1479 | ./compile qmail-rspawn.c | ||
| 1480 | |||
| 1481 | qmail-send: \ | ||
| 1482 | load qmail-send.o qsutil.o control.o constmap.o newfield.o prioq.o \ | ||
| 1483 | trigger.o fmtqfn.o quote.o now.o readsubdir.o qmail.o date822fmt.o \ | ||
| 1484 | datetime.a case.a ndelay.a getln.a wait.a seek.a fd.a sig.a open.a \ | ||
| 1485 | lock.a stralloc.a alloc.a substdio.a error.a str.a fs.a auto_qmail.o \ | ||
| 1486 | auto_split.o | ||
| 1487 | ./load qmail-send qsutil.o control.o constmap.o newfield.o \ | ||
| 1488 | prioq.o trigger.o fmtqfn.o quote.o now.o readsubdir.o \ | ||
| 1489 | qmail.o date822fmt.o datetime.a case.a ndelay.a getln.a \ | ||
| 1490 | wait.a seek.a fd.a sig.a open.a lock.a stralloc.a alloc.a \ | ||
| 1491 | substdio.a error.a str.a fs.a auto_qmail.o auto_split.o | ||
| 1492 | |||
| 1493 | qmail-send.0: \ | ||
| 1494 | qmail-send.8 | ||
| 1495 | nroff -man qmail-send.8 > qmail-send.0 | ||
| 1496 | |||
| 1497 | qmail-send.8: \ | ||
| 1498 | qmail-send.9 conf-break conf-spawn | ||
| 1499 | cat qmail-send.9 \ | ||
| 1500 | | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ | ||
| 1501 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 1502 | | sed s}SPAWN}"`head -1 conf-spawn`"}g \ | ||
| 1503 | > qmail-send.8 | ||
| 1504 | |||
| 1505 | qmail-send.o: \ | ||
| 1506 | compile qmail-send.c readwrite.h sig.h direntry.h control.h select.h \ | ||
| 1507 | open.h seek.h exit.h lock.h ndelay.h now.h datetime.h getln.h \ | ||
| 1508 | substdio.h alloc.h error.h stralloc.h gen_alloc.h str.h byte.h fmt.h \ | ||
| 1509 | scan.h case.h auto_qmail.h trigger.h newfield.h stralloc.h quote.h \ | ||
| 1510 | qmail.h substdio.h qsutil.h prioq.h datetime.h gen_alloc.h constmap.h \ | ||
| 1511 | fmtqfn.h readsubdir.h direntry.h | ||
| 1512 | ./compile qmail-send.c | ||
| 1513 | |||
| 1514 | qmail-showctl: \ | ||
| 1515 | load qmail-showctl.o auto_uids.o control.o open.a getln.a stralloc.a \ | ||
| 1516 | alloc.a substdio.a error.a str.a fs.a auto_qmail.o auto_break.o \ | ||
| 1517 | auto_patrn.o auto_spawn.o auto_split.o | ||
| 1518 | ./load qmail-showctl auto_uids.o control.o open.a getln.a \ | ||
| 1519 | stralloc.a alloc.a substdio.a error.a str.a fs.a \ | ||
| 1520 | auto_qmail.o auto_break.o auto_patrn.o auto_spawn.o \ | ||
| 1521 | auto_split.o | ||
| 1522 | |||
| 1523 | qmail-showctl.0: \ | ||
| 1524 | qmail-showctl.8 | ||
| 1525 | nroff -man qmail-showctl.8 > qmail-showctl.0 | ||
| 1526 | |||
| 1527 | qmail-showctl.o: \ | ||
| 1528 | compile qmail-showctl.c substdio.h subfd.h substdio.h exit.h fmt.h \ | ||
| 1529 | str.h control.h constmap.h stralloc.h gen_alloc.h direntry.h \ | ||
| 1530 | auto_uids.h auto_qmail.h auto_break.h auto_patrn.h auto_spawn.h \ | ||
| 1531 | auto_split.h | ||
| 1532 | ./compile qmail-showctl.c | ||
| 1533 | |||
| 1534 | qmail-smtpd: \ | ||
| 1535 | load qmail-smtpd.o rcpthosts.o commands.o timeoutread.o \ | ||
| 1536 | timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \ | ||
| 1537 | date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \ | ||
| 1538 | open.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a str.a \ | ||
| 1539 | fs.a auto_qmail.o socket.lib | ||
| 1540 | ./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \ | ||
| 1541 | timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \ | ||
| 1542 | received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \ | ||
| 1543 | datetime.a getln.a open.a sig.a case.a env.a stralloc.a \ | ||
| 1544 | alloc.a substdio.a error.a str.a fs.a auto_qmail.o `cat \ | ||
| 1545 | socket.lib` | ||
| 1546 | |||
| 1547 | qmail-smtpd.0: \ | ||
| 1548 | qmail-smtpd.8 | ||
| 1549 | nroff -man qmail-smtpd.8 > qmail-smtpd.0 | ||
| 1550 | |||
| 1551 | qmail-smtpd.o: \ | ||
| 1552 | compile qmail-smtpd.c sig.h readwrite.h stralloc.h gen_alloc.h \ | ||
| 1553 | substdio.h alloc.h auto_qmail.h control.h received.h constmap.h \ | ||
| 1554 | error.h ipme.h ip.h ipalloc.h ip.h gen_alloc.h ip.h qmail.h \ | ||
| 1555 | substdio.h str.h fmt.h scan.h byte.h case.h env.h now.h datetime.h \ | ||
| 1556 | exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h | ||
| 1557 | ./compile qmail-smtpd.c | ||
| 1558 | |||
| 1559 | qmail-start: \ | ||
| 1560 | load qmail-start.o prot.o fd.a auto_uids.o | ||
| 1561 | ./load qmail-start prot.o fd.a auto_uids.o | ||
| 1562 | |||
| 1563 | qmail-start.0: \ | ||
| 1564 | qmail-start.8 | ||
| 1565 | nroff -man qmail-start.8 > qmail-start.0 | ||
| 1566 | |||
| 1567 | qmail-start.8: \ | ||
| 1568 | qmail-start.9 conf-break conf-spawn | ||
| 1569 | cat qmail-start.9 \ | ||
| 1570 | | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ | ||
| 1571 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 1572 | | sed s}SPAWN}"`head -1 conf-spawn`"}g \ | ||
| 1573 | > qmail-start.8 | ||
| 1574 | |||
| 1575 | qmail-start.o: \ | ||
| 1576 | compile qmail-start.c fd.h prot.h exit.h fork.h auto_uids.h | ||
| 1577 | ./compile qmail-start.c | ||
| 1578 | |||
| 1579 | qmail-tcpok: \ | ||
| 1580 | load qmail-tcpok.o open.a lock.a strerr.a substdio.a error.a str.a \ | ||
| 1581 | auto_qmail.o | ||
| 1582 | ./load qmail-tcpok open.a lock.a strerr.a substdio.a \ | ||
| 1583 | error.a str.a auto_qmail.o | ||
| 1584 | |||
| 1585 | qmail-tcpok.0: \ | ||
| 1586 | qmail-tcpok.8 | ||
| 1587 | nroff -man qmail-tcpok.8 > qmail-tcpok.0 | ||
| 1588 | |||
| 1589 | qmail-tcpok.o: \ | ||
| 1590 | compile qmail-tcpok.c strerr.h substdio.h lock.h open.h readwrite.h \ | ||
| 1591 | auto_qmail.h exit.h | ||
| 1592 | ./compile qmail-tcpok.c | ||
| 1593 | |||
| 1594 | qmail-tcpto: \ | ||
| 1595 | load qmail-tcpto.o ip.o now.o open.a lock.a substdio.a error.a str.a \ | ||
| 1596 | fs.a auto_qmail.o | ||
| 1597 | ./load qmail-tcpto ip.o now.o open.a lock.a substdio.a \ | ||
| 1598 | error.a str.a fs.a auto_qmail.o | ||
| 1599 | |||
| 1600 | qmail-tcpto.0: \ | ||
| 1601 | qmail-tcpto.8 | ||
| 1602 | nroff -man qmail-tcpto.8 > qmail-tcpto.0 | ||
| 1603 | |||
| 1604 | qmail-tcpto.o: \ | ||
| 1605 | compile qmail-tcpto.c substdio.h subfd.h substdio.h auto_qmail.h \ | ||
| 1606 | fmt.h ip.h lock.h error.h exit.h datetime.h now.h datetime.h | ||
| 1607 | ./compile qmail-tcpto.c | ||
| 1608 | |||
| 1609 | qmail-upq: \ | ||
| 1610 | warn-auto.sh qmail-upq.sh conf-qmail conf-break conf-split | ||
| 1611 | cat warn-auto.sh qmail-upq.sh \ | ||
| 1612 | | sed s}QMAIL}"`head -1 conf-qmail`"}g \ | ||
| 1613 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 1614 | | sed s}SPLIT}"`head -1 conf-split`"}g \ | ||
| 1615 | > qmail-upq | ||
| 1616 | chmod 755 qmail-upq | ||
| 1617 | |||
| 1618 | qmail-users.0: \ | ||
| 1619 | qmail-users.5 | ||
| 1620 | nroff -man qmail-users.5 > qmail-users.0 | ||
| 1621 | |||
| 1622 | qmail-users.5: \ | ||
| 1623 | qmail-users.9 conf-break conf-spawn | ||
| 1624 | cat qmail-users.9 \ | ||
| 1625 | | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ | ||
| 1626 | | sed s}BREAK}"`head -1 conf-break`"}g \ | ||
| 1627 | | sed s}SPAWN}"`head -1 conf-spawn`"}g \ | ||
| 1628 | > qmail-users.5 | ||
| 1629 | |||
| 1630 | qmail.0: \ | ||
| 1631 | qmail.7 | ||
| 1632 | nroff -man qmail.7 > qmail.0 | ||
| 1633 | |||
| 1634 | qmail.o: \ | ||
| 1635 | compile qmail.c substdio.h readwrite.h wait.h exit.h fork.h fd.h \ | ||
| 1636 | qmail.h substdio.h auto_qmail.h | ||
| 1637 | ./compile qmail.c | ||
| 1638 | |||
| 1639 | qreceipt: \ | ||
| 1640 | load qreceipt.o headerbody.o hfield.o quote.o token822.o qmail.o \ | ||
| 1641 | getln.a fd.a wait.a sig.a env.a stralloc.a alloc.a substdio.a error.a \ | ||
| 1642 | str.a auto_qmail.o | ||
| 1643 | ./load qreceipt headerbody.o hfield.o quote.o token822.o \ | ||
| 1644 | qmail.o getln.a fd.a wait.a sig.a env.a stralloc.a alloc.a \ | ||
| 1645 | substdio.a error.a str.a auto_qmail.o | ||
| 1646 | |||
| 1647 | qreceipt.0: \ | ||
| 1648 | qreceipt.1 | ||
| 1649 | nroff -man qreceipt.1 > qreceipt.0 | ||
| 1650 | |||
| 1651 | qreceipt.o: \ | ||
| 1652 | compile qreceipt.c sig.h env.h substdio.h stralloc.h gen_alloc.h \ | ||
| 1653 | subfd.h substdio.h getln.h alloc.h str.h hfield.h token822.h \ | ||
| 1654 | gen_alloc.h error.h gen_alloc.h gen_allocdefs.h headerbody.h exit.h \ | ||
| 1655 | open.h quote.h qmail.h substdio.h | ||
| 1656 | ./compile qreceipt.c | ||
| 1657 | |||
| 1658 | qsmhook: \ | ||
| 1659 | load qsmhook.o sig.a case.a fd.a wait.a getopt.a env.a stralloc.a \ | ||
| 1660 | alloc.a substdio.a error.a str.a | ||
| 1661 | ./load qsmhook sig.a case.a fd.a wait.a getopt.a env.a \ | ||
| 1662 | stralloc.a alloc.a substdio.a error.a str.a | ||
| 1663 | |||
| 1664 | qsmhook.o: \ | ||
| 1665 | compile qsmhook.c fd.h stralloc.h gen_alloc.h readwrite.h sgetopt.h \ | ||
| 1666 | subgetopt.h wait.h env.h byte.h str.h alloc.h exit.h fork.h case.h \ | ||
| 1667 | subfd.h substdio.h error.h substdio.h sig.h | ||
| 1668 | ./compile qsmhook.c | ||
| 1669 | |||
| 1670 | qsutil.o: \ | ||
| 1671 | compile qsutil.c stralloc.h gen_alloc.h readwrite.h substdio.h \ | ||
| 1672 | qsutil.h | ||
| 1673 | ./compile qsutil.c | ||
| 1674 | |||
| 1675 | quote.o: \ | ||
| 1676 | compile quote.c stralloc.h gen_alloc.h str.h quote.h | ||
| 1677 | ./compile quote.c | ||
| 1678 | |||
| 1679 | rcpthosts.o: \ | ||
| 1680 | compile rcpthosts.c cdb.h uint32.h byte.h open.h error.h control.h \ | ||
| 1681 | constmap.h stralloc.h gen_alloc.h rcpthosts.h | ||
| 1682 | ./compile rcpthosts.c | ||
| 1683 | |||
| 1684 | readsubdir.o: \ | ||
| 1685 | compile readsubdir.c readsubdir.h direntry.h fmt.h scan.h str.h \ | ||
| 1686 | auto_split.h | ||
| 1687 | ./compile readsubdir.c | ||
| 1688 | |||
| 1689 | received.o: \ | ||
| 1690 | compile received.c fmt.h qmail.h substdio.h now.h datetime.h \ | ||
| 1691 | datetime.h date822fmt.h received.h | ||
| 1692 | ./compile received.c | ||
| 1693 | |||
| 1694 | remoteinfo.o: \ | ||
| 1695 | compile remoteinfo.c byte.h substdio.h ip.h fmt.h timeoutconn.h \ | ||
| 1696 | timeoutread.h timeoutwrite.h remoteinfo.h | ||
| 1697 | ./compile remoteinfo.c | ||
| 1698 | |||
| 1699 | scan_8long.o: \ | ||
| 1700 | compile scan_8long.c scan.h | ||
| 1701 | ./compile scan_8long.c | ||
| 1702 | |||
| 1703 | scan_ulong.o: \ | ||
| 1704 | compile scan_ulong.c scan.h | ||
| 1705 | ./compile scan_ulong.c | ||
| 1706 | |||
| 1707 | seek.a: \ | ||
| 1708 | makelib seek_cur.o seek_end.o seek_set.o seek_trunc.o | ||
| 1709 | ./makelib seek.a seek_cur.o seek_end.o seek_set.o \ | ||
| 1710 | seek_trunc.o | ||
| 1711 | |||
| 1712 | seek_cur.o: \ | ||
| 1713 | compile seek_cur.c seek.h | ||
| 1714 | ./compile seek_cur.c | ||
| 1715 | |||
| 1716 | seek_end.o: \ | ||
| 1717 | compile seek_end.c seek.h | ||
| 1718 | ./compile seek_end.c | ||
| 1719 | |||
| 1720 | seek_set.o: \ | ||
| 1721 | compile seek_set.c seek.h | ||
| 1722 | ./compile seek_set.c | ||
| 1723 | |||
| 1724 | seek_trunc.o: \ | ||
| 1725 | compile seek_trunc.c seek.h | ||
| 1726 | ./compile seek_trunc.c | ||
| 1727 | |||
| 1728 | select.h: \ | ||
| 1729 | compile trysysel.c select.h1 select.h2 | ||
| 1730 | ( ./compile trysysel.c >/dev/null 2>&1 \ | ||
| 1731 | && cat select.h2 || cat select.h1 ) > select.h | ||
| 1732 | rm -f trysysel.o trysysel | ||
| 1733 | |||
| 1734 | sendmail: \ | ||
| 1735 | load sendmail.o env.a getopt.a alloc.a substdio.a error.a str.a \ | ||
| 1736 | auto_qmail.o | ||
| 1737 | ./load sendmail env.a getopt.a alloc.a substdio.a error.a \ | ||
| 1738 | str.a auto_qmail.o | ||
| 1739 | |||
| 1740 | sendmail.o: \ | ||
| 1741 | compile sendmail.c sgetopt.h subgetopt.h substdio.h subfd.h \ | ||
| 1742 | substdio.h alloc.h auto_qmail.h exit.h env.h str.h | ||
| 1743 | ./compile sendmail.c | ||
| 1744 | |||
| 1745 | setup: \ | ||
| 1746 | it man | ||
| 1747 | ./install | ||
| 1748 | |||
| 1749 | sgetopt.o: \ | ||
| 1750 | compile sgetopt.c substdio.h subfd.h substdio.h sgetopt.h subgetopt.h \ | ||
| 1751 | subgetopt.h | ||
| 1752 | ./compile sgetopt.c | ||
| 1753 | |||
| 1754 | shar: \ | ||
| 1755 | FILES BLURB BLURB2 BLURB3 BLURB4 README FAQ INSTALL INSTALL.alias \ | ||
| 1756 | INSTALL.ctl INSTALL.ids INSTALL.maildir INSTALL.mbox INSTALL.vsm \ | ||
| 1757 | REMOVE.sendmail REMOVE.binmail TEST.deliver TEST.receive UPGRADE \ | ||
| 1758 | THOUGHTS TODO THANKS CHANGES SECURITY INTERNALS SENDMAIL \ | ||
| 1759 | PIC.local2alias PIC.local2ext PIC.local2local PIC.local2rem \ | ||
| 1760 | PIC.local2virt PIC.nullclient PIC.relaybad PIC.relaygood \ | ||
| 1761 | PIC.rem2local FILES VERSION SYSDEPS TARGETS Makefile BIN.README \ | ||
| 1762 | BIN.Makefile BIN.setup idedit.c conf-break auto_break.h conf-spawn \ | ||
| 1763 | auto_spawn.h chkspawn.c conf-split auto_split.h conf-patrn \ | ||
| 1764 | auto_patrn.h conf-users conf-groups auto_uids.h auto_usera.h extra.h \ | ||
| 1765 | addresses.5 except.1 bouncesaying.1 condredirect.1 dot-qmail.9 \ | ||
| 1766 | envelopes.5 forgeries.7 forward.1 maildir2mbox.1 maildirmake.1 \ | ||
| 1767 | maildirwatch.1 mailsubj.1 mbox.5 preline.1 qbiff.1 qmail-clean.8 \ | ||
| 1768 | qmail-command.8 qmail-control.9 qmail-getpw.9 qmail-header.5 \ | ||
| 1769 | qmail-inject.8 qmail-limits.9 qmail-local.8 qmail-log.5 \ | ||
| 1770 | qmail-lspawn.8 qmail-newmrh.9 qmail-newu.9 qmail-pop3d.8 \ | ||
| 1771 | qmail-popup.8 qmail-pw2u.9 qmail-qmqpc.8 qmail-qmqpd.8 qmail-qmtpd.8 \ | ||
| 1772 | qmail-qread.8 qmail-qstat.8 qmail-queue.8 qmail-remote.8 \ | ||
| 1773 | qmail-rspawn.8 qmail-send.9 qmail-showctl.8 qmail-smtpd.8 \ | ||
| 1774 | qmail-start.9 qmail-tcpok.8 qmail-tcpto.8 qmail-users.9 qmail.7 \ | ||
| 1775 | qreceipt.1 splogger.8 tcp-env.1 config.sh config-fast.sh \ | ||
| 1776 | qmail-clean.c qmail-getpw.c qmail-inject.c qmail-local.c \ | ||
| 1777 | qmail-lspawn.c qmail-newmrh.c qmail-newu.c qmail-pop3d.c \ | ||
| 1778 | qmail-popup.c qmail-pw2u.c qmail-qmqpc.c qmail-qmqpd.c qmail-qmtpd.c \ | ||
| 1779 | qmail-qread.c qmail-qstat.sh qmail-queue.c qmail-remote.c \ | ||
| 1780 | qmail-rspawn.c qmail-send.c qmail-showctl.c qmail-smtpd.c \ | ||
| 1781 | qmail-start.c qmail-tcpok.c qmail-tcpto.c spawn.c dnscname.c dnsfq.c \ | ||
| 1782 | dnsip.c dnsmxip.c dnsptr.c hostname.c ipmeprint.c tcp-env.c \ | ||
| 1783 | sendmail.c qreceipt.c qsmhook.c qbiff.c forward.c preline.c predate.c \ | ||
| 1784 | except.c bouncesaying.c condredirect.c maildirmake.c maildir2mbox.c \ | ||
| 1785 | maildirwatch.c splogger.c qail.sh elq.sh pinq.sh qmail-upq.sh \ | ||
| 1786 | datemail.sh mailsubj.sh qlx.h rcpthosts.h rcpthosts.c commands.h \ | ||
| 1787 | commands.c dnsdoe.h dnsdoe.c fmtqfn.h fmtqfn.c gfrom.h gfrom.c \ | ||
| 1788 | myctime.h myctime.c newfield.h newfield.c qsutil.h qsutil.c \ | ||
| 1789 | readsubdir.h readsubdir.c received.h received.c tcpto.h tcpto.c \ | ||
| 1790 | tcpto_clean.c trigger.h trigger.c triggerpull.h triggerpull.c \ | ||
| 1791 | trynpbg1.c trysyslog.c conf-cc conf-ld home.sh home+df.sh proc.sh \ | ||
| 1792 | proc+df.sh binm1.sh binm2.sh binm3.sh binm1+df.sh binm2+df.sh \ | ||
| 1793 | binm3+df.sh find-systype.sh make-compile.sh make-load.sh \ | ||
| 1794 | make-makelib.sh trycpp.c warn-auto.sh auto-str.c auto-int.c \ | ||
| 1795 | auto-int8.c auto-gid.c auto-uid.c hier.c install.c instcheck.c \ | ||
| 1796 | install-big.c alloc.3 alloc.h alloc.c alloc_re.c case.3 case.h \ | ||
| 1797 | case_diffb.c case_diffs.c case_lowerb.c case_lowers.c case_starts.c \ | ||
| 1798 | cdb.3 cdb.h cdb_hash.c cdb_seek.c cdb_unpack.c cdbmake.h \ | ||
| 1799 | cdbmake_add.c cdbmake_hash.c cdbmake_pack.c cdbmss.h cdbmss.c coe.3 \ | ||
| 1800 | coe.h coe.c fd.h fd_copy.3 fd_copy.c fd_move.3 fd_move.c fifo_make.3 \ | ||
| 1801 | fifo.h fifo.c trymkffo.c fork.h1 fork.h2 tryvfork.c now.3 now.h now.c \ | ||
| 1802 | open.h open_append.c open_excl.c open_read.c open_trunc.c \ | ||
| 1803 | open_write.c seek.h seek_cur.c seek_end.c seek_set.c seek_trunc.c \ | ||
| 1804 | conf-qmail auto_qmail.h qmail.h qmail.c gen_alloc.h gen_allocdefs.h \ | ||
| 1805 | stralloc.3 stralloc.h stralloc_eady.c stralloc_pend.c stralloc_copy.c \ | ||
| 1806 | stralloc_opyb.c stralloc_opys.c stralloc_cat.c stralloc_catb.c \ | ||
| 1807 | stralloc_cats.c stralloc_arts.c strerr.h strerr_sys.c strerr_die.c \ | ||
| 1808 | substdio.h substdio.c substdi.c substdo.c substdio_copy.c subfd.h \ | ||
| 1809 | subfderr.c subfdouts.c subfdout.c subfdins.c subfdin.c readwrite.h \ | ||
| 1810 | exit.h timeoutconn.h timeoutconn.c timeoutread.h timeoutread.c \ | ||
| 1811 | timeoutwrite.h timeoutwrite.c remoteinfo.h remoteinfo.c uint32.h1 \ | ||
| 1812 | uint32.h2 tryulong32.c wait.3 wait.h wait_pid.c wait_nohang.c \ | ||
| 1813 | trywaitp.c sig.h sig_alarm.c sig_block.c sig_catch.c sig_pause.c \ | ||
| 1814 | sig_pipe.c sig_child.c sig_term.c sig_hup.c sig_misc.c sig_bug.c \ | ||
| 1815 | trysgact.c trysgprm.c env.3 env.h env.c envread.c byte.h byte_chr.c \ | ||
| 1816 | byte_copy.c byte_cr.c byte_diff.c byte_rchr.c byte_zero.c str.h \ | ||
| 1817 | str_chr.c str_cpy.c str_diff.c str_diffn.c str_len.c str_rchr.c \ | ||
| 1818 | str_start.c lock.h lock_ex.c lock_exnb.c lock_un.c tryflock.c getln.3 \ | ||
| 1819 | getln.h getln.c getln2.3 getln2.c sgetopt.3 sgetopt.h sgetopt.c \ | ||
| 1820 | subgetopt.3 subgetopt.h subgetopt.c error.3 error_str.3 error_temp.3 \ | ||
| 1821 | error.h error.c error_str.c error_temp.c fmt.h fmt_str.c fmt_strn.c \ | ||
| 1822 | fmt_uint.c fmt_uint0.c fmt_ulong.c scan.h scan_ulong.c scan_8long.c \ | ||
| 1823 | slurpclose.h slurpclose.c quote.h quote.c hfield.h hfield.c \ | ||
| 1824 | headerbody.h headerbody.c token822.h token822.c control.h control.c \ | ||
| 1825 | datetime.3 datetime.h datetime.c datetime_un.c prioq.h prioq.c \ | ||
| 1826 | date822fmt.h date822fmt.c dns.h dns.c trylsock.c tryrsolv.c ip.h ip.c \ | ||
| 1827 | ipalloc.h ipalloc.c select.h1 select.h2 trysysel.c ndelay.h ndelay.c \ | ||
| 1828 | ndelay_off.c direntry.3 direntry.h1 direntry.h2 trydrent.c prot.h \ | ||
| 1829 | prot.c chkshsgr.c warn-shsgr tryshsgr.c ipme.h ipme.c trysalen.c \ | ||
| 1830 | maildir.5 maildir.h maildir.c tcp-environ.5 constmap.h constmap.c | ||
| 1831 | shar -m `cat FILES` > shar | ||
| 1832 | chmod 400 shar | ||
| 1833 | |||
| 1834 | sig.a: \ | ||
| 1835 | makelib sig_alarm.o sig_block.o sig_catch.o sig_pause.o sig_pipe.o \ | ||
| 1836 | sig_child.o sig_hup.o sig_term.o sig_bug.o sig_misc.o | ||
| 1837 | ./makelib sig.a sig_alarm.o sig_block.o sig_catch.o \ | ||
| 1838 | sig_pause.o sig_pipe.o sig_child.o sig_hup.o sig_term.o \ | ||
| 1839 | sig_bug.o sig_misc.o | ||
| 1840 | |||
| 1841 | sig_alarm.o: \ | ||
| 1842 | compile sig_alarm.c sig.h | ||
| 1843 | ./compile sig_alarm.c | ||
| 1844 | |||
| 1845 | sig_block.o: \ | ||
| 1846 | compile sig_block.c sig.h hassgprm.h | ||
| 1847 | ./compile sig_block.c | ||
| 1848 | |||
| 1849 | sig_bug.o: \ | ||
| 1850 | compile sig_bug.c sig.h | ||
| 1851 | ./compile sig_bug.c | ||
| 1852 | |||
| 1853 | sig_catch.o: \ | ||
| 1854 | compile sig_catch.c sig.h hassgact.h | ||
| 1855 | ./compile sig_catch.c | ||
| 1856 | |||
| 1857 | sig_child.o: \ | ||
| 1858 | compile sig_child.c sig.h | ||
| 1859 | ./compile sig_child.c | ||
| 1860 | |||
| 1861 | sig_hup.o: \ | ||
| 1862 | compile sig_hup.c sig.h | ||
| 1863 | ./compile sig_hup.c | ||
| 1864 | |||
| 1865 | sig_misc.o: \ | ||
| 1866 | compile sig_misc.c sig.h | ||
| 1867 | ./compile sig_misc.c | ||
| 1868 | |||
| 1869 | sig_pause.o: \ | ||
| 1870 | compile sig_pause.c sig.h hassgprm.h | ||
| 1871 | ./compile sig_pause.c | ||
| 1872 | |||
| 1873 | sig_pipe.o: \ | ||
| 1874 | compile sig_pipe.c sig.h | ||
| 1875 | ./compile sig_pipe.c | ||
| 1876 | |||
| 1877 | sig_term.o: \ | ||
| 1878 | compile sig_term.c sig.h | ||
| 1879 | ./compile sig_term.c | ||
| 1880 | |||
| 1881 | slurpclose.o: \ | ||
| 1882 | compile slurpclose.c stralloc.h gen_alloc.h readwrite.h slurpclose.h \ | ||
| 1883 | error.h | ||
| 1884 | ./compile slurpclose.c | ||
| 1885 | |||
| 1886 | socket.lib: \ | ||
| 1887 | trylsock.c compile load | ||
| 1888 | ( ( ./compile trylsock.c && \ | ||
| 1889 | ./load trylsock -lsocket -lnsl ) >/dev/null 2>&1 \ | ||
| 1890 | && echo -lsocket -lnsl || exit 0 ) > socket.lib | ||
| 1891 | rm -f trylsock.o trylsock | ||
| 1892 | |||
| 1893 | spawn.o: \ | ||
| 1894 | compile chkspawn spawn.c sig.h wait.h substdio.h byte.h str.h \ | ||
| 1895 | stralloc.h gen_alloc.h select.h exit.h coe.h open.h error.h \ | ||
| 1896 | auto_qmail.h auto_uids.h auto_spawn.h | ||
| 1897 | ./chkspawn | ||
| 1898 | ./compile spawn.c | ||
| 1899 | |||
| 1900 | splogger: \ | ||
| 1901 | load splogger.o substdio.a error.a str.a fs.a syslog.lib socket.lib | ||
| 1902 | ./load splogger substdio.a error.a str.a fs.a `cat \ | ||
| 1903 | syslog.lib` `cat socket.lib` | ||
| 1904 | |||
| 1905 | splogger.0: \ | ||
| 1906 | splogger.8 | ||
| 1907 | nroff -man splogger.8 > splogger.0 | ||
| 1908 | |||
| 1909 | splogger.o: \ | ||
| 1910 | compile splogger.c error.h substdio.h subfd.h substdio.h exit.h str.h \ | ||
| 1911 | scan.h fmt.h | ||
| 1912 | ./compile splogger.c | ||
| 1913 | |||
| 1914 | str.a: \ | ||
| 1915 | makelib str_len.o str_diff.o str_diffn.o str_cpy.o str_chr.o \ | ||
| 1916 | str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_diff.o byte_copy.o \ | ||
| 1917 | byte_cr.o byte_zero.o | ||
| 1918 | ./makelib str.a str_len.o str_diff.o str_diffn.o str_cpy.o \ | ||
| 1919 | str_chr.o str_rchr.o str_start.o byte_chr.o byte_rchr.o \ | ||
| 1920 | byte_diff.o byte_copy.o byte_cr.o byte_zero.o | ||
| 1921 | |||
| 1922 | str_chr.o: \ | ||
| 1923 | compile str_chr.c str.h | ||
| 1924 | ./compile str_chr.c | ||
| 1925 | |||
| 1926 | str_cpy.o: \ | ||
| 1927 | compile str_cpy.c str.h | ||
| 1928 | ./compile str_cpy.c | ||
| 1929 | |||
| 1930 | str_diff.o: \ | ||
| 1931 | compile str_diff.c str.h | ||
| 1932 | ./compile str_diff.c | ||
| 1933 | |||
| 1934 | str_diffn.o: \ | ||
| 1935 | compile str_diffn.c str.h | ||
| 1936 | ./compile str_diffn.c | ||
| 1937 | |||
| 1938 | str_len.o: \ | ||
| 1939 | compile str_len.c str.h | ||
| 1940 | ./compile str_len.c | ||
| 1941 | |||
| 1942 | str_rchr.o: \ | ||
| 1943 | compile str_rchr.c str.h | ||
| 1944 | ./compile str_rchr.c | ||
| 1945 | |||
| 1946 | str_start.o: \ | ||
| 1947 | compile str_start.c str.h | ||
| 1948 | ./compile str_start.c | ||
| 1949 | |||
| 1950 | stralloc.a: \ | ||
| 1951 | makelib stralloc_eady.o stralloc_pend.o stralloc_copy.o \ | ||
| 1952 | stralloc_opys.o stralloc_opyb.o stralloc_cat.o stralloc_cats.o \ | ||
| 1953 | stralloc_catb.o stralloc_arts.o | ||
| 1954 | ./makelib stralloc.a stralloc_eady.o stralloc_pend.o \ | ||
| 1955 | stralloc_copy.o stralloc_opys.o stralloc_opyb.o \ | ||
| 1956 | stralloc_cat.o stralloc_cats.o stralloc_catb.o \ | ||
| 1957 | stralloc_arts.o | ||
| 1958 | |||
| 1959 | stralloc_arts.o: \ | ||
| 1960 | compile stralloc_arts.c byte.h str.h stralloc.h gen_alloc.h | ||
| 1961 | ./compile stralloc_arts.c | ||
| 1962 | |||
| 1963 | stralloc_cat.o: \ | ||
| 1964 | compile stralloc_cat.c byte.h stralloc.h gen_alloc.h | ||
| 1965 | ./compile stralloc_cat.c | ||
| 1966 | |||
| 1967 | stralloc_catb.o: \ | ||
| 1968 | compile stralloc_catb.c stralloc.h gen_alloc.h byte.h | ||
| 1969 | ./compile stralloc_catb.c | ||
| 1970 | |||
| 1971 | stralloc_cats.o: \ | ||
| 1972 | compile stralloc_cats.c byte.h str.h stralloc.h gen_alloc.h | ||
| 1973 | ./compile stralloc_cats.c | ||
| 1974 | |||
| 1975 | stralloc_copy.o: \ | ||
| 1976 | compile stralloc_copy.c byte.h stralloc.h gen_alloc.h | ||
| 1977 | ./compile stralloc_copy.c | ||
| 1978 | |||
| 1979 | stralloc_eady.o: \ | ||
| 1980 | compile stralloc_eady.c alloc.h stralloc.h gen_alloc.h \ | ||
| 1981 | gen_allocdefs.h | ||
| 1982 | ./compile stralloc_eady.c | ||
| 1983 | |||
| 1984 | stralloc_opyb.o: \ | ||
| 1985 | compile stralloc_opyb.c stralloc.h gen_alloc.h byte.h | ||
| 1986 | ./compile stralloc_opyb.c | ||
| 1987 | |||
| 1988 | stralloc_opys.o: \ | ||
| 1989 | compile stralloc_opys.c byte.h str.h stralloc.h gen_alloc.h | ||
| 1990 | ./compile stralloc_opys.c | ||
| 1991 | |||
| 1992 | stralloc_pend.o: \ | ||
| 1993 | compile stralloc_pend.c alloc.h stralloc.h gen_alloc.h \ | ||
| 1994 | gen_allocdefs.h | ||
| 1995 | ./compile stralloc_pend.c | ||
| 1996 | |||
| 1997 | strerr.a: \ | ||
| 1998 | makelib strerr_sys.o strerr_die.o | ||
| 1999 | ./makelib strerr.a strerr_sys.o strerr_die.o | ||
| 2000 | |||
| 2001 | strerr_die.o: \ | ||
| 2002 | compile strerr_die.c substdio.h subfd.h substdio.h exit.h strerr.h | ||
| 2003 | ./compile strerr_die.c | ||
| 2004 | |||
| 2005 | strerr_sys.o: \ | ||
| 2006 | compile strerr_sys.c error.h strerr.h | ||
| 2007 | ./compile strerr_sys.c | ||
| 2008 | |||
| 2009 | subfderr.o: \ | ||
| 2010 | compile subfderr.c readwrite.h substdio.h subfd.h substdio.h | ||
| 2011 | ./compile subfderr.c | ||
| 2012 | |||
| 2013 | subfdin.o: \ | ||
| 2014 | compile subfdin.c readwrite.h substdio.h subfd.h substdio.h | ||
| 2015 | ./compile subfdin.c | ||
| 2016 | |||
| 2017 | subfdins.o: \ | ||
| 2018 | compile subfdins.c readwrite.h substdio.h subfd.h substdio.h | ||
| 2019 | ./compile subfdins.c | ||
| 2020 | |||
| 2021 | subfdout.o: \ | ||
| 2022 | compile subfdout.c readwrite.h substdio.h subfd.h substdio.h | ||
| 2023 | ./compile subfdout.c | ||
| 2024 | |||
| 2025 | subfdouts.o: \ | ||
| 2026 | compile subfdouts.c readwrite.h substdio.h subfd.h substdio.h | ||
| 2027 | ./compile subfdouts.c | ||
| 2028 | |||
| 2029 | subgetopt.o: \ | ||
| 2030 | compile subgetopt.c subgetopt.h | ||
| 2031 | ./compile subgetopt.c | ||
| 2032 | |||
| 2033 | substdi.o: \ | ||
| 2034 | compile substdi.c substdio.h byte.h error.h | ||
| 2035 | ./compile substdi.c | ||
| 2036 | |||
| 2037 | substdio.a: \ | ||
| 2038 | makelib substdio.o substdi.o substdo.o subfderr.o subfdout.o \ | ||
| 2039 | subfdouts.o subfdin.o subfdins.o substdio_copy.o | ||
| 2040 | ./makelib substdio.a substdio.o substdi.o substdo.o \ | ||
| 2041 | subfderr.o subfdout.o subfdouts.o subfdin.o subfdins.o \ | ||
| 2042 | substdio_copy.o | ||
| 2043 | |||
| 2044 | substdio.o: \ | ||
| 2045 | compile substdio.c substdio.h | ||
| 2046 | ./compile substdio.c | ||
| 2047 | |||
| 2048 | substdio_copy.o: \ | ||
| 2049 | compile substdio_copy.c substdio.h | ||
| 2050 | ./compile substdio_copy.c | ||
| 2051 | |||
| 2052 | substdo.o: \ | ||
| 2053 | compile substdo.c substdio.h str.h byte.h error.h | ||
| 2054 | ./compile substdo.c | ||
| 2055 | |||
| 2056 | syslog.lib: \ | ||
| 2057 | trysyslog.c compile load | ||
| 2058 | ( ( ./compile trysyslog.c && \ | ||
| 2059 | ./load trysyslog -lgen ) >/dev/null 2>&1 \ | ||
| 2060 | && echo -lgen || exit 0 ) > syslog.lib | ||
| 2061 | rm -f trysyslog.o trysyslog | ||
| 2062 | |||
| 2063 | systype: \ | ||
| 2064 | find-systype trycpp.c | ||
| 2065 | ./find-systype > systype | ||
| 2066 | |||
| 2067 | tcp-env: \ | ||
| 2068 | load tcp-env.o dns.o remoteinfo.o timeoutread.o timeoutwrite.o \ | ||
| 2069 | timeoutconn.o ip.o ipalloc.o case.a ndelay.a sig.a env.a getopt.a \ | ||
| 2070 | stralloc.a alloc.a substdio.a error.a str.a fs.a dns.lib socket.lib | ||
| 2071 | ./load tcp-env dns.o remoteinfo.o timeoutread.o \ | ||
| 2072 | timeoutwrite.o timeoutconn.o ip.o ipalloc.o case.a ndelay.a \ | ||
| 2073 | sig.a env.a getopt.a stralloc.a alloc.a substdio.a error.a \ | ||
| 2074 | str.a fs.a `cat dns.lib` `cat socket.lib` | ||
| 2075 | |||
| 2076 | tcp-env.0: \ | ||
| 2077 | tcp-env.1 | ||
| 2078 | nroff -man tcp-env.1 > tcp-env.0 | ||
| 2079 | |||
| 2080 | tcp-env.o: \ | ||
| 2081 | compile tcp-env.c sig.h stralloc.h gen_alloc.h str.h env.h fmt.h \ | ||
| 2082 | scan.h subgetopt.h ip.h dns.h byte.h remoteinfo.h exit.h case.h | ||
| 2083 | ./compile tcp-env.c | ||
| 2084 | |||
| 2085 | tcp-environ.0: \ | ||
| 2086 | tcp-environ.5 | ||
| 2087 | nroff -man tcp-environ.5 > tcp-environ.0 | ||
| 2088 | |||
| 2089 | tcpto.o: \ | ||
| 2090 | compile tcpto.c tcpto.h open.h lock.h seek.h now.h datetime.h ip.h \ | ||
| 2091 | byte.h datetime.h readwrite.h | ||
| 2092 | ./compile tcpto.c | ||
| 2093 | |||
| 2094 | tcpto_clean.o: \ | ||
| 2095 | compile tcpto_clean.c tcpto.h open.h substdio.h readwrite.h | ||
| 2096 | ./compile tcpto_clean.c | ||
| 2097 | |||
| 2098 | timeoutconn.o: \ | ||
| 2099 | compile timeoutconn.c ndelay.h select.h error.h readwrite.h ip.h \ | ||
| 2100 | byte.h timeoutconn.h | ||
| 2101 | ./compile timeoutconn.c | ||
| 2102 | |||
| 2103 | timeoutread.o: \ | ||
| 2104 | compile timeoutread.c timeoutread.h select.h error.h readwrite.h | ||
| 2105 | ./compile timeoutread.c | ||
| 2106 | |||
| 2107 | timeoutwrite.o: \ | ||
| 2108 | compile timeoutwrite.c timeoutwrite.h select.h error.h readwrite.h | ||
| 2109 | ./compile timeoutwrite.c | ||
| 2110 | |||
| 2111 | token822.o: \ | ||
| 2112 | compile token822.c stralloc.h gen_alloc.h alloc.h str.h token822.h \ | ||
| 2113 | gen_alloc.h gen_allocdefs.h | ||
| 2114 | ./compile token822.c | ||
| 2115 | |||
| 2116 | trigger.o: \ | ||
| 2117 | compile trigger.c select.h open.h trigger.h hasnpbg1.h | ||
| 2118 | ./compile trigger.c | ||
| 2119 | |||
| 2120 | triggerpull.o: \ | ||
| 2121 | compile triggerpull.c ndelay.h open.h triggerpull.h | ||
| 2122 | ./compile triggerpull.c | ||
| 2123 | |||
| 2124 | uint32.h: \ | ||
| 2125 | tryulong32.c compile load uint32.h1 uint32.h2 | ||
| 2126 | ( ( ./compile tryulong32.c && ./load tryulong32 && \ | ||
| 2127 | ./tryulong32 ) >/dev/null 2>&1 \ | ||
| 2128 | && cat uint32.h2 || cat uint32.h1 ) > uint32.h | ||
| 2129 | rm -f tryulong32.o tryulong32 | ||
| 2130 | |||
| 2131 | wait.a: \ | ||
| 2132 | makelib wait_pid.o wait_nohang.o | ||
| 2133 | ./makelib wait.a wait_pid.o wait_nohang.o | ||
| 2134 | |||
| 2135 | wait_nohang.o: \ | ||
| 2136 | compile wait_nohang.c haswaitp.h | ||
| 2137 | ./compile wait_nohang.c | ||
| 2138 | |||
| 2139 | wait_pid.o: \ | ||
| 2140 | compile wait_pid.c error.h haswaitp.h | ||
| 2141 | ./compile wait_pid.c | ||
diff --git a/PIC.local2alias b/PIC.local2alias new file mode 100644 index 0000000..75cff56 --- /dev/null +++ b/PIC.local2alias | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | Original message: | ||
| 2 | |||
| 3 | To: help | ||
| 4 | Hi. | ||
| 5 | |||
| 6 | qmail-inject Fill in the complete envelope and header: | ||
| 7 | |||
| 8 | | (envelope) from joe@heaven.af.mil to help@heaven.af.mil | ||
| 9 | | From: joe@heaven.af.mil | ||
| 10 | | To: help@heaven.af.mil | ||
| 11 | | | ||
| 12 | | Hi. | ||
| 13 | V | ||
| 14 | |||
| 15 | qmail-queue Store message safely on disk. | ||
| 16 | Trigger qmail-send. | ||
| 17 | | | ||
| 18 | V | ||
| 19 | |||
| 20 | qmail-send Look at envelope recipient, help@heaven.af.mil. | ||
| 21 | | Is heaven.af.mil in locals? Yes. | ||
| 22 | | Deliver locally to help@heaven.af.mil. | ||
| 23 | V | ||
| 24 | |||
| 25 | qmail-lspawn ./Mailbox | ||
| 26 | |||
| 27 | | Look at mailbox name, help. | ||
| 28 | | Is help listed in qmail-users? No. | ||
| 29 | | Is there a help account? No. | ||
| 30 | | Give control of the message to alias. | ||
| 31 | | Run qmail-local. | ||
| 32 | V | ||
| 33 | |||
| 34 | qmail-local alias ~alias help - help heaven.af.mil joe@heaven.af.mil ./Mailbox | ||
| 35 | |||
| 36 | Does ~alias/.qmail-help exist? Yes: "john". | ||
| 37 | Forward message to john. | ||
diff --git a/PIC.local2ext b/PIC.local2ext new file mode 100644 index 0000000..a8bf644 --- /dev/null +++ b/PIC.local2ext | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | Original message: | ||
| 2 | |||
| 3 | To: fred-sos | ||
| 4 | Hi. | ||
| 5 | |||
| 6 | qmail-inject Fill in the complete envelope and header: | ||
| 7 | |||
| 8 | | (envelope) from joe@heaven.af.mil to fred-sos@heaven.af.mil | ||
| 9 | | From: joe@heaven.af.mil | ||
| 10 | | To: fred-sos@heaven.af.mil | ||
| 11 | | | ||
| 12 | | Hi. | ||
| 13 | V | ||
| 14 | |||
| 15 | qmail-queue Store message safely on disk. | ||
| 16 | Trigger qmail-send. | ||
| 17 | | | ||
| 18 | V | ||
| 19 | |||
| 20 | qmail-send Look at envelope recipient, fred-sos@heaven.af.mil. | ||
| 21 | | Is heaven.af.mil in locals? Yes. | ||
| 22 | | Deliver locally to fred-sos@heaven.af.mil. | ||
| 23 | V | ||
| 24 | |||
| 25 | qmail-lspawn ./Mailbox | ||
| 26 | |||
| 27 | | Look at mailbox name, fred-sos. | ||
| 28 | | Is fred-sos listed in qmail-users? No. | ||
| 29 | | Is there a fred-sos account? No. | ||
| 30 | | Is there a fred account? Yes. | ||
| 31 | | Is fred's uid nonzero? Yes. | ||
| 32 | | Is ~fred visible to the qmailp user? Yes. | ||
| 33 | | Is ~fred owned by fred? Yes. | ||
| 34 | | Give control of the message to fred. | ||
| 35 | | Run qmail-local. | ||
| 36 | V | ||
| 37 | |||
| 38 | qmail-local fred ~fred fred-sos - sos heaven.af.mil joe@heaven.af.mil ./Mailbox | ||
| 39 | |||
| 40 | Does ~fred/.qmail-sos exist? Yes: "./Extramail". | ||
| 41 | Write message to ./Extramail in mbox format. | ||
diff --git a/PIC.local2local b/PIC.local2local new file mode 100644 index 0000000..3a067e0 --- /dev/null +++ b/PIC.local2local | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | Original message: | ||
| 2 | |||
| 3 | To: fred | ||
| 4 | Hi. | ||
| 5 | |||
| 6 | qmail-inject Fill in the complete envelope and header: | ||
| 7 | |||
| 8 | | (envelope) from joe@heaven.af.mil to fred@heaven.af.mil | ||
| 9 | | From: joe@heaven.af.mil | ||
| 10 | | To: fred@heaven.af.mil | ||
| 11 | | | ||
| 12 | | Hi. | ||
| 13 | V | ||
| 14 | |||
| 15 | qmail-queue Store message safely on disk. | ||
| 16 | Trigger qmail-send. | ||
| 17 | | | ||
| 18 | V | ||
| 19 | |||
| 20 | qmail-send Look at envelope recipient, fred@heaven.af.mil. | ||
| 21 | | Is heaven.af.mil in locals? Yes. | ||
| 22 | | Deliver locally to fred@heaven.af.mil. | ||
| 23 | V | ||
| 24 | |||
| 25 | qmail-lspawn ./Mailbox | ||
| 26 | |||
| 27 | | Look at mailbox name, fred. | ||
| 28 | | Is fred listed in qmail-users? No. | ||
| 29 | | Is there a fred account? Yes. | ||
| 30 | | Is fred's uid nonzero? Yes. | ||
| 31 | | Is ~fred visible to the qmailp user? Yes. | ||
| 32 | | Is ~fred owned by fred? Yes. | ||
| 33 | | Give control of the message to fred. | ||
| 34 | | Run qmail-local. | ||
| 35 | V | ||
| 36 | |||
| 37 | qmail-local fred ~fred fred '' '' heaven.af.mil joe@heaven.af.mil ./Mailbox | ||
| 38 | |||
| 39 | Does ~fred/.qmail exist? No. | ||
| 40 | Write message to ./Mailbox in mbox format. | ||
diff --git a/PIC.local2rem b/PIC.local2rem new file mode 100644 index 0000000..6857af5 --- /dev/null +++ b/PIC.local2rem | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | Original message: | ||
| 2 | |||
| 3 | To: bill@irs.gov | ||
| 4 | Hi. | ||
| 5 | |||
| 6 | qmail-inject Fill in the complete envelope and header: | ||
| 7 | |||
| 8 | | (envelope) from joe@heaven.af.mil to bill@irs.gov | ||
| 9 | | From: joe@heaven.af.mil | ||
| 10 | | To: bill@irs.gov | ||
| 11 | | | ||
| 12 | | Hi. | ||
| 13 | V | ||
| 14 | |||
| 15 | qmail-queue Store message safely on disk. | ||
| 16 | Trigger qmail-send. | ||
| 17 | | | ||
| 18 | V | ||
| 19 | |||
| 20 | qmail-send Look at envelope recipient, bill@irs.gov. | ||
| 21 | | Is irs.gov in locals? No. | ||
| 22 | | Is bill@irs.gov in virtualdomains? No. | ||
| 23 | | Is irs.gov in virtualdomains? No. | ||
| 24 | | Is .gov in virtualdomains? No. | ||
| 25 | | Deliver remotely to bill@irs.gov. | ||
| 26 | V | ||
| 27 | |||
| 28 | qmail-rspawn Run qmail-remote. | ||
| 29 | |||
| 30 | | | ||
| 31 | V | ||
| 32 | |||
| 33 | qmail-remote Look at host name, irs.gov. | ||
| 34 | Is irs.gov listed in smtproutes? No. | ||
| 35 | Look up DNS MX/A for irs.gov and connect to it by SMTP: | ||
| 36 | |||
| 37 | MAIL FROM:<joe@heaven.af.mil> | ||
| 38 | RCPT TO:<bill@irs.gov> | ||
diff --git a/PIC.local2virt b/PIC.local2virt new file mode 100644 index 0000000..60f80c8 --- /dev/null +++ b/PIC.local2virt | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | Original message: | ||
| 2 | |||
| 3 | To: dude@tommy.gov | ||
| 4 | Hi. | ||
| 5 | |||
| 6 | qmail-inject Fill in the complete envelope and header: | ||
| 7 | |||
| 8 | | (envelope) from joe@heaven.af.mil to dude@tommy.gov | ||
| 9 | | From: joe@heaven.af.mil | ||
| 10 | | To: dude@tommy.gov | ||
| 11 | | | ||
| 12 | | Hi. | ||
| 13 | V | ||
| 14 | |||
| 15 | qmail-queue Store message safely on disk. | ||
| 16 | Trigger qmail-send. | ||
| 17 | | | ||
| 18 | V | ||
| 19 | |||
| 20 | qmail-send Look at envelope recipient, dude@tommy.gov. | ||
| 21 | | Is tommy.gov in locals? No. | ||
| 22 | | Is dude@tommy.gov in virtualdomains? No. | ||
| 23 | | Is tommy.gov in virtualdomains? Yes: "tommy.gov:fred". | ||
| 24 | | Deliver locally to fred-dude@tommy.gov. | ||
| 25 | V | ||
| 26 | |||
| 27 | qmail-lspawn ./Mailbox | ||
| 28 | |||
| 29 | | Look at mailbox name, fred-dude. | ||
| 30 | | Is fred-dude listed in qmail-users? No. | ||
| 31 | | Is there a fred-dude account? No. | ||
| 32 | | Is there a fred account? Yes. | ||
| 33 | | Is fred's uid nonzero? Yes. | ||
| 34 | | Is ~fred visible to the qmailp user? Yes. | ||
| 35 | | Is ~fred owned by fred? Yes. | ||
| 36 | | Give control of the message to fred. | ||
| 37 | | Run qmail-local. | ||
| 38 | V | ||
| 39 | |||
| 40 | qmail-local fred ~fred fred-dude - dude tommy.gov joe@heaven.af.mil ./Mailbox | ||
| 41 | |||
| 42 | Does ~fred/.qmail-dude exist? No. | ||
| 43 | Does ~fred/.qmail-default exist? Yes: "./Mail.tommy". | ||
| 44 | Write message to ./Mail.tommy in mbox format. | ||
diff --git a/PIC.nullclient b/PIC.nullclient new file mode 100644 index 0000000..a90d7cb --- /dev/null +++ b/PIC.nullclient | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | Original message: | ||
| 2 | |||
| 3 | To: bill@irs.gov | ||
| 4 | Hi. | ||
| 5 | |||
| 6 | qmail-inject Fill in the complete envelope and header: | ||
| 7 | |||
| 8 | | (envelope) from joe@heaven.af.mil to bill@irs.gov | ||
| 9 | | From: joe@heaven.af.mil | ||
| 10 | | To: bill@irs.gov | ||
| 11 | | | ||
| 12 | | Hi. | ||
| 13 | V | ||
| 14 | |||
| 15 | qmail-queue Store message safely on disk. | ||
| 16 | Trigger qmail-send. | ||
| 17 | | | ||
| 18 | V | ||
| 19 | |||
| 20 | qmail-send Look at envelope recipient, bill@irs.gov. | ||
| 21 | | Is irs.gov in locals? No. | ||
| 22 | | Is bill@irs.gov in virtualdomains? No. | ||
| 23 | | Is irs.gov in virtualdomains? No. | ||
| 24 | | Is .gov in virtualdomains? No. | ||
| 25 | | Deliver remotely to bill@irs.gov. | ||
| 26 | V | ||
| 27 | |||
| 28 | qmail-rspawn Run qmail-remote. | ||
| 29 | |||
| 30 | | | ||
| 31 | V | ||
| 32 | |||
| 33 | qmail-remote Look at host name, irs.gov. | ||
| 34 | Is irs.gov listed in smtproutes? Yes: ":bigbang.af.mil". | ||
| 35 | Look up DNS A for bigbang.af.mil and connect by SMTP: | ||
| 36 | |||
| 37 | MAIL FROM:<joe@heaven.af.mil> | ||
| 38 | RCPT TO:<bill@irs.gov> | ||
diff --git a/PIC.relaybad b/PIC.relaybad new file mode 100644 index 0000000..513f74f --- /dev/null +++ b/PIC.relaybad | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | qmail-smtpd Receive message by SMTP from another host: | ||
| 2 | |||
| 3 | MAIL FROM:<spammer@aol.com> | ||
| 4 | RCPT TO:<bill@irs.gov> | ||
| 5 | |||
| 6 | Is $RELAYCLIENT set? No. | ||
| 7 | Is irs.gov in rcpthosts? No. | ||
| 8 | Reject RCPT. | ||
diff --git a/PIC.relaygood b/PIC.relaygood new file mode 100644 index 0000000..0d62fa9 --- /dev/null +++ b/PIC.relaygood | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | qmail-smtpd Receive message by SMTP from another host: | ||
| 2 | |||
| 3 | | MAIL FROM:<joe@heaven.af.mil> | ||
| 4 | | RCPT TO:<bill@irs.gov> | ||
| 5 | | | ||
| 6 | | Is $RELAYCLIENT set? Yes: "". | ||
| 7 | | Accept RCPT. | ||
| 8 | V | ||
| 9 | |||
| 10 | qmail-queue Store message safely on disk. | ||
| 11 | Trigger qmail-send. | ||
| 12 | | | ||
| 13 | V | ||
| 14 | |||
| 15 | qmail-send Look at envelope recipient, bill@irs.gov. | ||
| 16 | | Is irs.gov in locals? No. | ||
| 17 | | Is bill@irs.gov in virtualdomains? No. | ||
| 18 | | Is irs.gov in virtualdomains? No. | ||
| 19 | | Is .gov in virtualdomains? No. | ||
| 20 | | Deliver remotely to bill@irs.gov. | ||
| 21 | V | ||
| 22 | |||
| 23 | qmail-rspawn Run qmail-remote. | ||
| 24 | |||
| 25 | | | ||
| 26 | V | ||
| 27 | |||
| 28 | qmail-remote Look at host name, irs.gov. | ||
| 29 | Is irs.gov listed in smtproutes? No. | ||
| 30 | Look up DNS MX/A for irs.gov and connect to it by SMTP: | ||
| 31 | |||
| 32 | MAIL FROM:<joe@heaven.af.mil> | ||
| 33 | RCPT TO:<bill@irs.gov> | ||
diff --git a/PIC.rem2local b/PIC.rem2local new file mode 100644 index 0000000..62fe61a --- /dev/null +++ b/PIC.rem2local | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | qmail-smtpd Receive message by SMTP from another host: | ||
| 2 | |||
| 3 | | MAIL FROM:<bill@irs.gov> | ||
| 4 | | RCPT TO:<joe@heaven.af.mil> | ||
| 5 | | | ||
| 6 | | Is $RELAYCLIENT set? No. | ||
| 7 | | Is heaven.af.mil in rcpthosts? Yes. | ||
| 8 | | Accept RCPT. | ||
| 9 | V | ||
| 10 | |||
| 11 | qmail-queue Store message safely on disk. | ||
| 12 | Trigger qmail-send. | ||
| 13 | | | ||
| 14 | V | ||
| 15 | |||
| 16 | qmail-send Look at envelope recipient, joe@heaven.af.mil. | ||
| 17 | | Is heaven.af.mil in locals? Yes. | ||
| 18 | | Deliver locally to joe@heaven.af.mil. | ||
| 19 | V | ||
| 20 | |||
| 21 | qmail-lspawn ./Mailbox | ||
| 22 | |||
| 23 | | Look at mailbox name, joe. | ||
| 24 | | Is joe listed in qmail-users? No. | ||
| 25 | | Is there a joe account? Yes. | ||
| 26 | | Is joe's uid nonzero? Yes. | ||
| 27 | | Is ~joe visible to the qmailp user? Yes. | ||
| 28 | | Is ~joe owned by joe? Yes. | ||
| 29 | | Give control of the message to joe. | ||
| 30 | | Run qmail-local. | ||
| 31 | V | ||
| 32 | |||
| 33 | qmail-local joe ~joe joe '' '' heaven.af.mil bill@irs.gov ./Mailbox | ||
| 34 | |||
| 35 | Does ~joe/.qmail exist? No. | ||
| 36 | Write message to ./Mailbox in mbox format. | ||
| @@ -0,0 +1,269 @@ | |||
| 1 | qmail 1.03 | ||
| 2 | 19980615 | ||
| 3 | Copyright 1998 | ||
| 4 | D. J. Bernstein, qmail@pobox.com | ||
| 5 | |||
| 6 | qmail is a secure, reliable, efficient, simple message transfer agent. | ||
| 7 | It is meant as a replacement for the entire sendmail-binmail system on | ||
| 8 | typical Internet-connected UNIX hosts. See BLURB, BLURB2, BLURB3, and | ||
| 9 | BLURB4 for more detailed advertisements. | ||
| 10 | |||
| 11 | INSTALL says how to set up and test qmail. If you're upgrading from a | ||
| 12 | previous version, read UPGRADE instead. | ||
| 13 | |||
| 14 | See PIC.* for some ``end-to-end'' pictures of mail flowing through the | ||
| 15 | qmail system. | ||
| 16 | |||
| 17 | See http://pobox.com/~djb/qmail.html for other qmail-related software | ||
| 18 | and a pointer to the qmail mailing list. | ||
| 19 | |||
| 20 | Other documentation: http://pobox.com/~djb/proto.html shows solutions to | ||
| 21 | several Internet mail problems; many of these solutions are implemented | ||
| 22 | in qmail. CHANGES and THANKS show how qmail has changed since it was | ||
| 23 | first released. SECURITY, INTERNALS, THOUGHTS, and TODO record many of | ||
| 24 | the qmail design decisions. | ||
| 25 | |||
| 26 | The rest of this file is a list of systypes where various versions of | ||
| 27 | qmail have been reported to work. 0.96 was the final gamma version; 1.00 | ||
| 28 | had exactly the same code as 0.96. To see your systype, make systype; | ||
| 29 | cat systype. | ||
| 30 | |||
| 31 | 1.00: a.ux-3.0-svr2-:-:-:mc68030-:- (tnx RF) | ||
| 32 | 1.01: aix-3-2-:-:-:000000406300-:- (tnx DG) | ||
| 33 | 1.01: aix-3-2-:-:-:000011216700-:- (tnx JLB) | ||
| 34 | 1.01: aix-4-1-:-:-:000041574c00-:- (tnx M2H) | ||
| 35 | 1.01: aix-4-1-:-:-:000088581000-:- (tnx HJB) | ||
| 36 | 1.01: aix-4-1-:-:-:002b51134c00-:- (tnx MP) | ||
| 37 | 1.00: aix-4-1-:-:-:00910033a000-:- (tnx KJJ) | ||
| 38 | 1.01: aix-4-2-:-:-:000055247900-:- (tnx JLB) | ||
| 39 | 1.01: aix-4-2-:-:-:000062295800-:- (tnx TD) | ||
| 40 | 1.01: aix-4-2-:-:-:000136094c00-:- (tnx T2U) | ||
| 41 | 1.00: aix-4-2-:-:-:000205254600-:- (tnx MGM) | ||
| 42 | 1.01: aix-4-2-:-:-:005255bc4c00-:- (tnx DS) | ||
| 43 | 1.01: aix-4-2-:-:-:006030944c00-:- | ||
| 44 | 1.01: bsd.386-1.1-0-:i386-:-:i386-:- (tnx T2M) | ||
| 45 | 1.01: bsd.os-2.0-:i386-:-:pentium-:- (tnx MSS) | ||
| 46 | 1.01: bsd.os-2.0.1-:i386-:-:i486-:- (tnx KR) | ||
| 47 | 0.96: bsd.os-2.1-:i386-:-:-:- (tnx DAR) | ||
| 48 | 1.00: bsd.os-2.1-:i386-:-:i486-:- (tnx RJC) | ||
| 49 | 0.96: bsd.os-2.1-:i386-:-:pentium-:- (tnx UO) | ||
| 50 | 1.01: bsd.os-3.0-:i386-:-:-:- (tnx VU) | ||
| 51 | 1.01: bsd.os-3.0-:i386-:-:pentium-:- (tnx RJO) | ||
| 52 | 1.01: bsd.os-3.1-:i386-:-:pentium-:- (tnx ABC) | ||
| 53 | 1.01: bsd.os-3.1-:i386-:-:pentium.ii-:- (tnx UO) | ||
| 54 | 0.96: dgux-5.4r2.01-generic-:-:-:aviion-:- (tnx HWM) | ||
| 55 | 1.01: freebsd-2.1.0-release-:i386-:-:i486-dx-:- (tnx VV) | ||
| 56 | 1.01: freebsd-2.1.0-release-:i386-:-:i486.dx2-:- (tnx JLB) | ||
| 57 | 1.00: freebsd-2.1.0-release-:i386-:-:i486dx-:- (tnx chrisj=???) | ||
| 58 | 1.01: freebsd-2.1.0-release-:i386-:-:pentium.735\90.or.815\100-:- (tnx MBS) | ||
| 59 | 1.01: freebsd-2.1.5-release-:i386-:-:i486-dx-:- (tnx B1F) | ||
| 60 | 0.96: freebsd-2.1.5-release-:i386-:-:i486dx-:- (tnx FN) | ||
| 61 | 1.01: freebsd-2.1.5-release-:i386-:-:unknown.-:- (tnx BMF) | ||
| 62 | 1.00: freebsd-2.1.6-release-:i386-:-:-:- (tnx TM) | ||
| 63 | 0.96: freebsd-2.1.6-release-:i386-:-:Pentium-Pro.150-:- (tnx CH) | ||
| 64 | 1.01: freebsd-2.1.6-release-:i386-:-:cy486dlc-:- (tnx M3H) | ||
| 65 | 0.96: freebsd-2.1.6.1-release-:i386-:-:pentium.735\90.or.815\100-:- (tnx MF) | ||
| 66 | 1.01: freebsd-2.1.7-release-:i386-:-:i486-dx-:- (tnx AAF) | ||
| 67 | 1.00: freebsd-2.1.7-release-:i386-:-:pentium.735\90.or.815\100-:- (tnx JBB) | ||
| 68 | 1.01: freebsd-2.1.7-release-:i386-:-:pentium.815\100-:- (tnx B1F) | ||
| 69 | 1.01: freebsd-2.2-970422-releng-:i386-:-:-:- (tnx TM) | ||
| 70 | 1.00: freebsd-2.2-release-:i386-:-:-:- (tnx MT) | ||
| 71 | 1.01: freebsd-2.2-stable-:i386-:-:cyrix.5x86-:- (tnx A2B) | ||
| 72 | 1.01: freebsd-2.2-stable-:i386-:-:pentium-:- (tnx gary@systemics=???) | ||
| 73 | 1.01: freebsd-2.2.1-release-:i386-:-:-:- (tnx M2R) | ||
| 74 | 1.01: freebsd-2.2.1-release-:i386-:-:i486-dx-:- (tnx PGR) | ||
| 75 | 1.00: freebsd-2.2.1-release-:i386-:-:i486.dx2-:- (tnx BR) | ||
| 76 | 1.01: freebsd-2.2.1-release-:i386-:-:pentium-:- (tnx REB) | ||
| 77 | 1.01: freebsd-2.2.1-release-:i386-:-:pentium.pro-:- (tnx JS) | ||
| 78 | 1.01: freebsd-2.2.2-release-:i386-:-:amd.am5x86.write-through-:- (tnx AGB) | ||
| 79 | 1.01: freebsd-2.2.2-release-:i386-:-:i486-dx-:- (tnx A2L) | ||
| 80 | 1.01: freebsd-2.2.2-release-:i386-:-:i486.dx2-:- (tnx D3S) | ||
| 81 | 1.01: freebsd-2.2.2-release-:i386-:-:pentium-:- (tnx B2F) | ||
| 82 | 1.01: freebsd-2.2.2-release-:i386-:-:pentium.pro-:- (tnx M2G) | ||
| 83 | 1.01: freebsd-2.2.5-release-:i386-:-:i486-dx-:- (tnx R2N) | ||
| 84 | 1.01: freebsd-2.2.5-release-:i386-:-:i486.dx2-:- (tnx AY) | ||
| 85 | 1.01: freebsd-2.2.5-release-:i386-:-:pentium.pro-:- (tnx AI) | ||
| 86 | 1.01: freebsd-2.2.5-stable-:i386-:-:i486.dx2-:- (tnx JK) | ||
| 87 | 1.01: freebsd-2.2.5-stable-:i386-:-:pentium-:- (tnx root@defiant=???) | ||
| 88 | 1.01: freebsd-2.2.6-release-:i386-:-:-:- (tnx TM) | ||
| 89 | 1.01: freebsd-2.2.6-release-:i386-:-:amd.am5x86.write-through-:- (tnx root@skully=???) | ||
| 90 | 1.00: freebsd-3.0-970209-snap-:i386-:-:-:- (tnx YF) | ||
| 91 | 1.01: freebsd-3.0-970428-snap-:i386-:-:pentium-:- (tnx M3S) | ||
| 92 | 1.01: freebsd-3.0-970807-snap-:i386-:-:amd.k6-:- (tnx KMD) | ||
| 93 | 1.01: freebsd-3.0-980309-snap-:i386-:-:pentium-:- (tnx MM) | ||
| 94 | 1.01: freebsd-3.0-current-:i386-:-:pentium-:- (tnx KB) | ||
| 95 | 1.01: hp-ux-a.09.05-a-:-:-:9000.712-:- (tnx SV) | ||
| 96 | 1.01: hp-ux-a.09.07-a-:-:-:9000.712-:- (tnx LB) | ||
| 97 | 1.00: hp-ux-b.09.00-a-:-:-:9000.360-:- (tnx VV) | ||
| 98 | 1.01: hp-ux-b.10.20-a-:-:-:9000.755-:- (tnx BCK) | ||
| 99 | 1.01: irix-5.3-11091812-:-:-:ip22-:- (tnx JL) | ||
| 100 | 1.01: irix-6.2-03131015-:-:-:ip22-:- (tnx DS) | ||
| 101 | 1.01: irix64-6.2-03131016-:-:-:ip19-:- (tnx AH) | ||
| 102 | 1.01: irix64-6.2-06101031-:-:-:ip28-:- (tnx DB) | ||
| 103 | 1.01: linux-1.2.13-:i386-:-:i486-:- (tnx RF) | ||
| 104 | 1.01: linux-1.2.13-:i386-:-:pentium-:- (tnx MEE) | ||
| 105 | 1.01: linux-1.99.4-:i386-:-:pentium-:- (tnx C2H) | ||
| 106 | 1.01: linux-2.0.0-:i386-:-:i486-:- (tnx kragen@gentle=???) | ||
| 107 | 1.01: linux-2.0.0-:i386-:-:pentium-:- (tnx MJD) | ||
| 108 | 1.01: linux-2.0.6-:i386-:-:pentium-:- | ||
| 109 | 1.00: linux-2.0.6-:i386-:-:ppro-:- (tnx MR) | ||
| 110 | 1.01: linux-2.0.7-:i386-:-:i486-:- (tnx TLM) | ||
| 111 | 1.01: linux-2.0.9-:i386-:-:i486-:- (tnx VBM) | ||
| 112 | 0.96: linux-2.0.13-:i386-:-:pentium-:- (tnx BW) | ||
| 113 | 1.01: linux-2.0.15-:i386-:-:i486-:- (tnx JCD) | ||
| 114 | 1.01: linux-2.0.18-:i386-:-:i486-:- (tnx tk@avalon=???) | ||
| 115 | 1.01: linux-2.0.18-:i386-:-:pentium-:- (tnx root@webtvchat=???) | ||
| 116 | 1.00: linux-2.0.22-:i386-:-:pentium-:- (tnx MDI) | ||
| 117 | 1.00: linux-2.0.23-:i386-:-:i486-:- (tnx B2L) | ||
| 118 | 1.01: linux-2.0.24-:i386-:-:i486-:- (tnx GLM) | ||
| 119 | 1.00: linux-2.0.24-:i386-:-:pentium-:- (tnx VV) | ||
| 120 | 0.96: linux-2.0.25-:i386-:-:i486-:- (tnx BDB) | ||
| 121 | 1.01: linux-2.0.25-:i386-:-:pentium-:- (tnx KA) | ||
| 122 | 0.93: linux-2.0.26-:i386-:-:i486-:- (tnx blynch@texas=???) | ||
| 123 | 1.01: linux-2.0.26-:i386-:-:pentium-:- (tnx robbie@opus=???) | ||
| 124 | 1.00: linux-2.0.27-:-:-:sparc-:- (tnx SVD) | ||
| 125 | 1.00: linux-2.0.27-:i386-:-:i386-:- (tnx ECG) | ||
| 126 | 1.01: linux-2.0.27-:i386-:-:i486-:- (tnx BN) | ||
| 127 | 1.01: linux-2.0.27-:i386-:-:pentium-:- (tnx EK) | ||
| 128 | 1.01: linux-2.0.27-:i386-:-:ppro-:- (tnx L3L) | ||
| 129 | 1.01: linux-2.0.28-:i386-:-:i486-:- (tnx AAF) | ||
| 130 | 1.00: linux-2.0.28-:i386-:-:pentium-:- (tnx root@duggy=???) | ||
| 131 | 1.01: linux-2.0.28-:i386-:-:ppro-:- (tnx S3T) | ||
| 132 | 1.01: linux-2.0.28-osfmach3-:-:-:ppc-:- (tnx CG) | ||
| 133 | 1.01: linux-2.0.29-:alpha-:-:alpha-:- (tnx MB) | ||
| 134 | 1.01: linux-2.0.29-:i386-:-:i386-:- (tnx AJK) | ||
| 135 | 1.01: linux-2.0.29-:i386-:-:i486-:- (tnx FPL) | ||
| 136 | 1.01: linux-2.0.29-:i386-:-:pentium-:- (tnx FW) | ||
| 137 | 1.00: linux-2.0.29-:i386-:-:ppro-:- (tnx MMM) | ||
| 138 | 1.01: linux-2.0.30-:-:-:sparc-:- (tnx J2P) | ||
| 139 | 1.01: linux-2.0.30-:alpha-:-:alpha-:- (tnx WS) | ||
| 140 | 1.01: linux-2.0.30-:i386-:-:i386-:- (tnx OK) | ||
| 141 | 1.00: linux-2.0.30-:i386-:-:i486-:- (tnx KUT) | ||
| 142 | 1.01: linux-2.0.30-:i386-:-:i486-:- (tnx PK) | ||
| 143 | 1.01: linux-2.0.30-:i386-:-:pentium-:- (tnx AV) | ||
| 144 | 1.00: linux-2.0.30-:i386-:-:ppro-:- (tnx root@gate=???) | ||
| 145 | 1.01: linux-2.0.30-osfmach3-:-:-:ppc-:- (tnx PTW) | ||
| 146 | 1.01: linux-2.0.30u11-:i386-:-:pentium-:- (tnx JTB) | ||
| 147 | 1.01: linux-2.0.31-:i386-:-:i486-:- (tnx SAE) | ||
| 148 | 1.01: linux-2.0.31-:i386-:-:pentium-:- (tnx B3W) | ||
| 149 | 1.01: linux-2.0.31-:i386-:-:ppro-:- (tnx JAK) | ||
| 150 | 1.01: linux-2.0.32-:-:-:ie86-:- (tnx root@vmlinuz=???) | ||
| 151 | 1.01: linux-2.0.32-:alpha-:-:alpha-:- (tnx NR) | ||
| 152 | 1.01: linux-2.0.32-:i386-:-:i486-:- (tnx SC) | ||
| 153 | 1.01: linux-2.0.32-:i386-:-:pentium-:- (tnx HT) | ||
| 154 | 1.01: linux-2.0.32-:i386-:-:ppro-:- (tnx RK) | ||
| 155 | 1.01: linux-2.0.33-:i386-:-:i486-:- (tnx RAB) | ||
| 156 | 1.01: linux-2.0.33-:i386-:-:pentium-:- (tnx AF) | ||
| 157 | 1.01: linux-2.0.33-:i386-:-:ppro-:- (tnx B2W) | ||
| 158 | 1.01: linux-2.1.9-:i386-:-:i486-:- (tnx SJB) | ||
| 159 | 1.01: linux-2.1.10-:i386-:-:i486-:- (tnx JB) | ||
| 160 | 0.96: linux-2.1.13-:i386-:-:i486-:- (tnx ML) | ||
| 161 | 0.96: linux-2.1.14-:i386-:-:pentium-:- (tnx SCW) | ||
| 162 | 0.96: linux-2.1.23-:i386-:-:pentium-:- (tnx JF) | ||
| 163 | 1.01: linux-2.1.24-:-:-:ppc-:- (tnx meta=???) | ||
| 164 | 0.96: linux-2.1.25-:i386-:-:i486-:- (tnx JBF) | ||
| 165 | 0.96: linux-2.1.25-:i386-:-:pentium-:- (tnx UO) | ||
| 166 | 1.00: linux-2.1.26-:i386-:-:i486-:- (tnx DK) | ||
| 167 | 1.00: linux-2.1.27-:i386-:-:pentium-:- (tnx JF) | ||
| 168 | 1.01: linux-2.1.28-:i386-:-:i486-:- (tnx HDG) | ||
| 169 | 1.00: linux-2.1.28-:i386-:-:pentium-:- (tnx RGS) | ||
| 170 | 1.00: linux-2.1.29-:i386-:-:i486-:- (tnx SJW) | ||
| 171 | 1.01: linux-2.1.35-:i386-:-:pentium-:- (tnx JF) | ||
| 172 | 1.01: linux-2.1.36-:i386-:-:i486-:- (tnx ML) | ||
| 173 | 1.01: linux-2.1.42-:i386-:-:i486-:- (tnx wtanaka=???) | ||
| 174 | 1.01: linux-2.1.46-:i386-:-:pentium-:- (tnx VR) | ||
| 175 | 1.01: linux-2.1.51-:i386-:-:pentium-:- (tnx KO) | ||
| 176 | 1.01: linux-2.1.61-:i386-:-:i486-:- (tnx RO) | ||
| 177 | 1.01: linux-2.1.65-:i386-:-:i486-:- (tnx F2T) | ||
| 178 | 1.01: linux-2.1.71-:i386-:-:ppro-:- (tnx MJG) | ||
| 179 | 1.01: linux-2.1.78-:i386-:-:pentium-:- (tnx AS) | ||
| 180 | 1.01: linux-2.1.82-:i386-:-:pentium-:- (tnx AY) | ||
| 181 | 1.01: linux-2.1.85-:i386-:-:pentium-:- (tnx PJH) | ||
| 182 | 1.00: machten-4-0.4-:-:-:powerpc-:- (tnx RAM) | ||
| 183 | 1.01: netbsd-1.1-:i386-:-:pentium.(genuineintel.586-class.cpu)-:- (tnx GL) | ||
| 184 | 1.01: netbsd-1.2-:hp300-:-:-:- (tnx ML) | ||
| 185 | 1.01: netbsd-1.2-:i386-:-:i486dx.(genuineintel.486-class.cpu)-:- (tnx T2K) | ||
| 186 | 0.96: netbsd-1.2-:i386-:-:pentium.(genuineintel.586-class.cpu)-:- (tnx GH) | ||
| 187 | 1.01: netbsd-1.2.1-:mac68k-:-:apple.macintosh.se/30..(68030)-:- (tnx HM) | ||
| 188 | 1.01: netbsd-1.2.1-:sparc-:-:fmi,mb86904.@.110.mhz,.on-chip.fpu-:- (tnx ZU) | ||
| 189 | 0.96: netbsd-1.2c-:pmax-:-:-:- (tnx JLW) | ||
| 190 | 1.01: netbsd-1.3-:hp300-:-:hp.9000/433.(33mhz.mc68040.cpu+mmu+fpu,.4k.on-chip.physical.i/d.caches)-:- (tnx TB) | ||
| 191 | 1.01: netbsd-1.3.1-:sun3-:-:sun.3/60-:- (tnx MBS) | ||
| 192 | 1.01: netbsd-1.3_alpha-:i386-:-:intel.pentium.(p54c).(586-class)-:- (tnx GL) | ||
| 193 | 1.01: nextstep-3.1-:mc680x0-:-:68040-:- (tnx JRY) | ||
| 194 | 1.01: nextstep-3.3-:hppa-:-:7100lc-:- | ||
| 195 | 1.01: nextstep-3.3-:i386-:-:pentium-:- (tnx HM) | ||
| 196 | 1.01: nextstep-3.3-:mc680x0-:-:68040-:- (tnx WEB) | ||
| 197 | 1.01: nextstep-4.1-:mc680x0-:-:68040-:- (tnx FN) | ||
| 198 | 1.00: openbsd-2.0-hoth#0-:openbsd.i386-:-:i386-:- (tnx MBS) | ||
| 199 | 1.00: openbsd-2.0-mr_potatoe_head#2-:openbsd.i386-:-:i386-:- (tnx JJMK) | ||
| 200 | 0.96: openbsd-2.0-puma#1-:openbsd.m68k-:-:mac68k-:- (tnx AKB) | ||
| 201 | 1.01: openbsd-2.1-asgard#1-:openbsd.i386-:-:i386-:- (tnx ETT) | ||
| 202 | 1.01: openbsd-2.1-generic#71-:openbsd.sparc-:-:sparc-:- (tnx MMM2) | ||
| 203 | 1.01: openbsd-2.1-katana#2-:openbsd.i386-:-:i386-:- (tnx CHR) | ||
| 204 | 1.01: openbsd-2.1-puma#0-:openbsd.m68k-:-:mac68k-:- (tnx AKB) | ||
| 205 | 1.01: openbsd-2.2-ele#2-:openbsd.i386-:-:i386-:- (tnx RC) | ||
| 206 | 1.01: openbsd-2.2-generic#424-:openbsd.i386-:-:i386-:- (tnx ETT) | ||
| 207 | 1.01: osf1-v2.0-240-:-:-:alpha-:- (tnx JF) | ||
| 208 | 1.00: osf1-v3.2-148-:-:-:alpha-:- (tnx DL) | ||
| 209 | 1.01: osf1-v3.2-148-:-:-:alpha-:- (tnx RSK) | ||
| 210 | 1.01: osf1-v3.2-41-:-:-:alpha-:- (tnx MSD) | ||
| 211 | 1.01: osf1-v3.2-mp-4.2-:-:-:alpha-:- (tnx MSD) | ||
| 212 | 1.01: osf1-v4.0-386-:-:-:alpha-:- (tnx TEE) | ||
| 213 | 1.01: osf1-v4.0-464-:-:-:alpha-:- (tnx AWB) | ||
| 214 | 1.01: osf1-v4.0-564-:-:-:alpha-:- (tnx A2P) | ||
| 215 | 1.01: osf1-v4.0-564.32-:-:-:alpha-:- (tnx TLF) | ||
| 216 | 1.01: osf1-v4.0-878-:-:-:alpha-:- (tnx BJM) | ||
| 217 | 1.01: sco_sv-3.2-2-:-:-:i386-:- (tnx PW) | ||
| 218 | 1.01: sinix-l-5.41-d0005-:-:-:mx300i-:- (tnx IH) | ||
| 219 | 1.01: sunos-4.1.1-1-:mc68020-:sun3-:sun3-:sun3- (tnx JWB) | ||
| 220 | 1.01: sunos-4.1.1-1-:mc68020-:sun3-:sun3x-:sun3x- (tnx TT) | ||
| 221 | 1.01: sunos-4.1.3-jl-2-:sparc-:sun4-:sun4c-:sun4c- (tnx T2K) | ||
| 222 | 1.01: sunos-4.1.3_u1-1-:sparc-:sun4-:sun4c-:sun4c- (tnx MBS) | ||
| 223 | 1.01: sunos-4.1.3_u1-1-:sparc-:sun4-:sun4m-:sun4m- (tnx RSK) | ||
| 224 | 1.01: sunos-4.1.3_u1-10-:sparc-:sun4-:sun4m-:sun4m- (tnx aoki=???) | ||
| 225 | 1.00: sunos-4.1.3_u1-4-:unknown-:sun4-:sun4m-:sun4m- (tnx J2B) | ||
| 226 | 1.01: sunos-4.1.3_u1-6-:sparc-:sun4-:sun4m-:sun4m- (tnx RD) | ||
| 227 | 1.01: sunos-4.1.4-1-:unknown-:sun4-:sun4m-:sun4m- (tnx M3S) | ||
| 228 | 1.01: sunos-4.1.4-2-:sparc-:sun4-:sun4m-:sun4m- | ||
| 229 | 1.01: sunos-5.3-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx JDJ) | ||
| 230 | 1.01: sunos-5.4-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx jimo=???) | ||
| 231 | 0.96: sunos-5.4-generic_101945-10-:sparc-:sun4-:sun4m-:sun4m- (tnx W2K) | ||
| 232 | 1.00: sunos-5.4-generic_101945-34-:sparc-:sun4-:sun4m-:sun4m- (tnx ACB) | ||
| 233 | 0.96: sunos-5.4-generic_101946-35-:i386-:i86pc-:i86pc-:i86pc- (tnx CK) | ||
| 234 | 1.01: sunos-5.5-generic-:i386-:i86pc-:i86pc-:i86pc- (tnx seong=???) | ||
| 235 | 1.01: sunos-5.5-generic-:sparc-:sun4-:sun4c-:sun4c- (tnx SPM) | ||
| 236 | 1.01: sunos-5.5-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx RDM) | ||
| 237 | 1.01: sunos-5.5-generic-:sparc-:sun4-:sun4u-:sun4u- (tnx YC) | ||
| 238 | 1.01: sunos-5.5-generic_103093-02-:sparc-:sun4-:sun4m-:sun4m- (tnx RF) | ||
| 239 | 0.96: sunos-5.5-generic_103093-03-:sparc-:sun4-:sun4m-:sun4m- (tnx RDM) | ||
| 240 | 1.01: sunos-5.5-generic_103093-06-:sparc-:sun4-:sun4m-:sun4m- (tnx ERH) | ||
| 241 | 1.01: sunos-5.5-generic_103093-10-:sparc-:sun4-:sun4d-:sun4d- (tnx KT) | ||
| 242 | 1.01: sunos-5.5-generic_103094-05-:i386-:i86pc-:i86pc-:i86pc- (tnx M2G) | ||
| 243 | 1.01: sunos-5.5.1-generic-:i386-:i86pc-:i86pc-:i86pc- (tnx cro=???) | ||
| 244 | 1.01: sunos-5.5.1-generic-:sparc-:sun4-:sun4c-:sun4c- (tnx CG) | ||
| 245 | 1.01: sunos-5.5.1-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx MBS) | ||
| 246 | 1.01: sunos-5.5.1-generic-:sparc-:sun4-:sun4u-:sun4u- | ||
| 247 | 0.96: sunos-5.5.1-generic_103640-02-:sparc-:sun4-:sun4m-:sun4m- (tnx SGC) | ||
| 248 | 1.00: sunos-5.5.1-generic_103640-03-:sparc-:sun4-:sun4u-:sun4u- (tnx EG) | ||
| 249 | 1.00: sunos-5.5.1-generic_103640-05-:sparc-:sun4-:sun4m-:sun4m- (tnx L2L) | ||
| 250 | 1.01: sunos-5.5.1-generic_103640-05-:sparc-:sun4-:sun4u-:sun4u- (tnx KY) | ||
| 251 | 1.01: sunos-5.5.1-generic_103640-06-:sparc-:sun4-:sun4u-:sun4u- (tnx RA) | ||
| 252 | 1.01: sunos-5.5.1-generic_103640-08-:sparc-:sun4-:sun4c-:sun4c- (tnx RA) | ||
| 253 | 1.01: sunos-5.5.1-generic_103640-08-:sparc-:sun4-:sun4d-:sun4d- (tnx MS) | ||
| 254 | 1.01: sunos-5.5.1-generic_103640-08-:sparc-:sun4-:sun4m-:sun4m- (tnx S2P) | ||
| 255 | 1.01: sunos-5.5.1-generic_103640-08-:sparc-:sun4-:sun4u-:sun4u- (tnx CM) | ||
| 256 | 1.01: sunos-5.5.1-generic_103640-12-:sparc-:sun4-:sun4m-:sun4m- (tnx IK) | ||
| 257 | 1.01: sunos-5.5.1-generic_103640-18-:sparc-:sun4-:sun4u-:sun4u- (tnx PMH) | ||
| 258 | 1.01: sunos-5.5.1-generic_103641-08-:i386-:i86pc-:i86pc-:i86pc- (tnx TL) | ||
| 259 | 1.01: sunos-5.5.1-generic_103641-12-:i386-:i86pc-:i86pc-:i86pc- (tnx JS) | ||
| 260 | 1.01: sunos-5.5.1-generic_105428-01-:sparc-:sun4-:sun4u-:sun4u- (tnx BCM) | ||
| 261 | 0.96: sunos-5.5.1-generic_patch-:i386-:i86pc-:i86pc-:i86pc- (tnx D2K) | ||
| 262 | 1.01: sunos-5.6-generic-:sparc-:sun4-:sun4c-:sun4c- (tnx DS) | ||
| 263 | 1.01: sunos-5.6-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx BDM) | ||
| 264 | 1.01: sunos-5.6-generic-:sparc-:sun4-:sun4u-:sun4u- (tnx RPS) | ||
| 265 | 1.01: sunos-5.6-generic_105182-01-:i386-:i86pc-:i86pc-:i86pc- (tnx JFK) | ||
| 266 | 1.01: sunos-5.6-generic_105182-04-:i386-:i86pc-:i86pc-:i86pc- (tnx YC) | ||
| 267 | 0.96: ultrix-4.3-1-:pmax-:-:risc-:- (tnx YF) | ||
| 268 | 1.01: ultrix-4.4-0-:-:-:risc-:- (tnx RSK) | ||
| 269 | 1.01: unix_sv-4.2mp-2.1.2-:i386-:-:i386-:- (tnx J2W) | ||
diff --git a/REMOVE.binmail b/REMOVE.binmail new file mode 100644 index 0000000..9532ac9 --- /dev/null +++ b/REMOVE.binmail | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | Here's how to remove binmail from your system. Don't do this if you have | ||
| 2 | configured qmail to use binmail for local delivery. | ||
| 3 | |||
| 4 | |||
| 5 | 1. Find the binmail binary on your system: /usr/libexec/mail.local if | ||
| 6 | that exists, otherwise /bin/mail. | ||
| 7 | |||
| 8 | 2. Remove permissions from the binmail binary: | ||
| 9 | # chmod 0 /usr/libexec/mail.local | ||
| 10 | |||
| 11 | 3. If the binmail binary was /bin/mail, make sure that ``mail'' still | ||
| 12 | invokes a usable mailer. Under SVR4 you may want to link mail to | ||
| 13 | mailx. | ||
| 14 | |||
| 15 | 4. Comment out the comsat line in /etc/inetd.conf, and kill -HUP your | ||
| 16 | inetd. | ||
diff --git a/REMOVE.sendmail b/REMOVE.sendmail new file mode 100644 index 0000000..5be6e78 --- /dev/null +++ b/REMOVE.sendmail | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | Here's how to remove sendmail from your system. | ||
| 2 | |||
| 3 | 1. Find sendmail in your boot scripts. It's usually in either /etc/rc or | ||
| 4 | /etc/init.d/sendmail. It looks like | ||
| 5 | sendmail -bd -q15m | ||
| 6 | -q15m means that it should run the queue every 15 minutes; you may | ||
| 7 | see a different number. Comment out this line. | ||
| 8 | |||
| 9 | 2. Kill the sendmail daemon. You should first kill -STOP the daemon; if | ||
| 10 | any children are running, you should kill -CONT, wait, kill -STOP | ||
| 11 | again, and repeat ad nauseam. If there aren't any children, kill | ||
| 12 | -TERM and then kill -CONT. | ||
| 13 | |||
| 14 | 3. Check whether you have any messages in the sendmail queue, | ||
| 15 | /var/spool/mqueue. If you do, you will have to try flushing them with | ||
| 16 | sendmail.bak -q. If necessary, wait a while and run sendmail.bak -q | ||
| 17 | again. Repeat until the queue is empty. This may take several days. | ||
| 18 | |||
| 19 | 4. Remove the setuid bit on the sendmail binary, to prevent local users | ||
| 20 | from gaining extra privileges through sendmail's security holes. The | ||
| 21 | binary may be at several different locations: | ||
| 22 | # chmod 0 /usr/lib/sendmail | ||
| 23 | # chmod 0 /usr/sbin/sendmail | ||
| 24 | # chmod 0 /usr/lib/sendmail.mx | ||
| 25 | |||
| 26 | 5. Move the sendmail binary out of the way: | ||
| 27 | # mv /usr/lib/sendmail /usr/lib/sendmail.bak | ||
| 28 | # mv /usr/sbin/sendmail /usr/sbin/sendmail.bak | ||
diff --git a/SECURITY b/SECURITY new file mode 100644 index 0000000..098f124 --- /dev/null +++ b/SECURITY | |||
| @@ -0,0 +1,131 @@ | |||
| 1 | Background: Every few months CERT announces Yet Another Security Hole In | ||
| 2 | Sendmail---something that lets local or even remote users take complete | ||
| 3 | control of the machine. I'm sure there are many more holes waiting to be | ||
| 4 | discovered; sendmail's design means that any minor bug in 46000 lines of | ||
| 5 | code is a major security risk. Other popular mailers, such as Smail, and | ||
| 6 | even mailing-list managers, such as Majordomo, seem nearly as bad. | ||
| 7 | |||
| 8 | Note added in 1998: I wrote the above paragraph in December 1995, when | ||
| 9 | the latest version of sendmail was 8.6.12 (with 41000 lines of code). | ||
| 10 | Fourteen security holes were discovered from sendmail 8.6.12 through | ||
| 11 | 8.8.5. See http://pobox.com/~djb/docs/maildisasters/sendmail.html. | ||
| 12 | |||
| 13 | I started working on qmail because I was sick of this cycle of doom. | ||
| 14 | Here are some of the things I did to make sure that qmail will never let | ||
| 15 | an intruder into your machine. | ||
| 16 | |||
| 17 | |||
| 18 | 1. Programs and files are not addresses. Don't treat them as addresses. | ||
| 19 | |||
| 20 | sendmail treats programs and files as addresses. Obviously random people | ||
| 21 | can't be allowed to execute arbitrary programs or write to arbitrary | ||
| 22 | files, so sendmail goes through horrendous contortions trying to keep | ||
| 23 | track of whether a local user was ``responsible'' for an address. This | ||
| 24 | has proven to be an unmitigated disaster. | ||
| 25 | |||
| 26 | In qmail, programs and files are not addresses. The local delivery | ||
| 27 | agent, qmail-local, can run programs or write to files as directed by | ||
| 28 | ~user/.qmail, but it's always running as that user. (The notion of | ||
| 29 | ``user'' is configurable, but root is never a user. To prevent silly | ||
| 30 | mistakes, qmail-local makes sure that neither ~user nor ~user/.qmail is | ||
| 31 | group-writable or world-writable.) | ||
| 32 | |||
| 33 | Security impact: .qmail, like .cshrc and .exrc and various other files, | ||
| 34 | means that anyone who can write arbitrary files as a user can execute | ||
| 35 | arbitrary programs as that user. That's it. | ||
| 36 | |||
| 37 | |||
| 38 | 2. Do as little as possible in setuid programs. | ||
| 39 | |||
| 40 | A setuid program must operate in a very dangerous environment: a user is | ||
| 41 | under complete control of its fds, args, environ, cwd, tty, rlimits, | ||
| 42 | timers, signals, and more. Even worse, the list of controlled items | ||
| 43 | varies from one vendor's UNIX to the next, so it is very difficult to | ||
| 44 | write portable code that cleans up everything. | ||
| 45 | |||
| 46 | Of the twenty most recent sendmail security holes, eleven worked only | ||
| 47 | because the entire sendmail system is setuid. | ||
| 48 | |||
| 49 | Only one qmail program is setuid: qmail-queue. Its only purpose is to | ||
| 50 | add a new mail message to the outgoing queue. | ||
| 51 | |||
| 52 | |||
| 53 | 3. Do as little as possible as root. | ||
| 54 | |||
| 55 | The entire sendmail system runs as root, so there's no way that its | ||
| 56 | mistakes can be caught by the operating system's built-in protections. | ||
| 57 | In contrast, only two qmail programs, qmail-start and qmail-lspawn, | ||
| 58 | run as root. | ||
| 59 | |||
| 60 | |||
| 61 | 4. Move separate functions into mutually untrusting programs. | ||
| 62 | |||
| 63 | Five of the qmail programs---qmail-smtpd, qmail-send, qmail-rspawn, | ||
| 64 | qmail-remote, and tcp-env---are not security-critical. Even if all of | ||
| 65 | these programs are completely compromised, so that an intruder has | ||
| 66 | control over the qmaild, qmails, and qmailr accounts and the mail queue, | ||
| 67 | he still can't take over your system. None of the other programs trust | ||
| 68 | the results from these five. | ||
| 69 | |||
| 70 | In fact, these programs don't even trust each other. They are in three | ||
| 71 | groups: tcp-env and qmail-smtpd, which run as qmaild; qmail-rspawn and | ||
| 72 | qmail-remote, which run as qmailr; and qmail-send, the queue manager, | ||
| 73 | which runs as qmails. Each group is immune from attacks by the others. | ||
| 74 | |||
| 75 | (From root's point of view, as long as root doesn't send any mail, only | ||
| 76 | qmail-start and qmail-lspawn are security-critical. They don't write any | ||
| 77 | files or start any other programs as root.) | ||
| 78 | |||
| 79 | |||
| 80 | 5. Don't parse. | ||
| 81 | |||
| 82 | I have discovered that there are two types of command interfaces in the | ||
| 83 | world of computing: good interfaces and user interfaces. | ||
| 84 | |||
| 85 | The essence of user interfaces is _parsing_---converting an unstructured | ||
| 86 | sequence of commands, in a format usually determined more by psychology | ||
| 87 | than by solid engineering, into structured data. | ||
| 88 | |||
| 89 | When another programmer wants to talk to a user interface, he has to | ||
| 90 | _quote_: convert his structured data into an unstructured sequence of | ||
| 91 | commands that the parser will, he hopes, convert back into the original | ||
| 92 | structured data. | ||
| 93 | |||
| 94 | This situation is a recipe for disaster. The parser often has bugs: it | ||
| 95 | fails to handle some inputs according to the documented interface. The | ||
| 96 | quoter often has bugs: it produces outputs that do not have the right | ||
| 97 | meaning. Only on rare joyous occasions does it happen that the parser | ||
| 98 | and the quoter both misinterpret the interface in the same way. | ||
| 99 | |||
| 100 | When the original data is controlled by a malicious user, many of these | ||
| 101 | bugs translate into security holes. Some examples: the Linux login | ||
| 102 | -froot security hole; the classic find | xargs rm security hole; the | ||
| 103 | Majordomo injection security hole. Even a simple parser like getopt is | ||
| 104 | complicated enough for people to screw up the quoting. | ||
| 105 | |||
| 106 | In qmail, all the internal file structures are incredibly simple: text0 | ||
| 107 | lines beginning with single-character commands. (text0 format means that | ||
| 108 | lines are separated by a 0 byte instead of line feed.) The program-level | ||
| 109 | interfaces don't take options. | ||
| 110 | |||
| 111 | All the complexity of parsing RFC 822 address lists and rewriting | ||
| 112 | headers is in the qmail-inject program, which runs without privileges | ||
| 113 | and is essentially part of the UA. | ||
| 114 | |||
| 115 | |||
| 116 | 6. Keep it simple, stupid. | ||
| 117 | |||
| 118 | See BLURB for some of the reasons that qmail is so much smaller than | ||
| 119 | sendmail. There's nothing inherently complicated about writing a mailer. | ||
| 120 | (Except RFC 822 support; but that's only in qmail-inject.) Security | ||
| 121 | holes can't show up in features that don't exist. | ||
| 122 | |||
| 123 | |||
| 124 | 7. Write bug-free code. | ||
| 125 | |||
| 126 | I've mostly given up on the standard C library. Many of its facilities, | ||
| 127 | particularly stdio, seem designed to encourage bugs. A big chunk of | ||
| 128 | qmail is stolen from a basic C library that I've been developing for | ||
| 129 | several years for a variety of applications. The stralloc concept and | ||
| 130 | getln() make it very easy to avoid buffer overruns, memory leaks, and | ||
| 131 | artificial line length limits. | ||
diff --git a/SENDMAIL b/SENDMAIL new file mode 100644 index 0000000..9280c24 --- /dev/null +++ b/SENDMAIL | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | This document explains what you, as a user, will notice when the system | ||
| 2 | switches from sendmail to qmail. | ||
| 3 | |||
| 4 | This is a global document, part of the qmail package, not reflecting the | ||
| 5 | decisions made by your system administrator. For details on | ||
| 6 | |||
| 7 | * which local delivery agent qmail is configured to use, | ||
| 8 | * whether qmail is configured to use dot-forward, | ||
| 9 | * whether ezmlm is installed, | ||
| 10 | * whether fastforward is installed, and | ||
| 11 | * all other local configuration features, | ||
| 12 | |||
| 13 | see your local sendmail-qmail upgrade announcement (which your system | ||
| 14 | administrator may have placed into /var/qmail/doc/ANNOUNCE). | ||
| 15 | |||
| 16 | |||
| 17 | --- Mailbox location | ||
| 18 | |||
| 19 | If your system administrator has configured qmail to use binmail for | ||
| 20 | local deliveries, your mailbox will be in /var/spool/mail/you, just as | ||
| 21 | it was under sendmail. | ||
| 22 | |||
| 23 | If your system administrator has configured qmail to use qmail-local for | ||
| 24 | local deliveries, your mailbox will be moved to ~you/Mailbox. There is a | ||
| 25 | symbolic link from /var/spool/mail/you to ~you/Mailbox, so your mail | ||
| 26 | reader will find the mailbox at its new location. | ||
| 27 | |||
| 28 | |||
| 29 | --- Loop control | ||
| 30 | |||
| 31 | qmail-local automatically adds a Delivered-To field at the top of every | ||
| 32 | delivered message. It uses Delivered-To to prevent mail forwarding | ||
| 33 | loops, including cross-host mailing-list loops. | ||
| 34 | |||
| 35 | |||
| 36 | --- Outgoing messages | ||
| 37 | |||
| 38 | qmail lets you use environment variables to control the appearance of | ||
| 39 | your outgoing mail, supplementing the features offered by your MUA. For | ||
| 40 | example, qmail-inject will set up Mail-Followup-To for you automatically | ||
| 41 | if you tell it which mailing lists you are subscribed to. See | ||
| 42 | qmail-inject(8) for a complete list of features. | ||
| 43 | |||
| 44 | If you're at (say) sun.ee.movie.edu, qmail lets you type joe@mac for | ||
| 45 | joe@mac.ee.movie.edu, and joe@mac+ for joe@mac.movie.edu without the ee. | ||
| 46 | sendmail has a different interpretation of hostnames without dots. | ||
| 47 | |||
| 48 | |||
| 49 | --- Forwarding and mailing lists | ||
| 50 | |||
| 51 | qmail gives you the power to set up your own mailing lists without | ||
| 52 | pestering your system administrator. | ||
| 53 | |||
| 54 | Under qmail, you are in charge of all addresses of the form | ||
| 55 | you-anything. The delivery of you-anything is controlled by | ||
| 56 | ~you/.qmail-anything, a file in your home directory. | ||
| 57 | |||
| 58 | For example, if you want to set up a bug-of-the-month-club mailing list, | ||
| 59 | you can put a list of addresses into ~you/.qmail-botmc. Any mail to | ||
| 60 | you-botmc will be forwarded to all of those addresses. Mail directly to | ||
| 61 | you is controlled by ~you/.qmail. You can even set up a catch-all, | ||
| 62 | ~you/.qmail-default, to handle unknown you- addresses. | ||
| 63 | |||
| 64 | See dot-qmail(5) for the complete story. Beware that the syntax of | ||
| 65 | .qmail is different from the syntax of sendmail's .forward file. | ||
| 66 | |||
| 67 | If your system administrator has configured qmail to use the dot-forward | ||
| 68 | compatibility tool, you can put forwarding addresses (and programs) into | ||
| 69 | .forward the same way you did with sendmail. | ||
| 70 | |||
| 71 | If your system administrator has installed ezmlm, you can use ezmlm-make | ||
| 72 | to instantly set up a professional-quality mailing list, handling | ||
| 73 | subscriptions and archives automatically. | ||
| 74 | |||
| 75 | If your system administrator has installed fastforward, you can easily | ||
| 76 | manage a large database of forwarding addresses. | ||
| @@ -0,0 +1,17 @@ | |||
| 1 | VERSION | ||
| 2 | systype | ||
| 3 | hasshsgr.h | ||
| 4 | hasnpbg1.h | ||
| 5 | select.h | ||
| 6 | hasflock.h | ||
| 7 | hassalen.h | ||
| 8 | fork.h | ||
| 9 | hassgact.h | ||
| 10 | direntry.h | ||
| 11 | hassgprm.h | ||
| 12 | haswaitp.h | ||
| 13 | hasmkffo.h | ||
| 14 | uint32.h | ||
| 15 | dns.lib | ||
| 16 | socket.lib | ||
| 17 | syslog.lib | ||
| @@ -0,0 +1,387 @@ | |||
| 1 | auto-ccld.sh | ||
| 2 | make-load | ||
| 3 | find-systype | ||
| 4 | systype | ||
| 5 | load | ||
| 6 | make-compile | ||
| 7 | compile | ||
| 8 | fork.h | ||
| 9 | qmail-local.o | ||
| 10 | qmail.o | ||
| 11 | quote.o | ||
| 12 | now.o | ||
| 13 | gfrom.o | ||
| 14 | myctime.o | ||
| 15 | slurpclose.o | ||
| 16 | make-makelib | ||
| 17 | makelib | ||
| 18 | case_diffb.o | ||
| 19 | case_diffs.o | ||
| 20 | case_lowerb.o | ||
| 21 | case_lowers.o | ||
| 22 | case_starts.o | ||
| 23 | case.a | ||
| 24 | getln.o | ||
| 25 | getln2.o | ||
| 26 | getln.a | ||
| 27 | subgetopt.o | ||
| 28 | sgetopt.o | ||
| 29 | getopt.a | ||
| 30 | sig_alarm.o | ||
| 31 | hassgprm.h | ||
| 32 | sig_block.o | ||
| 33 | hassgact.h | ||
| 34 | sig_catch.o | ||
| 35 | sig_pause.o | ||
| 36 | sig_pipe.o | ||
| 37 | sig_child.o | ||
| 38 | sig_hup.o | ||
| 39 | sig_term.o | ||
| 40 | sig_bug.o | ||
| 41 | sig_misc.o | ||
| 42 | sig.a | ||
| 43 | open_append.o | ||
| 44 | open_excl.o | ||
| 45 | open_read.o | ||
| 46 | open_trunc.o | ||
| 47 | open_write.o | ||
| 48 | open.a | ||
| 49 | seek_cur.o | ||
| 50 | seek_end.o | ||
| 51 | seek_set.o | ||
| 52 | seek_trunc.o | ||
| 53 | seek.a | ||
| 54 | hasflock.h | ||
| 55 | lock_ex.o | ||
| 56 | lock_exnb.o | ||
| 57 | lock_un.o | ||
| 58 | lock.a | ||
| 59 | fd_copy.o | ||
| 60 | fd_move.o | ||
| 61 | fd.a | ||
| 62 | haswaitp.h | ||
| 63 | wait_pid.o | ||
| 64 | wait_nohang.o | ||
| 65 | wait.a | ||
| 66 | env.o | ||
| 67 | envread.o | ||
| 68 | env.a | ||
| 69 | stralloc_eady.o | ||
| 70 | stralloc_pend.o | ||
| 71 | stralloc_copy.o | ||
| 72 | stralloc_opys.o | ||
| 73 | stralloc_opyb.o | ||
| 74 | stralloc_cat.o | ||
| 75 | stralloc_cats.o | ||
| 76 | stralloc_catb.o | ||
| 77 | stralloc_arts.o | ||
| 78 | stralloc.a | ||
| 79 | alloc.o | ||
| 80 | alloc_re.o | ||
| 81 | alloc.a | ||
| 82 | strerr_sys.o | ||
| 83 | strerr_die.o | ||
| 84 | strerr.a | ||
| 85 | substdio.o | ||
| 86 | substdi.o | ||
| 87 | substdo.o | ||
| 88 | subfderr.o | ||
| 89 | subfdout.o | ||
| 90 | subfdouts.o | ||
| 91 | subfdin.o | ||
| 92 | subfdins.o | ||
| 93 | substdio_copy.o | ||
| 94 | substdio.a | ||
| 95 | error.o | ||
| 96 | error_str.o | ||
| 97 | error_temp.o | ||
| 98 | error.a | ||
| 99 | str_len.o | ||
| 100 | str_diff.o | ||
| 101 | str_diffn.o | ||
| 102 | str_cpy.o | ||
| 103 | str_chr.o | ||
| 104 | str_rchr.o | ||
| 105 | str_start.o | ||
| 106 | byte_chr.o | ||
| 107 | byte_rchr.o | ||
| 108 | byte_diff.o | ||
| 109 | byte_copy.o | ||
| 110 | byte_cr.o | ||
| 111 | byte_zero.o | ||
| 112 | str.a | ||
| 113 | fmt_str.o | ||
| 114 | fmt_strn.o | ||
| 115 | fmt_uint.o | ||
| 116 | fmt_uint0.o | ||
| 117 | fmt_ulong.o | ||
| 118 | scan_ulong.o | ||
| 119 | scan_8long.o | ||
| 120 | fs.a | ||
| 121 | datetime.o | ||
| 122 | datetime_un.o | ||
| 123 | datetime.a | ||
| 124 | auto-str.o | ||
| 125 | auto-str | ||
| 126 | auto_qmail.c | ||
| 127 | auto_qmail.o | ||
| 128 | auto-int8.o | ||
| 129 | auto-int8 | ||
| 130 | auto_patrn.c | ||
| 131 | auto_patrn.o | ||
| 132 | socket.lib | ||
| 133 | qmail-local | ||
| 134 | uint32.h | ||
| 135 | qmail-lspawn.o | ||
| 136 | select.h | ||
| 137 | chkspawn.o | ||
| 138 | auto-int.o | ||
| 139 | auto-int | ||
| 140 | auto_spawn.c | ||
| 141 | auto_spawn.o | ||
| 142 | chkspawn | ||
| 143 | spawn.o | ||
| 144 | chkshsgr.o | ||
| 145 | chkshsgr | ||
| 146 | hasshsgr.h | ||
| 147 | prot.o | ||
| 148 | coe.o | ||
| 149 | cdb_hash.o | ||
| 150 | cdb_unpack.o | ||
| 151 | cdb_seek.o | ||
| 152 | cdb.a | ||
| 153 | auto-uid.o | ||
| 154 | auto-uid | ||
| 155 | auto-gid.o | ||
| 156 | auto-gid | ||
| 157 | auto_uids.c | ||
| 158 | auto_uids.o | ||
| 159 | qmail-lspawn | ||
| 160 | qmail-getpw.o | ||
| 161 | auto_break.c | ||
| 162 | auto_break.o | ||
| 163 | auto_usera.c | ||
| 164 | auto_usera.o | ||
| 165 | qmail-getpw | ||
| 166 | qmail-remote.o | ||
| 167 | control.o | ||
| 168 | constmap.o | ||
| 169 | timeoutread.o | ||
| 170 | timeoutwrite.o | ||
| 171 | timeoutconn.o | ||
| 172 | tcpto.o | ||
| 173 | dns.o | ||
| 174 | ip.o | ||
| 175 | ipalloc.o | ||
| 176 | hassalen.h | ||
| 177 | ipme.o | ||
| 178 | ndelay.o | ||
| 179 | ndelay_off.o | ||
| 180 | ndelay.a | ||
| 181 | dns.lib | ||
| 182 | qmail-remote | ||
| 183 | qmail-rspawn.o | ||
| 184 | tcpto_clean.o | ||
| 185 | qmail-rspawn | ||
| 186 | direntry.h | ||
| 187 | qmail-clean.o | ||
| 188 | fmtqfn.o | ||
| 189 | auto_split.c | ||
| 190 | auto_split.o | ||
| 191 | qmail-clean | ||
| 192 | qmail-send.o | ||
| 193 | qsutil.o | ||
| 194 | newfield.o | ||
| 195 | prioq.o | ||
| 196 | hasmkffo.h | ||
| 197 | fifo.o | ||
| 198 | hasnpbg1.h | ||
| 199 | trigger.o | ||
| 200 | readsubdir.o | ||
| 201 | date822fmt.o | ||
| 202 | qmail-send | ||
| 203 | qmail-start.o | ||
| 204 | qmail-start | ||
| 205 | splogger.o | ||
| 206 | syslog.lib | ||
| 207 | splogger | ||
| 208 | qmail-queue.o | ||
| 209 | triggerpull.o | ||
| 210 | qmail-queue | ||
| 211 | qmail-inject.o | ||
| 212 | headerbody.o | ||
| 213 | hfield.o | ||
| 214 | token822.o | ||
| 215 | qmail-inject | ||
| 216 | predate.o | ||
| 217 | predate | ||
| 218 | datemail | ||
| 219 | mailsubj | ||
| 220 | qmail-upq | ||
| 221 | qmail-showctl.o | ||
| 222 | qmail-showctl | ||
| 223 | qmail-newu.o | ||
| 224 | cdbmss.o | ||
| 225 | cdbmake_pack.o | ||
| 226 | cdbmake_hash.o | ||
| 227 | cdbmake_add.o | ||
| 228 | cdbmake.a | ||
| 229 | qmail-newu | ||
| 230 | qmail-pw2u.o | ||
| 231 | qmail-pw2u | ||
| 232 | qmail-qread.o | ||
| 233 | qmail-qread | ||
| 234 | qmail-qstat | ||
| 235 | qmail-tcpto.o | ||
| 236 | qmail-tcpto | ||
| 237 | qmail-tcpok.o | ||
| 238 | qmail-tcpok | ||
| 239 | qmail-pop3d.o | ||
| 240 | commands.o | ||
| 241 | maildir.o | ||
| 242 | qmail-pop3d | ||
| 243 | qmail-popup.o | ||
| 244 | qmail-popup | ||
| 245 | qmail-qmqpc.o | ||
| 246 | qmail-qmqpc | ||
| 247 | qmail-qmqpd.o | ||
| 248 | received.o | ||
| 249 | qmail-qmqpd | ||
| 250 | qmail-qmtpd.o | ||
| 251 | rcpthosts.o | ||
| 252 | qmail-qmtpd | ||
| 253 | qmail-smtpd.o | ||
| 254 | qmail-smtpd | ||
| 255 | sendmail.o | ||
| 256 | sendmail | ||
| 257 | tcp-env.o | ||
| 258 | remoteinfo.o | ||
| 259 | tcp-env | ||
| 260 | qmail-newmrh.o | ||
| 261 | qmail-newmrh | ||
| 262 | config | ||
| 263 | config-fast | ||
| 264 | dnscname.o | ||
| 265 | dnsdoe.o | ||
| 266 | dnscname | ||
| 267 | dnsptr.o | ||
| 268 | dnsptr | ||
| 269 | dnsip.o | ||
| 270 | dnsip | ||
| 271 | dnsmxip.o | ||
| 272 | dnsmxip | ||
| 273 | dnsfq.o | ||
| 274 | dnsfq | ||
| 275 | hostname.o | ||
| 276 | hostname | ||
| 277 | ipmeprint.o | ||
| 278 | ipmeprint | ||
| 279 | qreceipt.o | ||
| 280 | qreceipt | ||
| 281 | qsmhook.o | ||
| 282 | qsmhook | ||
| 283 | qbiff.o | ||
| 284 | qbiff | ||
| 285 | forward.o | ||
| 286 | forward | ||
| 287 | preline.o | ||
| 288 | preline | ||
| 289 | condredirect.o | ||
| 290 | condredirect | ||
| 291 | bouncesaying.o | ||
| 292 | bouncesaying | ||
| 293 | except.o | ||
| 294 | except | ||
| 295 | maildirmake.o | ||
| 296 | maildirmake | ||
| 297 | maildir2mbox.o | ||
| 298 | maildir2mbox | ||
| 299 | maildirwatch.o | ||
| 300 | maildirwatch | ||
| 301 | qail | ||
| 302 | elq | ||
| 303 | pinq | ||
| 304 | idedit.o | ||
| 305 | idedit | ||
| 306 | install-big.o | ||
| 307 | install.o | ||
| 308 | install-big | ||
| 309 | hier.o | ||
| 310 | install | ||
| 311 | instcheck.o | ||
| 312 | instcheck | ||
| 313 | home | ||
| 314 | home+df | ||
| 315 | proc | ||
| 316 | proc+df | ||
| 317 | binm1 | ||
| 318 | binm1+df | ||
| 319 | binm2 | ||
| 320 | binm2+df | ||
| 321 | binm3 | ||
| 322 | binm3+df | ||
| 323 | it | ||
| 324 | qmail-local.0 | ||
| 325 | qmail-lspawn.0 | ||
| 326 | qmail-getpw.8 | ||
| 327 | qmail-getpw.0 | ||
| 328 | qmail-remote.0 | ||
| 329 | qmail-rspawn.0 | ||
| 330 | qmail-clean.0 | ||
| 331 | qmail-send.8 | ||
| 332 | qmail-send.0 | ||
| 333 | qmail-start.8 | ||
| 334 | qmail-start.0 | ||
| 335 | splogger.0 | ||
| 336 | qmail-queue.0 | ||
| 337 | qmail-inject.0 | ||
| 338 | mailsubj.0 | ||
| 339 | qmail-showctl.0 | ||
| 340 | qmail-newu.8 | ||
| 341 | qmail-newu.0 | ||
| 342 | qmail-pw2u.8 | ||
| 343 | qmail-pw2u.0 | ||
| 344 | qmail-qread.0 | ||
| 345 | qmail-qstat.0 | ||
| 346 | qmail-tcpto.0 | ||
| 347 | qmail-tcpok.0 | ||
| 348 | qmail-pop3d.0 | ||
| 349 | qmail-popup.0 | ||
| 350 | qmail-qmqpc.0 | ||
| 351 | qmail-qmqpd.0 | ||
| 352 | qmail-qmtpd.0 | ||
| 353 | qmail-smtpd.0 | ||
| 354 | tcp-env.0 | ||
| 355 | qmail-newmrh.8 | ||
| 356 | qmail-newmrh.0 | ||
| 357 | qreceipt.0 | ||
| 358 | qbiff.0 | ||
| 359 | forward.0 | ||
| 360 | preline.0 | ||
| 361 | condredirect.0 | ||
| 362 | bouncesaying.0 | ||
| 363 | except.0 | ||
| 364 | maildirmake.0 | ||
| 365 | maildir2mbox.0 | ||
| 366 | maildirwatch.0 | ||
| 367 | qmail.0 | ||
| 368 | qmail-limits.7 | ||
| 369 | qmail-limits.0 | ||
| 370 | qmail-log.0 | ||
| 371 | qmail-control.5 | ||
| 372 | qmail-control.0 | ||
| 373 | qmail-header.0 | ||
| 374 | qmail-users.5 | ||
| 375 | qmail-users.0 | ||
| 376 | dot-qmail.5 | ||
| 377 | dot-qmail.0 | ||
| 378 | qmail-command.0 | ||
| 379 | tcp-environ.0 | ||
| 380 | maildir.0 | ||
| 381 | mbox.0 | ||
| 382 | addresses.0 | ||
| 383 | envelopes.0 | ||
| 384 | forgeries.0 | ||
| 385 | man | ||
| 386 | setup | ||
| 387 | check | ||
diff --git a/TEST.deliver b/TEST.deliver new file mode 100644 index 0000000..4fc4c32 --- /dev/null +++ b/TEST.deliver | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | You can do several tests of qmail delivery without setting up qmail to | ||
| 2 | accept messages through SMTP or through /usr/lib/sendmail: | ||
| 3 | |||
| 4 | 1. After you start qmail, look for a | ||
| 5 | qmail: status: local 0/10 remote 0/20 | ||
| 6 | line in syslog. qmail-send always prints either ``cannot start'' or | ||
| 7 | ``status''. (The big number is a splogger timestamp.) | ||
| 8 | |||
| 9 | 2. Do a ps and look for the qmail daemons. There should be four of | ||
| 10 | them, all idle: qmail-send, running as qmails; qmail-lspawn, running | ||
| 11 | as root; qmail-rspawn, running as qmailr; and qmail-clean, running | ||
| 12 | as qmailq. You will also see splogger, running as qmaill. | ||
| 13 | |||
| 14 | 3. Local-local test: Send yourself an empty message. (Replace ``me'' | ||
| 15 | with your username. Make sure to include the ``to:'' colon.) | ||
| 16 | % echo to: me | /var/qmail/bin/qmail-inject | ||
| 17 | The message will show up immediately in your mailbox, and syslog | ||
| 18 | will show something like this: | ||
| 19 | qmail: new msg 53 | ||
| 20 | qmail: info msg 53: bytes 246 from <me@domain> qp 20345 uid 666 | ||
| 21 | qmail: starting delivery 1: msg 53 to local me@domain | ||
| 22 | qmail: status: local 1/10 remote 0/20 | ||
| 23 | qmail: delivery 1: success: did_1+0+0/ | ||
| 24 | qmail: status: local 0/10 remote 0/20 | ||
| 25 | qmail: end msg 53 | ||
| 26 | (53 is an inode number; 20345 is a process ID; your numbers will | ||
| 27 | probably be different.) | ||
| 28 | |||
| 29 | 4. Local-error test: Send a message to a nonexistent local address. | ||
| 30 | % echo to: nonexistent | /var/qmail/bin/qmail-inject | ||
| 31 | qmail: new msg 53 | ||
| 32 | qmail: info msg 53: bytes 246 from <me@domain> qp 20351 uid 666 | ||
| 33 | qmail: starting delivery 2: msg 53 to local nonexistent@domain | ||
| 34 | qmail: status: local 1/10 remote 0/20 | ||
| 35 | qmail: delivery 2: failure: No_such_address.__#5.1.1_/ | ||
| 36 | qmail: status: local 0/10 remote 0/20 | ||
| 37 | qmail: bounce msg 53 qp 20357 | ||
| 38 | qmail: end msg 53 | ||
| 39 | qmail: new msg 54 | ||
| 40 | qmail: info msg 54: bytes 743 from <> qp 20357 uid 666 | ||
| 41 | qmail: starting delivery 3: msg 54 to local me@domain | ||
| 42 | qmail: status: local 1/10 remote 0/20 | ||
| 43 | qmail: delivery 3: success: did_1+0+0/ | ||
| 44 | qmail: status: local 0/10 remote 0/20 | ||
| 45 | qmail: end msg 54 | ||
| 46 | You will now have a bounce message in your mailbox. | ||
| 47 | |||
| 48 | 5. Local-remote test: Send an empty message to your account on another | ||
| 49 | machine. | ||
| 50 | % echo to: me@wherever | /var/qmail/bin/qmail-inject | ||
| 51 | qmail: new msg 53 | ||
| 52 | qmail: info msg 53: bytes 246 from <me@domain> qp 20372 uid 666 | ||
| 53 | qmail: starting delivery 4: msg 53 to remote me@wherever | ||
| 54 | qmail: status: local 0/10 remote 1/20 | ||
| 55 | qmail: delivery 4: success: 1.2.3.4_accepted_message./... | ||
| 56 | qmail: status: local 0/10 remote 0/20 | ||
| 57 | qmail: end msg 53 | ||
| 58 | There will be a pause between ``starting delivery'' and ``success''; | ||
| 59 | SMTP is slow. Check that the message is in your mailbox on the other | ||
| 60 | machine. | ||
| 61 | |||
| 62 | 6. Local-postmaster test: Send mail to postmaster, any capitalization. | ||
| 63 | % echo to: POSTmaster | /var/qmail/bin/qmail-inject | ||
| 64 | Look for the message in the alias mailbox, normally ~alias/Mailbox. | ||
| 65 | |||
| 66 | 7. Double-bounce test: Send a message with a completely bad envelope. | ||
| 67 | % /var/qmail/bin/qmail-inject -f nonexistent | ||
| 68 | To: unknownuser | ||
| 69 | Subject: testing | ||
| 70 | |||
| 71 | This is a test. This is only a test. | ||
| 72 | % | ||
| 73 | (Use end-of-file, not dot, to end the message.) Look for the double | ||
| 74 | bounce in the alias mailbox. | ||
| 75 | |||
| 76 | 8. Group membership test: | ||
| 77 | % cat > ~me/.qmail-groups | ||
| 78 | |groups >> MYGROUPS; exit 0 | ||
| 79 | % /var/qmail/bin/qmail-inject me-groups < /dev/null | ||
| 80 | % cat ~me/MYGROUPS | ||
| 81 | MYGROUPS will show your normal gid and nothing else. (Under Solaris, | ||
| 82 | make sure to use /usr/ucb/groups; /usr/bin/groups is broken.) | ||
diff --git a/TEST.receive b/TEST.receive new file mode 100644 index 0000000..7644845 --- /dev/null +++ b/TEST.receive | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | You can do several tests of messages entering the qmail system: | ||
| 2 | |||
| 3 | 1. SMTP server test: Forge some mail locally via SMTP. Replace ``me'' | ||
| 4 | with your username and ``domain'' with your host's name. | ||
| 5 | % telnet 127.0.0.1 25 | ||
| 6 | Trying 127.0.0.1... | ||
| 7 | Connected to 127.0.0.1. | ||
| 8 | Escape character is '^]'. | ||
| 9 | 220 domain ESMTP | ||
| 10 | helo dude | ||
| 11 | 250 domain | ||
| 12 | mail <me@domain> | ||
| 13 | 250 ok | ||
| 14 | rcpt <me@domain> | ||
| 15 | 250 ok | ||
| 16 | data | ||
| 17 | 354 go ahead | ||
| 18 | Subject: testing | ||
| 19 | |||
| 20 | This is a test. | ||
| 21 | . | ||
| 22 | 250 ok 812345679 qp 12345 | ||
| 23 | quit | ||
| 24 | 221 domain | ||
| 25 | Connection closed by foreign host. | ||
| 26 | % | ||
| 27 | Look for the message in your mailbox. (Note for programmers: Most | ||
| 28 | SMTP servers need more text after MAIL and RCPT. See RFC 821.) | ||
| 29 | |||
| 30 | 2. Remote-local test: Send yourself some mail from another machine. | ||
| 31 | Look for the message in your mailbox. | ||
| 32 | |||
| 33 | 3. Remote-error test: Send some mail from another machine to | ||
| 34 | nonexistent@domain. Look for a bounce message in the remote mailbox. | ||
| 35 | |||
| 36 | 4. UA test: Try sending mail, first to a local account, then to a | ||
| 37 | remote account, with your normal user agent. | ||
| 38 | |||
| 39 | 5. Remote-postmaster test: Send mail from another machine to | ||
| 40 | PoStMaStEr@domain. Look for the message in the alias mailbox, | ||
| 41 | normally ~alias/Mailbox. | ||
| @@ -0,0 +1,337 @@ | |||
| 1 | Thanks to lots of people for success and failure reports, code, ideas, | ||
| 2 | and documentation. See CHANGES for details of specific contributions. | ||
| 3 | Sorry if I left anyone out. | ||
| 4 | |||
| 5 | A2B = Are Bryne | ||
| 6 | A2L = Ali Lomonaco | ||
| 7 | A2P = Andrea Paolini | ||
| 8 | AAF = Adam A. Frey | ||
| 9 | AB = Alan Briggs | ||
| 10 | ABC = Alan B. Clegg | ||
| 11 | AC = Arne Coucheron | ||
| 12 | ACB = Andy C. Brandt | ||
| 13 | AF = Andreas Faerber | ||
| 14 | AG = Armin Gruner | ||
| 15 | AGB = Andre Grosse Bley | ||
| 16 | AH = Amos Hayes | ||
| 17 | AI = Akihiro Iijima | ||
| 18 | AJ = Alan Jaffray | ||
| 19 | AJK = Antti-Juhani Kaijanaho | ||
| 20 | AKB = Allen K. Briggs | ||
| 21 | AL = Andreas Lamprecht | ||
| 22 | ALB = Allan L. Bazinet | ||
| 23 | ANR = Adriano Nagelschmidt Rodrigues | ||
| 24 | AP = Andrew Pam | ||
| 25 | AS = Akos Szalkai | ||
| 26 | AV = Alex Vostrikov | ||
| 27 | AWB = Andy W. Barclay | ||
| 28 | AY = Araki Yasuhiro | ||
| 29 | B1F = Bo Fussing | ||
| 30 | B2F = Brad Forschinger | ||
| 31 | B2H = Buck Huppmann | ||
| 32 | B2L = Brent Laminack | ||
| 33 | B2W = Bil Wendling | ||
| 34 | B3W = Boris Wedl | ||
| 35 | BB = Bruce Bodger | ||
| 36 | BC = Bob Collie | ||
| 37 | BCK = Benjamin C. Kite | ||
| 38 | BCM = Bill C. Miller | ||
| 39 | BDB = Boris D. Beletsky | ||
| 40 | BDM = Byron D. Miller | ||
| 41 | BEO = Bruce E. O'Neel | ||
| 42 | BET = Bennett E. Todd | ||
| 43 | BG = Bert Gijsbers | ||
| 44 | BH = Brad Howes | ||
| 45 | BJ = Brian Jackson | ||
| 46 | BJM = Barry J. Miller | ||
| 47 | BL = Brian Litzinger | ||
| 48 | BMF = Brian M. Fisk | ||
| 49 | BN = Bill Nugent | ||
| 50 | BP = Bruce Perens | ||
| 51 | BR = Brian J. Reichert | ||
| 52 | BS = Bjoern Stabell | ||
| 53 | BT = Brad Templeton | ||
| 54 | BTW = Brian T. Wightman | ||
| 55 | BW = Bill Weinman | ||
| 56 | BZ = Blaz Zupan | ||
| 57 | C2F = Chuck Foster | ||
| 58 | C2H = Christoph Heidermanns | ||
| 59 | C2S = Craig Shrimpton | ||
| 60 | CEJ = Colin Eric Johnson | ||
| 61 | CF = C. Ferree | ||
| 62 | CG = Chris Garrigues | ||
| 63 | CH = Chael Hall | ||
| 64 | CHR = Craig H. Rowland | ||
| 65 | CK = Christoph Kaesling | ||
| 66 | CL = Carsten Leonhardt | ||
| 67 | CLS = Christopher L. Seawood | ||
| 68 | CM = Charles Mattair | ||
| 69 | CMP = Chase M. Phillips | ||
| 70 | CR = Christian Riede | ||
| 71 | CS = Cloyce Spradling | ||
| 72 | CSH = Clayton S. Haapala | ||
| 73 | D1H = Dieter Heidner | ||
| 74 | D2H = Dan Hollis | ||
| 75 | D2K = Dax Kelson | ||
| 76 | D2S = Dan Senie | ||
| 77 | D3S = Don Samek | ||
| 78 | DA = Dave Arcuri | ||
| 79 | DAR = Daniel A. Reish | ||
| 80 | DB = David Buscher | ||
| 81 | DBK = Douglas B. Kerry | ||
| 82 | DC = Dan Cross | ||
| 83 | DCC = Daniel C. Cotey | ||
| 84 | DE = Daniel Egnor | ||
| 85 | DEH = Daniel E. Harris | ||
| 86 | DF = Dale Farnsworth | ||
| 87 | DG = David Guntner | ||
| 88 | DK = Dave Kopper | ||
| 89 | DL = Daniel Lawrence | ||
| 90 | DM = David Mazieres | ||
| 91 | DML = David M. Lew | ||
| 92 | DP = Dave Platt | ||
| 93 | DS = Dave Sill | ||
| 94 | DST = Daniel S. Thibadeau | ||
| 95 | DWS = David Wayne Summers | ||
| 96 | EC = Evan Champion | ||
| 97 | ECG = Eric C. Garrison | ||
| 98 | EG = Eivind Gjelseth | ||
| 99 | EK = Eric Krohn | ||
| 100 | EP = Emanuele Pucciarelli | ||
| 101 | ERH = Eric R. Hankins | ||
| 102 | ES = Eric Smith | ||
| 103 | ESM = Edward S. Marshall | ||
| 104 | ET = Eivind Tagseth | ||
| 105 | ETT = Emmanuel T. Tardieu | ||
| 106 | F2T = Frank Thieme | ||
| 107 | FE = Frank Ederveen | ||
| 108 | FN = Faried Nawaz | ||
| 109 | FPL = Frederik P. Lindberg | ||
| 110 | FT = Frank Tegtmeyer | ||
| 111 | FW = Frank Wagner | ||
| 112 | G1A = Graham Adams | ||
| 113 | G2A = Greg Andrews | ||
| 114 | GAW = Greg A. Woods | ||
| 115 | GB = Glenn Barry | ||
| 116 | GH = Gene Hightower | ||
| 117 | GL = Giles Lean | ||
| 118 | GLM = Grant L. Miller | ||
| 119 | H2S = Harley Silver | ||
| 120 | HCJ = Helio Coelho Jr. | ||
| 121 | HDG = Hans de Graaff | ||
| 122 | HG = Howard Goldstein | ||
| 123 | HHO = Harald Hanche-Olsen | ||
| 124 | HJB = Herbert J. Bernstein | ||
| 125 | HM = Hirokazu Morikawa | ||
| 126 | HS = Harlan Stenn | ||
| 127 | HT = Henry Timmerman | ||
| 128 | HW = Hal Wine | ||
| 129 | HWM = Henry W. Miller | ||
| 130 | IH = Ingmar Hupp | ||
| 131 | IK = Ivan Kohler | ||
| 132 | IKW = Ian Keith Wynne | ||
| 133 | IS = Icarus Sparry | ||
| 134 | IW = Ian Westcott | ||
| 135 | J1B = John Banghart | ||
| 136 | J1K = Jost Krieger | ||
| 137 | J2B = Jos Backus | ||
| 138 | J2K = Johannes Kroeger | ||
| 139 | J2M = Joel Maslak | ||
| 140 | J2P = John Parker | ||
| 141 | J2W = Jim Whitby | ||
| 142 | JAB = Jeremy A. Bussard | ||
| 143 | JAK = Johan A. Kullstam | ||
| 144 | JB = Joshua Buysse | ||
| 145 | JBB = Jason B. Brown | ||
| 146 | JBF = John B. Fleming | ||
| 147 | JC = Jim Clausing | ||
| 148 | JCD = Jeffrey C. Dege | ||
| 149 | JD = Joe Doupnik | ||
| 150 | JDHB = Johannes D. H. Beekhuizen | ||
| 151 | JDJ = Joshua D. Juran | ||
| 152 | JF = Janos Farkas | ||
| 153 | JFK = James F. Kane III | ||
| 154 | JGM = John G. Myers | ||
| 155 | JJB = J. J. Bailey | ||
| 156 | JJMK = Jonathan J. M. Katz | ||
| 157 | JJR = Jaron J. Rubenstein | ||
| 158 | JK = Jari Kirma | ||
| 159 | JL = Jim Littlefield | ||
| 160 | JLB = Julie L. Baumler | ||
| 161 | JLH = Jason L. Haar | ||
| 162 | JLW = Jason L. Wright | ||
| 163 | JM = Jim Meehan | ||
| 164 | JMS = Jason M. Stokes | ||
| 165 | JMT = John M. Twilley | ||
| 166 | JP = John Palkovic | ||
| 167 | JPB = Joe Block | ||
| 168 | JPH = Justin P. Hannah | ||
| 169 | JPR = Jean-Pierre Radley | ||
| 170 | JRL = John R. Levine | ||
| 171 | JRM = Jason R. Mastaler | ||
| 172 | JRY = Jamie R. Yukes | ||
| 173 | JS = Jesper Skriver | ||
| 174 | JTB = Jonathan T. Bowie | ||
| 175 | JW = John Whittaker | ||
| 176 | JWB = James W. Birdsall | ||
| 177 | K1J = Kyle Jones | ||
| 178 | K2J = Kevin Johnson | ||
| 179 | KA = Klaus Aigte | ||
| 180 | KB = Keith Burdis | ||
| 181 | KE = Kenny Elliott | ||
| 182 | KJJ = Kevin J. Johnson | ||
| 183 | KJS = Kevin J. Sawyer | ||
| 184 | KMD = Kevin M. Dulzo | ||
| 185 | KO = Keith Owens | ||
| 186 | KR = Kenji Rikitake | ||
| 187 | KT = Karsten Thygesen | ||
| 188 | KUT = Kai Uwe Tempel | ||
| 189 | KY = Kentaro Yoshitomi | ||
| 190 | L2L = Louis Larry | ||
| 191 | L3L = Luis Lopes | ||
| 192 | LB = Laurentiu Badea | ||
| 193 | LL = lilo | ||
| 194 | LW = Lionel Widdifield | ||
| 195 | M2C = Mark Crimmins | ||
| 196 | M2G = Michael R. Gile | ||
| 197 | M2H = Martin Hager | ||
| 198 | M2L = M. Lyons | ||
| 199 | M2R = Mark Riekenberg | ||
| 200 | M2S = Mikael Suokas | ||
| 201 | M3H = Michael Holzt | ||
| 202 | M3L = Michael Lazarou | ||
| 203 | M3S = Morten Skjelland | ||
| 204 | M4S = Michael Shields | ||
| 205 | MB = Martin Budsj? | ||
| 206 | MBS = Michael B. Scher | ||
| 207 | MC = Michael Cooley | ||
| 208 | MD = Mark Delany | ||
| 209 | MDI = Miguel de Icaza | ||
| 210 | ME = Marc Ewing | ||
| 211 | MEE = Mads E. Eilertsen | ||
| 212 | MF = Massimo Fusaro | ||
| 213 | MG = Michael Graff | ||
| 214 | MGM = Mitchell G. Morris | ||
| 215 | MH = Markus Hofmann | ||
| 216 | MJD = Mark-Jason Dominus | ||
| 217 | MJG = Manuel J. Galan | ||
| 218 | ML = Martin Lucina | ||
| 219 | MLH = May Liss Haarstad | ||
| 220 | MM = Martin Mersberger | ||
| 221 | MMM = Momchil M. Momchev | ||
| 222 | MMM2 = Marc M. Martinez | ||
| 223 | MP = Matt Paduano | ||
| 224 | MR = Mosfeq Rashid | ||
| 225 | MRG = Matthew R. Green | ||
| 226 | MS = Mark Spears | ||
| 227 | MSD = Mandell S. Degerness | ||
| 228 | MSS = Matthew S. Soffen | ||
| 229 | MT = Mark Thompson | ||
| 230 | MW = Mate Wierdl | ||
| 231 | MWE = Mark W. Eichin | ||
| 232 | NA = Norm Aleks | ||
| 233 | NAA = Nicholas A. Amato | ||
| 234 | NH = Nick Holloway | ||
| 235 | NND = N. Dudorov | ||
| 236 | NR = Norbert Roeding | ||
| 237 | NW = Nicholas Waples | ||
| 238 | OK = Oezguer Kesim | ||
| 239 | OR = Ollivier Robert | ||
| 240 | OS = Oliver Seiler | ||
| 241 | PB = Peter Bowyer | ||
| 242 | PCO = Peter C. Olsen | ||
| 243 | PGF = Paul Fox | ||
| 244 | PGR = Phil G. Rorex | ||
| 245 | PH = Paul Harrington | ||
| 246 | PJG = Paul Graham | ||
| 247 | PJH = Peter J. Hunter | ||
| 248 | PK = Petri Kaukasoina | ||
| 249 | PMH = Peter M. Haworth | ||
| 250 | PO = Paul Overell | ||
| 251 | PS = Paul Svensson | ||
| 252 | PT = Paul Taylor | ||
| 253 | PTW = P. T. Withington | ||
| 254 | PW = Peter Wilkinson | ||
| 255 | R2N = Rivo Nurges | ||
| 256 | RA = Russ Allbery | ||
| 257 | RAB = Randolph Allen Bentson | ||
| 258 | RAM = Robin A. McCollum | ||
| 259 | RB = Robert Bridgham | ||
| 260 | RC = Ryan Crum | ||
| 261 | RD = Rahul Dhesi | ||
| 262 | RDM = Raul D. Miller | ||
| 263 | REB = Ronald E. Bickers | ||
| 264 | RF = Rainer Fraedrich | ||
| 265 | RFH = Robert F. Harrison | ||
| 266 | RGS = Richard G. Sharman | ||
| 267 | RJC = Robert J. Carter | ||
| 268 | RJH = Randy Harmon | ||
| 269 | RJO = Richard J. Ohnemus | ||
| 270 | RK = Riho Kurg | ||
| 271 | RL = Robert Luce | ||
| 272 | RM = Rich McClellan | ||
| 273 | RN = Russell Nelson | ||
| 274 | RO = Roberto Oppedisano | ||
| 275 | RPS = Russell P. Sutherland | ||
| 276 | RS = Robert Sanders | ||
| 277 | RSK = Robert S. Krzaczek | ||
| 278 | S1R = Satish Ramachandran | ||
| 279 | S2P = Stefan Puscasu | ||
| 280 | S2R = Sean Reifschneider | ||
| 281 | S2S = Scott Schwartz | ||
| 282 | S2T = Steve Taylor | ||
| 283 | S3T = Steffen Thorsen | ||
| 284 | SA = Satoshi Adachi | ||
| 285 | SAE = Stefaan A. Eeckels | ||
| 286 | SAS = Steven A. Schrader | ||
| 287 | SB = Stephane Bortzmeyer | ||
| 288 | SC = Stefan Cars | ||
| 289 | SCW = Steven C. Work | ||
| 290 | SG = Steven Grimm | ||
| 291 | SGC = Stephen G. Comings | ||
| 292 | SJ = Sudish Joseph | ||
| 293 | SJB = SJ Burns | ||
| 294 | SJW = Stephen J. White | ||
| 295 | SLB = Steven L. Baur | ||
| 296 | SM = Shawn McHorse | ||
| 297 | SP = Stephen Parker | ||
| 298 | SPM = Salvatore P. Miccicke | ||
| 299 | SS = Simon Shapiro | ||
| 300 | SSB = Stik Bakken | ||
| 301 | ST = Steve Tylock | ||
| 302 | SV = Sven Velt | ||
| 303 | SVD = Stef Van Dessel | ||
| 304 | T2K = Tomoya Konishi | ||
| 305 | T2M = Toni Mueller | ||
| 306 | T2U = Todd Underwood | ||
| 307 | TA = Tetsuo Aoki | ||
| 308 | TB = Tobias Brox | ||
| 309 | TD = Tom Demmer | ||
| 310 | TEE = Thomas E. Erskine | ||
| 311 | TG = Tim Goodwin | ||
| 312 | TH = Ton Hospel | ||
| 313 | TJH = Timothy J. Hunt | ||
| 314 | TK = Terry Kennedy | ||
| 315 | TL = Timothy Lorenc | ||
| 316 | TLF = Timo L. Felbinger | ||
| 317 | TLM = Timothy L. Mayo | ||
| 318 | TM = Toshinori Maeno | ||
| 319 | TN = Thomas Neumann | ||
| 320 | TRR = Tracy R. Reed | ||
| 321 | TT = Takaki Taniguchi | ||
| 322 | TU = Tetsu Ushijima | ||
| 323 | TV = Tommi Virtanen | ||
| 324 | TVP = Tom van Peer | ||
| 325 | UO = Uwe Ohse | ||
| 326 | VBM = Vladimir B. Machulsky | ||
| 327 | VR = Vincenzo Romano | ||
| 328 | VU = Viriya Upatising | ||
| 329 | VV = Vince Vielhaber | ||
| 330 | W2K = Wolfram Kahl | ||
| 331 | WEB = William E. Baxter | ||
| 332 | WK = Werner Koch | ||
| 333 | WS = Wilbur Sims | ||
| 334 | WW = Wei Wu | ||
| 335 | YC = Yuji Chikahiro | ||
| 336 | YF = Yaroslav Faybishenko | ||
| 337 | ZU = Zin Uda | ||
diff --git a/THOUGHTS b/THOUGHTS new file mode 100644 index 0000000..d6910da --- /dev/null +++ b/THOUGHTS | |||
| @@ -0,0 +1,418 @@ | |||
| 1 | Please note that this file is not called ``Internet Mail For Dummies.'' | ||
| 2 | It _records_ my thoughts on various issues. It does not _explain_ them. | ||
| 3 | Paragraphs are not organized except by section. The required background | ||
| 4 | varies wildly from one paragraph to the next. | ||
| 5 | |||
| 6 | In this file, ``sendmail'' means Allman's creation; ``sendmail-clone'' | ||
| 7 | means the program in this package. | ||
| 8 | |||
| 9 | |||
| 10 | 1. Security | ||
| 11 | |||
| 12 | There are lots of interesting remote denial-of-service attacks on any | ||
| 13 | mail system. A long-term solution is to insist on prepayment for | ||
| 14 | unauthorized resource use. The tricky technical problem is to make the | ||
| 15 | prepayment enforcement mechanism cheaper than the expected cost of the | ||
| 16 | attacks. (For local denial-of-service attacks it's enough to be able to | ||
| 17 | figure out which user is responsible.) | ||
| 18 | |||
| 19 | qmail-send's log was originally designed for profiling. It subsequently | ||
| 20 | sprouted some tracing features. However, there's no way to verify | ||
| 21 | securely that a particular message came from a particular local user; | ||
| 22 | how do you know the recipient is telling you the truth about the | ||
| 23 | contents of the message? With QUEUE_EXTRA it'd be possible to record a | ||
| 24 | one-way hash of each outgoing message, but a user who wants to send | ||
| 25 | ``bad'' mail can avoid qmail entirely. | ||
| 26 | |||
| 27 | I originally decided on security grounds not to put qmail advertisements | ||
| 28 | into SMTP responses: advertisements often act as version identifiers. | ||
| 29 | But this problem went away when I found a stable qmail URL. | ||
| 30 | |||
| 31 | As qmail grows in popularity, the mere knowledge that rcpthosts is so | ||
| 32 | easily available will deter people from setting up unauthorized MXs. | ||
| 33 | (I've never seen an unauthorized MX, but I can imagine that it would be | ||
| 34 | rather annoying.) Note that, unlike the bat book checkcompat() kludge, | ||
| 35 | rcpthosts doesn't interfere with mailing lists. | ||
| 36 | |||
| 37 | qmail-start doesn't bother with tty dissociation. On some old machines | ||
| 38 | this means that random people can send tty signals to the qmail daemons. | ||
| 39 | That's a security flaw in the job control subsystem, not in qmail. | ||
| 40 | |||
| 41 | The resolver library isn't too bloated (before 4.9.4, at least), but it | ||
| 42 | uses stdio, which _is_ bloated. Reading /etc/resolv.conf costs lots of | ||
| 43 | memory in each qmail-remote process. So it's tempting to incorporate a | ||
| 44 | smaller resolver library into qmail. (Bonus: I'd avoid system-specific | ||
| 45 | problems with old resolvers.) The problem is that I'd then be writing a | ||
| 46 | fundamentally insecure library. I'd no longer be able to blame the BIND | ||
| 47 | authors and vendors for the fact that attackers can easily use DNS to | ||
| 48 | steal mail. Solution: insist that the resolver run on the same host; the | ||
| 49 | kernel can guarantee the security of low-numbered 127.0.0.1 UDP ports. | ||
| 50 | |||
| 51 | NFS is the primary enemy of security partitioning under UNIX. Here's the | ||
| 52 | story. Sun knew from the start that NFS was completely insecure. It | ||
| 53 | tried to hide that fact by disallowing root access over NFS. Intruders | ||
| 54 | nevertheless broke into system after system, first obtaining bin access | ||
| 55 | and then obtaining root access. Various people thus decided to compound | ||
| 56 | Sun's error and build a wall between root and all other users: if all | ||
| 57 | system files are owned by root, and if there are no security holes other | ||
| 58 | than NFS, someone who breaks in via NFS won't be able to wipe out the | ||
| 59 | operating system---he'll merely be able to wipe out all user files. This | ||
| 60 | clueless policy means that, for example, all the qmail users have to be | ||
| 61 | replaced by root. See what I mean by ``enemy''? ... Basic NFS comments: | ||
| 62 | Aside from the cryptographic problem of having hosts communicate | ||
| 63 | securely, it's obvious that there's an administrative problem of mapping | ||
| 64 | client uids to server uids. If a host is secure and under your control, | ||
| 65 | you shouldn't have to map anything. If a host is under someone else's | ||
| 66 | control, you'll want to map his uids to one local account; it's his | ||
| 67 | client's job to decide which of his users get to talk NFS in the first | ||
| 68 | place. Sun's original map---root to nobody, everyone else left alone--- | ||
| 69 | is, as far as I can tell, always wrong. | ||
| 70 | |||
| 71 | |||
| 72 | 2. Injecting mail locally (qmail-inject, sendmail-clone) | ||
| 73 | |||
| 74 | RFC 822 section 3.4.9 prohibits certain visual effects in headers, and | ||
| 75 | the 822bis draft prohibits even more. qmail-inject could enforce these | ||
| 76 | absurd restrictions, but why waste the time? If you will suffer from | ||
| 77 | someone sending you ``flash mail,'' go find a better mail reader. | ||
| 78 | |||
| 79 | qmail-inject's ``Cc: recipient list not shown: ;'' successfully stops | ||
| 80 | sendmail from adding Apparently-To. Unfortunately, old versions of | ||
| 81 | sendmail will append a host name. This wasn't fixed until sendmail 8.7. | ||
| 82 | How many years has it been since RFC 822 came out? | ||
| 83 | |||
| 84 | sendmail discards duplicate addresses. This has probably resulted in | ||
| 85 | more lost and stolen mail over the years than the entire Chicago branch | ||
| 86 | of the United States Postal Service. The qmail system delivers messages | ||
| 87 | exactly as it's told to do. Along the same lines: qmail-inject is both | ||
| 88 | unable and unwilling to support anything like sendmail's (default) | ||
| 89 | nometoo option. Of course, a list manager could support nometoo. | ||
| 90 | |||
| 91 | There should be a mechanism in qmail-inject that does for envelope | ||
| 92 | recipients what Return-Path does for the envelope sender. Then | ||
| 93 | qmail-inject -n could print the recipients. | ||
| 94 | |||
| 95 | Should qmail-inject bounce messages with no recipients? Should there be | ||
| 96 | an option for this? If it stays as is (accept the message), qmail-inject | ||
| 97 | could at least avoid invoking qmail-queue. | ||
| 98 | |||
| 99 | It is possible to extract non-unique Message-IDs out of qmail-inject. | ||
| 100 | Here's how: stop qmail-inject before it gets to the third line of | ||
| 101 | main(), then wait until the pids wrap around, then restart qmail-inject | ||
| 102 | and blast the message through, then start another qmail-inject with the | ||
| 103 | same pid in the same second. I'm not sure how to fix this without | ||
| 104 | system-supplied sequence numbers. (Of course, the user could just type | ||
| 105 | in his own non-unique Message-IDs.) | ||
| 106 | |||
| 107 | The bat book says: ``Rules that hide hosts in a domain should be applied | ||
| 108 | only to sender addresses.'' Recipient masquerading works fine with | ||
| 109 | qmail. None of sendmail's pitfalls apply, basically because qmail has a | ||
| 110 | straight paper path. | ||
| 111 | |||
| 112 | I predicted that I would receive some pressure to make up for the | ||
| 113 | failings of MUA writers who don't understand the concept of reliability. | ||
| 114 | (``Like, duh, you mean I'm supposed to check the sendmail exit code?'') | ||
| 115 | I was right. | ||
| 116 | |||
| 117 | |||
| 118 | 3. Receiving mail from the network (tcp-env, qmail-smtpd) | ||
| 119 | |||
| 120 | qmail-smtpd doesn't allow privacy-invading commands like VRFY and EXPN. | ||
| 121 | If you really want to publish such information, use a mechanism that | ||
| 122 | legitimate users actually know about, such as fingerd or httpd. | ||
| 123 | |||
| 124 | RFC 1123 says that VRFY and EXPN are important to track down cross-host | ||
| 125 | mailing list loops. With Delivered-To, mailing list loops do no damage, | ||
| 126 | _and_ one of the list administrators gets a bounce message that shows | ||
| 127 | exactly how the loop occurred. Solve the problem, not the symptom. | ||
| 128 | |||
| 129 | Should dns.c make special allowances for 127.0.0.1/localhost? | ||
| 130 | |||
| 131 | badmailfrom (like 8BITMIME) is a waste of code space. | ||
| 132 | |||
| 133 | In theory a MAIL or RCPT argument can contain unquoted LFs. In practice | ||
| 134 | there are a huge number of clients that terminate commands with just LF, | ||
| 135 | even if they use CR properly inside DATA. | ||
| 136 | |||
| 137 | |||
| 138 | 4. Adding messages to the queue (qmail-queue) | ||
| 139 | |||
| 140 | Should qmail-queue try to make sure enough disk space is free in | ||
| 141 | advance? When qmail-queue is invoked by qmail-local or (with ESMTP) | ||
| 142 | qmail-smtpd or qmail-qmtpd or qmail-qmqpd, it could be told a size in | ||
| 143 | advance. I wish UNIX had an atomic allocate-disk-space routine... | ||
| 144 | |||
| 145 | The qmail.h interface (reflecting the qmail-queue interface, which in | ||
| 146 | turn reflects the current queue file structure) is constitutionally | ||
| 147 | incapable of handling an address that contains a 0 byte. I can't imagine | ||
| 148 | that this will be a problem. | ||
| 149 | |||
| 150 | Should qmail-queue not bother queueing a message with no recipients? | ||
| 151 | |||
| 152 | |||
| 153 | 5. Handling queued mail (qmail-send, qmail-clean) | ||
| 154 | |||
| 155 | The queue directory must be local. Mounting it over NFS is extremely | ||
| 156 | dangerous---not that this stops people from running sendmail that way! | ||
| 157 | Diskless hosts should use mini-qmail instead. | ||
| 158 | |||
| 159 | Queue reliability demands that single-byte writes be atomic. This is | ||
| 160 | true for a fixed-block filesystem such as UFS, and for a logging | ||
| 161 | filesystem such as LFS. | ||
| 162 | |||
| 163 | qmail-send uses 8 bytes of memory per queued message. Double that for | ||
| 164 | reallocation. (Fix: use a small forest of heaps; i.e., keep several | ||
| 165 | prioqs.) Double again for buddy malloc()s. (Fix: be clever about the | ||
| 166 | heap sizes.) 32 bytes is worrisome, but not devastating. Even on my | ||
| 167 | disk-heavy memory-light machine, I'd run out of inodes long before | ||
| 168 | running out of memory. | ||
| 169 | |||
| 170 | Some mail systems organize the queue by host. This is pointless as a | ||
| 171 | means of splitting up the queue directory. The real issue is what to do | ||
| 172 | when you suddenly find out that a host is up. For local SLIP/PPP links | ||
| 173 | you know in advance which hosts need this treatment, so you can handle | ||
| 174 | them with virtualdomains and serialmail. | ||
| 175 | |||
| 176 | For the old queue structure I implemented recipient list compression: | ||
| 177 | if mail goes out to a giant mailing list, and most of the recipients are | ||
| 178 | delivered, make a new, compressed, todo list. But this really isn't | ||
| 179 | worth the effort: it saves only a tiny bit of CPU time. | ||
| 180 | |||
| 181 | qmail-send doesn't have any notions of precedence, priority, fairness, | ||
| 182 | importance, etc. It handles the queue in first-seen-first-served order. | ||
| 183 | One could put a lot of work into doing something different, but that | ||
| 184 | work would be a waste: given the triggering mechanism and qmail's | ||
| 185 | deferral strategy, it is exceedingly rare for the queue to contain more | ||
| 186 | than one deliverable message at any given moment. | ||
| 187 | |||
| 188 | Exception: Even with all the concurrency tricks, qmail-send can end up | ||
| 189 | spending a few minutes on a mailing list with thousands of remote | ||
| 190 | entries. A user might send a new message to a remote address in the | ||
| 191 | meantime. The simplest way to handle this would be to put big messages | ||
| 192 | on a separate channel. | ||
| 193 | |||
| 194 | qmail-send will never start a pass for a job that it already has. This | ||
| 195 | means that, if one delivery takes longer than the retry interval, the | ||
| 196 | next pass will be delayed. I implemented the opposite strategy for the | ||
| 197 | old queue structure. Some hassles: mark() had to understand how job | ||
| 198 | input was buffered; every new delivery had to check whether the same | ||
| 199 | mpos in the same message was already being done. | ||
| 200 | |||
| 201 | Some things that qmail-send does synchronously: queueing a bounce | ||
| 202 | message; doing a cleanup via qmail-clean; classifying and rewriting all | ||
| 203 | the addresses in a new message. As usual, making these asynchronous | ||
| 204 | would require some housekeeping, but could speed things up a bit. | ||
| 205 | (I'm willing to assume POSIX waitpid() for asynchronous bounces; putting | ||
| 206 | an unbounded buffer into wait_pid() for the sake of NeXTSTEP 3 is not | ||
| 207 | worthwhile.) | ||
| 208 | |||
| 209 | Disk I/O is a bottleneck; UFS is reliable but it isn't fast. A good | ||
| 210 | logging filesystem offers much better performance, but logging | ||
| 211 | filesystems aren't widely available. Solution: Keep a journal, separate | ||
| 212 | from the queue, adequate to rebuild the queue (with at worst some | ||
| 213 | duplicate deliveries). Compress the journal. This would dramatically | ||
| 214 | reduce total disk I/O. | ||
| 215 | |||
| 216 | Bounce aggregation is a dubious feature. Bounce records aren't | ||
| 217 | crashproof; there can be a huge delay between a failure and a bounce; | ||
| 218 | the resulting bounce format is unnecessarily complicated. I'm tempted to | ||
| 219 | scrap the bounce directory and send one bounce for each failing | ||
| 220 | recipient, with appropriate modifications in the accompanying text. | ||
| 221 | |||
| 222 | qmail-stop implementation: setuid to UID_SEND; kill -TERM -1. Or run | ||
| 223 | qmail-start under an external service controller, such as supervise; | ||
| 224 | that's why it runs in the foreground. | ||
| 225 | |||
| 226 | The readdir() interface hides I/O errors. Lower-level interfaces would | ||
| 227 | lead me into a thicket of portability problems. I'm really not sure what | ||
| 228 | to do about this. Of course, a hard I/O error means that mail is toast, | ||
| 229 | but a soft I/O error shouldn't cause any trouble. | ||
| 230 | |||
| 231 | job_open() or pass_dochan() could be paranoid about the same id,channel | ||
| 232 | already being open; but, since messdone() is so paranoid, the worst | ||
| 233 | possible effect of a bug along these lines would be double delivery. | ||
| 234 | |||
| 235 | Mathematical amusement: The optimal retry schedule is essentially, | ||
| 236 | though not exactly, independent of the actual distribution of message | ||
| 237 | delay times. What really matters is how much cost you assign to retries | ||
| 238 | and to particular increases in latency. qmail's current quadratic retry | ||
| 239 | schedule says that an hour-long delay in a day-old message is worth the | ||
| 240 | same as a ten-minute delay in an hour-old message; this doesn't seem so | ||
| 241 | unreasonable. | ||
| 242 | |||
| 243 | Insider information: AOL retries their messages every five minutes for | ||
| 244 | three days straight. Hmmm. | ||
| 245 | |||
| 246 | |||
| 247 | 6. Sending mail through the network (qmail-rspawn, qmail-remote) | ||
| 248 | |||
| 249 | Are there any hosts, anywhere, whose mailers are bogged down by huge | ||
| 250 | messages to multiple recipients at a single host? For typical hosts, | ||
| 251 | multiple RCPTs per SMTP aren't an ``efficiency feature''; they're a | ||
| 252 | _slowness_ feature. Separate SMTP transactions have much lower latency. | ||
| 253 | |||
| 254 | I've heard three complaints about bandwidth use from masochists sending | ||
| 255 | messages through a modem through a smarthost to thousands of users--- | ||
| 256 | without sublists! They can get much better performance with QMQP. | ||
| 257 | |||
| 258 | In the opposite direction: It's tempting to remove the @host part of the | ||
| 259 | qmail-remote recip argument. Or at least avoid double-dns_cname. | ||
| 260 | |||
| 261 | There are lots of reasons that qmail-rspawn should take a more active | ||
| 262 | role in qmail-remote's activities. It should call separate programs to | ||
| 263 | do (1) MX lookups, (2) SMTP connections, (3) QMTP connections. (But this | ||
| 264 | wouldn't be so important if the DNS library didn't burn so much memory.) | ||
| 265 | |||
| 266 | I bounce ambiguous MXs. (An ``ambiguous MX'' is a best-preference MX | ||
| 267 | record sending me mail for a host that I don't recognize as local.) | ||
| 268 | Automatically treating ambiguous MXs as local is incompatible with my | ||
| 269 | design decision to keep local delivery working when the network goes | ||
| 270 | down. It puts more faith in DNS than DNS deserves. Much better: Have | ||
| 271 | your MX records generated automatically from control/locals. | ||
| 272 | |||
| 273 | If I successfully connect to an MX host but it temporarily refuses to | ||
| 274 | accept the message, I give up and put the message back into the queue. | ||
| 275 | But several documents seem to suggest that I should try further MX | ||
| 276 | records. What are they thinking? My approach deals properly with downed | ||
| 277 | hosts, hosts that are unreachable through a firewall, and load | ||
| 278 | balancing; what else do people use multiple MX records for? | ||
| 279 | |||
| 280 | Currently qmail-remote sends data in 1024-byte buffers. Perhaps it | ||
| 281 | should try to take account of the MTU. | ||
| 282 | |||
| 283 | Perhaps qmail-remote should allocate a fixed amount of DNS/connect() | ||
| 284 | time across any number of MXs; this idea is due to Mark Delany. | ||
| 285 | |||
| 286 | RFC 821 doesn't say what it means by ``text.'' qmail-remote assumes that | ||
| 287 | the server's reply text doesn't contain bare LFs. | ||
| 288 | |||
| 289 | RFC 821 and RFC 1123 prohibit host names in MAIL FROM and RCPT TO from | ||
| 290 | being aliases. qmail-remote, like sendmail, rewrites aliases in RCPT; | ||
| 291 | people who don't list aliases in control/locals or sendmail's Cw are | ||
| 292 | implicitly relying on this conversion. It is course quite silly for an | ||
| 293 | internal DNS detail to have such an effect on mail delivery, but that's | ||
| 294 | how the Internet works. On the other hand, the compatibility arguments | ||
| 295 | do not apply to MAIL FROM. qmail-remote no longer bothers with CNAME | ||
| 296 | lookups for the envelope sender host. | ||
| 297 | |||
| 298 | |||
| 299 | 7. Delivering mail locally (qmail-lspawn, qmail-local) | ||
| 300 | |||
| 301 | qmail-local doesn't support comsat. comsat is a pointless abomination. | ||
| 302 | Use qbiff if you want that kind of notification. | ||
| 303 | |||
| 304 | The getpwnam() interface hides I/O errors. Solution: qmail-pw2u. | ||
| 305 | |||
| 306 | |||
| 307 | 8. sendmail V8's new features | ||
| 308 | |||
| 309 | sendmail-8.8.0/doc/op/op.me includes a list of big improvements of | ||
| 310 | sendmail 8.8.0 over sendmail 5.67. Here's how qmail stacks up against | ||
| 311 | each of those improvements. (Of course, qmail has its own improvements, | ||
| 312 | but that's not the point of this list.) | ||
| 313 | |||
| 314 | Connection caching, MX piggybacking: Nope. (Profile. Don't speculate.) | ||
| 315 | |||
| 316 | Response to RCPT command is fast: Yup. | ||
| 317 | |||
| 318 | IP addresses show up in Received lines: Yup. | ||
| 319 | |||
| 320 | Self domain literal is properly handled: Yup. | ||
| 321 | |||
| 322 | Different timeouts for QUIT, RCPT, etc.: No, just a single timeout. | ||
| 323 | |||
| 324 | Proper <> handling, route-address pruning: Yes, but not configurable. | ||
| 325 | |||
| 326 | ESMTP support: Yup. (Server-side, including PIPELINING.) | ||
| 327 | |||
| 328 | 8-bit clean: Yup. (Including server-side 8BITMIME support; same as | ||
| 329 | sendmail with the 8 option.) | ||
| 330 | |||
| 331 | Configurable user database: Yup. | ||
| 332 | |||
| 333 | BIND support: Yup. | ||
| 334 | |||
| 335 | Keyed files: Yes, in fastforward. | ||
| 336 | |||
| 337 | 931/1413/Ident/TAP: Yup. | ||
| 338 | |||
| 339 | Correct 822 address list parsing: Yup. (Note that sendmail still has | ||
| 340 | some major problems with quoting.) | ||
| 341 | |||
| 342 | List-owner handling: Yup. | ||
| 343 | |||
| 344 | Dynamic header allocation: Yup. | ||
| 345 | |||
| 346 | Minimum number of disk blocks: Yes, via tunefs -m. (Or quotas; the right | ||
| 347 | setup has qmailq with a small quota, qmails with a larger quota, so that | ||
| 348 | qmail-send always has room to work.) | ||
| 349 | |||
| 350 | Checkpointing: Yes, but not configurable---qmail always checkpoints. | ||
| 351 | |||
| 352 | Error message configuration: Nope. | ||
| 353 | |||
| 354 | GECOS matching: Not directly, but easy to hook in. | ||
| 355 | |||
| 356 | Hop limit configuration: No. (qmail's limit is 100 hops. qmail offers | ||
| 357 | automatic loop protection much more advanced than hop counting.) | ||
| 358 | |||
| 359 | MIME error messages: No. (qmail uses QSBMF error messages, which are | ||
| 360 | much easier to parse.) | ||
| 361 | |||
| 362 | Forward file path: Yes, via /etc/passwd. | ||
| 363 | |||
| 364 | Incoming SMTP configuration: Yes, via inetd or tcpserver. | ||
| 365 | |||
| 366 | Privacy options: Yes, but they're not options. | ||
| 367 | |||
| 368 | Best-MX mangling: Nope. See section 6 for further discussion. | ||
| 369 | |||
| 370 | 7-bit mangling: Nope. qmail always uses 8 bits. | ||
| 371 | |||
| 372 | Support for up to 20 MX records: Yes, and more. qmail has no limits | ||
| 373 | other than memory. | ||
| 374 | |||
| 375 | Correct quoting of name-and-address headers: Yup. | ||
| 376 | |||
| 377 | VRFY and EXPN now different: Nope. qmail always hides this information. | ||
| 378 | |||
| 379 | Multi-word classes, deferred macro expansion, separate envelope/header | ||
| 380 | $g processing, separate per-mailer envelope and header processing, new | ||
| 381 | command line flags, new configuration lines, new mailer flags, new | ||
| 382 | macros: These are sendmail-specific; they wouldn't even make sense for | ||
| 383 | qmail. For example, _of course_ qmail handles envelopes and headers | ||
| 384 | separately; they're almost entirely different objects! | ||
| 385 | |||
| 386 | |||
| 387 | 9. Miscellany | ||
| 388 | |||
| 389 | sendmail-clone and qsmhook are too bletcherous to be documented. (The | ||
| 390 | official replacement for qsmhook is preline, together with the | ||
| 391 | qmail-command environment variables.) | ||
| 392 | |||
| 393 | I've considered making install atomic, but this is very difficult to do | ||
| 394 | right, and pointless if it isn't done right. | ||
| 395 | |||
| 396 | RN suggests automatically putting together a reasonable set of lines for | ||
| 397 | /etc/passwd. I perceive this as getting into the adduser business, which | ||
| 398 | is worrisome: I'll be lynched the first time I screw up somebody's | ||
| 399 | passwd file. This should be left to OS-specific installation scripts. | ||
| 400 | |||
| 401 | The BSD 4.2 inetd didn't allow a username. I think I can safely forget | ||
| 402 | about this. (DS notes that the username works under Ultrix even though | ||
| 403 | it's undocumented.) | ||
| 404 | |||
| 405 | I should clean up the bput/put choices. | ||
| 406 | |||
| 407 | Some of the stralloc_0()s indicate that certain lower-level routines | ||
| 408 | should grok stralloc. | ||
| 409 | |||
| 410 | qmail assumes that all times are positive; that pid_t, time_t and ino_t | ||
| 411 | fit into unsigned long; that gid_t fits into int; that the character set | ||
| 412 | is ASCII; and that all pointers are interchangeable. Do I care? | ||
| 413 | |||
| 414 | The bat book justifies sendmail's insane line-splitting mechanism by | ||
| 415 | pointing out that it might be useful for ``a 40-character braille | ||
| 416 | print-driving program.'' C'mon, guys, is that your best excuse? | ||
| 417 | |||
| 418 | qmail's mascot is a dolphin. | ||
| @@ -0,0 +1,23 @@ | |||
| 1 | consider stripping vdoms for VERPs; tnx PJH | ||
| 2 | consider ~ in qmail-local for doing defaultdelivery (not recursively) | ||
| 3 | consider POP bulletins | ||
| 4 | turn qmail-upq into a more serious queue-moving utility | ||
| 5 | consider fast-greeting option in qmail-smtpd | ||
| 6 | build a returnmail package | ||
| 7 | |||
| 8 | expand strerr coverage | ||
| 9 | redo control interface | ||
| 10 | allow concurrency over 255 | ||
| 11 | allow more channels at compile time | ||
| 12 | test for linux fifo close bug at compile time | ||
| 13 | |||
| 14 | eliminate qsmhook | ||
| 15 | finish OTBS conversion | ||
| 16 | use mess822 in qmail-inject | ||
| 17 | use mess822 in qreceipt | ||
| 18 | use mess822 in qbiff | ||
| 19 | use mess822 in maildirwatch | ||
| 20 | eliminate token822, headerbody, hfield | ||
| 21 | replace INTERNALS and THOUGHTS with a real paper describing qmail | ||
| 22 | handle IPv6 | ||
| 23 | rewrite everything from scratch | ||
| @@ -0,0 +1,66 @@ | |||
| 1 | SAVE COPIES OF YOUR OUTGOING MAIL! Like any other piece of software (and | ||
| 2 | information generally), the qmail system comes with NO WARRANTY. It's | ||
| 3 | much more secure and reliable than sendmail, but that's not saying much. | ||
| 4 | |||
| 5 | |||
| 6 | Here's how to upgrade to qmail 1.03. This procedure will overwrite the | ||
| 7 | old qmail binaries. Furthermore, it may begin delivering messages from | ||
| 8 | the queue before you have had a chance to test it. | ||
| 9 | |||
| 10 | |||
| 11 | WARNING for upgrades from 1.00 or 1.01: qlist has been split into a | ||
| 12 | separate package. You can obtain it from http://pobox.com/~djb/qlist.html | ||
| 13 | if you have any users who need it. | ||
| 14 | |||
| 15 | WARNING for upgrades from 1.01: recipientmap is gone. The virtualdomains | ||
| 16 | mechanism has been expanded to support virtual users. | ||
| 17 | |||
| 18 | |||
| 19 | Before starting, compare conf* to your old conf*, and make any necessary | ||
| 20 | changes. You can copy conf* from 1.02. | ||
| 21 | |||
| 22 | |||
| 23 | How to install: | ||
| 24 | |||
| 25 | 1. Compile the programs and create the formatted man pages: | ||
| 26 | # make it man | ||
| 27 | |||
| 28 | 2. Inform your users that mail will not be accepted for a few minutes. | ||
| 29 | |||
| 30 | 3. Disable deliveries by killing your old qmail-send. Wait for it to | ||
| 31 | print ``exiting'' in the log. | ||
| 32 | |||
| 33 | 4. Disable SMTP service by commenting out the smtp line in inetd.conf; | ||
| 34 | kill -HUP your inetd. (If you are using tcpserver, simply kill -STOP | ||
| 35 | your tcpserver. If you are running a QMTP server, disable that too.) | ||
| 36 | Wait for current qmail-smtpd processes to die. | ||
| 37 | |||
| 38 | 5. Install the new binaries and man pages: | ||
| 39 | # make setup check | ||
| 40 | |||
| 41 | 6. If your boot scripts are using qmail-start instead of /var/qmail/rc: | ||
| 42 | Copy /var/qmail/boot/home to /var/qmail/rc. (Use home+df instead if | ||
| 43 | you have installed dot-forward; use proc or proc+df if you are using | ||
| 44 | procmail by default for local deliveries.) Compare /var/qmail/rc to | ||
| 45 | your qmail-start boot line, and edit /var/qmail/rc if necessary. | ||
| 46 | Replace your qmail-start boot line with | ||
| 47 | csh -cf '/var/qmail/rc &' | ||
| 48 | |||
| 49 | 7. Reenable deliveries: | ||
| 50 | # csh -cf '/var/qmail/rc &' | ||
| 51 | |||
| 52 | 8. Read TEST.deliver. | ||
| 53 | |||
| 54 | 9. Reenable SMTP service by restoring the smtp line in inetd.conf; kill | ||
| 55 | -HUP your inetd. (If you are using tcpserver, simply kill -CONT your | ||
| 56 | tcpserver. If you are running a QMTP server, reenable that too.) | ||
| 57 | |||
| 58 | 10. Read TEST.receive. | ||
| 59 | |||
| 60 | |||
| 61 | That's it! To report success: | ||
| 62 | % ( echo 'First M. Last'; cat `cat SYSDEPS` ) | mail djb-qst@cr.yp.to | ||
| 63 | Replace First M. Last with your name. | ||
| 64 | |||
| 65 | If you have questions about qmail, join the qmail mailing list; see | ||
| 66 | http://pobox.com/~djb/qmail.html. | ||
| @@ -0,0 +1 @@ | |||
| qmail 1.03 | |||
diff --git a/addresses.5 b/addresses.5 new file mode 100644 index 0000000..1fd4c5b --- /dev/null +++ b/addresses.5 | |||
| @@ -0,0 +1,260 @@ | |||
| 1 | .TH addresses 5 | ||
| 2 | .SH "NAME" | ||
| 3 | addresses \- formats for Internet mail addresses | ||
| 4 | .SH "INTRODUCTION" | ||
| 5 | A | ||
| 6 | .B mail address | ||
| 7 | is a string of characters containing @. | ||
| 8 | |||
| 9 | Every mail address has a | ||
| 10 | .B local part | ||
| 11 | and a | ||
| 12 | .B domain part\fR. | ||
| 13 | The domain part is everything after the final @. | ||
| 14 | The local part is everything before. | ||
| 15 | |||
| 16 | For example, the mail addresses | ||
| 17 | |||
| 18 | .EX | ||
| 19 | God@heaven.af.mil | ||
| 20 | @heaven.af.mil | ||
| 21 | @at@@heaven.af.mil | ||
| 22 | .EE | ||
| 23 | |||
| 24 | all have domain part | ||
| 25 | .BR heaven.af.mil . | ||
| 26 | The local parts are | ||
| 27 | .BR God , | ||
| 28 | empty, | ||
| 29 | and | ||
| 30 | .BR @at@ . | ||
| 31 | |||
| 32 | Some domains have owners. | ||
| 33 | It is up to the owner of | ||
| 34 | .B heaven.af.mil | ||
| 35 | to say how mail messages will be delivered to addresses with domain part | ||
| 36 | .BR heaven.af.mil . | ||
| 37 | |||
| 38 | The domain part of an address is interpreted without regard to case, so | ||
| 39 | |||
| 40 | .EX | ||
| 41 | God@heaven.af.mil | ||
| 42 | .br | ||
| 43 | God@HEAVEN.AF.MIL | ||
| 44 | .br | ||
| 45 | God@Heaven.AF.Mil | ||
| 46 | .EE | ||
| 47 | |||
| 48 | all refer to the same domain. | ||
| 49 | |||
| 50 | There is one exceptional address that does not contain an @: | ||
| 51 | namely, the empty string. | ||
| 52 | The empty string cannot be used as a recipient address. | ||
| 53 | It can be used as a sender address so that | ||
| 54 | the real sender doesn't receive bounces. | ||
| 55 | .SH "QMAIL EXTENSIONS" | ||
| 56 | The | ||
| 57 | .B qmail | ||
| 58 | system allows several further types of addresses in mail envelopes. | ||
| 59 | |||
| 60 | First, an envelope recipient address without an @ is interpreted as being at | ||
| 61 | .IR envnoathost . | ||
| 62 | For example, if | ||
| 63 | .I envnoathost | ||
| 64 | is | ||
| 65 | .BR heaven.af.mil , | ||
| 66 | the address | ||
| 67 | .B God | ||
| 68 | will be rewritten as | ||
| 69 | .BR God@heaven.af.mil . | ||
| 70 | |||
| 71 | Second, the address | ||
| 72 | .B #@[] | ||
| 73 | is used as an envelope sender address for double bounces. | ||
| 74 | |||
| 75 | Third, envelope sender addresses of the form | ||
| 76 | .I pre\fB@\fIhost\fB-@[] | ||
| 77 | are used to support variable envelope return paths (VERPs). | ||
| 78 | .B qmail-send | ||
| 79 | will rewrite | ||
| 80 | .I pre\fB@\fIhost\fB-@[] | ||
| 81 | as | ||
| 82 | .I prerecip\fB=\fIdomain\fB@\fIhost | ||
| 83 | for deliveries to | ||
| 84 | .IR recip\fB@\fIdomain . | ||
| 85 | Bounces directly from | ||
| 86 | .B qmail-send | ||
| 87 | will come back to | ||
| 88 | .IR pre\fB@\fIhost . | ||
| 89 | .SH "CHOOSING MAIL ADDRESSES" | ||
| 90 | Here are some suggestions on choosing mail addresses for the Internet. | ||
| 91 | |||
| 92 | Do not use non-ASCII characters. | ||
| 93 | Under RFC 822 and RFC 821, | ||
| 94 | these characters cannot be used in mail headers or in SMTP commands. | ||
| 95 | In practice, they are regularly corrupted. | ||
| 96 | |||
| 97 | Do not use ASCII control characters. | ||
| 98 | NUL is regularly corrupted. | ||
| 99 | CR and LF cannot be used in some combinations | ||
| 100 | and are corrupted in all. | ||
| 101 | None of these characters are usable on business cards. | ||
| 102 | |||
| 103 | Avoid spaces and the characters | ||
| 104 | |||
| 105 | .EX | ||
| 106 | \\"<>()[],;: | ||
| 107 | .EE | ||
| 108 | |||
| 109 | These all require quoting in mail headers and in SMTP. | ||
| 110 | Many existing mail programs do not handle quoting properly. | ||
| 111 | |||
| 112 | Do not use @ in a local part. | ||
| 113 | @ requires quoting in mail headers and in SMTP. | ||
| 114 | Many programs incorrectly look for the first @, | ||
| 115 | rather than the last @, | ||
| 116 | to find the domain part of an address. | ||
| 117 | |||
| 118 | In a local part, | ||
| 119 | do not use two consecutive dots, a dot at the beginning, or a dot at the end. | ||
| 120 | Any of these would require quoting in mail headers. | ||
| 121 | |||
| 122 | Do not use an empty local part; it cannot appear in SMTP commands. | ||
| 123 | |||
| 124 | Avoid local parts longer than 64 characters. | ||
| 125 | |||
| 126 | Be wary of uppercase letters in local parts. | ||
| 127 | Some mail programs (and users!) will incorrectly convert | ||
| 128 | .B God@heaven.af.mil | ||
| 129 | to | ||
| 130 | .BR god@heaven.af.mil . | ||
| 131 | |||
| 132 | Be wary of the following characters: | ||
| 133 | |||
| 134 | .EX | ||
| 135 | $&!#~`'^*|{} | ||
| 136 | .EE | ||
| 137 | |||
| 138 | Some users will not know | ||
| 139 | how to feed these characters safely to their mail programs. | ||
| 140 | |||
| 141 | In domain names, stick to letters, digits, dash, and dot. | ||
| 142 | One popular DNS resolver has, | ||
| 143 | under the banner of security, | ||
| 144 | recently begun destroying domain names | ||
| 145 | that contain certain other characters, | ||
| 146 | including underscore. | ||
| 147 | Exception: A dotted-decimal IP address in brackets, | ||
| 148 | such as | ||
| 149 | .BR [127.0.0.1] , | ||
| 150 | identifies a domain owned by whoever owns the host at that IP address, | ||
| 151 | and can be used safely. | ||
| 152 | |||
| 153 | In a domain name, | ||
| 154 | do not use two consecutive dots, | ||
| 155 | a dot at the beginning, | ||
| 156 | or a dot at the end. | ||
| 157 | This means that, | ||
| 158 | when a domain name is broken down into components separated by dots, | ||
| 159 | there are no empty components. | ||
| 160 | |||
| 161 | Always use at least one dot in a domain name. | ||
| 162 | If you own the | ||
| 163 | .B mil | ||
| 164 | domain, | ||
| 165 | don't bother using the address | ||
| 166 | .BR root@mil ; | ||
| 167 | most users will be unable to send messages to that address. | ||
| 168 | Same for the root domain. | ||
| 169 | |||
| 170 | Avoid domain names longer than 64 characters. | ||
| 171 | .SH "ENCODED ADDRESSES IN SMTP COMMANDS" | ||
| 172 | RFC 821 defines an encoding of mail addresses in SMTP. | ||
| 173 | For example, the addresses | ||
| 174 | |||
| 175 | .EX | ||
| 176 | God@heaven.af.mil | ||
| 177 | .br | ||
| 178 | a"quote@heaven.af.mil | ||
| 179 | .br | ||
| 180 | The Almighty.One@heaven.af.mil | ||
| 181 | .EE | ||
| 182 | |||
| 183 | could be encoded in RCPT commands as | ||
| 184 | |||
| 185 | .EX | ||
| 186 | RCPT TO:<God@heaven.af.mil> | ||
| 187 | .br | ||
| 188 | RCPT TO:<a\\"quote@heaven.af.mil> | ||
| 189 | .br | ||
| 190 | RCPT TO:<The\\ Almighty.One@heaven.af.mil> | ||
| 191 | .EE | ||
| 192 | |||
| 193 | There are several restrictions in RFC 821 | ||
| 194 | on the mail addresses that can be used over SMTP. | ||
| 195 | Non-ASCII characters are prohibited. | ||
| 196 | The local part must not be empty. | ||
| 197 | The domain part must be a sequence of elements separated by dots, | ||
| 198 | where each element is either a component, | ||
| 199 | a sequence of digits preceded by #, | ||
| 200 | or a dotted-decimal IP address surrounded by brackets. | ||
| 201 | The only allowable characters in components are | ||
| 202 | letters, digits, and dashes. | ||
| 203 | Every component must (believe it or not) | ||
| 204 | have at least three characters; | ||
| 205 | the first character must be a letter; | ||
| 206 | the last character must not be a hyphen. | ||
| 207 | .SH "ENCODED ADDRESSES IN MAIL HEADERS" | ||
| 208 | RFC 822 defines an encoding of mail addresses | ||
| 209 | in certain header fields in a mail message. | ||
| 210 | For example, the addresses | ||
| 211 | |||
| 212 | .EX | ||
| 213 | God@heaven.af.mil | ||
| 214 | .br | ||
| 215 | a"quote@heaven.af.mil | ||
| 216 | .br | ||
| 217 | The Almighty.One@heaven.af.mil | ||
| 218 | .EE | ||
| 219 | |||
| 220 | could be encoded in a | ||
| 221 | .B To | ||
| 222 | field as | ||
| 223 | |||
| 224 | .EX | ||
| 225 | To: God@heaven.af.mil, | ||
| 226 | .br | ||
| 227 | <@brl.mil:"a\\"quote"@heaven.af.mil>, | ||
| 228 | .br | ||
| 229 | "The Almighty".One@heaven.af.mil | ||
| 230 | .EE | ||
| 231 | |||
| 232 | or perhaps | ||
| 233 | |||
| 234 | .EX | ||
| 235 | To: < "God"@heaven .af.mil>, | ||
| 236 | .br | ||
| 237 | "a\\"quote" (Who?) @ heaven . af. mil | ||
| 238 | .br | ||
| 239 | , God<"The Almighty.One"@heaven.af.mil> | ||
| 240 | .EE | ||
| 241 | |||
| 242 | There are several restrictions on the mail addresses that can | ||
| 243 | be used in these header fields. | ||
| 244 | Non-ASCII characters are prohibited. | ||
| 245 | The domain part must be a sequence of elements separated by dots, | ||
| 246 | where each element either (1) begins with [ and ends with ] | ||
| 247 | or (2) is a nonempty string of printable ASCII characters | ||
| 248 | not including any of | ||
| 249 | |||
| 250 | .EX | ||
| 251 | \\".<>()[],;: | ||
| 252 | .EE | ||
| 253 | |||
| 254 | and not including space. | ||
| 255 | .SH "SEE ALSO" | ||
| 256 | envelopes(5), | ||
| 257 | qmail-header(5), | ||
| 258 | qmail-inject(8), | ||
| 259 | qmail-remote(8), | ||
| 260 | qmail-smtpd(8) | ||
| @@ -0,0 +1,62 @@ | |||
| 1 | .TH alloc 3 | ||
| 2 | .SH NAME | ||
| 3 | alloc \- allocate memory | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <alloc.h> | ||
| 6 | |||
| 7 | char *\fBalloc\fP(\fInew\fR); | ||
| 8 | |||
| 9 | void \fBalloc_free\fP(\fIx\fR); | ||
| 10 | |||
| 11 | void \fBalloc_re\fP(&\fIx\fR,\fIold\fR,\fInew\fR); | ||
| 12 | |||
| 13 | char *\fIx\fR; | ||
| 14 | .br | ||
| 15 | unsigned int \fIold\fR; | ||
| 16 | .br | ||
| 17 | unsigned int \fInew\fR; | ||
| 18 | .SH DESCRIPTION | ||
| 19 | .B alloc | ||
| 20 | allocates enough space from the heap for | ||
| 21 | .I new | ||
| 22 | bytes of data, | ||
| 23 | adequately aligned for any data type. | ||
| 24 | .I new | ||
| 25 | may be 0. | ||
| 26 | .B alloc | ||
| 27 | returns a pointer to the space. | ||
| 28 | If space is not available, | ||
| 29 | .B alloc | ||
| 30 | returns 0, | ||
| 31 | setting | ||
| 32 | .B errno | ||
| 33 | appropriately. | ||
| 34 | |||
| 35 | .B alloc_free | ||
| 36 | returns space to the heap. | ||
| 37 | |||
| 38 | .B alloc_re | ||
| 39 | expands the space allocated to | ||
| 40 | .I x | ||
| 41 | from | ||
| 42 | .I old | ||
| 43 | bytes to | ||
| 44 | .I new | ||
| 45 | bytes. | ||
| 46 | It allocates new space, | ||
| 47 | copies | ||
| 48 | .I old | ||
| 49 | bytes from the old space to the new space, | ||
| 50 | returns the old space to the heap, | ||
| 51 | and changes | ||
| 52 | .I x | ||
| 53 | to point to the new space. | ||
| 54 | It then returns 1. | ||
| 55 | If space is not available, | ||
| 56 | .B alloc_re | ||
| 57 | returns 0, | ||
| 58 | leaving the old space alone. | ||
| 59 | .SH "SEE ALSO" | ||
| 60 | sbrk(2), | ||
| 61 | malloc(3), | ||
| 62 | error(3) | ||
| @@ -0,0 +1,32 @@ | |||
| 1 | #include "alloc.h" | ||
| 2 | #include "error.h" | ||
| 3 | extern char *malloc(); | ||
| 4 | extern void free(); | ||
| 5 | |||
| 6 | #define ALIGNMENT 16 /* XXX: assuming that this alignment is enough */ | ||
| 7 | #define SPACE 4096 /* must be multiple of ALIGNMENT */ | ||
| 8 | |||
| 9 | typedef union { char irrelevant[ALIGNMENT]; double d; } aligned; | ||
| 10 | static aligned realspace[SPACE / ALIGNMENT]; | ||
| 11 | #define space ((char *) realspace) | ||
| 12 | static unsigned int avail = SPACE; /* multiple of ALIGNMENT; 0<=avail<=SPACE */ | ||
| 13 | |||
| 14 | /*@null@*//*@out@*/char *alloc(n) | ||
| 15 | unsigned int n; | ||
| 16 | { | ||
| 17 | char *x; | ||
| 18 | n = ALIGNMENT + n - (n & (ALIGNMENT - 1)); /* XXX: could overflow */ | ||
| 19 | if (n <= avail) { avail -= n; return space + avail; } | ||
| 20 | x = malloc(n); | ||
| 21 | if (!x) errno = error_nomem; | ||
| 22 | return x; | ||
| 23 | } | ||
| 24 | |||
| 25 | void alloc_free(x) | ||
| 26 | char *x; | ||
| 27 | { | ||
| 28 | if (x >= space) | ||
| 29 | if (x < space + SPACE) | ||
| 30 | return; /* XXX: assuming that pointers are flat */ | ||
| 31 | free(x); | ||
| 32 | } | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef ALLOC_H | ||
| 2 | #define ALLOC_H | ||
| 3 | |||
| 4 | extern /*@null@*//*@out@*/char *alloc(); | ||
| 5 | extern void alloc_free(); | ||
| 6 | extern int alloc_re(); | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/alloc_re.c b/alloc_re.c new file mode 100644 index 0000000..feb8b49 --- /dev/null +++ b/alloc_re.c | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #include "alloc.h" | ||
| 2 | #include "byte.h" | ||
| 3 | |||
| 4 | int alloc_re(x,m,n) | ||
| 5 | char **x; | ||
| 6 | unsigned int m; | ||
| 7 | unsigned int n; | ||
| 8 | { | ||
| 9 | char *y; | ||
| 10 | |||
| 11 | y = alloc(n); | ||
| 12 | if (!y) return 0; | ||
| 13 | byte_copy(y,m,*x); | ||
| 14 | alloc_free(*x); | ||
| 15 | *x = y; | ||
| 16 | return 1; | ||
| 17 | } | ||
diff --git a/auto-gid.c b/auto-gid.c new file mode 100644 index 0000000..774a8c1 --- /dev/null +++ b/auto-gid.c | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <grp.h> | ||
| 3 | #include "subfd.h" | ||
| 4 | #include "substdio.h" | ||
| 5 | #include "readwrite.h" | ||
| 6 | #include "exit.h" | ||
| 7 | #include "scan.h" | ||
| 8 | #include "fmt.h" | ||
| 9 | |||
| 10 | char buf1[256]; | ||
| 11 | substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1)); | ||
| 12 | |||
| 13 | void outs(s) | ||
| 14 | char *s; | ||
| 15 | { | ||
| 16 | if (substdio_puts(&ss1,s) == -1) _exit(111); | ||
| 17 | } | ||
| 18 | |||
| 19 | void main(argc,argv) | ||
| 20 | int argc; | ||
| 21 | char **argv; | ||
| 22 | { | ||
| 23 | char *name; | ||
| 24 | char *value; | ||
| 25 | struct group *gr; | ||
| 26 | char strnum[FMT_ULONG]; | ||
| 27 | |||
| 28 | name = argv[1]; | ||
| 29 | if (!name) _exit(100); | ||
| 30 | value = argv[2]; | ||
| 31 | if (!value) _exit(100); | ||
| 32 | |||
| 33 | gr = getgrnam(value); | ||
| 34 | if (!gr) { | ||
| 35 | substdio_puts(subfderr,"fatal: unable to find group "); | ||
| 36 | substdio_puts(subfderr,value); | ||
| 37 | substdio_puts(subfderr,"\n"); | ||
| 38 | substdio_flush(subfderr); | ||
| 39 | _exit(111); | ||
| 40 | } | ||
| 41 | |||
| 42 | strnum[fmt_ulong(strnum,(unsigned long) gr->gr_gid)] = 0; | ||
| 43 | |||
| 44 | outs("int "); | ||
| 45 | outs(name); | ||
| 46 | outs(" = "); | ||
| 47 | outs(strnum); | ||
| 48 | outs(";\n"); | ||
| 49 | if (substdio_flush(&ss1) == -1) _exit(111); | ||
| 50 | _exit(0); | ||
| 51 | } | ||
diff --git a/auto-int.c b/auto-int.c new file mode 100644 index 0000000..c138869 --- /dev/null +++ b/auto-int.c | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "readwrite.h" | ||
| 3 | #include "exit.h" | ||
| 4 | #include "scan.h" | ||
| 5 | #include "fmt.h" | ||
| 6 | |||
| 7 | char buf1[256]; | ||
| 8 | substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1)); | ||
| 9 | |||
| 10 | void puts(s) | ||
| 11 | char *s; | ||
| 12 | { | ||
| 13 | if (substdio_puts(&ss1,s) == -1) _exit(111); | ||
| 14 | } | ||
| 15 | |||
| 16 | void main(argc,argv) | ||
| 17 | int argc; | ||
| 18 | char **argv; | ||
| 19 | { | ||
| 20 | char *name; | ||
| 21 | char *value; | ||
| 22 | unsigned long num; | ||
| 23 | char strnum[FMT_ULONG]; | ||
| 24 | |||
| 25 | name = argv[1]; | ||
| 26 | if (!name) _exit(100); | ||
| 27 | value = argv[2]; | ||
| 28 | if (!value) _exit(100); | ||
| 29 | |||
| 30 | scan_ulong(value,&num); | ||
| 31 | strnum[fmt_ulong(strnum,num)] = 0; | ||
| 32 | |||
| 33 | puts("int "); | ||
| 34 | puts(name); | ||
| 35 | puts(" = "); | ||
| 36 | puts(strnum); | ||
| 37 | puts(";\n"); | ||
| 38 | if (substdio_flush(&ss1) == -1) _exit(111); | ||
| 39 | _exit(0); | ||
| 40 | } | ||
diff --git a/auto-int8.c b/auto-int8.c new file mode 100644 index 0000000..091978f --- /dev/null +++ b/auto-int8.c | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "readwrite.h" | ||
| 3 | #include "exit.h" | ||
| 4 | #include "scan.h" | ||
| 5 | #include "fmt.h" | ||
| 6 | |||
| 7 | char buf1[256]; | ||
| 8 | substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1)); | ||
| 9 | |||
| 10 | void puts(s) | ||
| 11 | char *s; | ||
| 12 | { | ||
| 13 | if (substdio_puts(&ss1,s) == -1) _exit(111); | ||
| 14 | } | ||
| 15 | |||
| 16 | void main(argc,argv) | ||
| 17 | int argc; | ||
| 18 | char **argv; | ||
| 19 | { | ||
| 20 | char *name; | ||
| 21 | char *value; | ||
| 22 | unsigned long num; | ||
| 23 | char strnum[FMT_ULONG]; | ||
| 24 | |||
| 25 | name = argv[1]; | ||
| 26 | if (!name) _exit(100); | ||
| 27 | value = argv[2]; | ||
| 28 | if (!value) _exit(100); | ||
| 29 | |||
| 30 | scan_8long(value,&num); | ||
| 31 | strnum[fmt_ulong(strnum,num)] = 0; | ||
| 32 | |||
| 33 | puts("int "); | ||
| 34 | puts(name); | ||
| 35 | puts(" = "); | ||
| 36 | puts(strnum); | ||
| 37 | puts(";\n"); | ||
| 38 | if (substdio_flush(&ss1) == -1) _exit(111); | ||
| 39 | _exit(0); | ||
| 40 | } | ||
diff --git a/auto-str.c b/auto-str.c new file mode 100644 index 0000000..acc3d60 --- /dev/null +++ b/auto-str.c | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "readwrite.h" | ||
| 3 | #include "exit.h" | ||
| 4 | |||
| 5 | char buf1[256]; | ||
| 6 | substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1)); | ||
| 7 | |||
| 8 | void puts(s) | ||
| 9 | char *s; | ||
| 10 | { | ||
| 11 | if (substdio_puts(&ss1,s) == -1) _exit(111); | ||
| 12 | } | ||
| 13 | |||
| 14 | void main(argc,argv) | ||
| 15 | int argc; | ||
| 16 | char **argv; | ||
| 17 | { | ||
| 18 | char *name; | ||
| 19 | char *value; | ||
| 20 | unsigned char ch; | ||
| 21 | char octal[4]; | ||
| 22 | |||
| 23 | name = argv[1]; | ||
| 24 | if (!name) _exit(100); | ||
| 25 | value = argv[2]; | ||
| 26 | if (!value) _exit(100); | ||
| 27 | |||
| 28 | puts("char "); | ||
| 29 | puts(name); | ||
| 30 | puts("[] = \"\\\n"); | ||
| 31 | |||
| 32 | while (ch = *value++) { | ||
| 33 | puts("\\"); | ||
| 34 | octal[3] = 0; | ||
| 35 | octal[2] = '0' + (ch & 7); ch >>= 3; | ||
| 36 | octal[1] = '0' + (ch & 7); ch >>= 3; | ||
| 37 | octal[0] = '0' + (ch & 7); | ||
| 38 | puts(octal); | ||
| 39 | } | ||
| 40 | |||
| 41 | puts("\\\n\";\n"); | ||
| 42 | if (substdio_flush(&ss1) == -1) _exit(111); | ||
| 43 | _exit(0); | ||
| 44 | } | ||
diff --git a/auto-uid.c b/auto-uid.c new file mode 100644 index 0000000..326051c --- /dev/null +++ b/auto-uid.c | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <pwd.h> | ||
| 3 | #include "subfd.h" | ||
| 4 | #include "substdio.h" | ||
| 5 | #include "readwrite.h" | ||
| 6 | #include "exit.h" | ||
| 7 | #include "scan.h" | ||
| 8 | #include "fmt.h" | ||
| 9 | |||
| 10 | char buf1[256]; | ||
| 11 | substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1)); | ||
| 12 | |||
| 13 | void outs(s) /* was named puts, but Solaris pwd.h includes stdio.h. dorks. */ | ||
| 14 | char *s; | ||
| 15 | { | ||
| 16 | if (substdio_puts(&ss1,s) == -1) _exit(111); | ||
| 17 | } | ||
| 18 | |||
| 19 | void main(argc,argv) | ||
| 20 | int argc; | ||
| 21 | char **argv; | ||
| 22 | { | ||
| 23 | char *name; | ||
| 24 | char *value; | ||
| 25 | struct passwd *pw; | ||
| 26 | char strnum[FMT_ULONG]; | ||
| 27 | |||
| 28 | name = argv[1]; | ||
| 29 | if (!name) _exit(100); | ||
| 30 | value = argv[2]; | ||
| 31 | if (!value) _exit(100); | ||
| 32 | |||
| 33 | pw = getpwnam(value); | ||
| 34 | if (!pw) { | ||
| 35 | substdio_puts(subfderr,"fatal: unable to find user "); | ||
| 36 | substdio_puts(subfderr,value); | ||
| 37 | substdio_puts(subfderr,"\n"); | ||
| 38 | substdio_flush(subfderr); | ||
| 39 | _exit(111); | ||
| 40 | } | ||
| 41 | |||
| 42 | strnum[fmt_ulong(strnum,(unsigned long) pw->pw_uid)] = 0; | ||
| 43 | |||
| 44 | outs("int "); | ||
| 45 | outs(name); | ||
| 46 | outs(" = "); | ||
| 47 | outs(strnum); | ||
| 48 | outs(";\n"); | ||
| 49 | if (substdio_flush(&ss1) == -1) _exit(111); | ||
| 50 | _exit(0); | ||
| 51 | } | ||
diff --git a/auto_break.h b/auto_break.h new file mode 100644 index 0000000..b7f3a63 --- /dev/null +++ b/auto_break.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef AUTO_BREAK_H | ||
| 2 | #define AUTO_BREAK_H | ||
| 3 | |||
| 4 | extern char auto_break[]; | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/auto_patrn.h b/auto_patrn.h new file mode 100644 index 0000000..77cdf1f --- /dev/null +++ b/auto_patrn.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef AUTO_PATRN_H | ||
| 2 | #define AUTO_PATRN_H | ||
| 3 | |||
| 4 | extern int auto_patrn; | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/auto_qmail.h b/auto_qmail.h new file mode 100644 index 0000000..0c56001 --- /dev/null +++ b/auto_qmail.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef AUTO_QMAIL_H | ||
| 2 | #define AUTO_QMAIL_H | ||
| 3 | |||
| 4 | extern char auto_qmail[]; | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/auto_spawn.h b/auto_spawn.h new file mode 100644 index 0000000..165d988 --- /dev/null +++ b/auto_spawn.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef AUTO_SPAWN_H | ||
| 2 | #define AUTO_SPAWN_H | ||
| 3 | |||
| 4 | extern int auto_spawn; | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/auto_split.h b/auto_split.h new file mode 100644 index 0000000..3754129 --- /dev/null +++ b/auto_split.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef AUTO_SPLIT_H | ||
| 2 | #define AUTO_SPLIT_H | ||
| 3 | |||
| 4 | extern int auto_split; | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/auto_uids.h b/auto_uids.h new file mode 100644 index 0000000..1252ecb --- /dev/null +++ b/auto_uids.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #ifndef AUTO_UIDS_H | ||
| 2 | #define AUTO_UIDS_H | ||
| 3 | |||
| 4 | extern int auto_uida; | ||
| 5 | extern int auto_uidd; | ||
| 6 | extern int auto_uidl; | ||
| 7 | extern int auto_uido; | ||
| 8 | extern int auto_uidp; | ||
| 9 | extern int auto_uidq; | ||
| 10 | extern int auto_uidr; | ||
| 11 | extern int auto_uids; | ||
| 12 | |||
| 13 | extern int auto_gidn; | ||
| 14 | extern int auto_gidq; | ||
| 15 | |||
| 16 | #endif | ||
diff --git a/auto_usera.h b/auto_usera.h new file mode 100644 index 0000000..49d7755 --- /dev/null +++ b/auto_usera.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef AUTO_USERA_H | ||
| 2 | #define AUTO_USERA_H | ||
| 3 | |||
| 4 | extern char auto_usera[]; | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/binm1+df.sh b/binm1+df.sh new file mode 100644 index 0000000..0ff1a68 --- /dev/null +++ b/binm1+df.sh | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | # Using splogger to send the log through syslog. | ||
| 4 | # Using dot-forward to support sendmail-style ~/.forward files. | ||
| 5 | # Using binmail to deliver messages to /var/spool/mail/$USER by default. | ||
| 6 | # Using BSD 4.4 binmail interface: /usr/libexec/mail.local -r | ||
| 7 | |||
| 8 | exec env - PATH="QMAIL/bin:$PATH" \ | ||
| 9 | qmail-start '|dot-forward .forward | ||
| 10 | |preline -f /usr/libexec/mail.local -r "${SENDER:-MAILER-DAEMON}" -d "$USER"' \ | ||
| 11 | splogger qmail | ||
diff --git a/binm1.sh b/binm1.sh new file mode 100644 index 0000000..db79cbd --- /dev/null +++ b/binm1.sh | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | # Using splogger to send the log through syslog. | ||
| 4 | # Using binmail to deliver messages to /var/spool/mail/$USER by default. | ||
| 5 | # Using BSD 4.4 binmail interface: /usr/libexec/mail.local -r | ||
| 6 | |||
| 7 | exec env - PATH="QMAIL/bin:$PATH" \ | ||
| 8 | qmail-start \ | ||
| 9 | '|preline -f /usr/libexec/mail.local -r "${SENDER:-MAILER-DAEMON}" -d "$USER"' \ | ||
| 10 | splogger qmail | ||
diff --git a/binm2+df.sh b/binm2+df.sh new file mode 100644 index 0000000..4f78101 --- /dev/null +++ b/binm2+df.sh | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | # Using splogger to send the log through syslog. | ||
| 4 | # Using dot-forward to support sendmail-style ~/.forward files. | ||
| 5 | # Using binmail to deliver messages to /var/spool/mail/$USER by default. | ||
| 6 | # Using SVR4 binmail interface: /bin/mail -r | ||
| 7 | |||
| 8 | exec env - PATH="QMAIL/bin:$PATH" \ | ||
| 9 | qmail-start '|dot-forward .forward | ||
| 10 | |preline -f /bin/mail -r "${SENDER:-MAILER-DAEMON}" -d "$USER"' \ | ||
| 11 | splogger qmail | ||
diff --git a/binm2.sh b/binm2.sh new file mode 100644 index 0000000..7905308 --- /dev/null +++ b/binm2.sh | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | # Using splogger to send the log through syslog. | ||
| 4 | # Using binmail to deliver messages to /var/spool/mail/$USER by default. | ||
| 5 | # Using SVR4 binmail interface: /bin/mail -r | ||
| 6 | |||
| 7 | exec env - PATH="QMAIL/bin:$PATH" \ | ||
| 8 | qmail-start \ | ||
| 9 | '|preline -f /bin/mail -r "${SENDER:-MAILER-DAEMON}" -d "$USER"' \ | ||
| 10 | splogger qmail | ||
diff --git a/binm3+df.sh b/binm3+df.sh new file mode 100644 index 0000000..3d69401 --- /dev/null +++ b/binm3+df.sh | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | # Using splogger to send the log through syslog. | ||
| 4 | # Using dot-forward to support sendmail-style ~/.forward files. | ||
| 5 | # Using binmail to deliver messages to /var/spool/mail/$USER by default. | ||
| 6 | # Using V7 binmail interface: /bin/mail -f | ||
| 7 | |||
| 8 | exec env - PATH="QMAIL/bin:$PATH" \ | ||
| 9 | qmail-start '|dot-forward .forward | ||
| 10 | |preline -f /bin/mail -f "${SENDER:-MAILER-DAEMON}" -d "$USER"' \ | ||
| 11 | splogger qmail | ||
diff --git a/binm3.sh b/binm3.sh new file mode 100644 index 0000000..eb139e6 --- /dev/null +++ b/binm3.sh | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | # Using splogger to send the log through syslog. | ||
| 4 | # Using binmail to deliver messages to /var/spool/mail/$USER by default. | ||
| 5 | # Using V7 binmail interface: /bin/mail -f | ||
| 6 | |||
| 7 | exec env - PATH="QMAIL/bin:$PATH" \ | ||
| 8 | qmail-start \ | ||
| 9 | '|preline -f /bin/mail -f "${SENDER:-MAILER-DAEMON}" -d "$USER"' \ | ||
| 10 | splogger qmail | ||
diff --git a/bouncesaying.1 b/bouncesaying.1 new file mode 100644 index 0000000..d99a460 --- /dev/null +++ b/bouncesaying.1 | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | .TH bouncesaying 1 | ||
| 2 | .SH NAME | ||
| 3 | bouncesaying \- perhaps bounce each incoming message | ||
| 4 | .SH SYNOPSIS | ||
| 5 | in | ||
| 6 | .BR .qmail : | ||
| 7 | .B |bouncesaying | ||
| 8 | .I error | ||
| 9 | [ | ||
| 10 | .I program | ||
| 11 | [ | ||
| 12 | .I arg ... | ||
| 13 | ] | ||
| 14 | ] | ||
| 15 | .SH DESCRIPTION | ||
| 16 | .B bouncesaying | ||
| 17 | feeds each new mail message to | ||
| 18 | .I program | ||
| 19 | with the given arguments. | ||
| 20 | If | ||
| 21 | .I program | ||
| 22 | exits 0, | ||
| 23 | .B bouncesaying | ||
| 24 | prints | ||
| 25 | .I error | ||
| 26 | and bounces the message. | ||
| 27 | |||
| 28 | If | ||
| 29 | .I program | ||
| 30 | exits 111, | ||
| 31 | .B bouncesaying | ||
| 32 | exits 111, | ||
| 33 | so delivery will be retried later. | ||
| 34 | |||
| 35 | If | ||
| 36 | .I program | ||
| 37 | exits anything else | ||
| 38 | (or does not exist), | ||
| 39 | .B bouncesaying | ||
| 40 | exits 0, | ||
| 41 | so the rest of | ||
| 42 | .B .qmail | ||
| 43 | will be processed as usual. | ||
| 44 | |||
| 45 | Note that | ||
| 46 | it is not safe for | ||
| 47 | .I program | ||
| 48 | to fork a child that | ||
| 49 | reads the message in the background. | ||
| 50 | |||
| 51 | If | ||
| 52 | .I program | ||
| 53 | is not supplied, | ||
| 54 | .B bouncesaying | ||
| 55 | always bounces the message: | ||
| 56 | |||
| 57 | .EX | ||
| 58 | |bouncesaying 'This address no longer accepts mail.' | ||
| 59 | .EE | ||
| 60 | |||
| 61 | .B WARNING: | ||
| 62 | If you create a | ||
| 63 | .B .qmail | ||
| 64 | file to enable | ||
| 65 | .BR bouncesaying , | ||
| 66 | make sure to also add a line specifying delivery to your normal mailbox. | ||
| 67 | .SH "SEE ALSO" | ||
| 68 | condredirect(1), | ||
| 69 | except(1), | ||
| 70 | dot-qmail(5), | ||
| 71 | qmail-command(8) | ||
diff --git a/bouncesaying.c b/bouncesaying.c new file mode 100644 index 0000000..c7d0026 --- /dev/null +++ b/bouncesaying.c | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | #include "fork.h" | ||
| 2 | #include "strerr.h" | ||
| 3 | #include "error.h" | ||
| 4 | #include "wait.h" | ||
| 5 | #include "sig.h" | ||
| 6 | #include "exit.h" | ||
| 7 | |||
| 8 | #define FATAL "bouncesaying: fatal: " | ||
| 9 | |||
| 10 | void main(argc,argv) | ||
| 11 | int argc; | ||
| 12 | char **argv; | ||
| 13 | { | ||
| 14 | int pid; | ||
| 15 | int wstat; | ||
| 16 | |||
| 17 | if (!argv[1]) | ||
| 18 | strerr_die1x(100,"bouncesaying: usage: bouncesaying error [ program [ arg ... ] ]"); | ||
| 19 | |||
| 20 | if (argv[2]) { | ||
| 21 | pid = fork(); | ||
| 22 | if (pid == -1) | ||
| 23 | strerr_die2sys(111,FATAL,"unable to fork: "); | ||
| 24 | if (pid == 0) { | ||
| 25 | execvp(argv[2],argv + 2); | ||
| 26 | if (error_temp(errno)) _exit(111); | ||
| 27 | _exit(100); | ||
| 28 | } | ||
| 29 | if (wait_pid(&wstat,pid) == -1) | ||
| 30 | strerr_die2x(111,FATAL,"wait failed"); | ||
| 31 | if (wait_crashed(wstat)) | ||
| 32 | strerr_die2x(111,FATAL,"child crashed"); | ||
| 33 | switch(wait_exitcode(wstat)) { | ||
| 34 | case 0: break; | ||
| 35 | case 111: strerr_die2x(111,FATAL,"temporary child error"); | ||
| 36 | default: _exit(0); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | strerr_die1x(100,argv[1]); | ||
| 41 | } | ||
| @@ -0,0 +1,13 @@ | |||
| 1 | #ifndef BYTE_H | ||
| 2 | #define BYTE_H | ||
| 3 | |||
| 4 | extern unsigned int byte_chr(); | ||
| 5 | extern unsigned int byte_rchr(); | ||
| 6 | extern void byte_copy(); | ||
| 7 | extern void byte_copyr(); | ||
| 8 | extern int byte_diff(); | ||
| 9 | extern void byte_zero(); | ||
| 10 | |||
| 11 | #define byte_equal(s,n,t) (!byte_diff((s),(n),(t))) | ||
| 12 | |||
| 13 | #endif | ||
diff --git a/byte_chr.c b/byte_chr.c new file mode 100644 index 0000000..f81dde8 --- /dev/null +++ b/byte_chr.c | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | #include "byte.h" | ||
| 2 | |||
| 3 | unsigned int byte_chr(s,n,c) | ||
| 4 | char *s; | ||
| 5 | register unsigned int n; | ||
| 6 | int c; | ||
| 7 | { | ||
| 8 | register char ch; | ||
| 9 | register char *t; | ||
| 10 | |||
| 11 | ch = c; | ||
| 12 | t = s; | ||
| 13 | for (;;) { | ||
| 14 | if (!n) break; if (*t == ch) break; ++t; --n; | ||
| 15 | if (!n) break; if (*t == ch) break; ++t; --n; | ||
| 16 | if (!n) break; if (*t == ch) break; ++t; --n; | ||
| 17 | if (!n) break; if (*t == ch) break; ++t; --n; | ||
| 18 | } | ||
| 19 | return t - s; | ||
| 20 | } | ||
diff --git a/byte_copy.c b/byte_copy.c new file mode 100644 index 0000000..eaad11b --- /dev/null +++ b/byte_copy.c | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | #include "byte.h" | ||
| 2 | |||
| 3 | void byte_copy(to,n,from) | ||
| 4 | register char *to; | ||
| 5 | register unsigned int n; | ||
| 6 | register char *from; | ||
| 7 | { | ||
| 8 | for (;;) { | ||
| 9 | if (!n) return; *to++ = *from++; --n; | ||
| 10 | if (!n) return; *to++ = *from++; --n; | ||
| 11 | if (!n) return; *to++ = *from++; --n; | ||
| 12 | if (!n) return; *to++ = *from++; --n; | ||
| 13 | } | ||
| 14 | } | ||
diff --git a/byte_cr.c b/byte_cr.c new file mode 100644 index 0000000..3e7a1d5 --- /dev/null +++ b/byte_cr.c | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #include "byte.h" | ||
| 2 | |||
| 3 | void byte_copyr(to,n,from) | ||
| 4 | register char *to; | ||
| 5 | register unsigned int n; | ||
| 6 | register char *from; | ||
| 7 | { | ||
| 8 | to += n; | ||
| 9 | from += n; | ||
| 10 | for (;;) { | ||
| 11 | if (!n) return; *--to = *--from; --n; | ||
| 12 | if (!n) return; *--to = *--from; --n; | ||
| 13 | if (!n) return; *--to = *--from; --n; | ||
| 14 | if (!n) return; *--to = *--from; --n; | ||
| 15 | } | ||
| 16 | } | ||
diff --git a/byte_diff.c b/byte_diff.c new file mode 100644 index 0000000..cdbd760 --- /dev/null +++ b/byte_diff.c | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #include "byte.h" | ||
| 2 | |||
| 3 | int byte_diff(s,n,t) | ||
| 4 | register char *s; | ||
| 5 | register unsigned int n; | ||
| 6 | register char *t; | ||
| 7 | { | ||
| 8 | for (;;) { | ||
| 9 | if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; | ||
| 10 | if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; | ||
| 11 | if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; | ||
| 12 | if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; | ||
| 13 | } | ||
| 14 | return ((int)(unsigned int)(unsigned char) *s) | ||
| 15 | - ((int)(unsigned int)(unsigned char) *t); | ||
| 16 | } | ||
diff --git a/byte_rchr.c b/byte_rchr.c new file mode 100644 index 0000000..476bc22 --- /dev/null +++ b/byte_rchr.c | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | #include "byte.h" | ||
| 2 | |||
| 3 | unsigned int byte_rchr(s,n,c) | ||
| 4 | char *s; | ||
| 5 | register unsigned int n; | ||
| 6 | int c; | ||
| 7 | { | ||
| 8 | register char ch; | ||
| 9 | register char *t; | ||
| 10 | register char *u; | ||
| 11 | |||
| 12 | ch = c; | ||
| 13 | t = s; | ||
| 14 | u = 0; | ||
| 15 | for (;;) { | ||
| 16 | if (!n) break; if (*t == ch) u = t; ++t; --n; | ||
| 17 | if (!n) break; if (*t == ch) u = t; ++t; --n; | ||
| 18 | if (!n) break; if (*t == ch) u = t; ++t; --n; | ||
| 19 | if (!n) break; if (*t == ch) u = t; ++t; --n; | ||
| 20 | } | ||
| 21 | if (!u) u = t; | ||
| 22 | return u - s; | ||
| 23 | } | ||
diff --git a/byte_zero.c b/byte_zero.c new file mode 100644 index 0000000..92009ba --- /dev/null +++ b/byte_zero.c | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | #include "byte.h" | ||
| 2 | |||
| 3 | void byte_zero(s,n) | ||
| 4 | char *s; | ||
| 5 | register unsigned int n; | ||
| 6 | { | ||
| 7 | for (;;) { | ||
| 8 | if (!n) break; *s++ = 0; --n; | ||
| 9 | if (!n) break; *s++ = 0; --n; | ||
| 10 | if (!n) break; *s++ = 0; --n; | ||
| 11 | if (!n) break; *s++ = 0; --n; | ||
| 12 | } | ||
| 13 | } | ||
| @@ -0,0 +1,100 @@ | |||
| 1 | .TH case 3 | ||
| 2 | .SH NAME | ||
| 3 | case \- convert ASCII uppercase bytes to lowercase | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <case.h> | ||
| 6 | |||
| 7 | void \fBcase_lowers\fP(\fIs\fR); | ||
| 8 | .br | ||
| 9 | void \fBcase_lowerb\fP(\fIs\fR,\fIlen\fR); | ||
| 10 | |||
| 11 | int \fBcase_diffs\fP(\fIs\fR,\fIt\fR); | ||
| 12 | .br | ||
| 13 | int \fBcase_equals\fP(\fIs\fR,\fIt\fR); | ||
| 14 | .br | ||
| 15 | int \fBcase_starts\fP(\fIs\fR,\fIt\fR); | ||
| 16 | |||
| 17 | int \fBcase_diffb\fP(\fIs\fR,\fIlen\fR,\fIt\fR); | ||
| 18 | .br | ||
| 19 | int \fBcase_startb\fP(\fIs\fR,\fIlen\fR,\fIt\fR); | ||
| 20 | |||
| 21 | char *\fIs\fR; | ||
| 22 | .br | ||
| 23 | char *\fIt\fR; | ||
| 24 | .br | ||
| 25 | unsigned int \fIlen\fR; | ||
| 26 | .SH DESCRIPTION | ||
| 27 | .B case_lowers | ||
| 28 | converts each uppercase byte in the string | ||
| 29 | .I s | ||
| 30 | to lowercase. | ||
| 31 | .I s | ||
| 32 | must be 0-terminated. | ||
| 33 | |||
| 34 | .B case_lowerb | ||
| 35 | converts each uppercase byte in the buffer | ||
| 36 | .IR s , | ||
| 37 | of length | ||
| 38 | .IR len , | ||
| 39 | to lowercase. | ||
| 40 | |||
| 41 | .B case_diffs | ||
| 42 | lexicographically compares lowercase versions of the strings | ||
| 43 | .I s | ||
| 44 | and | ||
| 45 | .IR t . | ||
| 46 | It returns something positive, negative, or zero | ||
| 47 | when the first is larger than, smaller than, or equal to the second. | ||
| 48 | .I s | ||
| 49 | and | ||
| 50 | .I t | ||
| 51 | must be 0-terminated. | ||
| 52 | |||
| 53 | .B case_equals | ||
| 54 | means | ||
| 55 | .BR !case_diffs . | ||
| 56 | |||
| 57 | .B case_starts | ||
| 58 | returns 1 if a lowercase version of | ||
| 59 | .I s | ||
| 60 | starts with a lowercase version of | ||
| 61 | .IR t . | ||
| 62 | .I s | ||
| 63 | and | ||
| 64 | .I t | ||
| 65 | must be 0-terminated. | ||
| 66 | |||
| 67 | .B case_diffb | ||
| 68 | lexicographically compares lowercase versions of the buffers | ||
| 69 | .I s | ||
| 70 | and | ||
| 71 | .IR t , | ||
| 72 | each of length | ||
| 73 | .IR len . | ||
| 74 | It returns something positive, negative, or zero | ||
| 75 | when the first is larger than, smaller than, or equal to the second. | ||
| 76 | |||
| 77 | .B case_startb | ||
| 78 | returns 1 if a lowercase version of the buffer | ||
| 79 | .IR s , | ||
| 80 | of length | ||
| 81 | .IR len , | ||
| 82 | starts with a lowercase version of the string | ||
| 83 | .IR t . | ||
| 84 | .I t | ||
| 85 | must be 0-terminated. | ||
| 86 | |||
| 87 | The | ||
| 88 | .B case | ||
| 89 | routines | ||
| 90 | are ASCII-specific. | ||
| 91 | They are suitable for programs that handle | ||
| 92 | case-independent networking protocols. | ||
| 93 | |||
| 94 | All comparisons are performed on unsigned bytes. | ||
| 95 | .SH "SEE ALSO" | ||
| 96 | byte_diff(3), | ||
| 97 | byte_equal(3), | ||
| 98 | str_diff(3), | ||
| 99 | str_equal(3), | ||
| 100 | str_start(3) | ||
| @@ -0,0 +1,13 @@ | |||
| 1 | #ifndef CASE_H | ||
| 2 | #define CASE_H | ||
| 3 | |||
| 4 | extern void case_lowers(); | ||
| 5 | extern void case_lowerb(); | ||
| 6 | extern int case_diffs(); | ||
| 7 | extern int case_diffb(); | ||
| 8 | extern int case_starts(); | ||
| 9 | extern int case_startb(); | ||
| 10 | |||
| 11 | #define case_equals(s,t) (!case_diffs((s),(t))) | ||
| 12 | |||
| 13 | #endif | ||
diff --git a/case_diffb.c b/case_diffb.c new file mode 100644 index 0000000..9064b8a --- /dev/null +++ b/case_diffb.c | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | #include "case.h" | ||
| 2 | |||
| 3 | int case_diffb(s,len,t) | ||
| 4 | register char *s; | ||
| 5 | unsigned int len; | ||
| 6 | register char *t; | ||
| 7 | { | ||
| 8 | register unsigned char x; | ||
| 9 | register unsigned char y; | ||
| 10 | |||
| 11 | while (len > 0) { | ||
| 12 | --len; | ||
| 13 | x = *s++ - 'A'; | ||
| 14 | if (x <= 'Z' - 'A') x += 'a'; else x += 'A'; | ||
| 15 | y = *t++ - 'A'; | ||
| 16 | if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; | ||
| 17 | if (x != y) | ||
| 18 | return ((int)(unsigned int) x) - ((int)(unsigned int) y); | ||
| 19 | } | ||
| 20 | return 0; | ||
| 21 | } | ||
diff --git a/case_diffs.c b/case_diffs.c new file mode 100644 index 0000000..212c645 --- /dev/null +++ b/case_diffs.c | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | #include "case.h" | ||
| 2 | |||
| 3 | int case_diffs(s,t) | ||
| 4 | register char *s; | ||
| 5 | register char *t; | ||
| 6 | { | ||
| 7 | register unsigned char x; | ||
| 8 | register unsigned char y; | ||
| 9 | |||
| 10 | for (;;) { | ||
| 11 | x = *s++ - 'A'; | ||
| 12 | if (x <= 'Z' - 'A') x += 'a'; else x += 'A'; | ||
| 13 | y = *t++ - 'A'; | ||
| 14 | if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; | ||
| 15 | if (x != y) break; | ||
| 16 | if (!x) break; | ||
| 17 | } | ||
| 18 | return ((int)(unsigned int) x) - ((int)(unsigned int) y); | ||
| 19 | } | ||
diff --git a/case_lowerb.c b/case_lowerb.c new file mode 100644 index 0000000..4034c14 --- /dev/null +++ b/case_lowerb.c | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | #include "case.h" | ||
| 2 | |||
| 3 | void case_lowerb(s,len) | ||
| 4 | char *s; | ||
| 5 | unsigned int len; | ||
| 6 | { | ||
| 7 | unsigned char x; | ||
| 8 | while (len > 0) { | ||
| 9 | --len; | ||
| 10 | x = *s - 'A'; | ||
| 11 | if (x <= 'Z' - 'A') *s = x + 'a'; | ||
| 12 | ++s; | ||
| 13 | } | ||
| 14 | } | ||
diff --git a/case_lowers.c b/case_lowers.c new file mode 100644 index 0000000..208b3f5 --- /dev/null +++ b/case_lowers.c | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #include "case.h" | ||
| 2 | |||
| 3 | void case_lowers(s) | ||
| 4 | char *s; | ||
| 5 | { | ||
| 6 | unsigned char x; | ||
| 7 | while (x = *s) { | ||
| 8 | x -= 'A'; | ||
| 9 | if (x <= 'Z' - 'A') *s = x + 'a'; | ||
| 10 | ++s; | ||
| 11 | } | ||
| 12 | } | ||
diff --git a/case_starts.c b/case_starts.c new file mode 100644 index 0000000..2278a0a --- /dev/null +++ b/case_starts.c | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | #include "case.h" | ||
| 2 | |||
| 3 | int case_starts(s,t) | ||
| 4 | register char *s; | ||
| 5 | register char *t; | ||
| 6 | { | ||
| 7 | register unsigned char x; | ||
| 8 | register unsigned char y; | ||
| 9 | |||
| 10 | for (;;) { | ||
| 11 | x = *s++ - 'A'; | ||
| 12 | if (x <= 'Z' - 'A') x += 'a'; else x += 'A'; | ||
| 13 | y = *t++ - 'A'; | ||
| 14 | if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; | ||
| 15 | if (!y) return 1; | ||
| 16 | if (x != y) return 0; | ||
| 17 | } | ||
| 18 | } | ||
| @@ -0,0 +1,62 @@ | |||
| 1 | .TH cdb 3 | ||
| 2 | .SH NAME | ||
| 3 | cdb \- read from a constant database | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <cdb.h> | ||
| 6 | |||
| 7 | int \fBcdb_seek(\fP\fIfd,key,len,dlen\fR\fB)\fP; | ||
| 8 | |||
| 9 | int \fIfd\fR; | ||
| 10 | .br | ||
| 11 | char *\fIkey\fR; | ||
| 12 | .br | ||
| 13 | unsigned int \fIlen\fR; | ||
| 14 | .br | ||
| 15 | uint32 *\fIdlen\fR; | ||
| 16 | .SH DESCRIPTION | ||
| 17 | .B cdb_seek | ||
| 18 | looks up | ||
| 19 | .I key | ||
| 20 | in a constant database. | ||
| 21 | It returns 1 if | ||
| 22 | .I key | ||
| 23 | is present, | ||
| 24 | 0 if | ||
| 25 | .I key | ||
| 26 | is not present, | ||
| 27 | or \-1 if there was a read error. | ||
| 28 | .I key | ||
| 29 | is an array of | ||
| 30 | .I len | ||
| 31 | characters. | ||
| 32 | |||
| 33 | .B cdb_seek | ||
| 34 | needs an open file descriptor, | ||
| 35 | .IR fd , | ||
| 36 | pointing to the database. | ||
| 37 | If | ||
| 38 | .B cdb_seek | ||
| 39 | returns 1, | ||
| 40 | it points | ||
| 41 | .I fd | ||
| 42 | at the beginning of the data portion of the first record | ||
| 43 | indexed by | ||
| 44 | .IR key , | ||
| 45 | and it stores the data length in | ||
| 46 | .IR dlen. | ||
| 47 | .B cdb_seek | ||
| 48 | does not provide a way to read subsequent records with the same key. | ||
| 49 | |||
| 50 | It's fine to do several | ||
| 51 | .B cdb_seek | ||
| 52 | lookups with the same open file descriptor. | ||
| 53 | Beware, however, that two simultaneous | ||
| 54 | .B cdb_seek | ||
| 55 | lookups can fail horribly; | ||
| 56 | separate processes should not share the same database descriptor. | ||
| 57 | Furthermore, any updates after the database was opened | ||
| 58 | will be invisible. | ||
| 59 | It's rarely a good idea for a long-running program | ||
| 60 | to hold a database open. | ||
| 61 | .SH "SEE ALSO" | ||
| 62 | cdbget(1) | ||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef CDB_H | ||
| 2 | #define CDB_H | ||
| 3 | |||
| 4 | #include "uint32.h" | ||
| 5 | |||
| 6 | extern uint32 cdb_hash(); | ||
| 7 | extern uint32 cdb_unpack(); | ||
| 8 | |||
| 9 | extern int cdb_bread(); | ||
| 10 | extern int cdb_seek(); | ||
| 11 | |||
| 12 | #endif | ||
diff --git a/cdb_hash.c b/cdb_hash.c new file mode 100644 index 0000000..8238020 --- /dev/null +++ b/cdb_hash.c | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #include "cdb.h" | ||
| 2 | |||
| 3 | uint32 cdb_hash(buf,len) | ||
| 4 | unsigned char *buf; | ||
| 5 | unsigned int len; | ||
| 6 | { | ||
| 7 | uint32 h; | ||
| 8 | |||
| 9 | h = 5381; | ||
| 10 | while (len) { | ||
| 11 | --len; | ||
| 12 | h += (h << 5); | ||
| 13 | h ^= (uint32) *buf++; | ||
| 14 | } | ||
| 15 | return h; | ||
| 16 | } | ||
diff --git a/cdb_seek.c b/cdb_seek.c new file mode 100644 index 0000000..87ab614 --- /dev/null +++ b/cdb_seek.c | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <errno.h> | ||
| 3 | extern int errno; | ||
| 4 | #include "cdb.h" | ||
| 5 | |||
| 6 | #ifndef SEEK_SET | ||
| 7 | #define SEEK_SET 0 | ||
| 8 | #endif | ||
| 9 | |||
| 10 | int cdb_bread(fd,buf,len) | ||
| 11 | int fd; | ||
| 12 | char *buf; | ||
| 13 | int len; | ||
| 14 | { | ||
| 15 | int r; | ||
| 16 | while (len > 0) { | ||
| 17 | do | ||
| 18 | r = read(fd,buf,len); | ||
| 19 | while ((r == -1) && (errno == EINTR)); | ||
| 20 | if (r == -1) return -1; | ||
| 21 | if (r == 0) { errno = EIO; return -1; } | ||
| 22 | buf += r; | ||
| 23 | len -= r; | ||
| 24 | } | ||
| 25 | return 0; | ||
| 26 | } | ||
| 27 | |||
| 28 | static int match(fd,key,len) | ||
| 29 | int fd; | ||
| 30 | char *key; | ||
| 31 | unsigned int len; | ||
| 32 | { | ||
| 33 | char buf[32]; | ||
| 34 | int n; | ||
| 35 | int i; | ||
| 36 | |||
| 37 | while (len > 0) { | ||
| 38 | n = sizeof(buf); | ||
| 39 | if (n > len) n = len; | ||
| 40 | if (cdb_bread(fd,buf,n) == -1) return -1; | ||
| 41 | for (i = 0;i < n;++i) if (buf[i] != key[i]) return 0; | ||
| 42 | key += n; | ||
| 43 | len -= n; | ||
| 44 | } | ||
| 45 | return 1; | ||
| 46 | } | ||
| 47 | |||
| 48 | int cdb_seek(fd,key,len,dlen) | ||
| 49 | int fd; | ||
| 50 | char *key; | ||
| 51 | unsigned int len; | ||
| 52 | uint32 *dlen; | ||
| 53 | { | ||
| 54 | char packbuf[8]; | ||
| 55 | uint32 pos; | ||
| 56 | uint32 h; | ||
| 57 | uint32 lenhash; | ||
| 58 | uint32 h2; | ||
| 59 | uint32 loop; | ||
| 60 | uint32 poskd; | ||
| 61 | |||
| 62 | h = cdb_hash(key,len); | ||
| 63 | |||
| 64 | pos = 8 * (h & 255); | ||
| 65 | if (lseek(fd,(off_t) pos,SEEK_SET) == -1) return -1; | ||
| 66 | |||
| 67 | if (cdb_bread(fd,packbuf,8) == -1) return -1; | ||
| 68 | |||
| 69 | pos = cdb_unpack(packbuf); | ||
| 70 | lenhash = cdb_unpack(packbuf + 4); | ||
| 71 | |||
| 72 | if (!lenhash) return 0; | ||
| 73 | h2 = (h >> 8) % lenhash; | ||
| 74 | |||
| 75 | for (loop = 0;loop < lenhash;++loop) { | ||
| 76 | if (lseek(fd,(off_t) (pos + 8 * h2),SEEK_SET) == -1) return -1; | ||
| 77 | if (cdb_bread(fd,packbuf,8) == -1) return -1; | ||
| 78 | poskd = cdb_unpack(packbuf + 4); | ||
| 79 | if (!poskd) return 0; | ||
| 80 | if (cdb_unpack(packbuf) == h) { | ||
| 81 | if (lseek(fd,(off_t) poskd,SEEK_SET) == -1) return -1; | ||
| 82 | if (cdb_bread(fd,packbuf,8) == -1) return -1; | ||
| 83 | if (cdb_unpack(packbuf) == len) | ||
| 84 | switch(match(fd,key,len)) { | ||
| 85 | case -1: | ||
| 86 | return -1; | ||
| 87 | case 1: | ||
| 88 | *dlen = cdb_unpack(packbuf + 4); | ||
| 89 | return 1; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | if (++h2 == lenhash) h2 = 0; | ||
| 93 | } | ||
| 94 | return 0; | ||
| 95 | } | ||
diff --git a/cdb_unpack.c b/cdb_unpack.c new file mode 100644 index 0000000..c882202 --- /dev/null +++ b/cdb_unpack.c | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #include "cdb.h" | ||
| 2 | |||
| 3 | uint32 cdb_unpack(buf) | ||
| 4 | unsigned char *buf; | ||
| 5 | { | ||
| 6 | uint32 num; | ||
| 7 | num = buf[3]; num <<= 8; | ||
| 8 | num += buf[2]; num <<= 8; | ||
| 9 | num += buf[1]; num <<= 8; | ||
| 10 | num += buf[0]; | ||
| 11 | return num; | ||
| 12 | } | ||
diff --git a/cdbmake.h b/cdbmake.h new file mode 100644 index 0000000..883a231 --- /dev/null +++ b/cdbmake.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | #ifndef CDBMAKE_H | ||
| 2 | #define CDBMAKE_H | ||
| 3 | |||
| 4 | #include "uint32.h" | ||
| 5 | |||
| 6 | #define CDBMAKE_HPLIST 1000 | ||
| 7 | |||
| 8 | struct cdbmake_hp { uint32 h; uint32 p; } ; | ||
| 9 | |||
| 10 | struct cdbmake_hplist { | ||
| 11 | struct cdbmake_hp hp[CDBMAKE_HPLIST]; | ||
| 12 | struct cdbmake_hplist *next; | ||
| 13 | int num; | ||
| 14 | } ; | ||
| 15 | |||
| 16 | struct cdbmake { | ||
| 17 | char final[2048]; | ||
| 18 | uint32 count[256]; | ||
| 19 | uint32 start[256]; | ||
| 20 | struct cdbmake_hplist *head; | ||
| 21 | struct cdbmake_hp *split; /* includes space for hash */ | ||
| 22 | struct cdbmake_hp *hash; | ||
| 23 | uint32 numentries; | ||
| 24 | } ; | ||
| 25 | |||
| 26 | extern void cdbmake_pack(); | ||
| 27 | #define CDBMAKE_HASHSTART ((uint32) 5381) | ||
| 28 | extern uint32 cdbmake_hashadd(); | ||
| 29 | |||
| 30 | extern void cdbmake_init(); | ||
| 31 | extern int cdbmake_add(); | ||
| 32 | extern int cdbmake_split(); | ||
| 33 | extern uint32 cdbmake_throw(); | ||
| 34 | |||
| 35 | #endif | ||
diff --git a/cdbmake_add.c b/cdbmake_add.c new file mode 100644 index 0000000..115f828 --- /dev/null +++ b/cdbmake_add.c | |||
| @@ -0,0 +1,117 @@ | |||
| 1 | #include "cdbmake.h" | ||
| 2 | |||
| 3 | void cdbmake_init(cdbm) | ||
| 4 | struct cdbmake *cdbm; | ||
| 5 | { | ||
| 6 | cdbm->head = 0; | ||
| 7 | cdbm->split = 0; | ||
| 8 | cdbm->hash = 0; | ||
| 9 | cdbm->numentries = 0; | ||
| 10 | } | ||
| 11 | |||
| 12 | int cdbmake_add(cdbm,h,p,alloc) | ||
| 13 | struct cdbmake *cdbm; | ||
| 14 | uint32 h; | ||
| 15 | uint32 p; | ||
| 16 | char *(*alloc)(); | ||
| 17 | { | ||
| 18 | struct cdbmake_hplist *head; | ||
| 19 | |||
| 20 | head = cdbm->head; | ||
| 21 | if (!head || (head->num >= CDBMAKE_HPLIST)) { | ||
| 22 | head = (struct cdbmake_hplist *) alloc(sizeof(struct cdbmake_hplist)); | ||
| 23 | if (!head) return 0; | ||
| 24 | head->num = 0; | ||
| 25 | head->next = cdbm->head; | ||
| 26 | cdbm->head = head; | ||
| 27 | } | ||
| 28 | head->hp[head->num].h = h; | ||
| 29 | head->hp[head->num].p = p; | ||
| 30 | ++head->num; | ||
| 31 | ++cdbm->numentries; | ||
| 32 | return 1; | ||
| 33 | } | ||
| 34 | |||
| 35 | int cdbmake_split(cdbm,alloc) | ||
| 36 | struct cdbmake *cdbm; | ||
| 37 | char *(*alloc)(); | ||
| 38 | { | ||
| 39 | int i; | ||
| 40 | uint32 u; | ||
| 41 | uint32 memsize; | ||
| 42 | struct cdbmake_hplist *x; | ||
| 43 | |||
| 44 | for (i = 0;i < 256;++i) | ||
| 45 | cdbm->count[i] = 0; | ||
| 46 | |||
| 47 | for (x = cdbm->head;x;x = x->next) { | ||
| 48 | i = x->num; | ||
| 49 | while (i--) | ||
| 50 | ++cdbm->count[255 & x->hp[i].h]; | ||
| 51 | } | ||
| 52 | |||
| 53 | memsize = 1; | ||
| 54 | for (i = 0;i < 256;++i) { | ||
| 55 | u = cdbm->count[i] * 2; | ||
| 56 | if (u > memsize) | ||
| 57 | memsize = u; | ||
| 58 | } | ||
| 59 | |||
| 60 | memsize += cdbm->numentries; /* no overflow possible up to now */ | ||
| 61 | u = (uint32) 0 - (uint32) 1; | ||
| 62 | u /= sizeof(struct cdbmake_hp); | ||
| 63 | if (memsize > u) return 0; | ||
| 64 | |||
| 65 | cdbm->split = (struct cdbmake_hp *) alloc(memsize * sizeof(struct cdbmake_hp)); | ||
| 66 | if (!cdbm->split) return 0; | ||
| 67 | |||
| 68 | cdbm->hash = cdbm->split + cdbm->numentries; | ||
| 69 | |||
| 70 | u = 0; | ||
| 71 | for (i = 0;i < 256;++i) { | ||
| 72 | u += cdbm->count[i]; /* bounded by numentries, so no overflow */ | ||
| 73 | cdbm->start[i] = u; | ||
| 74 | } | ||
| 75 | |||
| 76 | for (x = cdbm->head;x;x = x->next) { | ||
| 77 | i = x->num; | ||
| 78 | while (i--) | ||
| 79 | cdbm->split[--cdbm->start[255 & x->hp[i].h]] = x->hp[i]; | ||
| 80 | } | ||
| 81 | |||
| 82 | return 1; | ||
| 83 | } | ||
| 84 | |||
| 85 | uint32 cdbmake_throw(cdbm,pos,b) | ||
| 86 | struct cdbmake *cdbm; | ||
| 87 | uint32 pos; | ||
| 88 | int b; | ||
| 89 | { | ||
| 90 | uint32 len; | ||
| 91 | uint32 j; | ||
| 92 | uint32 count; | ||
| 93 | struct cdbmake_hp *hp; | ||
| 94 | uint32 where; | ||
| 95 | |||
| 96 | count = cdbm->count[b]; | ||
| 97 | |||
| 98 | len = count + count; /* no overflow possible */ | ||
| 99 | cdbmake_pack(cdbm->final + 8 * b,pos); | ||
| 100 | cdbmake_pack(cdbm->final + 8 * b + 4,len); | ||
| 101 | |||
| 102 | if (len) { | ||
| 103 | for (j = 0;j < len;++j) | ||
| 104 | cdbm->hash[j].h = cdbm->hash[j].p = 0; | ||
| 105 | |||
| 106 | hp = cdbm->split + cdbm->start[b]; | ||
| 107 | for (j = 0;j < count;++j) { | ||
| 108 | where = (hp->h >> 8) % len; | ||
| 109 | while (cdbm->hash[where].p) | ||
| 110 | if (++where == len) | ||
| 111 | where = 0; | ||
| 112 | cdbm->hash[where] = *hp++; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | return len; | ||
| 117 | } | ||
diff --git a/cdbmake_hash.c b/cdbmake_hash.c new file mode 100644 index 0000000..f9dc3e5 --- /dev/null +++ b/cdbmake_hash.c | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #include "cdbmake.h" | ||
| 2 | |||
| 3 | uint32 cdbmake_hashadd(h,c) | ||
| 4 | uint32 h; | ||
| 5 | unsigned int c; | ||
| 6 | { | ||
| 7 | h += (h << 5); | ||
| 8 | h ^= (uint32) (unsigned char) c; | ||
| 9 | return h; | ||
| 10 | } | ||
diff --git a/cdbmake_pack.c b/cdbmake_pack.c new file mode 100644 index 0000000..04b5f5b --- /dev/null +++ b/cdbmake_pack.c | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #include "cdbmake.h" | ||
| 2 | |||
| 3 | void cdbmake_pack(buf,num) | ||
| 4 | unsigned char *buf; | ||
| 5 | uint32 num; | ||
| 6 | { | ||
| 7 | *buf++ = num; num >>= 8; | ||
| 8 | *buf++ = num; num >>= 8; | ||
| 9 | *buf++ = num; num >>= 8; | ||
| 10 | *buf = num; | ||
| 11 | } | ||
diff --git a/cdbmss.c b/cdbmss.c new file mode 100644 index 0000000..2d8f367 --- /dev/null +++ b/cdbmss.c | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | #include "readwrite.h" | ||
| 2 | #include "seek.h" | ||
| 3 | #include "alloc.h" | ||
| 4 | #include "cdbmss.h" | ||
| 5 | |||
| 6 | int cdbmss_start(c,fd) | ||
| 7 | struct cdbmss *c; | ||
| 8 | int fd; | ||
| 9 | { | ||
| 10 | cdbmake_init(&c->cdbm); | ||
| 11 | c->fd = fd; | ||
| 12 | c->pos = sizeof(c->cdbm.final); | ||
| 13 | substdio_fdbuf(&c->ss,write,fd,c->ssbuf,sizeof(c->ssbuf)); | ||
| 14 | return seek_set(fd,(seek_pos) c->pos); | ||
| 15 | } | ||
| 16 | |||
| 17 | int cdbmss_add(c,key,keylen,data,datalen) | ||
| 18 | struct cdbmss *c; | ||
| 19 | unsigned char *key; | ||
| 20 | unsigned int keylen; | ||
| 21 | unsigned char *data; | ||
| 22 | unsigned int datalen; | ||
| 23 | { | ||
| 24 | uint32 h; | ||
| 25 | int i; | ||
| 26 | |||
| 27 | cdbmake_pack(c->packbuf,(uint32) keylen); | ||
| 28 | cdbmake_pack(c->packbuf + 4,(uint32) datalen); | ||
| 29 | if (substdio_put(&c->ss,c->packbuf,8) == -1) return -1; | ||
| 30 | if (substdio_put(&c->ss,key,keylen) == -1) return -1; | ||
| 31 | if (substdio_put(&c->ss,data,datalen) == -1) return -1; | ||
| 32 | |||
| 33 | h = CDBMAKE_HASHSTART; | ||
| 34 | for (i = 0;i < keylen;++i) | ||
| 35 | h = cdbmake_hashadd(h,(unsigned int) key[i]); | ||
| 36 | |||
| 37 | if (!cdbmake_add(&c->cdbm,h,c->pos,alloc)) return -1; | ||
| 38 | |||
| 39 | c->pos += 8 + keylen + datalen; /* XXX: overflow? */ | ||
| 40 | return 0; | ||
| 41 | } | ||
| 42 | |||
| 43 | int cdbmss_finish(c) | ||
| 44 | struct cdbmss *c; | ||
| 45 | { | ||
| 46 | int i; | ||
| 47 | uint32 len; | ||
| 48 | uint32 u; | ||
| 49 | |||
| 50 | if (!cdbmake_split(&c->cdbm,alloc)) return -1; | ||
| 51 | |||
| 52 | for (i = 0;i < 256;++i) { | ||
| 53 | len = cdbmake_throw(&c->cdbm,c->pos,i); | ||
| 54 | for (u = 0;u < len;++u) { | ||
| 55 | cdbmake_pack(c->packbuf,c->cdbm.hash[u].h); | ||
| 56 | cdbmake_pack(c->packbuf + 4,c->cdbm.hash[u].p); | ||
| 57 | if (substdio_put(&c->ss,c->packbuf,8) == -1) return -1; | ||
| 58 | c->pos += 8; /* XXX: overflow? */ | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | if (substdio_flush(&c->ss) == -1) return -1; | ||
| 63 | if (seek_begin(c->fd) == -1) return -1; | ||
| 64 | return substdio_putflush(&c->ss,c->cdbm.final,sizeof(c->cdbm.final)); | ||
| 65 | } | ||
diff --git a/cdbmss.h b/cdbmss.h new file mode 100644 index 0000000..5e6bdf4 --- /dev/null +++ b/cdbmss.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #ifndef CDBMSS_H | ||
| 2 | #define CDBMSS_H | ||
| 3 | |||
| 4 | #include "cdbmake.h" | ||
| 5 | #include "substdio.h" | ||
| 6 | |||
| 7 | struct cdbmss { | ||
| 8 | char ssbuf[1024]; | ||
| 9 | struct cdbmake cdbm; | ||
| 10 | substdio ss; | ||
| 11 | char packbuf[8]; | ||
| 12 | uint32 pos; | ||
| 13 | int fd; | ||
| 14 | } ; | ||
| 15 | |||
| 16 | #endif | ||
diff --git a/chkshsgr.c b/chkshsgr.c new file mode 100644 index 0000000..2bcdade --- /dev/null +++ b/chkshsgr.c | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #include "exit.h" | ||
| 2 | void main() | ||
| 3 | { | ||
| 4 | short x[4]; | ||
| 5 | |||
| 6 | x[0] = x[1] = 0; | ||
| 7 | if (getgroups(1,x) == 0) if (setgroups(1,x) == -1) _exit(1); | ||
| 8 | _exit(0); | ||
| 9 | } | ||
diff --git a/chkspawn.c b/chkspawn.c new file mode 100644 index 0000000..d19259e --- /dev/null +++ b/chkspawn.c | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "subfd.h" | ||
| 3 | #include "fmt.h" | ||
| 4 | #include "select.h" | ||
| 5 | #include "exit.h" | ||
| 6 | #include "auto_spawn.h" | ||
| 7 | |||
| 8 | char num[FMT_ULONG]; | ||
| 9 | fd_set fds; | ||
| 10 | |||
| 11 | void main() | ||
| 12 | { | ||
| 13 | unsigned long hiddenlimit; | ||
| 14 | unsigned long maxnumd; | ||
| 15 | |||
| 16 | hiddenlimit = sizeof(fds) * 8; | ||
| 17 | maxnumd = (hiddenlimit - 5) / 2; | ||
| 18 | |||
| 19 | if (auto_spawn < 1) { | ||
| 20 | substdio_puts(subfderr,"Oops. You have set conf-spawn lower than 1.\n"); | ||
| 21 | substdio_flush(subfderr); | ||
| 22 | _exit(1); | ||
| 23 | } | ||
| 24 | |||
| 25 | if (auto_spawn > 255) { | ||
| 26 | substdio_puts(subfderr,"Oops. You have set conf-spawn higher than 255.\n"); | ||
| 27 | substdio_flush(subfderr); | ||
| 28 | _exit(1); | ||
| 29 | } | ||
| 30 | |||
| 31 | if (auto_spawn > maxnumd) { | ||
| 32 | substdio_puts(subfderr,"Oops. Your system's FD_SET() has a hidden limit of "); | ||
| 33 | substdio_put(subfderr,num,fmt_ulong(num,hiddenlimit)); | ||
| 34 | substdio_puts(subfderr," descriptors.\n\ | ||
| 35 | This means that the qmail daemons could crash if you set the run-time\n\ | ||
| 36 | concurrency higher than "); | ||
| 37 | substdio_put(subfderr,num,fmt_ulong(num,maxnumd)); | ||
| 38 | substdio_puts(subfderr,". So I'm going to insist that the concurrency\n\ | ||
| 39 | limit in conf-spawn be at most "); | ||
| 40 | substdio_put(subfderr,num,fmt_ulong(num,maxnumd)); | ||
| 41 | substdio_puts(subfderr,". Right now it's "); | ||
| 42 | substdio_put(subfderr,num,fmt_ulong(num,(unsigned long) auto_spawn)); | ||
| 43 | substdio_puts(subfderr,".\n"); | ||
| 44 | substdio_flush(subfderr); | ||
| 45 | _exit(1); | ||
| 46 | } | ||
| 47 | _exit(0); | ||
| 48 | } | ||
| @@ -0,0 +1,25 @@ | |||
| 1 | .TH coe 3 | ||
| 2 | .SH NAME | ||
| 3 | coe \- set close-on-exec flag for a descriptor | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <coe.h> | ||
| 6 | |||
| 7 | int \fBcoe\fP(\fIfd\fR); | ||
| 8 | |||
| 9 | int \fIfd\fR; | ||
| 10 | .SH DESCRIPTION | ||
| 11 | .B coe | ||
| 12 | sets the close-on-exec flag for | ||
| 13 | file descriptor | ||
| 14 | .IR fd , | ||
| 15 | returning 0 if it was successful | ||
| 16 | or -1 on error. | ||
| 17 | If | ||
| 18 | .B coe | ||
| 19 | is successful, | ||
| 20 | .I fd | ||
| 21 | will be closed when the process calls | ||
| 22 | .BR execve . | ||
| 23 | .SH "SEE ALSO" | ||
| 24 | execve(2), | ||
| 25 | fcntl(2) | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | #include <fcntl.h> | ||
| 2 | #include "coe.h" | ||
| 3 | |||
| 4 | int coe(fd) | ||
| 5 | int fd; | ||
| 6 | { | ||
| 7 | return fcntl(fd,F_SETFD,1); | ||
| 8 | } | ||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef COE_H | ||
| 2 | #define COE_H | ||
| 3 | |||
| 4 | extern int coe(); | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/commands.c b/commands.c new file mode 100644 index 0000000..b0d3f61 --- /dev/null +++ b/commands.c | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | #include "commands.h" | ||
| 2 | #include "substdio.h" | ||
| 3 | #include "stralloc.h" | ||
| 4 | #include "str.h" | ||
| 5 | #include "case.h" | ||
| 6 | |||
| 7 | static stralloc cmd = {0}; | ||
| 8 | |||
| 9 | int commands(ss,c) | ||
| 10 | substdio *ss; | ||
| 11 | struct commands *c; | ||
| 12 | { | ||
| 13 | int i; | ||
| 14 | char *arg; | ||
| 15 | |||
| 16 | for (;;) { | ||
| 17 | if (!stralloc_copys(&cmd,"")) return -1; | ||
| 18 | |||
| 19 | for (;;) { | ||
| 20 | if (!stralloc_readyplus(&cmd,1)) return -1; | ||
| 21 | i = substdio_get(ss,cmd.s + cmd.len,1); | ||
| 22 | if (i != 1) return i; | ||
| 23 | if (cmd.s[cmd.len] == '\n') break; | ||
| 24 | ++cmd.len; | ||
| 25 | } | ||
| 26 | |||
| 27 | if (cmd.len > 0) if (cmd.s[cmd.len - 1] == '\r') --cmd.len; | ||
| 28 | |||
| 29 | cmd.s[cmd.len] = 0; | ||
| 30 | |||
| 31 | i = str_chr(cmd.s,' '); | ||
| 32 | arg = cmd.s + i; | ||
| 33 | while (*arg == ' ') ++arg; | ||
| 34 | cmd.s[i] = 0; | ||
| 35 | |||
| 36 | for (i = 0;c[i].text;++i) if (case_equals(c[i].text,cmd.s)) break; | ||
| 37 | c[i].fun(arg); | ||
| 38 | if (c[i].flush) c[i].flush(); | ||
| 39 | } | ||
| 40 | } | ||
diff --git a/commands.h b/commands.h new file mode 100644 index 0000000..da05a8d --- /dev/null +++ b/commands.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef COMMANDS_H | ||
| 2 | #define COMMANDS_H | ||
| 3 | |||
| 4 | struct commands { | ||
| 5 | char *text; | ||
| 6 | void (*fun)(); | ||
| 7 | void (*flush)(); | ||
| 8 | } ; | ||
| 9 | |||
| 10 | extern int commands(); | ||
| 11 | |||
| 12 | #endif | ||
diff --git a/condredirect.1 b/condredirect.1 new file mode 100644 index 0000000..9f9d3c4 --- /dev/null +++ b/condredirect.1 | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | .TH condredirect 1 | ||
| 2 | .SH NAME | ||
| 3 | condredirect \- perhaps redirect mail to another address | ||
| 4 | .SH SYNOPSIS | ||
| 5 | in | ||
| 6 | .BR .qmail : | ||
| 7 | .B |condredirect | ||
| 8 | .I newaddress | ||
| 9 | .I program | ||
| 10 | [ | ||
| 11 | .I arg ... | ||
| 12 | ] | ||
| 13 | .SH DESCRIPTION | ||
| 14 | .B condredirect | ||
| 15 | feeds each new mail message to | ||
| 16 | .I program | ||
| 17 | with the given arguments. | ||
| 18 | If | ||
| 19 | .I program | ||
| 20 | exits 0, | ||
| 21 | .B condredirect | ||
| 22 | forwards the mail message to | ||
| 23 | .IR newaddress , | ||
| 24 | and then exits 99, | ||
| 25 | so further commands in | ||
| 26 | .B .qmail | ||
| 27 | are ignored. | ||
| 28 | |||
| 29 | If | ||
| 30 | .I program | ||
| 31 | exits 111, | ||
| 32 | .B condredirect | ||
| 33 | exits 111, | ||
| 34 | so delivery will be retried later. | ||
| 35 | |||
| 36 | If | ||
| 37 | .I program | ||
| 38 | exits anything else | ||
| 39 | (or does not exist), | ||
| 40 | .B condredirect | ||
| 41 | exits 0, | ||
| 42 | so the rest of | ||
| 43 | .B .qmail | ||
| 44 | will be processed as usual. | ||
| 45 | |||
| 46 | Note that | ||
| 47 | it is not safe for | ||
| 48 | .I program | ||
| 49 | to fork a child that | ||
| 50 | reads the message in the background. | ||
| 51 | |||
| 52 | .B WARNING: | ||
| 53 | If you create a | ||
| 54 | .B .qmail | ||
| 55 | file to enable | ||
| 56 | .BR condredirect , | ||
| 57 | make sure to also add a line specifying delivery to your normal mailbox. | ||
| 58 | .SH "SEE ALSO" | ||
| 59 | bouncesaying(1), | ||
| 60 | except(1), | ||
| 61 | dot-qmail(5), | ||
| 62 | qmail-command(8), | ||
| 63 | qmail-queue(8) | ||
diff --git a/condredirect.c b/condredirect.c new file mode 100644 index 0000000..593d2f5 --- /dev/null +++ b/condredirect.c | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | #include "sig.h" | ||
| 2 | #include "readwrite.h" | ||
| 3 | #include "exit.h" | ||
| 4 | #include "env.h" | ||
| 5 | #include "error.h" | ||
| 6 | #include "fork.h" | ||
| 7 | #include "wait.h" | ||
| 8 | #include "seek.h" | ||
| 9 | #include "qmail.h" | ||
| 10 | #include "strerr.h" | ||
| 11 | #include "substdio.h" | ||
| 12 | #include "fmt.h" | ||
| 13 | |||
| 14 | #define FATAL "condredirect: fatal: " | ||
| 15 | |||
| 16 | struct qmail qqt; | ||
| 17 | |||
| 18 | int mywrite(fd,buf,len) int fd; char *buf; int len; | ||
| 19 | { | ||
| 20 | qmail_put(&qqt,buf,len); | ||
| 21 | return len; | ||
| 22 | } | ||
| 23 | |||
| 24 | char inbuf[SUBSTDIO_INSIZE]; | ||
| 25 | char outbuf[1]; | ||
| 26 | substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf); | ||
| 27 | substdio ssout = SUBSTDIO_FDBUF(mywrite,-1,outbuf,sizeof outbuf); | ||
| 28 | |||
| 29 | char num[FMT_ULONG]; | ||
| 30 | |||
| 31 | void main(argc,argv) | ||
| 32 | int argc; | ||
| 33 | char **argv; | ||
| 34 | { | ||
| 35 | char *sender; | ||
| 36 | char *dtline; | ||
| 37 | int pid; | ||
| 38 | int wstat; | ||
| 39 | char *qqx; | ||
| 40 | |||
| 41 | if (!argv[1] || !argv[2]) | ||
| 42 | strerr_die1x(100,"condredirect: usage: condredirect newaddress program [ arg ... ]"); | ||
| 43 | |||
| 44 | pid = fork(); | ||
| 45 | if (pid == -1) | ||
| 46 | strerr_die2sys(111,FATAL,"unable to fork: "); | ||
| 47 | if (pid == 0) { | ||
| 48 | execvp(argv[2],argv + 2); | ||
| 49 | if (error_temp(errno)) _exit(111); | ||
| 50 | _exit(100); | ||
| 51 | } | ||
| 52 | if (wait_pid(&wstat,pid) == -1) | ||
| 53 | strerr_die2x(111,FATAL,"wait failed"); | ||
| 54 | if (wait_crashed(wstat)) | ||
| 55 | strerr_die2x(111,FATAL,"child crashed"); | ||
| 56 | switch(wait_exitcode(wstat)) { | ||
| 57 | case 0: break; | ||
| 58 | case 111: strerr_die2x(111,FATAL,"temporary child error"); | ||
| 59 | default: _exit(0); | ||
| 60 | } | ||
| 61 | |||
| 62 | if (seek_begin(0) == -1) | ||
| 63 | strerr_die2sys(111,FATAL,"unable to rewind: "); | ||
| 64 | sig_pipeignore(); | ||
| 65 | |||
| 66 | sender = env_get("SENDER"); | ||
| 67 | if (!sender) strerr_die2x(100,FATAL,"SENDER not set"); | ||
| 68 | dtline = env_get("DTLINE"); | ||
| 69 | if (!dtline) strerr_die2x(100,FATAL,"DTLINE not set"); | ||
| 70 | |||
| 71 | if (qmail_open(&qqt) == -1) | ||
| 72 | strerr_die2sys(111,FATAL,"unable to fork: "); | ||
| 73 | qmail_puts(&qqt,dtline); | ||
| 74 | if (substdio_copy(&ssout,&ssin) != 0) | ||
| 75 | strerr_die2sys(111,FATAL,"unable to read message: "); | ||
| 76 | substdio_flush(&ssout); | ||
| 77 | |||
| 78 | num[fmt_ulong(num,qmail_qp(&qqt))] = 0; | ||
| 79 | |||
| 80 | qmail_from(&qqt,sender); | ||
| 81 | qmail_to(&qqt,argv[1]); | ||
| 82 | qqx = qmail_close(&qqt); | ||
| 83 | if (*qqx) strerr_die2x(*qqx == 'D' ? 100 : 111,FATAL,qqx + 1); | ||
| 84 | strerr_die2x(99,"condredirect: qp ",num); | ||
| 85 | } | ||
diff --git a/conf-break b/conf-break new file mode 100644 index 0000000..28fd977 --- /dev/null +++ b/conf-break | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | - | ||
| 2 | |||
| 3 | This character is the user-ext delimiter. The default delimiter is -, | ||
| 4 | meaning that user joe controls joe-anything. Some system administrators | ||
| 5 | prefer + or =. | ||
| 6 | |||
| 7 | You can override this choice at run time with the qmail-users mechanism. | ||
| 8 | |||
| 9 | Multicharacter delimiters are not permitted. | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | cc -O2 | ||
| 2 | |||
| 3 | This will be used to compile .c files. | ||
diff --git a/conf-groups b/conf-groups new file mode 100644 index 0000000..cec0845 --- /dev/null +++ b/conf-groups | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | qmail | ||
| 2 | nofiles | ||
| 3 | |||
| 4 | These are the qmail groups. The second group should not have access to | ||
| 5 | any files, but it must be usable for processes; this requirement | ||
| 6 | excludes the ``nogroup'' and ``nobody'' groups on many systems. | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | cc -s | ||
| 2 | |||
| 3 | This will be used to link .o files into an executable. | ||
diff --git a/conf-patrn b/conf-patrn new file mode 100644 index 0000000..70c72af --- /dev/null +++ b/conf-patrn | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | 002 | ||
| 2 | |||
| 3 | These stat bits are not allowed in ~ and ~/.qmail. On most systems, the | ||
| 4 | default umask is 022 or 077, so 022 will work here. | ||
| 5 | |||
| 6 | Note that ~ftp, ~www, ~uucp, etc. should be owned by root. | ||
diff --git a/conf-qmail b/conf-qmail new file mode 100644 index 0000000..0267f30 --- /dev/null +++ b/conf-qmail | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | /var/qmail | ||
| 2 | |||
| 3 | This is the qmail home directory. It must be a local directory, not | ||
| 4 | shared among machines. This is where qmail queues all mail messages. | ||
| 5 | |||
| 6 | The queue (except for bounce message contents) is crashproof, if the | ||
| 7 | filesystem guarantees that single-byte writes are atomic and that | ||
| 8 | directory operations are synchronous. These guarantees are provided by | ||
| 9 | fixed-block filesystems such as UFS and by journaling filesystems. Under | ||
| 10 | Linux, make sure that all mail-handling filesystems are mounted with | ||
| 11 | synchronous metadata. | ||
diff --git a/conf-spawn b/conf-spawn new file mode 100644 index 0000000..d6a4256 --- /dev/null +++ b/conf-spawn | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | 120 | ||
| 2 | |||
| 3 | This is a silent concurrency limit. You can't set it above 255. On some | ||
| 4 | systems you can't set it above 125. qmail will refuse to compile if the | ||
| 5 | limit is too high. | ||
diff --git a/conf-split b/conf-split new file mode 100644 index 0000000..dc6aaf1 --- /dev/null +++ b/conf-split | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | 23 | ||
| 2 | |||
| 3 | This is the queue subdirectory split. | ||
diff --git a/conf-users b/conf-users new file mode 100644 index 0000000..9bb35df --- /dev/null +++ b/conf-users | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | alias | ||
| 2 | qmaild | ||
| 3 | qmaill | ||
| 4 | root | ||
| 5 | qmailp | ||
| 6 | qmailq | ||
| 7 | qmailr | ||
| 8 | qmails | ||
| 9 | |||
| 10 | The qmail system is heavily partitioned for security; it does almost | ||
| 11 | nothing as root. | ||
| 12 | |||
| 13 | The first eight lines of this file are the alias user, the daemon user, | ||
| 14 | the log user, the owner of miscellaneous files such as binaries, the | ||
| 15 | passwd user, the queue user, the remote user, and the send user. | ||
diff --git a/config-fast.sh b/config-fast.sh new file mode 100644 index 0000000..d05cda9 --- /dev/null +++ b/config-fast.sh | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | fqdn="$1" | ||
| 2 | echo Your fully qualified host name is "$fqdn". | ||
| 3 | |||
| 4 | echo Putting "$fqdn" into control/me... | ||
| 5 | echo "$fqdn" > QMAIL/control/me | ||
| 6 | chmod 644 QMAIL/control/me | ||
| 7 | |||
| 8 | ( echo "$fqdn" | sed 's/^\([^\.]*\)\.\([^\.]*\)\./\2\./' | ( | ||
| 9 | read ddom | ||
| 10 | echo Putting "$ddom" into control/defaultdomain... | ||
| 11 | echo "$ddom" > QMAIL/control/defaultdomain | ||
| 12 | chmod 644 QMAIL/control/defaultdomain | ||
| 13 | ) ) | ||
| 14 | |||
| 15 | ( echo "$fqdn" | sed 's/^.*\.\([^\.]*\)\.\([^\.]*\)$/\1.\2/' | ( | ||
| 16 | read pdom | ||
| 17 | echo Putting "$pdom" into control/plusdomain... | ||
| 18 | echo "$pdom" > QMAIL/control/plusdomain | ||
| 19 | chmod 644 QMAIL/control/plusdomain | ||
| 20 | ) ) | ||
| 21 | |||
| 22 | echo Putting "$fqdn" into control/locals... | ||
| 23 | echo "$fqdn" >> QMAIL/control/locals | ||
| 24 | chmod 644 QMAIL/control/locals | ||
| 25 | |||
| 26 | echo Putting "$fqdn" into control/rcpthosts... | ||
| 27 | echo "$fqdn" >> QMAIL/control/rcpthosts | ||
| 28 | chmod 644 QMAIL/control/rcpthosts | ||
| 29 | echo "Now qmail will refuse to accept SMTP messages except to $fqdn." | ||
| 30 | echo 'Make sure to change rcpthosts if you add hosts to locals or virtualdomains!' | ||
diff --git a/config.sh b/config.sh new file mode 100644 index 0000000..8450070 --- /dev/null +++ b/config.sh | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | ./hostname | tr '[A-Z]' '[a-z]' | ( | ||
| 2 | if read host | ||
| 3 | then | ||
| 4 | echo Your hostname is "$host". | ||
| 5 | ./dnsfq "$host" | tr '[A-Z]' '[a-z]' | ( | ||
| 6 | if read fqdn | ||
| 7 | then | ||
| 8 | echo Your host\'s fully qualified name in DNS is "$fqdn". | ||
| 9 | echo Putting "$fqdn" into control/me... | ||
| 10 | echo "$fqdn" > QMAIL/control/me | ||
| 11 | chmod 644 QMAIL/control/me | ||
| 12 | ( echo "$fqdn" | sed 's/^\([^\.]*\)\.\([^\.]*\)\./\2\./' | ( | ||
| 13 | read ddom | ||
| 14 | echo Putting "$ddom" into control/defaultdomain... | ||
| 15 | echo "$ddom" > QMAIL/control/defaultdomain | ||
| 16 | chmod 644 QMAIL/control/defaultdomain | ||
| 17 | ) ) | ||
| 18 | ( echo "$fqdn" | sed 's/^.*\.\([^\.]*\)\.\([^\.]*\)$/\1.\2/' | ( | ||
| 19 | read pdom | ||
| 20 | echo Putting "$pdom" into control/plusdomain... | ||
| 21 | echo "$pdom" > QMAIL/control/plusdomain | ||
| 22 | chmod 644 QMAIL/control/plusdomain | ||
| 23 | ) ) | ||
| 24 | echo ' ' | ||
| 25 | echo Checking local IP addresses: | ||
| 26 | : > QMAIL/control/locals | ||
| 27 | chmod 644 QMAIL/control/locals | ||
| 28 | ( ./dnsip "$fqdn" | ||
| 29 | ./ipmeprint ) | sort -u | \ | ||
| 30 | ( | ||
| 31 | while read localip | ||
| 32 | do | ||
| 33 | echo "$localip: " | tr -d '\012' | ||
| 34 | ./dnsptr "$localip" 2>/dev/null | ( | ||
| 35 | if read local | ||
| 36 | then | ||
| 37 | echo Adding "$local" to control/locals... | ||
| 38 | echo "$local" >> QMAIL/control/locals | ||
| 39 | else | ||
| 40 | echo PTR lookup failed. I assume this address has no DNS name. | ||
| 41 | fi | ||
| 42 | ) | ||
| 43 | done | ||
| 44 | ) | ||
| 45 | echo ' ' | ||
| 46 | echo If there are any other domain names that point to you, | ||
| 47 | echo you will have to add them to QMAIL/control/locals. | ||
| 48 | echo You don\'t have to worry about aliases, i.e., domains with CNAME records. | ||
| 49 | echo ' ' | ||
| 50 | echo Copying QMAIL/control/locals to QMAIL/control/rcpthosts... | ||
| 51 | cp QMAIL/control/locals QMAIL/control/rcpthosts | ||
| 52 | chmod 644 QMAIL/control/rcpthosts | ||
| 53 | echo 'Now qmail will refuse to accept SMTP messages except to those hosts.' | ||
| 54 | echo 'Make sure to change rcpthosts if you add hosts to locals or virtualdomains!' | ||
| 55 | else | ||
| 56 | echo Sorry, I couldn\'t find your host\'s canonical name in DNS. | ||
| 57 | echo You will have to set up control/me yourself. | ||
| 58 | fi | ||
| 59 | ) | ||
| 60 | else | ||
| 61 | echo Sorry, I couldn\'t find your hostname. | ||
| 62 | echo You will have to set up control/me yourself. | ||
| 63 | fi | ||
| 64 | ) | ||
diff --git a/constmap.c b/constmap.c new file mode 100644 index 0000000..722e3b8 --- /dev/null +++ b/constmap.c | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | #include "constmap.h" | ||
| 2 | #include "alloc.h" | ||
| 3 | #include "case.h" | ||
| 4 | |||
| 5 | static constmap_hash hash(s,len) | ||
| 6 | char *s; | ||
| 7 | int len; | ||
| 8 | { | ||
| 9 | unsigned char ch; | ||
| 10 | constmap_hash h; | ||
| 11 | h = 5381; | ||
| 12 | while (len > 0) { | ||
| 13 | ch = *s++ - 'A'; | ||
| 14 | if (ch <= 'Z' - 'A') ch += 'a' - 'A'; | ||
| 15 | h = ((h << 5) + h) ^ ch; | ||
| 16 | --len; | ||
| 17 | } | ||
| 18 | return h; | ||
| 19 | } | ||
| 20 | |||
| 21 | char *constmap(cm,s,len) | ||
| 22 | struct constmap *cm; | ||
| 23 | char *s; | ||
| 24 | int len; | ||
| 25 | { | ||
| 26 | constmap_hash h; | ||
| 27 | int pos; | ||
| 28 | h = hash(s,len); | ||
| 29 | pos = cm->first[h & cm->mask]; | ||
| 30 | while (pos != -1) { | ||
| 31 | if (h == cm->hash[pos]) | ||
| 32 | if (len == cm->inputlen[pos]) | ||
| 33 | if (!case_diffb(cm->input[pos],len,s)) | ||
| 34 | return cm->input[pos] + cm->inputlen[pos] + 1; | ||
| 35 | pos = cm->next[pos]; | ||
| 36 | } | ||
| 37 | return 0; | ||
| 38 | } | ||
| 39 | |||
| 40 | int constmap_init(cm,s,len,flagcolon) | ||
| 41 | struct constmap *cm; | ||
| 42 | char *s; | ||
| 43 | int len; | ||
| 44 | int flagcolon; | ||
| 45 | { | ||
| 46 | int i; | ||
| 47 | int j; | ||
| 48 | int k; | ||
| 49 | int pos; | ||
| 50 | constmap_hash h; | ||
| 51 | |||
| 52 | cm->num = 0; | ||
| 53 | for (j = 0;j < len;++j) if (!s[j]) ++cm->num; | ||
| 54 | |||
| 55 | h = 64; | ||
| 56 | while (h && (h < cm->num)) h += h; | ||
| 57 | cm->mask = h - 1; | ||
| 58 | |||
| 59 | cm->first = (int *) alloc(sizeof(int) * h); | ||
| 60 | if (cm->first) { | ||
| 61 | cm->input = (char **) alloc(sizeof(char *) * cm->num); | ||
| 62 | if (cm->input) { | ||
| 63 | cm->inputlen = (int *) alloc(sizeof(int) * cm->num); | ||
| 64 | if (cm->inputlen) { | ||
| 65 | cm->hash = (constmap_hash *) alloc(sizeof(constmap_hash) * cm->num); | ||
| 66 | if (cm->hash) { | ||
| 67 | cm->next = (int *) alloc(sizeof(int) * cm->num); | ||
| 68 | if (cm->next) { | ||
| 69 | for (h = 0;h <= cm->mask;++h) | ||
| 70 | cm->first[h] = -1; | ||
| 71 | pos = 0; | ||
| 72 | i = 0; | ||
| 73 | for (j = 0;j < len;++j) | ||
| 74 | if (!s[j]) { | ||
| 75 | k = j - i; | ||
| 76 | if (flagcolon) { | ||
| 77 | for (k = i;k < j;++k) | ||
| 78 | if (s[k] == ':') | ||
| 79 | break; | ||
| 80 | if (k >= j) { i = j + 1; continue; } | ||
| 81 | k -= i; | ||
| 82 | } | ||
| 83 | cm->input[pos] = s + i; | ||
| 84 | cm->inputlen[pos] = k; | ||
| 85 | h = hash(s + i,k); | ||
| 86 | cm->hash[pos] = h; | ||
| 87 | h &= cm->mask; | ||
| 88 | cm->next[pos] = cm->first[h]; | ||
| 89 | cm->first[h] = pos; | ||
| 90 | ++pos; | ||
| 91 | i = j + 1; | ||
| 92 | } | ||
| 93 | return 1; | ||
| 94 | } | ||
| 95 | alloc_free(cm->hash); | ||
| 96 | } | ||
| 97 | alloc_free(cm->inputlen); | ||
| 98 | } | ||
| 99 | alloc_free(cm->input); | ||
| 100 | } | ||
| 101 | alloc_free(cm->first); | ||
| 102 | } | ||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | void constmap_free(cm) | ||
| 107 | struct constmap *cm; | ||
| 108 | { | ||
| 109 | alloc_free(cm->next); | ||
| 110 | alloc_free(cm->hash); | ||
| 111 | alloc_free(cm->inputlen); | ||
| 112 | alloc_free(cm->input); | ||
| 113 | alloc_free(cm->first); | ||
| 114 | } | ||
diff --git a/constmap.h b/constmap.h new file mode 100644 index 0000000..3f29179 --- /dev/null +++ b/constmap.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | #ifndef CONSTMAP_H | ||
| 2 | #define CONSTMAP_H | ||
| 3 | |||
| 4 | typedef unsigned long constmap_hash; | ||
| 5 | |||
| 6 | struct constmap { | ||
| 7 | int num; | ||
| 8 | constmap_hash mask; | ||
| 9 | constmap_hash *hash; | ||
| 10 | int *first; | ||
| 11 | int *next; | ||
| 12 | char **input; | ||
| 13 | int *inputlen; | ||
| 14 | } ; | ||
| 15 | |||
| 16 | extern int constmap_init(); | ||
| 17 | extern void constmap_free(); | ||
| 18 | extern char *constmap(); | ||
| 19 | |||
| 20 | #endif | ||
diff --git a/control.c b/control.c new file mode 100644 index 0000000..b655352 --- /dev/null +++ b/control.c | |||
| @@ -0,0 +1,130 @@ | |||
| 1 | #include "readwrite.h" | ||
| 2 | #include "open.h" | ||
| 3 | #include "getln.h" | ||
| 4 | #include "stralloc.h" | ||
| 5 | #include "substdio.h" | ||
| 6 | #include "error.h" | ||
| 7 | #include "control.h" | ||
| 8 | #include "alloc.h" | ||
| 9 | #include "scan.h" | ||
| 10 | |||
| 11 | static char inbuf[64]; | ||
| 12 | static stralloc line = {0}; | ||
| 13 | static stralloc me = {0}; | ||
| 14 | static int meok = 0; | ||
| 15 | |||
| 16 | static void striptrailingwhitespace(sa) | ||
| 17 | stralloc *sa; | ||
| 18 | { | ||
| 19 | while (sa->len > 0) | ||
| 20 | switch(sa->s[sa->len - 1]) | ||
| 21 | { | ||
| 22 | case '\n': case ' ': case '\t': | ||
| 23 | --sa->len; | ||
| 24 | break; | ||
| 25 | default: | ||
| 26 | return; | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | int control_init() | ||
| 31 | { | ||
| 32 | int r; | ||
| 33 | r = control_readline(&me,"control/me"); | ||
| 34 | if (r == 1) meok = 1; | ||
| 35 | return r; | ||
| 36 | } | ||
| 37 | |||
| 38 | int control_rldef(sa,fn,flagme,def) | ||
| 39 | stralloc *sa; | ||
| 40 | char *fn; | ||
| 41 | int flagme; | ||
| 42 | char *def; | ||
| 43 | { | ||
| 44 | int r; | ||
| 45 | r = control_readline(sa,fn); | ||
| 46 | if (r) return r; | ||
| 47 | if (flagme) if (meok) return stralloc_copy(sa,&me) ? 1 : -1; | ||
| 48 | if (def) return stralloc_copys(sa,def) ? 1 : -1; | ||
| 49 | return r; | ||
| 50 | } | ||
| 51 | |||
| 52 | int control_readline(sa,fn) | ||
| 53 | stralloc *sa; | ||
| 54 | char *fn; | ||
| 55 | { | ||
| 56 | substdio ss; | ||
| 57 | int fd; | ||
| 58 | int match; | ||
| 59 | |||
| 60 | fd = open_read(fn); | ||
| 61 | if (fd == -1) { if (errno == error_noent) return 0; return -1; } | ||
| 62 | |||
| 63 | substdio_fdbuf(&ss,read,fd,inbuf,sizeof(inbuf)); | ||
| 64 | |||
| 65 | if (getln(&ss,sa,&match,'\n') == -1) { close(fd); return -1; } | ||
| 66 | |||
| 67 | striptrailingwhitespace(sa); | ||
| 68 | close(fd); | ||
| 69 | return 1; | ||
| 70 | } | ||
| 71 | |||
| 72 | int control_readint(i,fn) | ||
| 73 | int *i; | ||
| 74 | char *fn; | ||
| 75 | { | ||
| 76 | unsigned long u; | ||
| 77 | switch(control_readline(&line,fn)) | ||
| 78 | { | ||
| 79 | case 0: return 0; | ||
| 80 | case -1: return -1; | ||
| 81 | } | ||
| 82 | if (!stralloc_0(&line)) return -1; | ||
| 83 | if (!scan_ulong(line.s,&u)) return 0; | ||
| 84 | *i = u; | ||
| 85 | return 1; | ||
| 86 | } | ||
| 87 | |||
| 88 | int control_readfile(sa,fn,flagme) | ||
| 89 | stralloc *sa; | ||
| 90 | char *fn; | ||
| 91 | int flagme; | ||
| 92 | { | ||
| 93 | substdio ss; | ||
| 94 | int fd; | ||
| 95 | int match; | ||
| 96 | |||
| 97 | if (!stralloc_copys(sa,"")) return -1; | ||
| 98 | |||
| 99 | fd = open_read(fn); | ||
| 100 | if (fd == -1) | ||
| 101 | { | ||
| 102 | if (errno == error_noent) | ||
| 103 | { | ||
| 104 | if (flagme && meok) | ||
| 105 | { | ||
| 106 | if (!stralloc_copy(sa,&me)) return -1; | ||
| 107 | if (!stralloc_0(sa)) return -1; | ||
| 108 | return 1; | ||
| 109 | } | ||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | return -1; | ||
| 113 | } | ||
| 114 | |||
| 115 | substdio_fdbuf(&ss,read,fd,inbuf,sizeof(inbuf)); | ||
| 116 | |||
| 117 | for (;;) | ||
| 118 | { | ||
| 119 | if (getln(&ss,&line,&match,'\n') == -1) break; | ||
| 120 | if (!match && !line.len) { close(fd); return 1; } | ||
| 121 | striptrailingwhitespace(&line); | ||
| 122 | if (!stralloc_0(&line)) break; | ||
| 123 | if (line.s[0]) | ||
| 124 | if (line.s[0] != '#') | ||
| 125 | if (!stralloc_cat(sa,&line)) break; | ||
| 126 | if (!match) { close(fd); return 1; } | ||
| 127 | } | ||
| 128 | close(fd); | ||
| 129 | return -1; | ||
| 130 | } | ||
diff --git a/control.h b/control.h new file mode 100644 index 0000000..7cba89b --- /dev/null +++ b/control.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #ifndef CONTROL_H | ||
| 2 | #define CONTROL_H | ||
| 3 | |||
| 4 | extern int control_init(); | ||
| 5 | extern int control_readline(); | ||
| 6 | extern int control_rldef(); | ||
| 7 | extern int control_readint(); | ||
| 8 | extern int control_readfile(); | ||
| 9 | |||
| 10 | #endif | ||
diff --git a/date822fmt.c b/date822fmt.c new file mode 100644 index 0000000..7674bd1 --- /dev/null +++ b/date822fmt.c | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | #include "datetime.h" | ||
| 2 | #include "fmt.h" | ||
| 3 | #include "date822fmt.h" | ||
| 4 | |||
| 5 | static char *montab[12] = { | ||
| 6 | "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" | ||
| 7 | }; | ||
| 8 | |||
| 9 | unsigned int date822fmt(s,dt) | ||
| 10 | char *s; | ||
| 11 | struct datetime *dt; | ||
| 12 | { | ||
| 13 | unsigned int i; | ||
| 14 | unsigned int len; | ||
| 15 | len = 0; | ||
| 16 | i = fmt_uint(s,dt->mday); len += i; if (s) s += i; | ||
| 17 | i = fmt_str(s," "); len += i; if (s) s += i; | ||
| 18 | i = fmt_str(s,montab[dt->mon]); len += i; if (s) s += i; | ||
| 19 | i = fmt_str(s," "); len += i; if (s) s += i; | ||
| 20 | i = fmt_uint(s,dt->year + 1900); len += i; if (s) s += i; | ||
| 21 | i = fmt_str(s," "); len += i; if (s) s += i; | ||
| 22 | i = fmt_uint0(s,dt->hour,2); len += i; if (s) s += i; | ||
| 23 | i = fmt_str(s,":"); len += i; if (s) s += i; | ||
| 24 | i = fmt_uint0(s,dt->min,2); len += i; if (s) s += i; | ||
| 25 | i = fmt_str(s,":"); len += i; if (s) s += i; | ||
| 26 | i = fmt_uint0(s,dt->sec,2); len += i; if (s) s += i; | ||
| 27 | i = fmt_str(s," -0000\n"); len += i; if (s) s += i; | ||
| 28 | return len; | ||
| 29 | } | ||
diff --git a/date822fmt.h b/date822fmt.h new file mode 100644 index 0000000..1848e5a --- /dev/null +++ b/date822fmt.h | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef DATE822FMT_H | ||
| 2 | #define DATE822FMT_H | ||
| 3 | |||
| 4 | extern unsigned int date822fmt(); | ||
| 5 | #define DATE822FMT 60 | ||
| 6 | |||
| 7 | #endif | ||
diff --git a/datemail.sh b/datemail.sh new file mode 100644 index 0000000..fd28f46 --- /dev/null +++ b/datemail.sh | |||
| @@ -0,0 +1 @@ | |||
| exec QMAIL/bin/predate QMAIL/bin/sendmail ${1+"$@"} | |||
diff --git a/datetime.3 b/datetime.3 new file mode 100644 index 0000000..33a623f --- /dev/null +++ b/datetime.3 | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | .TH datetime 3 | ||
| 2 | .SH NAME | ||
| 3 | datetime \- convert between TAI labels and seconds | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <datetime.h> | ||
| 6 | |||
| 7 | void \fBdatetime_tai\fP(&\fIdt\fR,\fIt\fR); | ||
| 8 | |||
| 9 | datetime_sec \fBdatetime_untai\fP(&\fIdt\fR); | ||
| 10 | |||
| 11 | struct datetime \fIdt\fR; | ||
| 12 | .br | ||
| 13 | datetime_sec \fIt\fR; | ||
| 14 | .SH DESCRIPTION | ||
| 15 | International Atomic Time, TAI, | ||
| 16 | is the fundamental unit for time measurements. | ||
| 17 | TAI has one label for every second of real time, | ||
| 18 | without complications such as leap seconds. | ||
| 19 | |||
| 20 | A | ||
| 21 | struct datetime | ||
| 22 | variable, | ||
| 23 | such as | ||
| 24 | .IR dt , | ||
| 25 | stores a TAI label. | ||
| 26 | .I dt\fB.year | ||
| 27 | is the year number minus 1900; | ||
| 28 | .I dt\fB.mon | ||
| 29 | is the month number, from 0 (January) through 11 (December); | ||
| 30 | .I dt\fB.mday | ||
| 31 | is the day of the month, from 1 through 31; | ||
| 32 | .I dt\fB.hour | ||
| 33 | is the hour, from 0 through 23; | ||
| 34 | .I dt\fB.min | ||
| 35 | is the minute, from 0 through 59; | ||
| 36 | .I dt\fB.sec | ||
| 37 | is the second, from 0 through 59; | ||
| 38 | .I dt\fB.wday | ||
| 39 | is the day of the week, from 0 (Sunday) through 6 (Saturday); | ||
| 40 | .I dt\fB.yday | ||
| 41 | is the day of the year, from 0 through 365. | ||
| 42 | |||
| 43 | The | ||
| 44 | .B datetime | ||
| 45 | library supports more convenient TAI manipulation with | ||
| 46 | the datetime_sec type. | ||
| 47 | A datetime_sec value, such as | ||
| 48 | .IR t , | ||
| 49 | is an integer referring to the | ||
| 50 | .IR t th | ||
| 51 | second after the beginning of 1970 TAI. | ||
| 52 | The first second of 1970 TAI was 0; | ||
| 53 | the next second was 1; | ||
| 54 | the last second of 1969 TAI was -1. | ||
| 55 | The difference between two datetime_sec values is a number | ||
| 56 | of real-time seconds. | ||
| 57 | |||
| 58 | .B datetime_tai | ||
| 59 | converts a datetime_sec to a TAI label. | ||
| 60 | |||
| 61 | .B datetime_untai | ||
| 62 | reads a TAI label | ||
| 63 | (specifically | ||
| 64 | .IR dt\fB.year , | ||
| 65 | .IR dt\fB.mon , | ||
| 66 | .IR dt\fB.mday , | ||
| 67 | .IR dt\fB.hour , | ||
| 68 | .IR dt\fB.min , | ||
| 69 | and | ||
| 70 | .IR dt\fB.sec ) | ||
| 71 | and returns a datetime_sec. | ||
| 72 | .SH "SEE ALSO" | ||
| 73 | now(3) | ||
diff --git a/datetime.c b/datetime.c new file mode 100644 index 0000000..7b8a803 --- /dev/null +++ b/datetime.c | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | /* 19950925 */ | ||
| 2 | #include "datetime.h" | ||
| 3 | |||
| 4 | void datetime_tai(dt,t) | ||
| 5 | struct datetime *dt; | ||
| 6 | datetime_sec t; | ||
| 7 | { | ||
| 8 | int day; | ||
| 9 | int tod; | ||
| 10 | int year; | ||
| 11 | int yday; | ||
| 12 | int wday; | ||
| 13 | int mon; | ||
| 14 | |||
| 15 | tod = t % 86400; | ||
| 16 | day = t / 86400; | ||
| 17 | if (tod < 0) { tod += 86400; --day; } | ||
| 18 | |||
| 19 | dt->hour = tod / 3600; | ||
| 20 | tod %= 3600; | ||
| 21 | dt->min = tod / 60; | ||
| 22 | dt->sec = tod % 60; | ||
| 23 | |||
| 24 | wday = (day + 4) % 7; if (wday < 0) wday += 7; | ||
| 25 | dt->wday = wday; | ||
| 26 | |||
| 27 | day -= 11017; | ||
| 28 | /* day 0 is march 1, 2000 */ | ||
| 29 | year = 5 + day / 146097; | ||
| 30 | day = day % 146097; if (day < 0) { day += 146097; --year; } | ||
| 31 | /* from now on, day is nonnegative */ | ||
| 32 | year *= 4; | ||
| 33 | if (day == 146096) { year += 3; day = 36524; } | ||
| 34 | else { year += day / 36524; day %= 36524; } | ||
| 35 | year *= 25; | ||
| 36 | year += day / 1461; | ||
| 37 | day %= 1461; | ||
| 38 | year *= 4; | ||
| 39 | yday = (day < 306); | ||
| 40 | if (day == 1460) { year += 3; day = 365; } | ||
| 41 | else { year += day / 365; day %= 365; } | ||
| 42 | yday += day; | ||
| 43 | |||
| 44 | day *= 10; | ||
| 45 | mon = (day + 5) / 306; | ||
| 46 | day = day + 5 - 306 * mon; | ||
| 47 | day /= 10; | ||
| 48 | if (mon >= 10) { yday -= 306; ++year; mon -= 10; } | ||
| 49 | else { yday += 59; mon += 2; } | ||
| 50 | |||
| 51 | dt->yday = yday; | ||
| 52 | dt->year = year - 1900; | ||
| 53 | dt->mon = mon; | ||
| 54 | dt->mday = day + 1; | ||
| 55 | } | ||
diff --git a/datetime.h b/datetime.h new file mode 100644 index 0000000..cde2a9b --- /dev/null +++ b/datetime.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | #ifndef DATETIME_H | ||
| 2 | #define DATETIME_H | ||
| 3 | |||
| 4 | struct datetime { | ||
| 5 | int hour; | ||
| 6 | int min; | ||
| 7 | int sec; | ||
| 8 | int wday; | ||
| 9 | int mday; | ||
| 10 | int yday; | ||
| 11 | int mon; | ||
| 12 | int year; | ||
| 13 | } ; | ||
| 14 | |||
| 15 | typedef long datetime_sec; | ||
| 16 | |||
| 17 | extern void datetime_tai(); | ||
| 18 | extern datetime_sec datetime_untai(); | ||
| 19 | |||
| 20 | #endif | ||
diff --git a/datetime_un.c b/datetime_un.c new file mode 100644 index 0000000..b5048f8 --- /dev/null +++ b/datetime_un.c | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | #include "datetime.h" | ||
| 2 | |||
| 3 | /* roughly 100x faster than mktime() */ | ||
| 4 | datetime_sec datetime_untai(dt) | ||
| 5 | struct datetime *dt; | ||
| 6 | { | ||
| 7 | int year; | ||
| 8 | int day; | ||
| 9 | int mon; | ||
| 10 | |||
| 11 | year = dt->year + 1900; | ||
| 12 | |||
| 13 | mon = dt->mon; | ||
| 14 | if (mon >= 2) { mon -= 2; } | ||
| 15 | else { mon += 10; --year; } | ||
| 16 | |||
| 17 | day = (dt->mday - 1) * 10 + 5 + 306 * mon; | ||
| 18 | day /= 10; | ||
| 19 | |||
| 20 | if (day == 365) { year -= 3; day = 1460; } | ||
| 21 | else { day += 365 * (year % 4); } | ||
| 22 | year /= 4; | ||
| 23 | |||
| 24 | day += 1461 * (year % 25); | ||
| 25 | year /= 25; | ||
| 26 | |||
| 27 | if (day == 36524) { year -= 3; day = 146096; } | ||
| 28 | else { day += 36524 * (year % 4); } | ||
| 29 | year /= 4; | ||
| 30 | |||
| 31 | day += 146097 * (year - 5); | ||
| 32 | day += 11017; | ||
| 33 | |||
| 34 | return ((day * 24 + dt->hour) * 60 + dt->min) * 60 + dt->sec; | ||
| 35 | } | ||
diff --git a/direntry.3 b/direntry.3 new file mode 100644 index 0000000..8928fbb --- /dev/null +++ b/direntry.3 | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | .TH direntry 3 | ||
| 2 | .SH NAME | ||
| 3 | direntry \- read directory entries | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <direntry.h> | ||
| 6 | |||
| 7 | DIR *\fBopendir\fP(\fIfn\fR); | ||
| 8 | |||
| 9 | struct direntry *\fBreaddir\fP(\fIdir\fP); | ||
| 10 | |||
| 11 | void \fBclosedir\fP(\fIdir\fP); | ||
| 12 | |||
| 13 | DIR *\fIdir\fR; | ||
| 14 | .br | ||
| 15 | char *\fIfn\fR; | ||
| 16 | .SH DESCRIPTION | ||
| 17 | The point of | ||
| 18 | .B direntry.h | ||
| 19 | is to provide a uniform interface to BSD's | ||
| 20 | .B sys/dir.h | ||
| 21 | and POSIX's | ||
| 22 | .BR dirent.h . | ||
| 23 | |||
| 24 | The | ||
| 25 | .B readdir | ||
| 26 | interface is highly unsatisfactory. | ||
| 27 | It does not distinguish between I/O errors and end-of-directory. | ||
| 28 | It uses | ||
| 29 | .BR malloc . | ||
| 30 | The return type for | ||
| 31 | .B closedir | ||
| 32 | varies: some implementations return the | ||
| 33 | .B close | ||
| 34 | return value. | ||
| 35 | .SH "SEE ALSO" | ||
| 36 | readdir(3) | ||
diff --git a/direntry.h1 b/direntry.h1 new file mode 100644 index 0000000..f737676 --- /dev/null +++ b/direntry.h1 | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef DIRENTRY_H | ||
| 2 | #define DIRENTRY_H | ||
| 3 | |||
| 4 | #include <sys/types.h> | ||
| 5 | #include <sys/dir.h> | ||
| 6 | #define direntry struct direct | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/direntry.h2 b/direntry.h2 new file mode 100644 index 0000000..0302ebe --- /dev/null +++ b/direntry.h2 | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef DIRENTRY_H | ||
| 2 | #define DIRENTRY_H | ||
| 3 | |||
| 4 | #include <sys/types.h> | ||
| 5 | #include <dirent.h> | ||
| 6 | #define direntry struct dirent | ||
| 7 | |||
| 8 | #endif | ||
| @@ -0,0 +1,400 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <netdb.h> | ||
| 3 | #include <sys/types.h> | ||
| 4 | #include <netinet/in.h> | ||
| 5 | #include <arpa/nameser.h> | ||
| 6 | #include <resolv.h> | ||
| 7 | #include <errno.h> | ||
| 8 | extern int res_query(); | ||
| 9 | extern int res_search(); | ||
| 10 | extern int errno; | ||
| 11 | extern int h_errno; | ||
| 12 | #include "ip.h" | ||
| 13 | #include "ipalloc.h" | ||
| 14 | #include "fmt.h" | ||
| 15 | #include "alloc.h" | ||
| 16 | #include "str.h" | ||
| 17 | #include "stralloc.h" | ||
| 18 | #include "dns.h" | ||
| 19 | #include "case.h" | ||
| 20 | |||
| 21 | static unsigned short getshort(c) unsigned char *c; | ||
| 22 | { unsigned short u; u = c[0]; return (u << 8) + c[1]; } | ||
| 23 | |||
| 24 | static union { HEADER hdr; unsigned char buf[PACKETSZ]; } response; | ||
| 25 | static int responselen; | ||
| 26 | static unsigned char *responseend; | ||
| 27 | static unsigned char *responsepos; | ||
| 28 | |||
| 29 | static int numanswers; | ||
| 30 | static char name[MAXDNAME]; | ||
| 31 | static struct ip_address ip; | ||
| 32 | unsigned short pref; | ||
| 33 | |||
| 34 | static stralloc glue = {0}; | ||
| 35 | |||
| 36 | static int (*lookup)() = res_query; | ||
| 37 | |||
| 38 | static int resolve(domain,type) | ||
| 39 | stralloc *domain; | ||
| 40 | int type; | ||
| 41 | { | ||
| 42 | int n; | ||
| 43 | int i; | ||
| 44 | |||
| 45 | errno = 0; | ||
| 46 | if (!stralloc_copy(&glue,domain)) return DNS_MEM; | ||
| 47 | if (!stralloc_0(&glue)) return DNS_MEM; | ||
| 48 | responselen = lookup(glue.s,C_IN,type,response.buf,sizeof(response)); | ||
| 49 | if (responselen <= 0) | ||
| 50 | { | ||
| 51 | if (errno == ECONNREFUSED) return DNS_SOFT; | ||
| 52 | if (h_errno == TRY_AGAIN) return DNS_SOFT; | ||
| 53 | return DNS_HARD; | ||
| 54 | } | ||
| 55 | if (responselen >= sizeof(response)) | ||
| 56 | responselen = sizeof(response); | ||
| 57 | responseend = response.buf + responselen; | ||
| 58 | responsepos = response.buf + sizeof(HEADER); | ||
| 59 | n = ntohs(response.hdr.qdcount); | ||
| 60 | while (n-- > 0) | ||
| 61 | { | ||
| 62 | i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); | ||
| 63 | if (i < 0) return DNS_SOFT; | ||
| 64 | responsepos += i; | ||
| 65 | i = responseend - responsepos; | ||
| 66 | if (i < QFIXEDSZ) return DNS_SOFT; | ||
| 67 | responsepos += QFIXEDSZ; | ||
| 68 | } | ||
| 69 | numanswers = ntohs(response.hdr.ancount); | ||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | static int findname(wanttype) | ||
| 74 | int wanttype; | ||
| 75 | { | ||
| 76 | unsigned short rrtype; | ||
| 77 | unsigned short rrdlen; | ||
| 78 | int i; | ||
| 79 | |||
| 80 | if (numanswers <= 0) return 2; | ||
| 81 | --numanswers; | ||
| 82 | if (responsepos == responseend) return DNS_SOFT; | ||
| 83 | |||
| 84 | i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); | ||
| 85 | if (i < 0) return DNS_SOFT; | ||
| 86 | responsepos += i; | ||
| 87 | |||
| 88 | i = responseend - responsepos; | ||
| 89 | if (i < 4 + 3 * 2) return DNS_SOFT; | ||
| 90 | |||
| 91 | rrtype = getshort(responsepos); | ||
| 92 | rrdlen = getshort(responsepos + 8); | ||
| 93 | responsepos += 10; | ||
| 94 | |||
| 95 | if (rrtype == wanttype) | ||
| 96 | { | ||
| 97 | if (dn_expand(response.buf,responseend,responsepos,name,MAXDNAME) < 0) | ||
| 98 | return DNS_SOFT; | ||
| 99 | responsepos += rrdlen; | ||
| 100 | return 1; | ||
| 101 | } | ||
| 102 | |||
| 103 | responsepos += rrdlen; | ||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | static int findip(wanttype) | ||
| 108 | int wanttype; | ||
| 109 | { | ||
| 110 | unsigned short rrtype; | ||
| 111 | unsigned short rrdlen; | ||
| 112 | int i; | ||
| 113 | |||
| 114 | if (numanswers <= 0) return 2; | ||
| 115 | --numanswers; | ||
| 116 | if (responsepos == responseend) return DNS_SOFT; | ||
| 117 | |||
| 118 | i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); | ||
| 119 | if (i < 0) return DNS_SOFT; | ||
| 120 | responsepos += i; | ||
| 121 | |||
| 122 | i = responseend - responsepos; | ||
| 123 | if (i < 4 + 3 * 2) return DNS_SOFT; | ||
| 124 | |||
| 125 | rrtype = getshort(responsepos); | ||
| 126 | rrdlen = getshort(responsepos + 8); | ||
| 127 | responsepos += 10; | ||
| 128 | |||
| 129 | if (rrtype == wanttype) | ||
| 130 | { | ||
| 131 | if (rrdlen < 4) | ||
| 132 | return DNS_SOFT; | ||
| 133 | ip.d[0] = responsepos[0]; | ||
| 134 | ip.d[1] = responsepos[1]; | ||
| 135 | ip.d[2] = responsepos[2]; | ||
| 136 | ip.d[3] = responsepos[3]; | ||
| 137 | responsepos += rrdlen; | ||
| 138 | return 1; | ||
| 139 | } | ||
| 140 | |||
| 141 | responsepos += rrdlen; | ||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | |||
| 145 | static int findmx(wanttype) | ||
| 146 | int wanttype; | ||
| 147 | { | ||
| 148 | unsigned short rrtype; | ||
| 149 | unsigned short rrdlen; | ||
| 150 | int i; | ||
| 151 | |||
| 152 | if (numanswers <= 0) return 2; | ||
| 153 | --numanswers; | ||
| 154 | if (responsepos == responseend) return DNS_SOFT; | ||
| 155 | |||
| 156 | i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); | ||
| 157 | if (i < 0) return DNS_SOFT; | ||
| 158 | responsepos += i; | ||
| 159 | |||
| 160 | i = responseend - responsepos; | ||
| 161 | if (i < 4 + 3 * 2) return DNS_SOFT; | ||
| 162 | |||
| 163 | rrtype = getshort(responsepos); | ||
| 164 | rrdlen = getshort(responsepos + 8); | ||
| 165 | responsepos += 10; | ||
| 166 | |||
| 167 | if (rrtype == wanttype) | ||
| 168 | { | ||
| 169 | if (rrdlen < 3) | ||
| 170 | return DNS_SOFT; | ||
| 171 | pref = (responsepos[0] << 8) + responsepos[1]; | ||
| 172 | if (dn_expand(response.buf,responseend,responsepos + 2,name,MAXDNAME) < 0) | ||
| 173 | return DNS_SOFT; | ||
| 174 | responsepos += rrdlen; | ||
| 175 | return 1; | ||
| 176 | } | ||
| 177 | |||
| 178 | responsepos += rrdlen; | ||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | void dns_init(flagsearch) | ||
| 183 | int flagsearch; | ||
| 184 | { | ||
| 185 | res_init(); | ||
| 186 | if (flagsearch) lookup = res_search; | ||
| 187 | } | ||
| 188 | |||
| 189 | int dns_cname(sa) | ||
| 190 | stralloc *sa; | ||
| 191 | { | ||
| 192 | int r; | ||
| 193 | int loop; | ||
| 194 | for (loop = 0;loop < 10;++loop) | ||
| 195 | { | ||
| 196 | if (!sa->len) return loop; | ||
| 197 | if (sa->s[sa->len - 1] == ']') return loop; | ||
| 198 | if (sa->s[sa->len - 1] == '.') { --sa->len; continue; } | ||
| 199 | switch(resolve(sa,T_ANY)) | ||
| 200 | { | ||
| 201 | case DNS_MEM: return DNS_MEM; | ||
| 202 | case DNS_SOFT: return DNS_SOFT; | ||
| 203 | case DNS_HARD: return loop; | ||
| 204 | default: | ||
| 205 | while ((r = findname(T_CNAME)) != 2) | ||
| 206 | { | ||
| 207 | if (r == DNS_SOFT) return DNS_SOFT; | ||
| 208 | if (r == 1) | ||
| 209 | { | ||
| 210 | if (!stralloc_copys(sa,name)) return DNS_MEM; | ||
| 211 | break; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | if (r == 2) return loop; | ||
| 215 | } | ||
| 216 | } | ||
| 217 | return DNS_HARD; /* alias loop */ | ||
| 218 | } | ||
| 219 | |||
| 220 | #define FMT_IAA 40 | ||
| 221 | |||
| 222 | static int iaafmt(s,ip) | ||
| 223 | char *s; | ||
| 224 | struct ip_address *ip; | ||
| 225 | { | ||
| 226 | unsigned int i; | ||
| 227 | unsigned int len; | ||
| 228 | len = 0; | ||
| 229 | i = fmt_ulong(s,(unsigned long) ip->d[3]); len += i; if (s) s += i; | ||
| 230 | i = fmt_str(s,"."); len += i; if (s) s += i; | ||
| 231 | i = fmt_ulong(s,(unsigned long) ip->d[2]); len += i; if (s) s += i; | ||
| 232 | i = fmt_str(s,"."); len += i; if (s) s += i; | ||
| 233 | i = fmt_ulong(s,(unsigned long) ip->d[1]); len += i; if (s) s += i; | ||
| 234 | i = fmt_str(s,"."); len += i; if (s) s += i; | ||
| 235 | i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i; | ||
| 236 | i = fmt_str(s,".in-addr.arpa."); len += i; if (s) s += i; | ||
| 237 | return len; | ||
| 238 | } | ||
| 239 | |||
| 240 | int dns_ptr(sa,ip) | ||
| 241 | stralloc *sa; | ||
| 242 | struct ip_address *ip; | ||
| 243 | { | ||
| 244 | int r; | ||
| 245 | |||
| 246 | if (!stralloc_ready(sa,iaafmt((char *) 0,ip))) return DNS_MEM; | ||
| 247 | sa->len = iaafmt(sa->s,ip); | ||
| 248 | switch(resolve(sa,T_PTR)) | ||
| 249 | { | ||
| 250 | case DNS_MEM: return DNS_MEM; | ||
| 251 | case DNS_SOFT: return DNS_SOFT; | ||
| 252 | case DNS_HARD: return DNS_HARD; | ||
| 253 | } | ||
| 254 | while ((r = findname(T_PTR)) != 2) | ||
| 255 | { | ||
| 256 | if (r == DNS_SOFT) return DNS_SOFT; | ||
| 257 | if (r == 1) | ||
| 258 | { | ||
| 259 | if (!stralloc_copys(sa,name)) return DNS_MEM; | ||
| 260 | return 0; | ||
| 261 | } | ||
| 262 | } | ||
| 263 | return DNS_HARD; | ||
| 264 | } | ||
| 265 | |||
| 266 | static int dns_ipplus(ia,sa,pref) | ||
| 267 | ipalloc *ia; | ||
| 268 | stralloc *sa; | ||
| 269 | int pref; | ||
| 270 | { | ||
| 271 | int r; | ||
| 272 | struct ip_mx ix; | ||
| 273 | |||
| 274 | if (!stralloc_copy(&glue,sa)) return DNS_MEM; | ||
| 275 | if (!stralloc_0(&glue)) return DNS_MEM; | ||
| 276 | if (glue.s[0]) { | ||
| 277 | ix.pref = 0; | ||
| 278 | if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)]) | ||
| 279 | { | ||
| 280 | if (!ipalloc_append(ia,&ix)) return DNS_MEM; | ||
| 281 | return 0; | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | switch(resolve(sa,T_A)) | ||
| 286 | { | ||
| 287 | case DNS_MEM: return DNS_MEM; | ||
| 288 | case DNS_SOFT: return DNS_SOFT; | ||
| 289 | case DNS_HARD: return DNS_HARD; | ||
| 290 | } | ||
| 291 | while ((r = findip(T_A)) != 2) | ||
| 292 | { | ||
| 293 | ix.ip = ip; | ||
| 294 | ix.pref = pref; | ||
| 295 | if (r == DNS_SOFT) return DNS_SOFT; | ||
| 296 | if (r == 1) | ||
| 297 | if (!ipalloc_append(ia,&ix)) return DNS_MEM; | ||
| 298 | } | ||
| 299 | return 0; | ||
| 300 | } | ||
| 301 | |||
| 302 | int dns_ip(ia,sa) | ||
| 303 | ipalloc *ia; | ||
| 304 | stralloc *sa; | ||
| 305 | { | ||
| 306 | if (!ipalloc_readyplus(ia,0)) return DNS_MEM; | ||
| 307 | ia->len = 0; | ||
| 308 | return dns_ipplus(ia,sa,0); | ||
| 309 | } | ||
| 310 | |||
| 311 | int dns_mxip(ia,sa,random) | ||
| 312 | ipalloc *ia; | ||
| 313 | stralloc *sa; | ||
| 314 | unsigned long random; | ||
| 315 | { | ||
| 316 | int r; | ||
| 317 | struct mx { stralloc sa; unsigned short p; } *mx; | ||
| 318 | struct ip_mx ix; | ||
| 319 | int nummx; | ||
| 320 | int i; | ||
| 321 | int j; | ||
| 322 | int flagsoft; | ||
| 323 | |||
| 324 | if (!ipalloc_readyplus(ia,0)) return DNS_MEM; | ||
| 325 | ia->len = 0; | ||
| 326 | |||
| 327 | if (!stralloc_copy(&glue,sa)) return DNS_MEM; | ||
| 328 | if (!stralloc_0(&glue)) return DNS_MEM; | ||
| 329 | if (glue.s[0]) { | ||
| 330 | ix.pref = 0; | ||
| 331 | if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)]) | ||
| 332 | { | ||
| 333 | if (!ipalloc_append(ia,&ix)) return DNS_MEM; | ||
| 334 | return 0; | ||
| 335 | } | ||
| 336 | } | ||
| 337 | |||
| 338 | switch(resolve(sa,T_MX)) | ||
| 339 | { | ||
| 340 | case DNS_MEM: return DNS_MEM; | ||
| 341 | case DNS_SOFT: return DNS_SOFT; | ||
| 342 | case DNS_HARD: return dns_ip(ia,sa); | ||
| 343 | } | ||
| 344 | |||
| 345 | mx = (struct mx *) alloc(numanswers * sizeof(struct mx)); | ||
| 346 | if (!mx) return DNS_MEM; | ||
| 347 | nummx = 0; | ||
| 348 | |||
| 349 | while ((r = findmx(T_MX)) != 2) | ||
| 350 | { | ||
| 351 | if (r == DNS_SOFT) { alloc_free(mx); return DNS_SOFT; } | ||
| 352 | if (r == 1) | ||
| 353 | { | ||
| 354 | mx[nummx].p = pref; | ||
| 355 | mx[nummx].sa.s = 0; | ||
| 356 | if (!stralloc_copys(&mx[nummx].sa,name)) | ||
| 357 | { | ||
| 358 | while (nummx > 0) alloc_free(mx[--nummx].sa.s); | ||
| 359 | alloc_free(mx); return DNS_MEM; | ||
| 360 | } | ||
| 361 | ++nummx; | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | if (!nummx) return dns_ip(ia,sa); /* e.g., CNAME -> A */ | ||
| 366 | |||
| 367 | flagsoft = 0; | ||
| 368 | while (nummx > 0) | ||
| 369 | { | ||
| 370 | unsigned long numsame; | ||
| 371 | |||
| 372 | i = 0; | ||
| 373 | numsame = 1; | ||
| 374 | for (j = 1;j < nummx;++j) | ||
| 375 | if (mx[j].p < mx[i].p) | ||
| 376 | { | ||
| 377 | i = j; | ||
| 378 | numsame = 1; | ||
| 379 | } | ||
| 380 | else if (mx[j].p == mx[i].p) | ||
| 381 | { | ||
| 382 | ++numsame; | ||
| 383 | random = random * 69069 + 1; | ||
| 384 | if ((random / 2) < (2147483647 / numsame)) | ||
| 385 | i = j; | ||
| 386 | } | ||
| 387 | |||
| 388 | switch(dns_ipplus(ia,&mx[i].sa,mx[i].p)) | ||
| 389 | { | ||
| 390 | case DNS_MEM: case DNS_SOFT: | ||
| 391 | flagsoft = 1; break; | ||
| 392 | } | ||
| 393 | |||
| 394 | alloc_free(mx[i].sa.s); | ||
| 395 | mx[i] = mx[--nummx]; | ||
| 396 | } | ||
| 397 | |||
| 398 | alloc_free(mx); | ||
| 399 | return flagsoft; | ||
| 400 | } | ||
| @@ -0,0 +1,14 @@ | |||
| 1 | #ifndef DNS_H | ||
| 2 | #define DNS_H | ||
| 3 | |||
| 4 | #define DNS_SOFT -1 | ||
| 5 | #define DNS_HARD -2 | ||
| 6 | #define DNS_MEM -3 | ||
| 7 | |||
| 8 | void dns_init(); | ||
| 9 | int dns_cname(); | ||
| 10 | int dns_mxip(); | ||
| 11 | int dns_ip(); | ||
| 12 | int dns_ptr(); | ||
| 13 | |||
| 14 | #endif | ||
diff --git a/dnscname.c b/dnscname.c new file mode 100644 index 0000000..b3cd6f1 --- /dev/null +++ b/dnscname.c | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "subfd.h" | ||
| 3 | #include "stralloc.h" | ||
| 4 | #include "dns.h" | ||
| 5 | #include "dnsdoe.h" | ||
| 6 | #include "readwrite.h" | ||
| 7 | #include "exit.h" | ||
| 8 | |||
| 9 | stralloc sa = {0}; | ||
| 10 | |||
| 11 | void main(argc,argv) | ||
| 12 | int argc; | ||
| 13 | char **argv; | ||
| 14 | { | ||
| 15 | if (!argv[1]) _exit(100); | ||
| 16 | |||
| 17 | if (!stralloc_copys(&sa,argv[1])) | ||
| 18 | { substdio_putsflush(subfderr,"out of memory\n"); _exit(111); } | ||
| 19 | |||
| 20 | dns_init(0); | ||
| 21 | dnsdoe(dns_cname(&sa)); | ||
| 22 | substdio_putflush(subfdout,sa.s,sa.len); | ||
| 23 | substdio_putsflush(subfdout,"\n"); | ||
| 24 | _exit(0); | ||
| 25 | } | ||
diff --git a/dnsdoe.c b/dnsdoe.c new file mode 100644 index 0000000..806ca53 --- /dev/null +++ b/dnsdoe.c | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "subfd.h" | ||
| 3 | #include "exit.h" | ||
| 4 | #include "dns.h" | ||
| 5 | #include "dnsdoe.h" | ||
| 6 | |||
| 7 | void dnsdoe(r) | ||
| 8 | int r; | ||
| 9 | { | ||
| 10 | switch (r) | ||
| 11 | { | ||
| 12 | case DNS_HARD: substdio_putsflush(subfderr,"hard error\n"); _exit(100); | ||
| 13 | case DNS_SOFT: substdio_putsflush(subfderr,"soft error\n"); _exit(111); | ||
| 14 | case DNS_MEM: substdio_putsflush(subfderr,"out of memory\n"); _exit(111); | ||
| 15 | } | ||
| 16 | } | ||
diff --git a/dnsdoe.h b/dnsdoe.h new file mode 100644 index 0000000..0e47bf6 --- /dev/null +++ b/dnsdoe.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef DNSDOE_H | ||
| 2 | #define DNSDOE_H | ||
| 3 | |||
| 4 | extern void dnsdoe(); | ||
| 5 | |||
| 6 | #endif | ||
| @@ -0,0 +1,32 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "subfd.h" | ||
| 3 | #include "stralloc.h" | ||
| 4 | #include "dns.h" | ||
| 5 | #include "dnsdoe.h" | ||
| 6 | #include "ip.h" | ||
| 7 | #include "ipalloc.h" | ||
| 8 | #include "exit.h" | ||
| 9 | |||
| 10 | stralloc sa = {0}; | ||
| 11 | ipalloc ia = {0}; | ||
| 12 | |||
| 13 | void main(argc,argv) | ||
| 14 | int argc; | ||
| 15 | char **argv; | ||
| 16 | { | ||
| 17 | if (!argv[1]) _exit(100); | ||
| 18 | |||
| 19 | if (!stralloc_copys(&sa,argv[1])) | ||
| 20 | { substdio_putsflush(subfderr,"out of memory\n"); _exit(111); } | ||
| 21 | |||
| 22 | dns_init(1); | ||
| 23 | dnsdoe(dns_ip(&ia,&sa)); | ||
| 24 | if (ia.len <= 0) | ||
| 25 | { | ||
| 26 | substdio_putsflush(subfderr,"no IP addresses\n"); _exit(100); | ||
| 27 | } | ||
| 28 | dnsdoe(dns_ptr(&sa,&ia.ix[0].ip)); | ||
| 29 | substdio_putflush(subfdout,sa.s,sa.len); | ||
| 30 | substdio_putsflush(subfdout,"\n"); | ||
| 31 | _exit(0); | ||
| 32 | } | ||
| @@ -0,0 +1,34 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "subfd.h" | ||
| 3 | #include "stralloc.h" | ||
| 4 | #include "dns.h" | ||
| 5 | #include "dnsdoe.h" | ||
| 6 | #include "ip.h" | ||
| 7 | #include "ipalloc.h" | ||
| 8 | #include "exit.h" | ||
| 9 | |||
| 10 | char temp[IPFMT]; | ||
| 11 | |||
| 12 | stralloc sa = {0}; | ||
| 13 | ipalloc ia = {0}; | ||
| 14 | |||
| 15 | void main(argc,argv) | ||
| 16 | int argc; | ||
| 17 | char **argv; | ||
| 18 | { | ||
| 19 | int j; | ||
| 20 | |||
| 21 | if (!argv[1]) _exit(100); | ||
| 22 | |||
| 23 | if (!stralloc_copys(&sa,argv[1])) | ||
| 24 | { substdio_putsflush(subfderr,"out of memory\n"); _exit(111); } | ||
| 25 | |||
| 26 | dns_init(0); | ||
| 27 | dnsdoe(dns_ip(&ia,&sa)); | ||
| 28 | for (j = 0;j < ia.len;++j) | ||
| 29 | { | ||
| 30 | substdio_put(subfdout,temp,ip_fmt(temp,&ia.ix[j].ip)); | ||
| 31 | substdio_putsflush(subfdout,"\n"); | ||
| 32 | } | ||
| 33 | _exit(0); | ||
| 34 | } | ||
diff --git a/dnsmxip.c b/dnsmxip.c new file mode 100644 index 0000000..6d8e137 --- /dev/null +++ b/dnsmxip.c | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "subfd.h" | ||
| 3 | #include "stralloc.h" | ||
| 4 | #include "fmt.h" | ||
| 5 | #include "dns.h" | ||
| 6 | #include "dnsdoe.h" | ||
| 7 | #include "ip.h" | ||
| 8 | #include "ipalloc.h" | ||
| 9 | #include "now.h" | ||
| 10 | #include "exit.h" | ||
| 11 | |||
| 12 | char temp[IPFMT + FMT_ULONG]; | ||
| 13 | |||
| 14 | stralloc sa = {0}; | ||
| 15 | ipalloc ia = {0}; | ||
| 16 | |||
| 17 | void main(argc,argv) | ||
| 18 | int argc; | ||
| 19 | char **argv; | ||
| 20 | { | ||
| 21 | int j; | ||
| 22 | unsigned long r; | ||
| 23 | |||
| 24 | if (!argv[1]) _exit(100); | ||
| 25 | |||
| 26 | if (!stralloc_copys(&sa,argv[1])) | ||
| 27 | { substdio_putsflush(subfderr,"out of memory\n"); _exit(111); } | ||
| 28 | |||
| 29 | r = now() + getpid(); | ||
| 30 | dns_init(0); | ||
| 31 | dnsdoe(dns_mxip(&ia,&sa,r)); | ||
| 32 | for (j = 0;j < ia.len;++j) | ||
| 33 | { | ||
| 34 | substdio_put(subfdout,temp,ip_fmt(temp,&ia.ix[j].ip)); | ||
| 35 | substdio_puts(subfdout," "); | ||
| 36 | substdio_put(subfdout,temp,fmt_ulong(temp,(unsigned long) ia.ix[j].pref)); | ||
| 37 | substdio_putsflush(subfdout,"\n"); | ||
| 38 | } | ||
| 39 | _exit(0); | ||
| 40 | } | ||
diff --git a/dnsptr.c b/dnsptr.c new file mode 100644 index 0000000..6a92fe0 --- /dev/null +++ b/dnsptr.c | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "subfd.h" | ||
| 3 | #include "stralloc.h" | ||
| 4 | #include "str.h" | ||
| 5 | #include "scan.h" | ||
| 6 | #include "dns.h" | ||
| 7 | #include "dnsdoe.h" | ||
| 8 | #include "ip.h" | ||
| 9 | #include "exit.h" | ||
| 10 | |||
| 11 | stralloc sa = {0}; | ||
| 12 | struct ip_address ip; | ||
| 13 | |||
| 14 | void main(argc,argv) | ||
| 15 | int argc; | ||
| 16 | char **argv; | ||
| 17 | { | ||
| 18 | if (!argv[1]) _exit(100); | ||
| 19 | |||
| 20 | ip_scan(argv[1],&ip); | ||
| 21 | |||
| 22 | dns_init(0); | ||
| 23 | dnsdoe(dns_ptr(&sa,&ip)); | ||
| 24 | substdio_putflush(subfdout,sa.s,sa.len); | ||
| 25 | substdio_putsflush(subfdout,"\n"); | ||
| 26 | _exit(0); | ||
| 27 | } | ||
diff --git a/dot-qmail.9 b/dot-qmail.9 new file mode 100644 index 0000000..4fa1358 --- /dev/null +++ b/dot-qmail.9 | |||
| @@ -0,0 +1,394 @@ | |||
| 1 | .TH dot-qmail 5 | ||
| 2 | .SH NAME | ||
| 3 | dot-qmail \- control the delivery of mail messages | ||
| 4 | .SH DESCRIPTION | ||
| 5 | Normally the | ||
| 6 | .B qmail-local | ||
| 7 | program delivers each incoming message to your system mailbox, | ||
| 8 | .IR homedir\fB/Mailbox , | ||
| 9 | where | ||
| 10 | .I homedir | ||
| 11 | is your home directory. | ||
| 12 | |||
| 13 | It can instead | ||
| 14 | write the mail to a different file or directory, | ||
| 15 | forward it to another address, | ||
| 16 | distribute it to a mailing list, | ||
| 17 | or even execute programs, | ||
| 18 | all under your control. | ||
| 19 | .SH "THE QMAIL FILE" | ||
| 20 | To change | ||
| 21 | .BR qmail-local 's | ||
| 22 | behavior, set up a | ||
| 23 | .B .qmail | ||
| 24 | file in your home directory. | ||
| 25 | |||
| 26 | .B .qmail | ||
| 27 | contains one or more lines. | ||
| 28 | Each line is a delivery instruction. | ||
| 29 | .B qmail-local | ||
| 30 | follows each instruction in turn. | ||
| 31 | There are five types of delivery instructions: | ||
| 32 | (1) comment; (2) program; (3) forward; (4) mbox; (5) maildir. | ||
| 33 | .TP 5 | ||
| 34 | (1) | ||
| 35 | A comment line begins with a number sign: | ||
| 36 | |||
| 37 | .EX | ||
| 38 | # this is a comment | ||
| 39 | .EE | ||
| 40 | |||
| 41 | .B qmail-local | ||
| 42 | ignores the line. | ||
| 43 | .TP 5 | ||
| 44 | (2) | ||
| 45 | A program line begins with a vertical bar: | ||
| 46 | |||
| 47 | .EX | ||
| 48 | |preline /usr/ucb/vacation djb | ||
| 49 | .EE | ||
| 50 | |||
| 51 | .B qmail-local | ||
| 52 | takes the rest of the line as a command to supply to | ||
| 53 | .BR sh . | ||
| 54 | See | ||
| 55 | .B qmail-command(8) | ||
| 56 | for further information. | ||
| 57 | .TP 5 | ||
| 58 | (3) | ||
| 59 | A forward line begins with an ampersand: | ||
| 60 | |||
| 61 | .EX | ||
| 62 | &me@new.job.com | ||
| 63 | .EE | ||
| 64 | |||
| 65 | .B qmail-local | ||
| 66 | takes the rest of the line as a mail address; | ||
| 67 | it uses | ||
| 68 | .B qmail-queue | ||
| 69 | to forward the message to that address. | ||
| 70 | The address must contain a fully qualified domain name; | ||
| 71 | it must not contain extra spaces, angle brackets, or comments: | ||
| 72 | |||
| 73 | .EX | ||
| 74 | # the following examples are WRONG | ||
| 75 | .br | ||
| 76 | &me@new | ||
| 77 | .br | ||
| 78 | &<me@new.job.com> | ||
| 79 | .br | ||
| 80 | & me@new.job.com | ||
| 81 | .br | ||
| 82 | &me@new.job.com (New Address) | ||
| 83 | .EE | ||
| 84 | |||
| 85 | If the address begins with a letter or number, | ||
| 86 | you may leave out the ampersand: | ||
| 87 | |||
| 88 | .EX | ||
| 89 | me@new.job.com | ||
| 90 | .EE | ||
| 91 | |||
| 92 | Note that | ||
| 93 | .B qmail-local | ||
| 94 | omits its new | ||
| 95 | .B Return-Path | ||
| 96 | line when forwarding messages. | ||
| 97 | .TP 5 | ||
| 98 | (4) | ||
| 99 | An | ||
| 100 | .I mbox | ||
| 101 | line begins with a slash or dot, | ||
| 102 | and does not end with a slash: | ||
| 103 | |||
| 104 | .EX | ||
| 105 | /home/djb/Mailbox.sos | ||
| 106 | .EE | ||
| 107 | |||
| 108 | .B qmail-local | ||
| 109 | takes the entire line as a filename. | ||
| 110 | It appends the mail message to that file, | ||
| 111 | using | ||
| 112 | .BR flock -style | ||
| 113 | file locking if possible. | ||
| 114 | .B qmail-local | ||
| 115 | stores the mail message in | ||
| 116 | .I mbox | ||
| 117 | format, as described in | ||
| 118 | .BR mbox(5) . | ||
| 119 | |||
| 120 | .B WARNING: | ||
| 121 | On many systems, | ||
| 122 | anyone who can read a file can | ||
| 123 | .B flock | ||
| 124 | it, and thus hold up | ||
| 125 | .BR qmail-local 's | ||
| 126 | delivery forever. | ||
| 127 | Do not deliver mail to a publicly accessible file! | ||
| 128 | |||
| 129 | If | ||
| 130 | .B qmail-local | ||
| 131 | is able to lock the file, but has trouble writing to it | ||
| 132 | (because, for example, the disk is full), | ||
| 133 | it will truncate the file back to its original length. | ||
| 134 | However, it cannot prevent mailbox corruption if the system | ||
| 135 | crashes during delivery. | ||
| 136 | .TP 5 | ||
| 137 | (5) | ||
| 138 | A | ||
| 139 | .I maildir | ||
| 140 | line begins with a slash or dot, | ||
| 141 | and ends with a slash: | ||
| 142 | |||
| 143 | .EX | ||
| 144 | /home/djb/Maildir/ | ||
| 145 | .EE | ||
| 146 | |||
| 147 | .B qmail-local | ||
| 148 | takes the entire line as the name of a directory in | ||
| 149 | .I maildir | ||
| 150 | format. | ||
| 151 | It reliably stores the incoming message in that directory. | ||
| 152 | See | ||
| 153 | .B maildir(5) | ||
| 154 | for more details. | ||
| 155 | .PP | ||
| 156 | If | ||
| 157 | .B .qmail | ||
| 158 | has the execute bit set, | ||
| 159 | it must not contain any | ||
| 160 | program lines, | ||
| 161 | .I mbox | ||
| 162 | lines, | ||
| 163 | or | ||
| 164 | .I maildir | ||
| 165 | lines. | ||
| 166 | If | ||
| 167 | .B qmail-local | ||
| 168 | sees any such lines, | ||
| 169 | it will stop and indicate a temporary failure. | ||
| 170 | |||
| 171 | If | ||
| 172 | .B .qmail | ||
| 173 | is completely empty (0 bytes long), or does not exist, | ||
| 174 | .B qmail-local | ||
| 175 | follows the | ||
| 176 | .I defaultdelivery | ||
| 177 | instructions set by your system administrator; | ||
| 178 | normally | ||
| 179 | .I defaultdelivery | ||
| 180 | is | ||
| 181 | .BR ./Mailbox , | ||
| 182 | so | ||
| 183 | .B qmail-local | ||
| 184 | appends the mail message to | ||
| 185 | .B Mailbox | ||
| 186 | in | ||
| 187 | .I mbox | ||
| 188 | format. | ||
| 189 | |||
| 190 | .B .qmail | ||
| 191 | may contain extra spaces and tabs at the end of a line. | ||
| 192 | Blank lines are allowed, but not for the first line of | ||
| 193 | .BR .qmail . | ||
| 194 | |||
| 195 | If | ||
| 196 | .B .qmail | ||
| 197 | is world-writable or group-writable, | ||
| 198 | .B qmail-local | ||
| 199 | stops and indicates a temporary failure. | ||
| 200 | .SH "SAFE QMAIL EDITING" | ||
| 201 | Incoming messages can arrive at any moment. | ||
| 202 | If you want to safely edit your | ||
| 203 | .B .qmail | ||
| 204 | file, first set the sticky bit on your home directory: | ||
| 205 | |||
| 206 | .EX | ||
| 207 | chmod +t $HOME | ||
| 208 | .EE | ||
| 209 | |||
| 210 | .B qmail-local | ||
| 211 | will temporarily defer delivery of any message to you | ||
| 212 | if your home directory is sticky | ||
| 213 | (or group-writable or other-writable, | ||
| 214 | which should never happen). | ||
| 215 | Make sure to | ||
| 216 | |||
| 217 | .EX | ||
| 218 | chmod -t $HOME | ||
| 219 | .EE | ||
| 220 | |||
| 221 | when you are done! | ||
| 222 | It's a good idea to test your new | ||
| 223 | .B .qmail | ||
| 224 | file as follows: | ||
| 225 | |||
| 226 | .EX | ||
| 227 | qmail-local -n $USER ~ $USER '' '' '' '' ./Mailbox | ||
| 228 | .EE | ||
| 229 | .SH "EXTENSION ADDRESSES" | ||
| 230 | In the | ||
| 231 | .B qmail | ||
| 232 | system, | ||
| 233 | you control all local addresses of the form | ||
| 234 | .IR user\fBBREAK\fIanything , | ||
| 235 | as well as the address | ||
| 236 | .I user | ||
| 237 | itself, | ||
| 238 | where | ||
| 239 | .I user | ||
| 240 | is your account name. | ||
| 241 | Delivery to | ||
| 242 | .I user\fBBREAK\fIanything | ||
| 243 | is controlled by the file | ||
| 244 | .IR homedir/\fB.qmail\-\fIanything . | ||
| 245 | (These rules may be changed by the system administrator; | ||
| 246 | see | ||
| 247 | .BR qmail-users (5).) | ||
| 248 | |||
| 249 | The | ||
| 250 | .B alias | ||
| 251 | user controls all other addresses. | ||
| 252 | Delivery to | ||
| 253 | .I local | ||
| 254 | is controlled by the file | ||
| 255 | .IR homedir/\fB.qmail\-\fIlocal , | ||
| 256 | where | ||
| 257 | .I homedir | ||
| 258 | is | ||
| 259 | .BR alias 's | ||
| 260 | home directory. | ||
| 261 | |||
| 262 | In the following description, | ||
| 263 | .B qmail-local | ||
| 264 | is handling a message addressed to | ||
| 265 | .IR local@domain , | ||
| 266 | where | ||
| 267 | .I local | ||
| 268 | is controlled by | ||
| 269 | .BR .qmail\-\fIext . | ||
| 270 | Here is what it does. | ||
| 271 | |||
| 272 | If | ||
| 273 | .B .qmail\-\fIext | ||
| 274 | is completely empty, | ||
| 275 | .B qmail-local | ||
| 276 | follows the | ||
| 277 | .I defaultdelivery | ||
| 278 | instructions set by your system administrator. | ||
| 279 | |||
| 280 | If | ||
| 281 | .B .qmail\-\fIext | ||
| 282 | doesn't exist, | ||
| 283 | .B qmail-local | ||
| 284 | will try some default | ||
| 285 | .B .qmail | ||
| 286 | files. | ||
| 287 | For example, | ||
| 288 | if | ||
| 289 | .I ext | ||
| 290 | is | ||
| 291 | .BR foo-bar , | ||
| 292 | .B qmail-local | ||
| 293 | will try first | ||
| 294 | .BR .qmail-foo-bar , | ||
| 295 | then | ||
| 296 | .BR .qmail-foo-default , | ||
| 297 | and finally | ||
| 298 | .BR .qmail-default . | ||
| 299 | If none of these exist, | ||
| 300 | .B qmail-local | ||
| 301 | will bounce the message. | ||
| 302 | (Exception: for the basic | ||
| 303 | .I user | ||
| 304 | address, | ||
| 305 | .B qmail-local | ||
| 306 | treats a nonexistent | ||
| 307 | .B .qmail | ||
| 308 | the same as an empty | ||
| 309 | .BR .qmail .) | ||
| 310 | |||
| 311 | .B WARNING: | ||
| 312 | For security, | ||
| 313 | .B qmail-local | ||
| 314 | replaces any dots in | ||
| 315 | .I ext | ||
| 316 | with colons before checking | ||
| 317 | .BR .qmail\-\fIext . | ||
| 318 | For convenience, | ||
| 319 | .B qmail-local | ||
| 320 | converts any uppercase letters in | ||
| 321 | .I ext | ||
| 322 | to lowercase. | ||
| 323 | |||
| 324 | When | ||
| 325 | .B qmail-local | ||
| 326 | forwards a message as instructed in | ||
| 327 | .B .qmail\-\fIext | ||
| 328 | (or | ||
| 329 | .BR .qmail-default ), | ||
| 330 | it checks whether | ||
| 331 | .B .qmail\-\fIext\fB-owner\fP | ||
| 332 | exists. | ||
| 333 | If so, | ||
| 334 | it uses | ||
| 335 | .I local\fB-owner@\fIdomain | ||
| 336 | as the envelope sender for the forwarded message. | ||
| 337 | Otherwise it retains the envelope sender of the original message. | ||
| 338 | Exception: | ||
| 339 | .B qmail-local | ||
| 340 | always retains the original envelope sender | ||
| 341 | if it is the empty address or | ||
| 342 | .BR #@[] , | ||
| 343 | i.e., if this is a bounce message. | ||
| 344 | |||
| 345 | .B qmail-local | ||
| 346 | also supports | ||
| 347 | .B variable envelope return paths | ||
| 348 | (VERPs): | ||
| 349 | if | ||
| 350 | .B .qmail\-\fIext\fB-owner\fP | ||
| 351 | and | ||
| 352 | .B .qmail\-\fIext\fB-owner-default\fP | ||
| 353 | both exist, it uses | ||
| 354 | .I local\fB\-owner\-@\fIdomain\fB-@[] | ||
| 355 | as the envelope sender. | ||
| 356 | This will cause a recipient | ||
| 357 | .I recip\fB@\fIreciphost | ||
| 358 | to see an envelope sender of | ||
| 359 | .IR local\fB\-owner\-\fIrecip\fB=\fIreciphost\fB@\fIdomain . | ||
| 360 | .SH "ERROR HANDLING" | ||
| 361 | If a delivery instruction fails, | ||
| 362 | .B qmail-local | ||
| 363 | stops immediately and reports failure. | ||
| 364 | .B qmail-local | ||
| 365 | handles forwarding after all other instructions, | ||
| 366 | so any error in another type of delivery will prevent all forwarding. | ||
| 367 | |||
| 368 | If a program returns exit code 99, | ||
| 369 | .B qmail-local | ||
| 370 | ignores all succeeding lines in | ||
| 371 | .BR .qmail , | ||
| 372 | but it still pays attention to previous forward lines. | ||
| 373 | |||
| 374 | To set up independent instructions, | ||
| 375 | where a temporary or permanent failure in one instruction | ||
| 376 | does not affect the others, | ||
| 377 | move each instruction into a separate | ||
| 378 | .B .qmail\-\fIext | ||
| 379 | file, and set up a central | ||
| 380 | .B .qmail | ||
| 381 | file that forwards to all of the | ||
| 382 | .BR .qmail\-\fIext s. | ||
| 383 | Note that | ||
| 384 | .B qmail-local | ||
| 385 | can handle any number of forward lines simultaneously. | ||
| 386 | .SH "SEE ALSO" | ||
| 387 | envelopes(5), | ||
| 388 | maildir(5), | ||
| 389 | mbox(5), | ||
| 390 | qmail-users(5), | ||
| 391 | qmail-local(8), | ||
| 392 | qmail-command(8), | ||
| 393 | qmail-queue(8), | ||
| 394 | qmail-lspawn(8) | ||
| @@ -0,0 +1 @@ | |||
| QMAIL/bin/maildir2mbox && exec elm ${1+"$@"} | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | .TH env 3 | ||
| 2 | .SH NAME | ||
| 3 | env \- manage the environment | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <env.h> | ||
| 6 | |||
| 7 | char **\fBenviron\fP; | ||
| 8 | |||
| 9 | char *\fBenv_get\fP(\fIname\fR); | ||
| 10 | .br | ||
| 11 | char *\fBenv_pick\fP(); | ||
| 12 | |||
| 13 | char *\fIname\fR; | ||
| 14 | .SH DESCRIPTION | ||
| 15 | The environment, | ||
| 16 | .BR environ , | ||
| 17 | is a 0-terminated array of 0-terminated strings, | ||
| 18 | called environment variables. | ||
| 19 | Each environment variable is of the form | ||
| 20 | .IR name\fB=\fIvalue . | ||
| 21 | |||
| 22 | .B env_get | ||
| 23 | returns the value of the first variable whose name is | ||
| 24 | .IR name , | ||
| 25 | or 0 if there is no such variable. | ||
| 26 | |||
| 27 | .B env_pick | ||
| 28 | returns any variable in the environment, | ||
| 29 | or 0 if the environment is empty. | ||
| 30 | .SH "SEE ALSO" | ||
| 31 | environ(7) | ||
| @@ -0,0 +1,113 @@ | |||
| 1 | /* env.c, envread.c, env.h: environ library | ||
| 2 | Daniel J. Bernstein, djb@silverton.berkeley.edu. | ||
| 3 | Depends on str.h, alloc.h. | ||
| 4 | Requires environ. | ||
| 5 | 19960113: rewrite. warning: interface is different. | ||
| 6 | No known patent problems. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include "str.h" | ||
| 10 | #include "alloc.h" | ||
| 11 | #include "env.h" | ||
| 12 | |||
| 13 | int env_isinit = 0; /* if env_isinit: */ | ||
| 14 | static int ea; /* environ is a pointer to ea+1 char*'s. */ | ||
| 15 | static int en; /* the first en of those are ALLOCATED. environ[en] is 0. */ | ||
| 16 | |||
| 17 | static void env_goodbye(i) int i; | ||
| 18 | { | ||
| 19 | alloc_free(environ[i]); | ||
| 20 | environ[i] = environ[--en]; | ||
| 21 | environ[en] = 0; | ||
| 22 | } | ||
| 23 | |||
| 24 | static char *null = 0; | ||
| 25 | |||
| 26 | void env_clear() | ||
| 27 | { | ||
| 28 | if (env_isinit) while (en) env_goodbye(0); | ||
| 29 | else environ = &null; | ||
| 30 | } | ||
| 31 | |||
| 32 | static void env_unsetlen(s,len) char *s; int len; | ||
| 33 | { | ||
| 34 | int i; | ||
| 35 | for (i = en - 1;i >= 0;--i) | ||
| 36 | if (!str_diffn(s,environ[i],len)) | ||
| 37 | if (environ[i][len] == '=') | ||
| 38 | env_goodbye(i); | ||
| 39 | } | ||
| 40 | |||
| 41 | int env_unset(s) char *s; | ||
| 42 | { | ||
| 43 | if (!env_isinit) if (!env_init()) return 0; | ||
| 44 | env_unsetlen(s,str_len(s)); | ||
| 45 | return 1; | ||
| 46 | } | ||
| 47 | |||
| 48 | static int env_add(s) char *s; | ||
| 49 | { | ||
| 50 | char *t; | ||
| 51 | t = env_findeq(s); | ||
| 52 | if (t) env_unsetlen(s,t - s); | ||
| 53 | if (en == ea) | ||
| 54 | { | ||
| 55 | ea += 30; | ||
| 56 | if (!alloc_re(&environ,(en + 1) * sizeof(char *),(ea + 1) * sizeof(char *))) | ||
| 57 | { ea = en; return 0; } | ||
| 58 | } | ||
| 59 | environ[en++] = s; | ||
| 60 | environ[en] = 0; | ||
| 61 | return 1; | ||
| 62 | } | ||
| 63 | |||
| 64 | int env_put(s) char *s; | ||
| 65 | { | ||
| 66 | char *u; | ||
| 67 | if (!env_isinit) if (!env_init()) return 0; | ||
| 68 | u = alloc(str_len(s) + 1); | ||
| 69 | if (!u) return 0; | ||
| 70 | str_copy(u,s); | ||
| 71 | if (!env_add(u)) { alloc_free(u); return 0; } | ||
| 72 | return 1; | ||
| 73 | } | ||
| 74 | |||
| 75 | int env_put2(s,t) char *s; char *t; | ||
| 76 | { | ||
| 77 | char *u; | ||
| 78 | int slen; | ||
| 79 | if (!env_isinit) if (!env_init()) return 0; | ||
| 80 | slen = str_len(s); | ||
| 81 | u = alloc(slen + str_len(t) + 2); | ||
| 82 | if (!u) return 0; | ||
| 83 | str_copy(u,s); | ||
| 84 | u[slen] = '='; | ||
| 85 | str_copy(u + slen + 1,t); | ||
| 86 | if (!env_add(u)) { alloc_free(u); return 0; } | ||
| 87 | return 1; | ||
| 88 | } | ||
| 89 | |||
| 90 | int env_init() | ||
| 91 | { | ||
| 92 | char **newenviron; | ||
| 93 | int i; | ||
| 94 | for (en = 0;environ[en];++en) ; | ||
| 95 | ea = en + 10; | ||
| 96 | newenviron = (char **) alloc((ea + 1) * sizeof(char *)); | ||
| 97 | if (!newenviron) return 0; | ||
| 98 | for (en = 0;environ[en];++en) | ||
| 99 | { | ||
| 100 | newenviron[en] = alloc(str_len(environ[en]) + 1); | ||
| 101 | if (!newenviron[en]) | ||
| 102 | { | ||
| 103 | for (i = 0;i < en;++i) alloc_free(newenviron[i]); | ||
| 104 | alloc_free(newenviron); | ||
| 105 | return 0; | ||
| 106 | } | ||
| 107 | str_copy(newenviron[en],environ[en]); | ||
| 108 | } | ||
| 109 | newenviron[en] = 0; | ||
| 110 | environ = newenviron; | ||
| 111 | env_isinit = 1; | ||
| 112 | return 1; | ||
| 113 | } | ||
| @@ -0,0 +1,17 @@ | |||
| 1 | #ifndef ENV_H | ||
| 2 | #define ENV_H | ||
| 3 | |||
| 4 | extern int env_isinit; | ||
| 5 | |||
| 6 | extern int env_init(); | ||
| 7 | extern int env_put(); | ||
| 8 | extern int env_put2(); | ||
| 9 | extern int env_unset(); | ||
| 10 | extern /*@null@*/char *env_get(); | ||
| 11 | extern char *env_pick(); | ||
| 12 | extern void env_clear(); | ||
| 13 | extern char *env_findeq(); | ||
| 14 | |||
| 15 | extern char **environ; | ||
| 16 | |||
| 17 | #endif | ||
diff --git a/envelopes.5 b/envelopes.5 new file mode 100644 index 0000000..5f7084a --- /dev/null +++ b/envelopes.5 | |||
| @@ -0,0 +1,231 @@ | |||
| 1 | .TH envelopes 5 | ||
| 2 | .SH "NAME" | ||
| 3 | envelopes \- sender/recipient lists attached to messages | ||
| 4 | .SH "INTRODUCTION" | ||
| 5 | Electronic mail messages are delivered in | ||
| 6 | .IR envelopes . | ||
| 7 | |||
| 8 | An envelope lists a | ||
| 9 | .I sender | ||
| 10 | and one or more | ||
| 11 | .IR recipients . | ||
| 12 | Usually these | ||
| 13 | envelope addresses are the same | ||
| 14 | as the addresses listed in the message header: | ||
| 15 | |||
| 16 | .EX | ||
| 17 | (envelope) from djb to root | ||
| 18 | .br | ||
| 19 | From: djb | ||
| 20 | .br | ||
| 21 | To: root | ||
| 22 | .EE | ||
| 23 | |||
| 24 | In more complicated situations, though, | ||
| 25 | the envelope addresses may differ from the header addresses. | ||
| 26 | .SH "ENVELOPE EXAMPLES" | ||
| 27 | When a message is delivered to | ||
| 28 | several people at different locations, | ||
| 29 | it is first photocopied | ||
| 30 | and placed into several envelopes: | ||
| 31 | |||
| 32 | .EX | ||
| 33 | (envelope) from djb to root | ||
| 34 | .br | ||
| 35 | From: djb Copy #1 of message | ||
| 36 | .br | ||
| 37 | To: root, god@brl.mil | ||
| 38 | .EE | ||
| 39 | |||
| 40 | .EX | ||
| 41 | (envelope) from djb to god@brl.mil | ||
| 42 | .br | ||
| 43 | From: djb Copy #2 of message | ||
| 44 | .br | ||
| 45 | To: root, god@brl.mil | ||
| 46 | .EE | ||
| 47 | |||
| 48 | When a message is delivered | ||
| 49 | to several people at the same location, | ||
| 50 | the sender doesn't have to photocopy it. | ||
| 51 | He can instead stuff it into | ||
| 52 | one envelope with several addresses; | ||
| 53 | the recipients will make the photocopy: | ||
| 54 | |||
| 55 | .EX | ||
| 56 | (envelope) from djb to god@brl.mil, angel@brl.mil | ||
| 57 | .br | ||
| 58 | From: djb | ||
| 59 | .br | ||
| 60 | To: god@brl.mil, angel@brl.mil, joe, frde | ||
| 61 | .EE | ||
| 62 | |||
| 63 | Bounced mail is sent back to the envelope sender address. | ||
| 64 | The bounced mail doesn't list an envelope sender, | ||
| 65 | so bounce loops are impossible: | ||
| 66 | |||
| 67 | .EX | ||
| 68 | (envelope) from <> to djb | ||
| 69 | .br | ||
| 70 | From: MAILER-DAEMON | ||
| 71 | .br | ||
| 72 | To: djb | ||
| 73 | .br | ||
| 74 | Subject: unknown user frde | ||
| 75 | .EE | ||
| 76 | |||
| 77 | The recipient of a message may make another copy | ||
| 78 | and forward it in a new envelope: | ||
| 79 | |||
| 80 | .EX | ||
| 81 | (envelope) from djb to joe | ||
| 82 | .br | ||
| 83 | From: djb Original message | ||
| 84 | .br | ||
| 85 | To: joe | ||
| 86 | .EE | ||
| 87 | |||
| 88 | .EX | ||
| 89 | (envelope) from joe to fred | ||
| 90 | .br | ||
| 91 | From: djb Forwarded message | ||
| 92 | .br | ||
| 93 | To: joe | ||
| 94 | .EE | ||
| 95 | |||
| 96 | A mailing list works almost the same way: | ||
| 97 | |||
| 98 | .EX | ||
| 99 | (envelope) from djb to sos-list | ||
| 100 | .br | ||
| 101 | From: djb Original message | ||
| 102 | .br | ||
| 103 | To: sos-list | ||
| 104 | .EE | ||
| 105 | |||
| 106 | .EX | ||
| 107 | (envelope) from sos-owner to god@brl.mil | ||
| 108 | .br | ||
| 109 | From: djb Forwarded message | ||
| 110 | .br | ||
| 111 | To: sos-list to recipient #1 | ||
| 112 | .EE | ||
| 113 | |||
| 114 | .EX | ||
| 115 | (envelope) from sos-owner to frde | ||
| 116 | .br | ||
| 117 | From: djb Forwarded message | ||
| 118 | .br | ||
| 119 | To: sos-list to recipient #2 | ||
| 120 | .EE | ||
| 121 | |||
| 122 | Notice that the mailing list is set up | ||
| 123 | to replace the envelope sender with something new, | ||
| 124 | .BR sos-owner . | ||
| 125 | So bounces will come back to | ||
| 126 | .BR sos-owner : | ||
| 127 | |||
| 128 | .EX | ||
| 129 | (envelope) from <> to sos-owner | ||
| 130 | .br | ||
| 131 | From: MAILER-DAEMON | ||
| 132 | .br | ||
| 133 | To: sos-owner | ||
| 134 | .br | ||
| 135 | Subject: unknown user frde | ||
| 136 | .EE | ||
| 137 | |||
| 138 | It's a good idea to set up an extra address, | ||
| 139 | .BR sos-owner , | ||
| 140 | like this: | ||
| 141 | the original envelope sender (\fBdjb\fP) | ||
| 142 | has no way to fix bad | ||
| 143 | .B sos-list | ||
| 144 | addresses, | ||
| 145 | and of course bounces must not be sent to | ||
| 146 | .B sos-list | ||
| 147 | itself. | ||
| 148 | .SH "HOW ENVELOPE ADDRESSES ARE STORED" | ||
| 149 | Envelope sender and envelope recipient addresses | ||
| 150 | are transmitted and recorded in several ways. | ||
| 151 | |||
| 152 | When a user injects mail through | ||
| 153 | .BR qmail-inject , | ||
| 154 | he can supply a | ||
| 155 | .B Return-Path | ||
| 156 | line or a | ||
| 157 | .B \-f | ||
| 158 | option for the envelope sender; | ||
| 159 | by default the envelope sender is his login name. | ||
| 160 | The envelope recipient addresses can be taken | ||
| 161 | from the command line or from various header fields, | ||
| 162 | depending on the options to | ||
| 163 | .BR qmail-inject . | ||
| 164 | Similar comments apply to | ||
| 165 | .BR sendmail . | ||
| 166 | |||
| 167 | When a message is transferred from one machine to another through SMTP, | ||
| 168 | the envelope sender is given in a | ||
| 169 | .B MAIL FROM | ||
| 170 | command, | ||
| 171 | the envelope recipients are given in | ||
| 172 | .B RCPT TO | ||
| 173 | commands, | ||
| 174 | and the message is supplied separately by a | ||
| 175 | .B DATA | ||
| 176 | command. | ||
| 177 | |||
| 178 | When a message is delivered by | ||
| 179 | .B qmail | ||
| 180 | to a single local recipient, | ||
| 181 | .B qmail-local | ||
| 182 | records the recipient in | ||
| 183 | .B Delivered-To | ||
| 184 | and the envelope sender in | ||
| 185 | .BR Return-Path . | ||
| 186 | It uses | ||
| 187 | .B Delivered-To | ||
| 188 | to detect mail forwarding loops. | ||
| 189 | |||
| 190 | .B sendmail | ||
| 191 | normally records the envelope sender in | ||
| 192 | .BR Return-Path . | ||
| 193 | It does not record envelope recipient addresses, | ||
| 194 | on the theory that they are redundant: | ||
| 195 | you received the mail, | ||
| 196 | so you must have been one of the envelope recipients. | ||
| 197 | |||
| 198 | Note that, | ||
| 199 | if the header doesn't have any recipient addresses, | ||
| 200 | .B sendmail | ||
| 201 | will move envelope recipient addresses back into the header. | ||
| 202 | This situation occurs if all addresses were originally listed as | ||
| 203 | .BR Bcc , | ||
| 204 | since | ||
| 205 | .B Bcc | ||
| 206 | is automatically removed. | ||
| 207 | When | ||
| 208 | .B sendmail | ||
| 209 | sees this, it creates a new | ||
| 210 | .B Apparently-To | ||
| 211 | header field with the envelope recipient addresses. | ||
| 212 | This has the strange effect that each blind-carbon-copy recipient will see | ||
| 213 | a list of all recipients on the same machine. | ||
| 214 | |||
| 215 | When a message is stored in | ||
| 216 | .B mbox | ||
| 217 | format, | ||
| 218 | the envelope sender is recorded at the top of the message | ||
| 219 | as a UUCP-style | ||
| 220 | .B From | ||
| 221 | (no colon) line. | ||
| 222 | Note that this line is less reliable than the | ||
| 223 | .B Return-Path | ||
| 224 | line added by | ||
| 225 | .B qmail-local | ||
| 226 | or | ||
| 227 | .B sendmail\fP. | ||
| 228 | .SH "SEE ALSO" | ||
| 229 | qmail-header(5), | ||
| 230 | qmail-local(8), | ||
| 231 | qmail-inject(8) | ||
diff --git a/envread.c b/envread.c new file mode 100644 index 0000000..80185de --- /dev/null +++ b/envread.c | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | #include "env.h" | ||
| 2 | #include "str.h" | ||
| 3 | |||
| 4 | extern /*@null@*/char *env_get(s) | ||
| 5 | char *s; | ||
| 6 | { | ||
| 7 | int i; | ||
| 8 | unsigned int slen; | ||
| 9 | char *envi; | ||
| 10 | |||
| 11 | slen = str_len(s); | ||
| 12 | for (i = 0;envi = environ[i];++i) | ||
| 13 | if ((!str_diffn(s,envi,slen)) && (envi[slen] == '=')) | ||
| 14 | return envi + slen + 1; | ||
| 15 | return 0; | ||
| 16 | } | ||
| 17 | |||
| 18 | extern char *env_pick() | ||
| 19 | { | ||
| 20 | return environ[0]; | ||
| 21 | } | ||
| 22 | |||
| 23 | extern char *env_findeq(s) | ||
| 24 | char *s; | ||
| 25 | { | ||
| 26 | for (;*s;++s) | ||
| 27 | if (*s == '=') | ||
| 28 | return s; | ||
| 29 | return 0; | ||
| 30 | } | ||
| @@ -0,0 +1,45 @@ | |||
| 1 | .TH error 3 | ||
| 2 | .SH NAME | ||
| 3 | error \- syscall error codes | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <error.h> | ||
| 6 | |||
| 7 | extern int \fBerrno\fP; | ||
| 8 | |||
| 9 | extern int \fBerror_intr\fP; | ||
| 10 | .br | ||
| 11 | extern int \fBerror_nomem\fP; | ||
| 12 | .br | ||
| 13 | extern int \fBerror_noent\fP; | ||
| 14 | .br | ||
| 15 | extern int \fBerror_txtbsy\fP; | ||
| 16 | .br | ||
| 17 | extern int \fBerror_io\fP; | ||
| 18 | .br | ||
| 19 | extern int \fBerror_exist\fP; | ||
| 20 | .br | ||
| 21 | extern int \fBerror_timeout\fP; | ||
| 22 | .br | ||
| 23 | extern int \fBerror_inprogress\fP; | ||
| 24 | .br | ||
| 25 | extern int \fBerror_wouldblock\fP; | ||
| 26 | .br | ||
| 27 | extern int \fBerror_again\fP; | ||
| 28 | .br | ||
| 29 | extern int \fBerror_pipe\fP; | ||
| 30 | .br | ||
| 31 | extern int \fBerror_perm\fP; | ||
| 32 | .br | ||
| 33 | extern int \fBerror_acces\fP; | ||
| 34 | .SH DESCRIPTION | ||
| 35 | UNIX syscalls provide detailed error codes in the | ||
| 36 | .B errno | ||
| 37 | variable. | ||
| 38 | The | ||
| 39 | .B error | ||
| 40 | library provides portable names for a variety of possible | ||
| 41 | .B errno | ||
| 42 | values. | ||
| 43 | .SH "SEE ALSO" | ||
| 44 | error_str(3), | ||
| 45 | error_temp(3) | ||
| @@ -0,0 +1,95 @@ | |||
| 1 | #include <errno.h> | ||
| 2 | #include "error.h" | ||
| 3 | |||
| 4 | /* warning: as coverage improves here, should update error_{str,temp} */ | ||
| 5 | |||
| 6 | int error_intr = | ||
| 7 | #ifdef EINTR | ||
| 8 | EINTR; | ||
| 9 | #else | ||
| 10 | -1; | ||
| 11 | #endif | ||
| 12 | |||
| 13 | int error_nomem = | ||
| 14 | #ifdef ENOMEM | ||
| 15 | ENOMEM; | ||
| 16 | #else | ||
| 17 | -2; | ||
| 18 | #endif | ||
| 19 | |||
| 20 | int error_noent = | ||
| 21 | #ifdef ENOENT | ||
| 22 | ENOENT; | ||
| 23 | #else | ||
| 24 | -3; | ||
| 25 | #endif | ||
| 26 | |||
| 27 | int error_txtbsy = | ||
| 28 | #ifdef ETXTBSY | ||
| 29 | ETXTBSY; | ||
| 30 | #else | ||
| 31 | -4; | ||
| 32 | #endif | ||
| 33 | |||
| 34 | int error_io = | ||
| 35 | #ifdef EIO | ||
| 36 | EIO; | ||
| 37 | #else | ||
| 38 | -5; | ||
| 39 | #endif | ||
| 40 | |||
| 41 | int error_exist = | ||
| 42 | #ifdef EEXIST | ||
| 43 | EEXIST; | ||
| 44 | #else | ||
| 45 | -6; | ||
| 46 | #endif | ||
| 47 | |||
| 48 | int error_timeout = | ||
| 49 | #ifdef ETIMEDOUT | ||
| 50 | ETIMEDOUT; | ||
| 51 | #else | ||
| 52 | -7; | ||
| 53 | #endif | ||
| 54 | |||
| 55 | int error_inprogress = | ||
| 56 | #ifdef EINPROGRESS | ||
| 57 | EINPROGRESS; | ||
| 58 | #else | ||
| 59 | -8; | ||
| 60 | #endif | ||
| 61 | |||
| 62 | int error_wouldblock = | ||
| 63 | #ifdef EWOULDBLOCK | ||
| 64 | EWOULDBLOCK; | ||
| 65 | #else | ||
| 66 | -9; | ||
| 67 | #endif | ||
| 68 | |||
| 69 | int error_again = | ||
| 70 | #ifdef EAGAIN | ||
| 71 | EAGAIN; | ||
| 72 | #else | ||
| 73 | -10; | ||
| 74 | #endif | ||
| 75 | |||
| 76 | int error_pipe = | ||
| 77 | #ifdef EPIPE | ||
| 78 | EPIPE; | ||
| 79 | #else | ||
| 80 | -11; | ||
| 81 | #endif | ||
| 82 | |||
| 83 | int error_perm = | ||
| 84 | #ifdef EPERM | ||
| 85 | EPERM; | ||
| 86 | #else | ||
| 87 | -12; | ||
| 88 | #endif | ||
| 89 | |||
| 90 | int error_acces = | ||
| 91 | #ifdef EACCES | ||
| 92 | EACCES; | ||
| 93 | #else | ||
| 94 | -13; | ||
| 95 | #endif | ||
| @@ -0,0 +1,23 @@ | |||
| 1 | #ifndef ERROR_H | ||
| 2 | #define ERROR_H | ||
| 3 | |||
| 4 | extern int errno; | ||
| 5 | |||
| 6 | extern int error_intr; | ||
| 7 | extern int error_nomem; | ||
| 8 | extern int error_noent; | ||
| 9 | extern int error_txtbsy; | ||
| 10 | extern int error_io; | ||
| 11 | extern int error_exist; | ||
| 12 | extern int error_timeout; | ||
| 13 | extern int error_inprogress; | ||
| 14 | extern int error_wouldblock; | ||
| 15 | extern int error_again; | ||
| 16 | extern int error_pipe; | ||
| 17 | extern int error_perm; | ||
| 18 | extern int error_acces; | ||
| 19 | |||
| 20 | extern char *error_str(); | ||
| 21 | extern int error_temp(); | ||
| 22 | |||
| 23 | #endif | ||
diff --git a/error_str.3 b/error_str.3 new file mode 100644 index 0000000..62043c4 --- /dev/null +++ b/error_str.3 | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | .TH error_str 3 | ||
| 2 | .SH NAME | ||
| 3 | error_str \- names for syscall error codes | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <error.h> | ||
| 6 | |||
| 7 | char *\fBerror_str\fP(\fIe\fR); | ||
| 8 | |||
| 9 | int \fIe\fR; | ||
| 10 | .SH DESCRIPTION | ||
| 11 | .B error_str | ||
| 12 | returns a printable string describing syscall error code | ||
| 13 | .IR e . | ||
| 14 | Normally | ||
| 15 | .I e | ||
| 16 | is | ||
| 17 | .BR errno . | ||
| 18 | .SH "SEE ALSO" | ||
| 19 | error(3) | ||
diff --git a/error_str.c b/error_str.c new file mode 100644 index 0000000..804d1fa --- /dev/null +++ b/error_str.c | |||
| @@ -0,0 +1,276 @@ | |||
| 1 | #include <errno.h> | ||
| 2 | #include "error.h" | ||
| 3 | |||
| 4 | #define X(e,s) if (i == e) return s; | ||
| 5 | |||
| 6 | char *error_str(i) | ||
| 7 | int i; | ||
| 8 | { | ||
| 9 | X(0,"no error") | ||
| 10 | X(error_intr,"interrupted system call") | ||
| 11 | X(error_nomem,"out of memory") | ||
| 12 | X(error_noent,"file does not exist") | ||
| 13 | X(error_txtbsy,"text busy") | ||
| 14 | X(error_io,"input/output error") | ||
| 15 | X(error_exist,"file already exists") | ||
| 16 | X(error_timeout,"timed out") | ||
| 17 | X(error_inprogress,"operation in progress") | ||
| 18 | X(error_again,"temporary failure") | ||
| 19 | X(error_wouldblock,"input/output would block") | ||
| 20 | X(error_pipe,"broken pipe") | ||
| 21 | X(error_perm,"permission denied") | ||
| 22 | X(error_acces,"access denied") | ||
| 23 | #ifdef ESRCH | ||
| 24 | X(ESRCH,"no such process") | ||
| 25 | #endif | ||
| 26 | #ifdef ENXIO | ||
| 27 | X(ENXIO,"device not configured") | ||
| 28 | #endif | ||
| 29 | #ifdef E2BIG | ||
| 30 | X(E2BIG,"argument list too long") | ||
| 31 | #endif | ||
| 32 | #ifdef ENOEXEC | ||
| 33 | X(ENOEXEC,"exec format error") | ||
| 34 | #endif | ||
| 35 | #ifdef EBADF | ||
| 36 | X(EBADF,"file descriptor not open") | ||
| 37 | #endif | ||
| 38 | #ifdef ECHILD | ||
| 39 | X(ECHILD,"no child processes") | ||
| 40 | #endif | ||
| 41 | #ifdef EDEADLK | ||
| 42 | X(EDEADLK,"operation would cause deadlock") | ||
| 43 | #endif | ||
| 44 | #ifdef EFAULT | ||
| 45 | X(EFAULT,"bad address") | ||
| 46 | #endif | ||
| 47 | #ifdef ENOTBLK | ||
| 48 | X(ENOTBLK,"not a block device") | ||
| 49 | #endif | ||
| 50 | #ifdef EBUSY | ||
| 51 | X(EBUSY,"device busy") | ||
| 52 | #endif | ||
| 53 | #ifdef EXDEV | ||
| 54 | X(EXDEV,"cross-device link") | ||
| 55 | #endif | ||
| 56 | #ifdef ENODEV | ||
| 57 | X(ENODEV,"device does not support operation") | ||
| 58 | #endif | ||
| 59 | #ifdef ENOTDIR | ||
| 60 | X(ENOTDIR,"not a directory") | ||
| 61 | #endif | ||
| 62 | #ifdef EISDIR | ||
| 63 | X(EISDIR,"is a directory") | ||
| 64 | #endif | ||
| 65 | #ifdef EINVAL | ||
| 66 | X(EINVAL,"invalid argument") | ||
| 67 | #endif | ||
| 68 | #ifdef ENFILE | ||
| 69 | X(ENFILE,"system cannot open more files") | ||
| 70 | #endif | ||
| 71 | #ifdef EMFILE | ||
| 72 | X(EMFILE,"process cannot open more files") | ||
| 73 | #endif | ||
| 74 | #ifdef ENOTTY | ||
| 75 | X(ENOTTY,"not a tty") | ||
| 76 | #endif | ||
| 77 | #ifdef EFBIG | ||
| 78 | X(EFBIG,"file too big") | ||
| 79 | #endif | ||
| 80 | #ifdef ENOSPC | ||
| 81 | X(ENOSPC,"out of disk space") | ||
| 82 | #endif | ||
| 83 | #ifdef ESPIPE | ||
| 84 | X(ESPIPE,"unseekable descriptor") | ||
| 85 | #endif | ||
| 86 | #ifdef EROFS | ||
| 87 | X(EROFS,"read-only file system") | ||
| 88 | #endif | ||
| 89 | #ifdef EMLINK | ||
| 90 | X(EMLINK,"too many links") | ||
| 91 | #endif | ||
| 92 | #ifdef EDOM | ||
| 93 | X(EDOM,"input out of range") | ||
| 94 | #endif | ||
| 95 | #ifdef ERANGE | ||
| 96 | X(ERANGE,"output out of range") | ||
| 97 | #endif | ||
| 98 | #ifdef EALREADY | ||
| 99 | X(EALREADY,"operation already in progress") | ||
| 100 | #endif | ||
| 101 | #ifdef ENOTSOCK | ||
| 102 | X(ENOTSOCK,"not a socket") | ||
| 103 | #endif | ||
| 104 | #ifdef EDESTADDRREQ | ||
| 105 | X(EDESTADDRREQ,"destination address required") | ||
| 106 | #endif | ||
| 107 | #ifdef EMSGSIZE | ||
| 108 | X(EMSGSIZE,"message too long") | ||
| 109 | #endif | ||
| 110 | #ifdef EPROTOTYPE | ||
| 111 | X(EPROTOTYPE,"incorrect protocol type") | ||
| 112 | #endif | ||
| 113 | #ifdef ENOPROTOOPT | ||
| 114 | X(ENOPROTOOPT,"protocol not available") | ||
| 115 | #endif | ||
| 116 | #ifdef EPROTONOSUPPORT | ||
| 117 | X(EPROTONOSUPPORT,"protocol not supported") | ||
| 118 | #endif | ||
| 119 | #ifdef ESOCKTNOSUPPORT | ||
| 120 | X(ESOCKTNOSUPPORT,"socket type not supported") | ||
| 121 | #endif | ||
| 122 | #ifdef EOPNOTSUPP | ||
| 123 | X(EOPNOTSUPP,"operation not supported") | ||
| 124 | #endif | ||
| 125 | #ifdef EPFNOSUPPORT | ||
| 126 | X(EPFNOSUPPORT,"protocol family not supported") | ||
| 127 | #endif | ||
| 128 | #ifdef EAFNOSUPPORT | ||
| 129 | X(EAFNOSUPPORT,"address family not supported") | ||
| 130 | #endif | ||
| 131 | #ifdef EADDRINUSE | ||
| 132 | X(EADDRINUSE,"address already used") | ||
| 133 | #endif | ||
| 134 | #ifdef EADDRNOTAVAIL | ||
| 135 | X(EADDRNOTAVAIL,"address not available") | ||
| 136 | #endif | ||
| 137 | #ifdef ENETDOWN | ||
| 138 | X(ENETDOWN,"network down") | ||
| 139 | #endif | ||
| 140 | #ifdef ENETUNREACH | ||
| 141 | X(ENETUNREACH,"network unreachable") | ||
| 142 | #endif | ||
| 143 | #ifdef ENETRESET | ||
| 144 | X(ENETRESET,"network reset") | ||
| 145 | #endif | ||
| 146 | #ifdef ECONNABORTED | ||
| 147 | X(ECONNABORTED,"connection aborted") | ||
| 148 | #endif | ||
| 149 | #ifdef ECONNRESET | ||
| 150 | X(ECONNRESET,"connection reset") | ||
| 151 | #endif | ||
| 152 | #ifdef ENOBUFS | ||
| 153 | X(ENOBUFS,"out of buffer space") | ||
| 154 | #endif | ||
| 155 | #ifdef EISCONN | ||
| 156 | X(EISCONN,"already connected") | ||
| 157 | #endif | ||
| 158 | #ifdef ENOTCONN | ||
| 159 | X(ENOTCONN,"not connected") | ||
| 160 | #endif | ||
| 161 | #ifdef ESHUTDOWN | ||
| 162 | X(ESHUTDOWN,"socket shut down") | ||
| 163 | #endif | ||
| 164 | #ifdef ETOOMANYREFS | ||
| 165 | X(ETOOMANYREFS,"too many references") | ||
| 166 | #endif | ||
| 167 | #ifdef ECONNREFUSED | ||
| 168 | X(ECONNREFUSED,"connection refused") | ||
| 169 | #endif | ||
| 170 | #ifdef ELOOP | ||
| 171 | X(ELOOP,"symbolic link loop") | ||
| 172 | #endif | ||
| 173 | #ifdef ENAMETOOLONG | ||
| 174 | X(ENAMETOOLONG,"file name too long") | ||
| 175 | #endif | ||
| 176 | #ifdef EHOSTDOWN | ||
| 177 | X(EHOSTDOWN,"host down") | ||
| 178 | #endif | ||
| 179 | #ifdef EHOSTUNREACH | ||
| 180 | X(EHOSTUNREACH,"host unreachable") | ||
| 181 | #endif | ||
| 182 | #ifdef ENOTEMPTY | ||
| 183 | X(ENOTEMPTY,"directory not empty") | ||
| 184 | #endif | ||
| 185 | #ifdef EPROCLIM | ||
| 186 | X(EPROCLIM,"too many processes") | ||
| 187 | #endif | ||
| 188 | #ifdef EUSERS | ||
| 189 | X(EUSERS,"too many users") | ||
| 190 | #endif | ||
| 191 | #ifdef EDQUOT | ||
| 192 | X(EDQUOT,"disk quota exceeded") | ||
| 193 | #endif | ||
| 194 | #ifdef ESTALE | ||
| 195 | X(ESTALE,"stale NFS file handle") | ||
| 196 | #endif | ||
| 197 | #ifdef EREMOTE | ||
| 198 | X(EREMOTE,"too many levels of remote in path") | ||
| 199 | #endif | ||
| 200 | #ifdef EBADRPC | ||
| 201 | X(EBADRPC,"RPC structure is bad") | ||
| 202 | #endif | ||
| 203 | #ifdef ERPCMISMATCH | ||
| 204 | X(ERPCMISMATCH,"RPC version mismatch") | ||
| 205 | #endif | ||
| 206 | #ifdef EPROGUNAVAIL | ||
| 207 | X(EPROGUNAVAIL,"RPC program unavailable") | ||
| 208 | #endif | ||
| 209 | #ifdef EPROGMISMATCH | ||
| 210 | X(EPROGMISMATCH,"program version mismatch") | ||
| 211 | #endif | ||
| 212 | #ifdef EPROCUNAVAIL | ||
| 213 | X(EPROCUNAVAIL,"bad procedure for program") | ||
| 214 | #endif | ||
| 215 | #ifdef ENOLCK | ||
| 216 | X(ENOLCK,"no locks available") | ||
| 217 | #endif | ||
| 218 | #ifdef ENOSYS | ||
| 219 | X(ENOSYS,"system call not available") | ||
| 220 | #endif | ||
| 221 | #ifdef EFTYPE | ||
| 222 | X(EFTYPE,"bad file type") | ||
| 223 | #endif | ||
| 224 | #ifdef EAUTH | ||
| 225 | X(EAUTH,"authentication error") | ||
| 226 | #endif | ||
| 227 | #ifdef ENEEDAUTH | ||
| 228 | X(ENEEDAUTH,"not authenticated") | ||
| 229 | #endif | ||
| 230 | #ifdef ENOSTR | ||
| 231 | X(ENOSTR,"not a stream device") | ||
| 232 | #endif | ||
| 233 | #ifdef ETIME | ||
| 234 | X(ETIME,"timer expired") | ||
| 235 | #endif | ||
| 236 | #ifdef ENOSR | ||
| 237 | X(ENOSR,"out of stream resources") | ||
| 238 | #endif | ||
| 239 | #ifdef ENOMSG | ||
| 240 | X(ENOMSG,"no message of desired type") | ||
| 241 | #endif | ||
| 242 | #ifdef EBADMSG | ||
| 243 | X(EBADMSG,"bad message type") | ||
| 244 | #endif | ||
| 245 | #ifdef EIDRM | ||
| 246 | X(EIDRM,"identifier removed") | ||
| 247 | #endif | ||
| 248 | #ifdef ENONET | ||
| 249 | X(ENONET,"machine not on network") | ||
| 250 | #endif | ||
| 251 | #ifdef ERREMOTE | ||
| 252 | X(ERREMOTE,"object not local") | ||
| 253 | #endif | ||
| 254 | #ifdef ENOLINK | ||
| 255 | X(ENOLINK,"link severed") | ||
| 256 | #endif | ||
| 257 | #ifdef EADV | ||
| 258 | X(EADV,"advertise error") | ||
| 259 | #endif | ||
| 260 | #ifdef ESRMNT | ||
| 261 | X(ESRMNT,"srmount error") | ||
| 262 | #endif | ||
| 263 | #ifdef ECOMM | ||
| 264 | X(ECOMM,"communication error") | ||
| 265 | #endif | ||
| 266 | #ifdef EPROTO | ||
| 267 | X(EPROTO,"protocol error") | ||
| 268 | #endif | ||
| 269 | #ifdef EMULTIHOP | ||
| 270 | X(EMULTIHOP,"multihop attempted") | ||
| 271 | #endif | ||
| 272 | #ifdef EREMCHG | ||
| 273 | X(EREMCHG,"remote address changed") | ||
| 274 | #endif | ||
| 275 | return "unknown error"; | ||
| 276 | } | ||
diff --git a/error_temp.3 b/error_temp.3 new file mode 100644 index 0000000..2f8229d --- /dev/null +++ b/error_temp.3 | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | .TH error_temp 3 | ||
| 2 | .SH NAME | ||
| 3 | error_temp \- identify soft syscall error codes | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <error.h> | ||
| 6 | |||
| 7 | int \fBerror_temp\fP(\fIe\fR); | ||
| 8 | |||
| 9 | int \fIe\fR; | ||
| 10 | .SH DESCRIPTION | ||
| 11 | .B error_temp | ||
| 12 | returns 1 if syscall error code | ||
| 13 | .I e | ||
| 14 | is a soft error, 0 if it is a hard error. | ||
| 15 | Normally | ||
| 16 | .I e | ||
| 17 | is | ||
| 18 | .BR errno . | ||
| 19 | |||
| 20 | A hard error is persistent: | ||
| 21 | file not found, read-only file system, symbolic link loop, etc. | ||
| 22 | |||
| 23 | A soft error is usually transient: | ||
| 24 | out of memory, out of disk space, I/O error, disk quota exceeded, | ||
| 25 | connection refused, host unreachable, etc. | ||
| 26 | .SH "SEE ALSO" | ||
| 27 | error(3) | ||
diff --git a/error_temp.c b/error_temp.c new file mode 100644 index 0000000..6782cef --- /dev/null +++ b/error_temp.c | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | #include <errno.h> | ||
| 2 | #include "error.h" | ||
| 3 | |||
| 4 | #define X(n) if (e == n) return 1; | ||
| 5 | |||
| 6 | int error_temp(e) | ||
| 7 | int e; | ||
| 8 | { | ||
| 9 | X(error_intr) | ||
| 10 | X(error_nomem) | ||
| 11 | X(error_txtbsy) | ||
| 12 | X(error_io) | ||
| 13 | X(error_timeout) | ||
| 14 | X(error_wouldblock) | ||
| 15 | X(error_again) | ||
| 16 | #ifdef EDEADLK | ||
| 17 | X(EDEADLK) | ||
| 18 | #endif | ||
| 19 | #ifdef EBUSY | ||
| 20 | X(EBUSY) | ||
| 21 | #endif | ||
| 22 | #ifdef ENFILE | ||
| 23 | X(ENFILE) | ||
| 24 | #endif | ||
| 25 | #ifdef EMFILE | ||
| 26 | X(EMFILE) | ||
| 27 | #endif | ||
| 28 | #ifdef EFBIG | ||
| 29 | X(EFBIG) | ||
| 30 | #endif | ||
| 31 | #ifdef ENOSPC | ||
| 32 | X(ENOSPC) | ||
| 33 | #endif | ||
| 34 | #ifdef ENETDOWN | ||
| 35 | X(ENETDOWN) | ||
| 36 | #endif | ||
| 37 | #ifdef ENETUNREACH | ||
| 38 | X(ENETUNREACH) | ||
| 39 | #endif | ||
| 40 | #ifdef ENETRESET | ||
| 41 | X(ENETRESET) | ||
| 42 | #endif | ||
| 43 | #ifdef ECONNABORTED | ||
| 44 | X(ECONNABORTED) | ||
| 45 | #endif | ||
| 46 | #ifdef ECONNRESET | ||
| 47 | X(ECONNRESET) | ||
| 48 | #endif | ||
| 49 | #ifdef ENOBUFS | ||
| 50 | X(ENOBUFS) | ||
| 51 | #endif | ||
| 52 | #ifdef ETOOMANYREFS | ||
| 53 | X(ETOOMANYREFS) | ||
| 54 | #endif | ||
| 55 | #ifdef ECONNREFUSED | ||
| 56 | X(ECONNREFUSED) | ||
| 57 | #endif | ||
| 58 | #ifdef EHOSTDOWN | ||
| 59 | X(EHOSTDOWN) | ||
| 60 | #endif | ||
| 61 | #ifdef EHOSTUNREACH | ||
| 62 | X(EHOSTUNREACH) | ||
| 63 | #endif | ||
| 64 | #ifdef EPROCLIM | ||
| 65 | X(EPROCLIM) | ||
| 66 | #endif | ||
| 67 | #ifdef EUSERS | ||
| 68 | X(EUSERS) | ||
| 69 | #endif | ||
| 70 | #ifdef EDQUOT | ||
| 71 | X(EDQUOT) | ||
| 72 | #endif | ||
| 73 | #ifdef ESTALE | ||
| 74 | X(ESTALE) | ||
| 75 | #endif | ||
| 76 | #ifdef ENOLCK | ||
| 77 | X(ENOLCK) | ||
| 78 | #endif | ||
| 79 | return 0; | ||
| 80 | } | ||
diff --git a/except.1 b/except.1 new file mode 100644 index 0000000..4198cc2 --- /dev/null +++ b/except.1 | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | .TH except 1 | ||
| 2 | .SH NAME | ||
| 3 | except \- reverse the exit code of a program | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B except | ||
| 6 | .I program | ||
| 7 | [ | ||
| 8 | .I arg ... | ||
| 9 | ] | ||
| 10 | .SH DESCRIPTION | ||
| 11 | .B except | ||
| 12 | runs | ||
| 13 | .I program | ||
| 14 | with the given arguments. | ||
| 15 | |||
| 16 | If | ||
| 17 | .I program | ||
| 18 | exits 0, | ||
| 19 | .B except | ||
| 20 | exits 100. | ||
| 21 | If | ||
| 22 | .I program | ||
| 23 | exits 111, | ||
| 24 | .B except | ||
| 25 | exits 111. | ||
| 26 | If | ||
| 27 | .I program | ||
| 28 | exits anything else, | ||
| 29 | .B except | ||
| 30 | exits 0. | ||
| 31 | .SH "SEE ALSO" | ||
| 32 | bouncesaying(1), | ||
| 33 | condredirect(1) | ||
diff --git a/except.c b/except.c new file mode 100644 index 0000000..c553b3b --- /dev/null +++ b/except.c | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | #include "fork.h" | ||
| 2 | #include "strerr.h" | ||
| 3 | #include "wait.h" | ||
| 4 | #include "error.h" | ||
| 5 | #include "exit.h" | ||
| 6 | |||
| 7 | #define FATAL "except: fatal: " | ||
| 8 | |||
| 9 | void main(argc,argv) | ||
| 10 | int argc; | ||
| 11 | char **argv; | ||
| 12 | { | ||
| 13 | int pid; | ||
| 14 | int wstat; | ||
| 15 | |||
| 16 | if (!argv[1]) | ||
| 17 | strerr_die1x(100,"except: usage: except program [ arg ... ]"); | ||
| 18 | |||
| 19 | pid = fork(); | ||
| 20 | if (pid == -1) | ||
| 21 | strerr_die2sys(111,FATAL,"unable to fork: "); | ||
| 22 | if (pid == 0) { | ||
| 23 | execvp(argv[1],argv + 1); | ||
| 24 | if (error_temp(errno)) _exit(111); | ||
| 25 | _exit(100); | ||
| 26 | } | ||
| 27 | |||
| 28 | if (wait_pid(&wstat,pid) == -1) | ||
| 29 | strerr_die2x(111,FATAL,"wait failed"); | ||
| 30 | if (wait_crashed(wstat)) | ||
| 31 | strerr_die2x(111,FATAL,"child crashed"); | ||
| 32 | switch(wait_exitcode(wstat)) { | ||
| 33 | case 0: _exit(100); | ||
| 34 | case 111: strerr_die2x(111,FATAL,"temporary child error"); | ||
| 35 | default: _exit(0); | ||
| 36 | } | ||
| 37 | } | ||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef EXIT_H | ||
| 2 | #define EXIT_H | ||
| 3 | |||
| 4 | extern void _exit(); | ||
| 5 | |||
| 6 | #endif | ||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef EXTRA_H | ||
| 2 | #define EXTRA_H | ||
| 3 | |||
| 4 | #define QUEUE_EXTRA "" | ||
| 5 | #define QUEUE_EXTRALEN 0 | ||
| 6 | |||
| 7 | #endif | ||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef FD_H | ||
| 2 | #define FD_H | ||
| 3 | |||
| 4 | extern int fd_copy(); | ||
| 5 | extern int fd_move(); | ||
| 6 | |||
| 7 | #endif | ||
diff --git a/fd_copy.3 b/fd_copy.3 new file mode 100644 index 0000000..758a7e7 --- /dev/null +++ b/fd_copy.3 | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | .TH fd_copy 3 | ||
| 2 | .SH NAME | ||
| 3 | fd_copy \- duplicate a descriptor | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <fd.h> | ||
| 6 | |||
| 7 | int \fBfd_copy\fP(\fIto\fR,\fIfrom\fR); | ||
| 8 | |||
| 9 | int \fIto\fR; | ||
| 10 | .br | ||
| 11 | int \fIfrom\fR; | ||
| 12 | .SH DESCRIPTION | ||
| 13 | .B fd_copy | ||
| 14 | copies | ||
| 15 | descriptor | ||
| 16 | .I from | ||
| 17 | to descriptor | ||
| 18 | .IR to . | ||
| 19 | If | ||
| 20 | .I to | ||
| 21 | was already open, | ||
| 22 | .B fd_copy | ||
| 23 | closes it. | ||
| 24 | .B fd_copy | ||
| 25 | always leaves | ||
| 26 | .I from | ||
| 27 | intact; | ||
| 28 | if | ||
| 29 | .I to | ||
| 30 | and | ||
| 31 | .I from | ||
| 32 | are the same number, | ||
| 33 | .B fd_copy | ||
| 34 | does nothing. | ||
| 35 | |||
| 36 | .B fd_copy | ||
| 37 | returns 0 on success, -1 on error. | ||
| 38 | .B fd_copy | ||
| 39 | does not guarantee that | ||
| 40 | .I to | ||
| 41 | will remain open, if it was open, in case of error. | ||
| 42 | .SH "SEE ALSO" | ||
| 43 | dup(2), | ||
| 44 | fd_move(3) | ||
diff --git a/fd_copy.c b/fd_copy.c new file mode 100644 index 0000000..b9f7167 --- /dev/null +++ b/fd_copy.c | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | #include <fcntl.h> | ||
| 2 | #include "fd.h" | ||
| 3 | |||
| 4 | int fd_copy(to,from) | ||
| 5 | int to; | ||
| 6 | int from; | ||
| 7 | { | ||
| 8 | if (to == from) return 0; | ||
| 9 | if (fcntl(from,F_GETFL,0) == -1) return -1; | ||
| 10 | close(to); | ||
| 11 | if (fcntl(from,F_DUPFD,to) == -1) return -1; | ||
| 12 | return 0; | ||
| 13 | } | ||
diff --git a/fd_move.3 b/fd_move.3 new file mode 100644 index 0000000..94aa1b7 --- /dev/null +++ b/fd_move.3 | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | .TH fd_move 3 | ||
| 2 | .SH NAME | ||
| 3 | fd_move \- renumber a descriptor | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <fd.h> | ||
| 6 | |||
| 7 | int \fBfd_move\fP(\fIto\fR,\fIfrom\fR); | ||
| 8 | |||
| 9 | int \fIto\fR; | ||
| 10 | .br | ||
| 11 | int \fIfrom\fR; | ||
| 12 | .SH DESCRIPTION | ||
| 13 | .B fd_move | ||
| 14 | moves | ||
| 15 | descriptor | ||
| 16 | .I from | ||
| 17 | to descriptor | ||
| 18 | .IR to . | ||
| 19 | If | ||
| 20 | .I to | ||
| 21 | was already open, | ||
| 22 | .B fd_move | ||
| 23 | closes it. | ||
| 24 | If the move is successful, | ||
| 25 | .B fd_move | ||
| 26 | closes | ||
| 27 | .IR from . | ||
| 28 | Exception: | ||
| 29 | if | ||
| 30 | .I to | ||
| 31 | and | ||
| 32 | .I from | ||
| 33 | are the same number, | ||
| 34 | .B fd_move | ||
| 35 | does nothing. | ||
| 36 | |||
| 37 | .B fd_move | ||
| 38 | returns 0 on success, -1 on error. | ||
| 39 | .SH "SEE ALSO" | ||
| 40 | dup(2), | ||
| 41 | fd_copy(3) | ||
diff --git a/fd_move.c b/fd_move.c new file mode 100644 index 0000000..1aa557f --- /dev/null +++ b/fd_move.c | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #include "fd.h" | ||
| 2 | |||
| 3 | int fd_move(to,from) | ||
| 4 | int to; | ||
| 5 | int from; | ||
| 6 | { | ||
| 7 | if (to == from) return 0; | ||
| 8 | if (fd_copy(to,from) == -1) return -1; | ||
| 9 | close(from); | ||
| 10 | return 0; | ||
| 11 | } | ||
| @@ -0,0 +1,10 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include "hasmkffo.h" | ||
| 4 | #include "fifo.h" | ||
| 5 | |||
| 6 | #ifdef HASMKFIFO | ||
| 7 | int fifo_make(fn,mode) char *fn; int mode; { return mkfifo(fn,mode); } | ||
| 8 | #else | ||
| 9 | int fifo_make(fn,mode) char *fn; int mode; { return mknod(fn,S_IFIFO | mode,0); } | ||
| 10 | #endif | ||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef FIFO_H | ||
| 2 | #define FIFO_H | ||
| 3 | |||
| 4 | extern int fifo_make(); | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/fifo_make.3 b/fifo_make.3 new file mode 100644 index 0000000..489233d --- /dev/null +++ b/fifo_make.3 | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | .TH fifo_make 3 | ||
| 2 | .SH NAME | ||
| 3 | fifo_make \- create a named pipe | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <fifo.h> | ||
| 6 | |||
| 7 | int \fBfifo_make\fP(\fIfn\fR,\fImode\fR); | ||
| 8 | |||
| 9 | char *\fIfn\fR; | ||
| 10 | .br | ||
| 11 | int \fImode\fR; | ||
| 12 | .SH DESCRIPTION | ||
| 13 | .B fifo_make | ||
| 14 | creates a new named pipe | ||
| 15 | with name | ||
| 16 | .I fn | ||
| 17 | and mode | ||
| 18 | .I mode | ||
| 19 | (modified by the process umask). | ||
| 20 | |||
| 21 | .B fifo_make | ||
| 22 | returns 0 on success, -1 on error. | ||
| 23 | .SH "SEE ALSO" | ||
| 24 | mkfifo(2) | ||
diff --git a/find-systype.sh b/find-systype.sh new file mode 100644 index 0000000..16266d3 --- /dev/null +++ b/find-systype.sh | |||
| @@ -0,0 +1,144 @@ | |||
| 1 | # oper-:arch-:syst-:chip-:kern- | ||
| 2 | # oper = operating system type; e.g., sunos-4.1.4 | ||
| 3 | # arch = machine language; e.g., sparc | ||
| 4 | # syst = which binaries can run; e.g., sun4 | ||
| 5 | # chip = chip model; e.g., micro-2-80 | ||
| 6 | # kern = kernel version; e.g., sun4m | ||
| 7 | # dependence: arch --- chip | ||
| 8 | # \ \ | ||
| 9 | # oper --- syst --- kern | ||
| 10 | # so, for example, syst is interpreted in light of oper, but chip is not. | ||
| 11 | # anyway, no slashes, no extra colons, no uppercase letters. | ||
| 12 | # the point of the extra -'s is to ease parsing: can add hierarchies later. | ||
| 13 | # e.g., *:i386-*:*:pentium-*:* would handle pentium-100 as well as pentium, | ||
| 14 | # and i386-486 (486s do have more instructions, you know) as well as i386. | ||
| 15 | # the idea here is to include ALL useful available information. | ||
| 16 | |||
| 17 | exec 2>/dev/null | ||
| 18 | sys="`uname -s | tr '/:[A-Z]' '..[a-z]'`" | ||
| 19 | if [ x"$sys" != x ] | ||
| 20 | then | ||
| 21 | unamer="`uname -r | tr /: ..`" | ||
| 22 | unamem="`uname -m | tr /: ..`" | ||
| 23 | unamev="`uname -v | tr /: ..`" | ||
| 24 | |||
| 25 | case "$sys" in | ||
| 26 | bsd.os) | ||
| 27 | # in bsd 4.4, uname -v does not have useful info. | ||
| 28 | # in bsd 4.4, uname -m is arch, not chip. | ||
| 29 | oper="$sys-$unamer" | ||
| 30 | arch="$unamem" | ||
| 31 | syst="" | ||
| 32 | chip="`sysctl -n hw.model`" | ||
| 33 | kern="" | ||
| 34 | ;; | ||
| 35 | freebsd) | ||
| 36 | # see above about bsd 4.4 | ||
| 37 | oper="$sys-$unamer" | ||
| 38 | arch="$unamem" | ||
| 39 | syst="" | ||
| 40 | chip="`sysctl -n hw.model`" # hopefully | ||
| 41 | kern="" | ||
| 42 | ;; | ||
| 43 | netbsd) | ||
| 44 | # see above about bsd 4.4 | ||
| 45 | oper="$sys-$unamer" | ||
| 46 | arch="$unamem" | ||
| 47 | syst="" | ||
| 48 | chip="`sysctl -n hw.model`" # hopefully | ||
| 49 | kern="" | ||
| 50 | ;; | ||
| 51 | linux) | ||
| 52 | # as in bsd 4.4, uname -v does not have useful info. | ||
| 53 | oper="$sys-$unamer" | ||
| 54 | syst="" | ||
| 55 | chip="$unamem" | ||
| 56 | kern="" | ||
| 57 | case "$chip" in | ||
| 58 | i386|i486|i586|i686) | ||
| 59 | arch="i386" | ||
| 60 | ;; | ||
| 61 | alpha) | ||
| 62 | arch="alpha" | ||
| 63 | ;; | ||
| 64 | esac | ||
| 65 | ;; | ||
| 66 | aix) | ||
| 67 | # naturally IBM has to get uname -r and uname -v backwards. dorks. | ||
| 68 | oper="$sys-$unamev-$unamer" | ||
| 69 | arch="`arch | tr /: ..`" | ||
| 70 | syst="" | ||
| 71 | chip="$unamem" | ||
| 72 | kern="" | ||
| 73 | ;; | ||
| 74 | sunos) | ||
| 75 | oper="$sys-$unamer-$unamev" | ||
| 76 | arch="`(uname -p || mach) | tr /: ..`" | ||
| 77 | syst="`arch | tr /: ..`" | ||
| 78 | chip="$unamem" # this is wrong; is there any way to get the real info? | ||
| 79 | kern="`arch -k | tr /: ..`" | ||
| 80 | ;; | ||
| 81 | unix_sv) | ||
| 82 | oper="$sys-$unamer-$unamev" | ||
| 83 | arch="`uname -m`" | ||
| 84 | syst="" | ||
| 85 | chip="$unamem" | ||
| 86 | kern="" | ||
| 87 | ;; | ||
| 88 | *) | ||
| 89 | oper="$sys-$unamer-$unamev" | ||
| 90 | arch="`arch | tr /: ..`" | ||
| 91 | syst="" | ||
| 92 | chip="$unamem" | ||
| 93 | kern="" | ||
| 94 | ;; | ||
| 95 | esac | ||
| 96 | else | ||
| 97 | $CC -c trycpp.c | ||
| 98 | $LD -o trycpp trycpp.o | ||
| 99 | case `./trycpp` in | ||
| 100 | nextstep) | ||
| 101 | oper="nextstep-`hostinfo | sed -n 's/^[ ]*NeXT Mach \([^:]*\):.*$/\1/p'`" | ||
| 102 | arch="`hostinfo | sed -n 's/^Processor type: \(.*\) (.*)$/\1/p' | tr /: ..`" | ||
| 103 | syst="" | ||
| 104 | chip="`hostinfo | sed -n 's/^Processor type: .* (\(.*\))$/\1/p' | tr ' /:' '...'`" | ||
| 105 | kern="" | ||
| 106 | ;; | ||
| 107 | *) | ||
| 108 | oper="unknown" | ||
| 109 | arch="" | ||
| 110 | syst="" | ||
| 111 | chip="" | ||
| 112 | kern="" | ||
| 113 | ;; | ||
| 114 | esac | ||
| 115 | rm -f trycpp.o trycpp | ||
| 116 | fi | ||
| 117 | |||
| 118 | case "$chip" in | ||
| 119 | 80486) | ||
| 120 | # let's try to be consistent here. (BSD/OS) | ||
| 121 | chip=i486 | ||
| 122 | ;; | ||
| 123 | i486DX) | ||
| 124 | # respect the hyphen hierarchy. (FreeBSD) | ||
| 125 | chip=i486-dx | ||
| 126 | ;; | ||
| 127 | i486.DX2) | ||
| 128 | # respect the hyphen hierarchy. (FreeBSD) | ||
| 129 | chip=i486-dx2 | ||
| 130 | ;; | ||
| 131 | Intel.586) | ||
| 132 | # no, you nitwits, there is no such chip. (NeXTStep) | ||
| 133 | chip=pentium | ||
| 134 | ;; | ||
| 135 | i586) | ||
| 136 | # no, you nitwits, there is no such chip. (Linux) | ||
| 137 | chip=pentium | ||
| 138 | ;; | ||
| 139 | i686) | ||
| 140 | # STOP SAYING THAT! (Linux) | ||
| 141 | chip=ppro | ||
| 142 | esac | ||
| 143 | |||
| 144 | echo "$oper-:$arch-:$syst-:$chip-:$kern-" | tr ' [A-Z]' '.[a-z]' | ||
| @@ -0,0 +1,25 @@ | |||
| 1 | #ifndef FMT_H | ||
| 2 | #define FMT_H | ||
| 3 | |||
| 4 | #define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */ | ||
| 5 | #define FMT_LEN ((char *) 0) /* convenient abbreviation */ | ||
| 6 | |||
| 7 | extern unsigned int fmt_uint(); | ||
| 8 | extern unsigned int fmt_uint0(); | ||
| 9 | extern unsigned int fmt_xint(); | ||
| 10 | extern unsigned int fmt_nbbint(); | ||
| 11 | extern unsigned int fmt_ushort(); | ||
| 12 | extern unsigned int fmt_xshort(); | ||
| 13 | extern unsigned int fmt_nbbshort(); | ||
| 14 | extern unsigned int fmt_ulong(); | ||
| 15 | extern unsigned int fmt_xlong(); | ||
| 16 | extern unsigned int fmt_nbblong(); | ||
| 17 | |||
| 18 | extern unsigned int fmt_plusminus(); | ||
| 19 | extern unsigned int fmt_minus(); | ||
| 20 | extern unsigned int fmt_0x(); | ||
| 21 | |||
| 22 | extern unsigned int fmt_str(); | ||
| 23 | extern unsigned int fmt_strn(); | ||
| 24 | |||
| 25 | #endif | ||
diff --git a/fmt_str.c b/fmt_str.c new file mode 100644 index 0000000..48930cf --- /dev/null +++ b/fmt_str.c | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #include "fmt.h" | ||
| 2 | |||
| 3 | unsigned int fmt_str(s,t) | ||
| 4 | register char *s; register char *t; | ||
| 5 | { | ||
| 6 | register unsigned int len; | ||
| 7 | char ch; | ||
| 8 | len = 0; | ||
| 9 | if (s) { while (ch = t[len]) s[len++] = ch; } | ||
| 10 | else while (t[len]) len++; | ||
| 11 | return len; | ||
| 12 | } | ||
diff --git a/fmt_strn.c b/fmt_strn.c new file mode 100644 index 0000000..3ef58a6 --- /dev/null +++ b/fmt_strn.c | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #include "fmt.h" | ||
| 2 | |||
| 3 | unsigned int fmt_strn(s,t,n) | ||
| 4 | register char *s; register char *t; register unsigned int n; | ||
| 5 | { | ||
| 6 | register unsigned int len; | ||
| 7 | char ch; | ||
| 8 | len = 0; | ||
| 9 | if (s) { while (n-- && (ch = t[len])) s[len++] = ch; } | ||
| 10 | else while (n-- && t[len]) len++; | ||
| 11 | return len; | ||
| 12 | } | ||
diff --git a/fmt_uint.c b/fmt_uint.c new file mode 100644 index 0000000..8595be8 --- /dev/null +++ b/fmt_uint.c | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #include "fmt.h" | ||
| 2 | |||
| 3 | unsigned int fmt_uint(s,u) register char *s; register unsigned int u; | ||
| 4 | { | ||
| 5 | register unsigned long l; l = u; return fmt_ulong(s,l); | ||
| 6 | } | ||
diff --git a/fmt_uint0.c b/fmt_uint0.c new file mode 100644 index 0000000..81705f6 --- /dev/null +++ b/fmt_uint0.c | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #include "fmt.h" | ||
| 2 | |||
| 3 | unsigned int fmt_uint0(s,u,n) char *s; unsigned int u; unsigned int n; | ||
| 4 | { | ||
| 5 | unsigned int len; | ||
| 6 | len = fmt_uint(FMT_LEN,u); | ||
| 7 | while (len < n) { if (s) *s++ = '0'; ++len; } | ||
| 8 | if (s) fmt_uint(s,u); | ||
| 9 | return len; | ||
| 10 | } | ||
diff --git a/fmt_ulong.c b/fmt_ulong.c new file mode 100644 index 0000000..ab12e8c --- /dev/null +++ b/fmt_ulong.c | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | #include "fmt.h" | ||
| 2 | |||
| 3 | unsigned int fmt_ulong(s,u) register char *s; register unsigned long u; | ||
| 4 | { | ||
| 5 | register unsigned int len; register unsigned long q; | ||
| 6 | len = 1; q = u; | ||
| 7 | while (q > 9) { ++len; q /= 10; } | ||
| 8 | if (s) { | ||
| 9 | s += len; | ||
| 10 | do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */ | ||
| 11 | } | ||
| 12 | return len; | ||
| 13 | } | ||
diff --git a/fmtqfn.c b/fmtqfn.c new file mode 100644 index 0000000..6229b4a --- /dev/null +++ b/fmtqfn.c | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | #include "fmtqfn.h" | ||
| 2 | #include "fmt.h" | ||
| 3 | #include "auto_split.h" | ||
| 4 | |||
| 5 | unsigned int fmtqfn(s,dirslash,id,flagsplit) | ||
| 6 | char *s; | ||
| 7 | char *dirslash; | ||
| 8 | unsigned long id; | ||
| 9 | int flagsplit; | ||
| 10 | { | ||
| 11 | unsigned int len; | ||
| 12 | unsigned int i; | ||
| 13 | |||
| 14 | len = 0; | ||
| 15 | i = fmt_str(s,dirslash); len += i; if (s) s += i; | ||
| 16 | if (flagsplit) | ||
| 17 | { | ||
| 18 | i = fmt_ulong(s,id % auto_split); len += i; if (s) s += i; | ||
| 19 | i = fmt_str(s,"/"); len += i; if (s) s += i; | ||
| 20 | } | ||
| 21 | i = fmt_ulong(s,id); len += i; if (s) s += i; | ||
| 22 | if (s) *s++ = 0; ++len; | ||
| 23 | return len; | ||
| 24 | } | ||
diff --git a/fmtqfn.h b/fmtqfn.h new file mode 100644 index 0000000..a449aa1 --- /dev/null +++ b/fmtqfn.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef FMTQFN_H | ||
| 2 | #define FMTQFN_H | ||
| 3 | |||
| 4 | extern unsigned int fmtqfn(); | ||
| 5 | |||
| 6 | #define FMTQFN 40 /* maximum space needed, if len(dirslash) <= 10 */ | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/forgeries.7 b/forgeries.7 new file mode 100644 index 0000000..cb99fa7 --- /dev/null +++ b/forgeries.7 | |||
| @@ -0,0 +1,104 @@ | |||
| 1 | .TH forgeries 7 | ||
| 2 | .SH "NAME" | ||
| 3 | forgeries \- how easy it is to forge mail | ||
| 4 | .SH "SUMMARY" | ||
| 5 | An electronic mail message can easily be forged. | ||
| 6 | Almost everything in it, | ||
| 7 | including the return address, | ||
| 8 | is completely under the control of the sender. | ||
| 9 | |||
| 10 | An electronic mail message can be manually traced to its origin | ||
| 11 | if (1) all system administrators of intermediate machines | ||
| 12 | are both cooperative and competent, | ||
| 13 | (2) the sender did not break low-level TCP/IP security, | ||
| 14 | and | ||
| 15 | (3) all intermediate machines are secure. | ||
| 16 | |||
| 17 | Users of | ||
| 18 | .I cryptography | ||
| 19 | can automatically ensure the integrity and secrecy | ||
| 20 | of their mail messages, as long as | ||
| 21 | the sending and receiving machines are secure. | ||
| 22 | .SH "FORGERIES" | ||
| 23 | Like postal mail, | ||
| 24 | electronic mail can be created entirely at the whim of the sender. | ||
| 25 | .BR From , | ||
| 26 | .BR Sender , | ||
| 27 | .BR Return-Path , | ||
| 28 | and | ||
| 29 | .BR Message-ID | ||
| 30 | can all contain whatever information the sender wants. | ||
| 31 | |||
| 32 | For example, if you inject a message through | ||
| 33 | .B sendmail | ||
| 34 | or | ||
| 35 | .B qmail-inject | ||
| 36 | or | ||
| 37 | .BR SMTP , | ||
| 38 | you can simply type in a | ||
| 39 | .B From | ||
| 40 | field. | ||
| 41 | In fact, | ||
| 42 | .B qmail-inject | ||
| 43 | lets you set up | ||
| 44 | .BR MAILUSER , | ||
| 45 | .BR MAILHOST , | ||
| 46 | and | ||
| 47 | .B MAILNAME | ||
| 48 | environment variables | ||
| 49 | to produce your desired | ||
| 50 | .B From | ||
| 51 | field on every message. | ||
| 52 | .SH "TRACING FORGERIES" | ||
| 53 | Like postal mail, | ||
| 54 | electronic mail is postmarked when it is sent. | ||
| 55 | Each machine that receives an electronic mail message | ||
| 56 | adds a | ||
| 57 | .B Received | ||
| 58 | line to the top. | ||
| 59 | |||
| 60 | A modern | ||
| 61 | .B Received | ||
| 62 | line contains quite a bit of information. | ||
| 63 | In conjunction with the machine's logs, | ||
| 64 | it lets a competent system administrator | ||
| 65 | determine where the machine received the message from, | ||
| 66 | as long as the sender did not break low-level TCP/IP security | ||
| 67 | or security on that machine. | ||
| 68 | |||
| 69 | Large multi-user machines often come with inadequate logging software. | ||
| 70 | Fortunately, a system administrator can easily obtain a copy of a | ||
| 71 | 931/1413/Ident/TAP server, such as | ||
| 72 | .BR pidentd . | ||
| 73 | Unfortunately, | ||
| 74 | some system administrators fail to do this, | ||
| 75 | and are thus unable to figure out which local user | ||
| 76 | was responsible for generating a message. | ||
| 77 | |||
| 78 | If all intermediate system administrators are competent, | ||
| 79 | and the sender did not break machine security or low-level TCP/IP security, | ||
| 80 | it is possible to trace a message backwards. | ||
| 81 | Unfortunately, some traces are stymied by intermediate system | ||
| 82 | administrators who are uncooperative or untrustworthy. | ||
| 83 | .SH "CRYPTOGRAPHY" | ||
| 84 | The sender of a mail message may place his message into a | ||
| 85 | .I cryptographic | ||
| 86 | envelope stamped with his seal. | ||
| 87 | Strong cryptography guarantees that any two messages with the same seal | ||
| 88 | were sent by the same cryptographic entity: | ||
| 89 | perhaps a single person, perhaps a group of cooperating people, | ||
| 90 | but in any case somebody who knows a secret originally held | ||
| 91 | only by the creator of the seal. | ||
| 92 | The seal is called a | ||
| 93 | .I public key\fR. | ||
| 94 | |||
| 95 | Unfortunately, the creator of the seal is often an insecure machine, | ||
| 96 | or an untrustworthy central agency, | ||
| 97 | but most of the time seals are kept secure. | ||
| 98 | |||
| 99 | One popular cryptographic program is | ||
| 100 | .BR pgp . | ||
| 101 | .SH "SEE ALSO" | ||
| 102 | pgp(1), | ||
| 103 | identd(8), | ||
| 104 | qmail-header(8) | ||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef FORK_H | ||
| 2 | #define FORK_H | ||
| 3 | |||
| 4 | extern int fork(); | ||
| 5 | #define vfork fork | ||
| 6 | |||
| 7 | #endif | ||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef FORK_H | ||
| 2 | #define FORK_H | ||
| 3 | |||
| 4 | extern int fork(); | ||
| 5 | extern int vfork(); | ||
| 6 | |||
| 7 | #endif | ||
diff --git a/forward.1 b/forward.1 new file mode 100644 index 0000000..d0a7f95 --- /dev/null +++ b/forward.1 | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | .TH forward 1 | ||
| 2 | .SH NAME | ||
| 3 | forward \- forward new mail to one or more addresses | ||
| 4 | .SH SYNOPSIS | ||
| 5 | in | ||
| 6 | .BR .qmail : | ||
| 7 | .B |forward | ||
| 8 | .I address ... | ||
| 9 | .SH DESCRIPTION | ||
| 10 | .B forward | ||
| 11 | forwards each new mail message to the specified list of addresses. | ||
| 12 | It is a simple wrapper around | ||
| 13 | .BR qmail-queue . | ||
| 14 | It achieves the same results as listing each | ||
| 15 | .I address | ||
| 16 | separately in | ||
| 17 | .BR .qmail , | ||
| 18 | but it is more programmable since | ||
| 19 | .I address | ||
| 20 | can be constructed on the fly. | ||
| 21 | .SH "SEE ALSO" | ||
| 22 | dot-qmail(5), | ||
| 23 | qmail-command(8), | ||
| 24 | qmail-queue(8) | ||
diff --git a/forward.c b/forward.c new file mode 100644 index 0000000..e7390aa --- /dev/null +++ b/forward.c | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | #include "sig.h" | ||
| 2 | #include "readwrite.h" | ||
| 3 | #include "exit.h" | ||
| 4 | #include "env.h" | ||
| 5 | #include "qmail.h" | ||
| 6 | #include "strerr.h" | ||
| 7 | #include "substdio.h" | ||
| 8 | #include "fmt.h" | ||
| 9 | |||
| 10 | #define FATAL "forward: fatal: " | ||
| 11 | |||
| 12 | void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); } | ||
| 13 | |||
| 14 | struct qmail qqt; | ||
| 15 | |||
| 16 | int mywrite(fd,buf,len) int fd; char *buf; int len; | ||
| 17 | { | ||
| 18 | qmail_put(&qqt,buf,len); | ||
| 19 | return len; | ||
| 20 | } | ||
| 21 | |||
| 22 | char inbuf[SUBSTDIO_INSIZE]; | ||
| 23 | char outbuf[1]; | ||
| 24 | substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf); | ||
| 25 | substdio ssout = SUBSTDIO_FDBUF(mywrite,-1,outbuf,sizeof outbuf); | ||
| 26 | |||
| 27 | char num[FMT_ULONG]; | ||
| 28 | |||
| 29 | void main(argc,argv) | ||
| 30 | int argc; | ||
| 31 | char **argv; | ||
| 32 | { | ||
| 33 | char *sender; | ||
| 34 | char *dtline; | ||
| 35 | char *qqx; | ||
| 36 | |||
| 37 | sig_pipeignore(); | ||
| 38 | |||
| 39 | sender = env_get("NEWSENDER"); | ||
| 40 | if (!sender) | ||
| 41 | strerr_die2x(100,FATAL,"NEWSENDER not set"); | ||
| 42 | dtline = env_get("DTLINE"); | ||
| 43 | if (!dtline) | ||
| 44 | strerr_die2x(100,FATAL,"DTLINE not set"); | ||
| 45 | |||
| 46 | if (qmail_open(&qqt) == -1) | ||
| 47 | strerr_die2sys(111,FATAL,"unable to fork: "); | ||
| 48 | qmail_puts(&qqt,dtline); | ||
| 49 | if (substdio_copy(&ssout,&ssin) != 0) | ||
| 50 | strerr_die2sys(111,FATAL,"unable to read message: "); | ||
| 51 | substdio_flush(&ssout); | ||
| 52 | |||
| 53 | num[fmt_ulong(num,qmail_qp(&qqt))] = 0; | ||
| 54 | |||
| 55 | qmail_from(&qqt,sender); | ||
| 56 | while (*++argv) qmail_to(&qqt,*argv); | ||
| 57 | qqx = qmail_close(&qqt); | ||
| 58 | if (*qqx) strerr_die2x(*qqx == 'D' ? 100 : 111,FATAL,qqx + 1); | ||
| 59 | strerr_die2x(0,"forward: qp ",num); | ||
| 60 | } | ||
diff --git a/gen_alloc.h b/gen_alloc.h new file mode 100644 index 0000000..b94a956 --- /dev/null +++ b/gen_alloc.h | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef GEN_ALLOC_H | ||
| 2 | #define GEN_ALLOC_H | ||
| 3 | |||
| 4 | #define GEN_ALLOC_typedef(ta,type,field,len,a) \ | ||
| 5 | typedef struct ta { type *field; unsigned int len; unsigned int a; } ta; | ||
| 6 | |||
| 7 | #endif | ||
diff --git a/gen_allocdefs.h b/gen_allocdefs.h new file mode 100644 index 0000000..783a9b1 --- /dev/null +++ b/gen_allocdefs.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | #ifndef GEN_ALLOC_DEFS_H | ||
| 2 | #define GEN_ALLOC_DEFS_H | ||
| 3 | |||
| 4 | #define GEN_ALLOC_ready(ta,type,field,len,a,i,n,x,base,ta_ready) \ | ||
| 5 | int ta_ready(x,n) register ta *x; register unsigned int n; \ | ||
| 6 | { register unsigned int i; \ | ||
| 7 | if (x->field) { \ | ||
| 8 | i = x->a; \ | ||
| 9 | if (n > i) { \ | ||
| 10 | x->a = base + n + (n >> 3); \ | ||
| 11 | if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \ | ||
| 12 | x->a = i; return 0; } \ | ||
| 13 | return 1; } \ | ||
| 14 | x->len = 0; \ | ||
| 15 | return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); } | ||
| 16 | |||
| 17 | #define GEN_ALLOC_readyplus(ta,type,field,len,a,i,n,x,base,ta_rplus) \ | ||
| 18 | int ta_rplus(x,n) register ta *x; register unsigned int n; \ | ||
| 19 | { register unsigned int i; \ | ||
| 20 | if (x->field) { \ | ||
| 21 | i = x->a; n += x->len; \ | ||
| 22 | if (n > i) { \ | ||
| 23 | x->a = base + n + (n >> 3); \ | ||
| 24 | if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \ | ||
| 25 | x->a = i; return 0; } \ | ||
| 26 | return 1; } \ | ||
| 27 | x->len = 0; \ | ||
| 28 | return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); } | ||
| 29 | |||
| 30 | #define GEN_ALLOC_append(ta,type,field,len,a,i,n,x,base,ta_rplus,ta_append) \ | ||
| 31 | int ta_append(x,i) register ta *x; register type *i; \ | ||
| 32 | { if (!ta_rplus(x,1)) return 0; x->field[x->len++] = *i; return 1; } | ||
| 33 | |||
| 34 | #endif | ||
| @@ -0,0 +1,51 @@ | |||
| 1 | .TH getln 3 | ||
| 2 | .SH NAME | ||
| 3 | getln \- read one line of data | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <getln.h> | ||
| 6 | |||
| 7 | int \fBgetln\fP(&\fIss\fR,&\fIsa\fR,&\fImatch\fR,\fIsep\fR); | ||
| 8 | |||
| 9 | substdio \fIss\fR; | ||
| 10 | .br | ||
| 11 | stralloc \fIsa\fR; | ||
| 12 | .br | ||
| 13 | int \fImatch\fR; | ||
| 14 | .br | ||
| 15 | int \fIsep\fR; | ||
| 16 | .SH DESCRIPTION | ||
| 17 | .B getln | ||
| 18 | reads a line of characters, terminated by a | ||
| 19 | .I sep | ||
| 20 | character, | ||
| 21 | from | ||
| 22 | .IR ss . | ||
| 23 | It returns the line in | ||
| 24 | .I sa | ||
| 25 | and sets | ||
| 26 | .I match | ||
| 27 | to 1. | ||
| 28 | |||
| 29 | If | ||
| 30 | .B getln | ||
| 31 | sees end-of-input before it sees | ||
| 32 | .IR sep , | ||
| 33 | it returns the partial line in | ||
| 34 | .I sa | ||
| 35 | and sets | ||
| 36 | .I match | ||
| 37 | to 0. | ||
| 38 | |||
| 39 | .B getln | ||
| 40 | normally returns 0. | ||
| 41 | If it runs out of memory, | ||
| 42 | or encounters an error from | ||
| 43 | .IR ss , | ||
| 44 | it returns -1, | ||
| 45 | setting | ||
| 46 | .B errno | ||
| 47 | appropriately. | ||
| 48 | .SH "SEE ALSO" | ||
| 49 | stralloc(3), | ||
| 50 | substdio(3), | ||
| 51 | getln2(3) | ||
| @@ -0,0 +1,20 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "byte.h" | ||
| 3 | #include "stralloc.h" | ||
| 4 | #include "getln.h" | ||
| 5 | |||
| 6 | int getln(ss,sa,match,sep) | ||
| 7 | register substdio *ss; | ||
| 8 | register stralloc *sa; | ||
| 9 | int *match; | ||
| 10 | int sep; | ||
| 11 | { | ||
| 12 | char *cont; | ||
| 13 | unsigned int clen; | ||
| 14 | |||
| 15 | if (getln2(ss,sa,&cont,&clen,sep) == -1) return -1; | ||
| 16 | if (!clen) { *match = 0; return 0; } | ||
| 17 | if (!stralloc_catb(sa,cont,clen)) return -1; | ||
| 18 | *match = 1; | ||
| 19 | return 0; | ||
| 20 | } | ||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef GETLN_H | ||
| 2 | #define GETLN_H | ||
| 3 | |||
| 4 | extern int getln(); | ||
| 5 | extern int getln2(); | ||
| 6 | |||
| 7 | #endif | ||
diff --git a/getln2.3 b/getln2.3 new file mode 100644 index 0000000..f95105a --- /dev/null +++ b/getln2.3 | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | .TH getln2 3 | ||
| 2 | .SH NAME | ||
| 3 | getln2 \- read one line of data | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <getln.h> | ||
| 6 | |||
| 7 | int \fBgetln2\fP(&\fIss\fR,&\fIsa\fR,&\fIcont\fR,&\fIclen\fR,\fIsep\fR); | ||
| 8 | |||
| 9 | substdio \fIss\fR; | ||
| 10 | .br | ||
| 11 | stralloc \fIsa\fR; | ||
| 12 | .br | ||
| 13 | char *\fIcont\fR; | ||
| 14 | .br | ||
| 15 | unsigned int \fIclen\fR; | ||
| 16 | .br | ||
| 17 | int \fIsep\fR; | ||
| 18 | .SH DESCRIPTION | ||
| 19 | .B getln2 | ||
| 20 | reads a line of characters, terminated by a | ||
| 21 | .I sep | ||
| 22 | character, | ||
| 23 | from | ||
| 24 | .IR ss . | ||
| 25 | |||
| 26 | The line is returned in two pieces. | ||
| 27 | The first piece is stored in | ||
| 28 | .IR sa . | ||
| 29 | The second piece is | ||
| 30 | .IR cont , | ||
| 31 | a pointer to | ||
| 32 | .I clen | ||
| 33 | characters inside the | ||
| 34 | .I ss | ||
| 35 | buffer. | ||
| 36 | The second piece must be copied somewhere else | ||
| 37 | before | ||
| 38 | .I ss | ||
| 39 | is used again. | ||
| 40 | |||
| 41 | If | ||
| 42 | .B getln2 | ||
| 43 | sees end-of-input before it sees | ||
| 44 | .IR sep , | ||
| 45 | it sets | ||
| 46 | .I clen | ||
| 47 | to 0 and does not set | ||
| 48 | .IR cont . | ||
| 49 | It puts the partial line into | ||
| 50 | .IR sa . | ||
| 51 | |||
| 52 | .B getln2 | ||
| 53 | normally returns 0. | ||
| 54 | If it runs out of memory, | ||
| 55 | or encounters an error from | ||
| 56 | .IR ss , | ||
| 57 | it returns -1, | ||
| 58 | setting | ||
| 59 | .B errno | ||
| 60 | appropriately. | ||
| 61 | .SH "SEE ALSO" | ||
| 62 | stralloc(3), | ||
| 63 | substdio(3), | ||
| 64 | getln(3) | ||
diff --git a/getln2.c b/getln2.c new file mode 100644 index 0000000..9e576e9 --- /dev/null +++ b/getln2.c | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "stralloc.h" | ||
| 3 | #include "byte.h" | ||
| 4 | #include "getln.h" | ||
| 5 | |||
| 6 | int getln2(ss,sa,cont,clen,sep) | ||
| 7 | register substdio *ss; | ||
| 8 | register stralloc *sa; | ||
| 9 | /*@out@*/char **cont; | ||
| 10 | /*@out@*/unsigned int *clen; | ||
| 11 | int sep; | ||
| 12 | { | ||
| 13 | register char *x; | ||
| 14 | register unsigned int i; | ||
| 15 | int n; | ||
| 16 | |||
| 17 | if (!stralloc_ready(sa,0)) return -1; | ||
| 18 | sa->len = 0; | ||
| 19 | |||
| 20 | for (;;) { | ||
| 21 | n = substdio_feed(ss); | ||
| 22 | if (n < 0) return -1; | ||
| 23 | if (n == 0) { *clen = 0; return 0; } | ||
| 24 | x = substdio_PEEK(ss); | ||
| 25 | i = byte_chr(x,n,sep); | ||
| 26 | if (i < n) { substdio_SEEK(ss,*clen = i + 1); *cont = x; return 0; } | ||
| 27 | if (!stralloc_readyplus(sa,n)) return -1; | ||
| 28 | i = sa->len; | ||
| 29 | sa->len = i + substdio_get(ss,sa->s + i,n); | ||
| 30 | } | ||
| 31 | } | ||
| @@ -0,0 +1,10 @@ | |||
| 1 | #include "str.h" | ||
| 2 | #include "gfrom.h" | ||
| 3 | |||
| 4 | int gfrom(s,len) | ||
| 5 | char *s; | ||
| 6 | int len; | ||
| 7 | { | ||
| 8 | while ((len > 0) && (*s == '>')) { ++s; --len; } | ||
| 9 | return (len >= 5) && !str_diffn(s,"From ",5); | ||
| 10 | } | ||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef GFROM_H | ||
| 2 | #define GFROM_H | ||
| 3 | |||
| 4 | extern int gfrom(); | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/headerbody.c b/headerbody.c new file mode 100644 index 0000000..91965c0 --- /dev/null +++ b/headerbody.c | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | #include "stralloc.h" | ||
| 2 | #include "substdio.h" | ||
| 3 | #include "getln.h" | ||
| 4 | #include "hfield.h" | ||
| 5 | #include "headerbody.h" | ||
| 6 | |||
| 7 | static int getsa(ss,sa,match) | ||
| 8 | substdio *ss; | ||
| 9 | stralloc *sa; | ||
| 10 | int *match; | ||
| 11 | { | ||
| 12 | if (!*match) return 0; | ||
| 13 | if (getln(ss,sa,match,'\n') == -1) return -1; | ||
| 14 | if (*match) return 1; | ||
| 15 | if (!sa->len) return 0; | ||
| 16 | if (!stralloc_append(sa,"\n")) return -1; | ||
| 17 | return 1; | ||
| 18 | } | ||
| 19 | |||
| 20 | static stralloc line = {0}; | ||
| 21 | static stralloc nextline = {0}; | ||
| 22 | |||
| 23 | int headerbody(ss,dohf,hdone,dobl) | ||
| 24 | substdio *ss; | ||
| 25 | void (*dohf)(); | ||
| 26 | void (*hdone)(); | ||
| 27 | void (*dobl)(); | ||
| 28 | { | ||
| 29 | int match; | ||
| 30 | int flaglineok; | ||
| 31 | match = 1; | ||
| 32 | flaglineok = 0; | ||
| 33 | for (;;) | ||
| 34 | { | ||
| 35 | switch(getsa(ss,&nextline,&match)) | ||
| 36 | { | ||
| 37 | case -1: | ||
| 38 | return -1; | ||
| 39 | case 0: | ||
| 40 | if (flaglineok) dohf(&line); | ||
| 41 | hdone(); | ||
| 42 | /* no message body; could insert blank line here */ | ||
| 43 | return 0; | ||
| 44 | } | ||
| 45 | if (flaglineok) | ||
| 46 | { | ||
| 47 | if ((nextline.s[0] == ' ') || (nextline.s[0] == '\t')) | ||
| 48 | { | ||
| 49 | if (!stralloc_cat(&line,&nextline)) return -1; | ||
| 50 | continue; | ||
| 51 | } | ||
| 52 | dohf(&line); | ||
| 53 | } | ||
| 54 | if (nextline.len == 1) | ||
| 55 | { | ||
| 56 | hdone(); | ||
| 57 | dobl(&nextline); | ||
| 58 | break; | ||
| 59 | } | ||
| 60 | if (stralloc_starts(&nextline,"From ")) | ||
| 61 | { | ||
| 62 | if (!stralloc_copys(&line,"MBOX-Line: ")) return -1; | ||
| 63 | if (!stralloc_cat(&line,&nextline)) return -1; | ||
| 64 | } | ||
| 65 | else | ||
| 66 | if (hfield_valid(nextline.s,nextline.len)) | ||
| 67 | { | ||
| 68 | if (!stralloc_copy(&line,&nextline)) return -1; | ||
| 69 | } | ||
| 70 | else | ||
| 71 | { | ||
| 72 | hdone(); | ||
| 73 | if (!stralloc_copys(&line,"\n")) return -1; | ||
| 74 | dobl(&line); | ||
| 75 | dobl(&nextline); | ||
| 76 | break; | ||
| 77 | } | ||
| 78 | flaglineok = 1; | ||
| 79 | } | ||
| 80 | for (;;) | ||
| 81 | switch(getsa(ss,&nextline,&match)) | ||
| 82 | { | ||
| 83 | case -1: return -1; | ||
| 84 | case 0: return 0; | ||
| 85 | case 1: dobl(&nextline); | ||
| 86 | } | ||
| 87 | } | ||
diff --git a/headerbody.h b/headerbody.h new file mode 100644 index 0000000..3bb2e2f --- /dev/null +++ b/headerbody.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef HEADERBODY_H | ||
| 2 | #define HEADERBODY_H | ||
| 3 | |||
| 4 | extern int headerbody(); | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/hfield.c b/hfield.c new file mode 100644 index 0000000..06de0be --- /dev/null +++ b/hfield.c | |||
| @@ -0,0 +1,125 @@ | |||
| 1 | #include "hfield.h" | ||
| 2 | |||
| 3 | static char *(hname[]) = { | ||
| 4 | "unknown-header" | ||
| 5 | , "sender" | ||
| 6 | , "from" | ||
| 7 | , "reply-to" | ||
| 8 | , "to" | ||
| 9 | , "cc" | ||
| 10 | , "bcc" | ||
| 11 | , "date" | ||
| 12 | , "message-id" | ||
| 13 | , "subject" | ||
| 14 | , "resent-sender" | ||
| 15 | , "resent-from" | ||
| 16 | , "resent-reply-to" | ||
| 17 | , "resent-to" | ||
| 18 | , "resent-cc" | ||
| 19 | , "resent-bcc" | ||
| 20 | , "resent-date" | ||
| 21 | , "resent-message-id" | ||
| 22 | , "return-receipt-to" | ||
| 23 | , "errors-to" | ||
| 24 | , "apparently-to" | ||
| 25 | , "received" | ||
| 26 | , "return-path" | ||
| 27 | , "delivered-to" | ||
| 28 | , "content-length" | ||
| 29 | , "content-type" | ||
| 30 | , "content-transfer-encoding" | ||
| 31 | , "notice-requested-upon-delivery-to" | ||
| 32 | , "mail-followup-to" | ||
| 33 | , 0 | ||
| 34 | }; | ||
| 35 | |||
| 36 | static int hmatch(s,len,t) | ||
| 37 | char *s; | ||
| 38 | int len; | ||
| 39 | char *t; | ||
| 40 | { | ||
| 41 | int i; | ||
| 42 | char ch; | ||
| 43 | |||
| 44 | for (i = 0;ch = t[i];++i) | ||
| 45 | { | ||
| 46 | if (i >= len) return 0; | ||
| 47 | if (ch != s[i]) | ||
| 48 | { | ||
| 49 | if (ch == '-') return 0; | ||
| 50 | if (ch - 32 != s[i]) return 0; | ||
| 51 | } | ||
| 52 | } | ||
| 53 | for (;;) | ||
| 54 | { | ||
| 55 | if (i >= len) return 0; | ||
| 56 | ch = s[i]; | ||
| 57 | if (ch == ':') return 1; | ||
| 58 | if ((ch != ' ') && (ch != '\t')) return 0; | ||
| 59 | ++i; | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | int hfield_known(s,len) | ||
| 64 | char *s; | ||
| 65 | int len; | ||
| 66 | { | ||
| 67 | int i; | ||
| 68 | char *t; | ||
| 69 | |||
| 70 | for (i = 1;t = hname[i];++i) | ||
| 71 | if (hmatch(s,len,t)) | ||
| 72 | return i; | ||
| 73 | return 0; | ||
| 74 | } | ||
| 75 | |||
| 76 | int hfield_valid(s,len) | ||
| 77 | char *s; | ||
| 78 | int len; | ||
| 79 | { | ||
| 80 | int i; | ||
| 81 | int j; | ||
| 82 | char ch; | ||
| 83 | |||
| 84 | for (j = 0;j < len;++j) | ||
| 85 | if (s[j] == ':') | ||
| 86 | break; | ||
| 87 | if (j >= len) return 0; | ||
| 88 | while (j) | ||
| 89 | { | ||
| 90 | ch = s[j - 1]; | ||
| 91 | if ((ch != ' ') && (ch != '\t')) | ||
| 92 | break; | ||
| 93 | --j; | ||
| 94 | } | ||
| 95 | if (!j) return 0; | ||
| 96 | |||
| 97 | for (i = 0;i < j;++i) | ||
| 98 | { | ||
| 99 | ch = s[i]; | ||
| 100 | if (ch <= 32) return 0; | ||
| 101 | if (ch >= 127) return 0; | ||
| 102 | } | ||
| 103 | return 1; | ||
| 104 | } | ||
| 105 | |||
| 106 | unsigned int hfield_skipname(s,len) | ||
| 107 | char *s; | ||
| 108 | int len; | ||
| 109 | { | ||
| 110 | int i; | ||
| 111 | char ch; | ||
| 112 | |||
| 113 | for (i = 0;i < len;++i) | ||
| 114 | if (s[i] == ':') | ||
| 115 | break; | ||
| 116 | if (i < len) ++i; | ||
| 117 | while (i < len) | ||
| 118 | { | ||
| 119 | ch = s[i]; | ||
| 120 | if ((ch != '\t') && (ch != '\n') && (ch != '\r') && (ch != ' ')) | ||
| 121 | break; | ||
| 122 | ++i; | ||
| 123 | } | ||
| 124 | return i; | ||
| 125 | } | ||
diff --git a/hfield.h b/hfield.h new file mode 100644 index 0000000..20b30a5 --- /dev/null +++ b/hfield.h | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | #ifndef HFIELD_H | ||
| 2 | #define HFIELD_H | ||
| 3 | |||
| 4 | extern unsigned int hfield_skipname(); | ||
| 5 | extern int hfield_known(); | ||
| 6 | extern int hfield_valid(); | ||
| 7 | |||
| 8 | #define H_SENDER 1 | ||
| 9 | #define H_FROM 2 | ||
| 10 | #define H_REPLYTO 3 | ||
| 11 | #define H_TO 4 | ||
| 12 | #define H_CC 5 | ||
| 13 | #define H_BCC 6 | ||
| 14 | #define H_DATE 7 | ||
| 15 | #define H_MESSAGEID 8 | ||
| 16 | #define H_SUBJECT 9 | ||
| 17 | #define H_R_SENDER 10 | ||
| 18 | #define H_R_FROM 11 | ||
| 19 | #define H_R_REPLYTO 12 | ||
| 20 | #define H_R_TO 13 | ||
| 21 | #define H_R_CC 14 | ||
| 22 | #define H_R_BCC 15 | ||
| 23 | #define H_R_DATE 16 | ||
| 24 | #define H_R_MESSAGEID 17 | ||
| 25 | #define H_RETURNRECEIPTTO 18 | ||
| 26 | #define H_ERRORSTO 19 | ||
| 27 | #define H_APPARENTLYTO 20 | ||
| 28 | #define H_RECEIVED 21 | ||
| 29 | #define H_RETURNPATH 22 | ||
| 30 | #define H_DELIVEREDTO 23 | ||
| 31 | #define H_CONTENTLENGTH 24 | ||
| 32 | #define H_CONTENTTYPE 25 | ||
| 33 | #define H_CONTENTTRANSFERENCODING 26 | ||
| 34 | #define H_NOTICEREQUESTEDUPONDELIVERYTO 27 | ||
| 35 | #define H_MAILFOLLOWUPTO 28 | ||
| 36 | #define H_NUM 29 | ||
| 37 | |||
| 38 | #endif | ||
| @@ -0,0 +1,252 @@ | |||
| 1 | #include "auto_qmail.h" | ||
| 2 | #include "auto_split.h" | ||
| 3 | #include "auto_uids.h" | ||
| 4 | #include "fmt.h" | ||
| 5 | #include "fifo.h" | ||
| 6 | |||
| 7 | char buf[100 + FMT_ULONG]; | ||
| 8 | |||
| 9 | void dsplit(base,uid,mode) | ||
| 10 | char *base; /* must be under 100 bytes */ | ||
| 11 | int uid; | ||
| 12 | int mode; | ||
| 13 | { | ||
| 14 | char *x; | ||
| 15 | unsigned long i; | ||
| 16 | |||
| 17 | d(auto_qmail,base,uid,auto_gidq,mode); | ||
| 18 | |||
| 19 | for (i = 0;i < auto_split;++i) { | ||
| 20 | x = buf; | ||
| 21 | x += fmt_str(x,base); | ||
| 22 | x += fmt_str(x,"/"); | ||
| 23 | x += fmt_ulong(x,i); | ||
| 24 | *x = 0; | ||
| 25 | |||
| 26 | d(auto_qmail,buf,uid,auto_gidq,mode); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | void hier() | ||
| 31 | { | ||
| 32 | h(auto_qmail,auto_uido,auto_gidq,0755); | ||
| 33 | |||
| 34 | d(auto_qmail,"control",auto_uido,auto_gidq,0755); | ||
| 35 | d(auto_qmail,"users",auto_uido,auto_gidq,0755); | ||
| 36 | d(auto_qmail,"bin",auto_uido,auto_gidq,0755); | ||
| 37 | d(auto_qmail,"boot",auto_uido,auto_gidq,0755); | ||
| 38 | d(auto_qmail,"doc",auto_uido,auto_gidq,0755); | ||
| 39 | d(auto_qmail,"man",auto_uido,auto_gidq,0755); | ||
| 40 | d(auto_qmail,"man/cat1",auto_uido,auto_gidq,0755); | ||
| 41 | d(auto_qmail,"man/cat5",auto_uido,auto_gidq,0755); | ||
| 42 | d(auto_qmail,"man/cat7",auto_uido,auto_gidq,0755); | ||
| 43 | d(auto_qmail,"man/cat8",auto_uido,auto_gidq,0755); | ||
| 44 | d(auto_qmail,"man/man1",auto_uido,auto_gidq,0755); | ||
| 45 | d(auto_qmail,"man/man5",auto_uido,auto_gidq,0755); | ||
| 46 | d(auto_qmail,"man/man7",auto_uido,auto_gidq,0755); | ||
| 47 | d(auto_qmail,"man/man8",auto_uido,auto_gidq,0755); | ||
| 48 | |||
| 49 | d(auto_qmail,"alias",auto_uida,auto_gidq,02755); | ||
| 50 | |||
| 51 | d(auto_qmail,"queue",auto_uidq,auto_gidq,0750); | ||
| 52 | d(auto_qmail,"queue/pid",auto_uidq,auto_gidq,0700); | ||
| 53 | d(auto_qmail,"queue/intd",auto_uidq,auto_gidq,0700); | ||
| 54 | d(auto_qmail,"queue/todo",auto_uidq,auto_gidq,0750); | ||
| 55 | d(auto_qmail,"queue/bounce",auto_uids,auto_gidq,0700); | ||
| 56 | |||
| 57 | dsplit("queue/mess",auto_uidq,0750); | ||
| 58 | dsplit("queue/info",auto_uids,0700); | ||
| 59 | dsplit("queue/local",auto_uids,0700); | ||
| 60 | dsplit("queue/remote",auto_uids,0700); | ||
| 61 | |||
| 62 | d(auto_qmail,"queue/lock",auto_uidq,auto_gidq,0750); | ||
| 63 | z(auto_qmail,"queue/lock/tcpto",1024,auto_uidr,auto_gidq,0644); | ||
| 64 | z(auto_qmail,"queue/lock/sendmutex",0,auto_uids,auto_gidq,0600); | ||
| 65 | p(auto_qmail,"queue/lock/trigger",auto_uids,auto_gidq,0622); | ||
| 66 | |||
| 67 | c(auto_qmail,"boot","home",auto_uido,auto_gidq,0755); | ||
| 68 | c(auto_qmail,"boot","home+df",auto_uido,auto_gidq,0755); | ||
| 69 | c(auto_qmail,"boot","proc",auto_uido,auto_gidq,0755); | ||
| 70 | c(auto_qmail,"boot","proc+df",auto_uido,auto_gidq,0755); | ||
| 71 | c(auto_qmail,"boot","binm1",auto_uido,auto_gidq,0755); | ||
| 72 | c(auto_qmail,"boot","binm1+df",auto_uido,auto_gidq,0755); | ||
| 73 | c(auto_qmail,"boot","binm2",auto_uido,auto_gidq,0755); | ||
| 74 | c(auto_qmail,"boot","binm2+df",auto_uido,auto_gidq,0755); | ||
| 75 | c(auto_qmail,"boot","binm3",auto_uido,auto_gidq,0755); | ||
| 76 | c(auto_qmail,"boot","binm3+df",auto_uido,auto_gidq,0755); | ||
| 77 | |||
| 78 | c(auto_qmail,"doc","FAQ",auto_uido,auto_gidq,0644); | ||
| 79 | c(auto_qmail,"doc","UPGRADE",auto_uido,auto_gidq,0644); | ||
| 80 | c(auto_qmail,"doc","SENDMAIL",auto_uido,auto_gidq,0644); | ||
| 81 | c(auto_qmail,"doc","INSTALL",auto_uido,auto_gidq,0644); | ||
| 82 | c(auto_qmail,"doc","INSTALL.alias",auto_uido,auto_gidq,0644); | ||
| 83 | c(auto_qmail,"doc","INSTALL.ctl",auto_uido,auto_gidq,0644); | ||
| 84 | c(auto_qmail,"doc","INSTALL.ids",auto_uido,auto_gidq,0644); | ||
| 85 | c(auto_qmail,"doc","INSTALL.maildir",auto_uido,auto_gidq,0644); | ||
| 86 | c(auto_qmail,"doc","INSTALL.mbox",auto_uido,auto_gidq,0644); | ||
| 87 | c(auto_qmail,"doc","INSTALL.vsm",auto_uido,auto_gidq,0644); | ||
| 88 | c(auto_qmail,"doc","TEST.deliver",auto_uido,auto_gidq,0644); | ||
| 89 | c(auto_qmail,"doc","TEST.receive",auto_uido,auto_gidq,0644); | ||
| 90 | c(auto_qmail,"doc","REMOVE.sendmail",auto_uido,auto_gidq,0644); | ||
| 91 | c(auto_qmail,"doc","REMOVE.binmail",auto_uido,auto_gidq,0644); | ||
| 92 | c(auto_qmail,"doc","PIC.local2alias",auto_uido,auto_gidq,0644); | ||
| 93 | c(auto_qmail,"doc","PIC.local2ext",auto_uido,auto_gidq,0644); | ||
| 94 | c(auto_qmail,"doc","PIC.local2local",auto_uido,auto_gidq,0644); | ||
| 95 | c(auto_qmail,"doc","PIC.local2rem",auto_uido,auto_gidq,0644); | ||
| 96 | c(auto_qmail,"doc","PIC.local2virt",auto_uido,auto_gidq,0644); | ||
| 97 | c(auto_qmail,"doc","PIC.nullclient",auto_uido,auto_gidq,0644); | ||
| 98 | c(auto_qmail,"doc","PIC.relaybad",auto_uido,auto_gidq,0644); | ||
| 99 | c(auto_qmail,"doc","PIC.relaygood",auto_uido,auto_gidq,0644); | ||
| 100 | c(auto_qmail,"doc","PIC.rem2local",auto_uido,auto_gidq,0644); | ||
| 101 | |||
| 102 | c(auto_qmail,"bin","qmail-queue",auto_uidq,auto_gidq,04711); | ||
| 103 | c(auto_qmail,"bin","qmail-lspawn",auto_uido,auto_gidq,0700); | ||
| 104 | c(auto_qmail,"bin","qmail-start",auto_uido,auto_gidq,0700); | ||
| 105 | c(auto_qmail,"bin","qmail-getpw",auto_uido,auto_gidq,0711); | ||
| 106 | c(auto_qmail,"bin","qmail-local",auto_uido,auto_gidq,0711); | ||
| 107 | c(auto_qmail,"bin","qmail-remote",auto_uido,auto_gidq,0711); | ||
| 108 | c(auto_qmail,"bin","qmail-rspawn",auto_uido,auto_gidq,0711); | ||
| 109 | c(auto_qmail,"bin","qmail-clean",auto_uido,auto_gidq,0711); | ||
| 110 | c(auto_qmail,"bin","qmail-send",auto_uido,auto_gidq,0711); | ||
| 111 | c(auto_qmail,"bin","splogger",auto_uido,auto_gidq,0711); | ||
| 112 | c(auto_qmail,"bin","qmail-newu",auto_uido,auto_gidq,0700); | ||
| 113 | c(auto_qmail,"bin","qmail-newmrh",auto_uido,auto_gidq,0700); | ||
| 114 | c(auto_qmail,"bin","qmail-pw2u",auto_uido,auto_gidq,0711); | ||
| 115 | c(auto_qmail,"bin","qmail-inject",auto_uido,auto_gidq,0755); | ||
| 116 | c(auto_qmail,"bin","predate",auto_uido,auto_gidq,0755); | ||
| 117 | c(auto_qmail,"bin","datemail",auto_uido,auto_gidq,0755); | ||
| 118 | c(auto_qmail,"bin","mailsubj",auto_uido,auto_gidq,0755); | ||
| 119 | c(auto_qmail,"bin","qmail-showctl",auto_uido,auto_gidq,0755); | ||
| 120 | c(auto_qmail,"bin","qmail-qread",auto_uido,auto_gidq,0755); | ||
| 121 | c(auto_qmail,"bin","qmail-qstat",auto_uido,auto_gidq,0755); | ||
| 122 | c(auto_qmail,"bin","qmail-tcpto",auto_uido,auto_gidq,0755); | ||
| 123 | c(auto_qmail,"bin","qmail-tcpok",auto_uido,auto_gidq,0755); | ||
| 124 | c(auto_qmail,"bin","qmail-pop3d",auto_uido,auto_gidq,0755); | ||
| 125 | c(auto_qmail,"bin","qmail-popup",auto_uido,auto_gidq,0711); | ||
| 126 | c(auto_qmail,"bin","qmail-qmqpc",auto_uido,auto_gidq,0755); | ||
| 127 | c(auto_qmail,"bin","qmail-qmqpd",auto_uido,auto_gidq,0755); | ||
| 128 | c(auto_qmail,"bin","qmail-qmtpd",auto_uido,auto_gidq,0755); | ||
| 129 | c(auto_qmail,"bin","qmail-smtpd",auto_uido,auto_gidq,0755); | ||
| 130 | c(auto_qmail,"bin","sendmail",auto_uido,auto_gidq,0755); | ||
| 131 | c(auto_qmail,"bin","tcp-env",auto_uido,auto_gidq,0755); | ||
| 132 | c(auto_qmail,"bin","qreceipt",auto_uido,auto_gidq,0755); | ||
| 133 | c(auto_qmail,"bin","qsmhook",auto_uido,auto_gidq,0755); | ||
| 134 | c(auto_qmail,"bin","qbiff",auto_uido,auto_gidq,0755); | ||
| 135 | c(auto_qmail,"bin","forward",auto_uido,auto_gidq,0755); | ||
| 136 | c(auto_qmail,"bin","preline",auto_uido,auto_gidq,0755); | ||
| 137 | c(auto_qmail,"bin","condredirect",auto_uido,auto_gidq,0755); | ||
| 138 | c(auto_qmail,"bin","bouncesaying",auto_uido,auto_gidq,0755); | ||
| 139 | c(auto_qmail,"bin","except",auto_uido,auto_gidq,0755); | ||
| 140 | c(auto_qmail,"bin","maildirmake",auto_uido,auto_gidq,0755); | ||
| 141 | c(auto_qmail,"bin","maildir2mbox",auto_uido,auto_gidq,0755); | ||
| 142 | c(auto_qmail,"bin","maildirwatch",auto_uido,auto_gidq,0755); | ||
| 143 | c(auto_qmail,"bin","qail",auto_uido,auto_gidq,0755); | ||
| 144 | c(auto_qmail,"bin","elq",auto_uido,auto_gidq,0755); | ||
| 145 | c(auto_qmail,"bin","pinq",auto_uido,auto_gidq,0755); | ||
| 146 | |||
| 147 | c(auto_qmail,"man/man5","addresses.5",auto_uido,auto_gidq,0644); | ||
| 148 | c(auto_qmail,"man/cat5","addresses.0",auto_uido,auto_gidq,0644); | ||
| 149 | c(auto_qmail,"man/man5","envelopes.5",auto_uido,auto_gidq,0644); | ||
| 150 | c(auto_qmail,"man/cat5","envelopes.0",auto_uido,auto_gidq,0644); | ||
| 151 | c(auto_qmail,"man/man5","maildir.5",auto_uido,auto_gidq,0644); | ||
| 152 | c(auto_qmail,"man/cat5","maildir.0",auto_uido,auto_gidq,0644); | ||
| 153 | c(auto_qmail,"man/man5","mbox.5",auto_uido,auto_gidq,0644); | ||
| 154 | c(auto_qmail,"man/cat5","mbox.0",auto_uido,auto_gidq,0644); | ||
| 155 | c(auto_qmail,"man/man5","dot-qmail.5",auto_uido,auto_gidq,0644); | ||
| 156 | c(auto_qmail,"man/cat5","dot-qmail.0",auto_uido,auto_gidq,0644); | ||
| 157 | c(auto_qmail,"man/man5","qmail-control.5",auto_uido,auto_gidq,0644); | ||
| 158 | c(auto_qmail,"man/cat5","qmail-control.0",auto_uido,auto_gidq,0644); | ||
| 159 | c(auto_qmail,"man/man5","qmail-header.5",auto_uido,auto_gidq,0644); | ||
| 160 | c(auto_qmail,"man/cat5","qmail-header.0",auto_uido,auto_gidq,0644); | ||
| 161 | c(auto_qmail,"man/man5","qmail-log.5",auto_uido,auto_gidq,0644); | ||
| 162 | c(auto_qmail,"man/cat5","qmail-log.0",auto_uido,auto_gidq,0644); | ||
| 163 | c(auto_qmail,"man/man5","qmail-users.5",auto_uido,auto_gidq,0644); | ||
| 164 | c(auto_qmail,"man/cat5","qmail-users.0",auto_uido,auto_gidq,0644); | ||
| 165 | c(auto_qmail,"man/man5","tcp-environ.5",auto_uido,auto_gidq,0644); | ||
| 166 | c(auto_qmail,"man/cat5","tcp-environ.0",auto_uido,auto_gidq,0644); | ||
| 167 | |||
| 168 | c(auto_qmail,"man/man7","forgeries.7",auto_uido,auto_gidq,0644); | ||
| 169 | c(auto_qmail,"man/cat7","forgeries.0",auto_uido,auto_gidq,0644); | ||
| 170 | c(auto_qmail,"man/man7","qmail-limits.7",auto_uido,auto_gidq,0644); | ||
| 171 | c(auto_qmail,"man/cat7","qmail-limits.0",auto_uido,auto_gidq,0644); | ||
| 172 | c(auto_qmail,"man/man7","qmail.7",auto_uido,auto_gidq,0644); | ||
| 173 | c(auto_qmail,"man/cat7","qmail.0",auto_uido,auto_gidq,0644); | ||
| 174 | |||
| 175 | c(auto_qmail,"man/man1","forward.1",auto_uido,auto_gidq,0644); | ||
| 176 | c(auto_qmail,"man/cat1","forward.0",auto_uido,auto_gidq,0644); | ||
| 177 | c(auto_qmail,"man/man1","condredirect.1",auto_uido,auto_gidq,0644); | ||
| 178 | c(auto_qmail,"man/cat1","condredirect.0",auto_uido,auto_gidq,0644); | ||
| 179 | c(auto_qmail,"man/man1","bouncesaying.1",auto_uido,auto_gidq,0644); | ||
| 180 | c(auto_qmail,"man/cat1","bouncesaying.0",auto_uido,auto_gidq,0644); | ||
| 181 | c(auto_qmail,"man/man1","except.1",auto_uido,auto_gidq,0644); | ||
| 182 | c(auto_qmail,"man/cat1","except.0",auto_uido,auto_gidq,0644); | ||
| 183 | c(auto_qmail,"man/man1","maildirmake.1",auto_uido,auto_gidq,0644); | ||
| 184 | c(auto_qmail,"man/cat1","maildirmake.0",auto_uido,auto_gidq,0644); | ||
| 185 | c(auto_qmail,"man/man1","maildir2mbox.1",auto_uido,auto_gidq,0644); | ||
| 186 | c(auto_qmail,"man/cat1","maildir2mbox.0",auto_uido,auto_gidq,0644); | ||
| 187 | c(auto_qmail,"man/man1","maildirwatch.1",auto_uido,auto_gidq,0644); | ||
| 188 | c(auto_qmail,"man/cat1","maildirwatch.0",auto_uido,auto_gidq,0644); | ||
| 189 | c(auto_qmail,"man/man1","mailsubj.1",auto_uido,auto_gidq,0644); | ||
| 190 | c(auto_qmail,"man/cat1","mailsubj.0",auto_uido,auto_gidq,0644); | ||
| 191 | c(auto_qmail,"man/man1","qreceipt.1",auto_uido,auto_gidq,0644); | ||
| 192 | c(auto_qmail,"man/cat1","qreceipt.0",auto_uido,auto_gidq,0644); | ||
| 193 | c(auto_qmail,"man/man1","qbiff.1",auto_uido,auto_gidq,0644); | ||
| 194 | c(auto_qmail,"man/cat1","qbiff.0",auto_uido,auto_gidq,0644); | ||
| 195 | c(auto_qmail,"man/man1","preline.1",auto_uido,auto_gidq,0644); | ||
| 196 | c(auto_qmail,"man/cat1","preline.0",auto_uido,auto_gidq,0644); | ||
| 197 | c(auto_qmail,"man/man1","tcp-env.1",auto_uido,auto_gidq,0644); | ||
| 198 | c(auto_qmail,"man/cat1","tcp-env.0",auto_uido,auto_gidq,0644); | ||
| 199 | |||
| 200 | c(auto_qmail,"man/man8","qmail-local.8",auto_uido,auto_gidq,0644); | ||
| 201 | c(auto_qmail,"man/cat8","qmail-local.0",auto_uido,auto_gidq,0644); | ||
| 202 | c(auto_qmail,"man/man8","qmail-lspawn.8",auto_uido,auto_gidq,0644); | ||
| 203 | c(auto_qmail,"man/cat8","qmail-lspawn.0",auto_uido,auto_gidq,0644); | ||
| 204 | c(auto_qmail,"man/man8","qmail-getpw.8",auto_uido,auto_gidq,0644); | ||
| 205 | c(auto_qmail,"man/cat8","qmail-getpw.0",auto_uido,auto_gidq,0644); | ||
| 206 | c(auto_qmail,"man/man8","qmail-remote.8",auto_uido,auto_gidq,0644); | ||
| 207 | c(auto_qmail,"man/cat8","qmail-remote.0",auto_uido,auto_gidq,0644); | ||
| 208 | c(auto_qmail,"man/man8","qmail-rspawn.8",auto_uido,auto_gidq,0644); | ||
| 209 | c(auto_qmail,"man/cat8","qmail-rspawn.0",auto_uido,auto_gidq,0644); | ||
| 210 | c(auto_qmail,"man/man8","qmail-clean.8",auto_uido,auto_gidq,0644); | ||
| 211 | c(auto_qmail,"man/cat8","qmail-clean.0",auto_uido,auto_gidq,0644); | ||
| 212 | c(auto_qmail,"man/man8","qmail-send.8",auto_uido,auto_gidq,0644); | ||
| 213 | c(auto_qmail,"man/cat8","qmail-send.0",auto_uido,auto_gidq,0644); | ||
| 214 | c(auto_qmail,"man/man8","qmail-start.8",auto_uido,auto_gidq,0644); | ||
| 215 | c(auto_qmail,"man/cat8","qmail-start.0",auto_uido,auto_gidq,0644); | ||
| 216 | c(auto_qmail,"man/man8","splogger.8",auto_uido,auto_gidq,0644); | ||
| 217 | c(auto_qmail,"man/cat8","splogger.0",auto_uido,auto_gidq,0644); | ||
| 218 | c(auto_qmail,"man/man8","qmail-queue.8",auto_uido,auto_gidq,0644); | ||
| 219 | c(auto_qmail,"man/cat8","qmail-queue.0",auto_uido,auto_gidq,0644); | ||
| 220 | c(auto_qmail,"man/man8","qmail-inject.8",auto_uido,auto_gidq,0644); | ||
| 221 | c(auto_qmail,"man/cat8","qmail-inject.0",auto_uido,auto_gidq,0644); | ||
| 222 | c(auto_qmail,"man/man8","qmail-showctl.8",auto_uido,auto_gidq,0644); | ||
| 223 | c(auto_qmail,"man/cat8","qmail-showctl.0",auto_uido,auto_gidq,0644); | ||
| 224 | c(auto_qmail,"man/man8","qmail-newmrh.8",auto_uido,auto_gidq,0644); | ||
| 225 | c(auto_qmail,"man/cat8","qmail-newmrh.0",auto_uido,auto_gidq,0644); | ||
| 226 | c(auto_qmail,"man/man8","qmail-newu.8",auto_uido,auto_gidq,0644); | ||
| 227 | c(auto_qmail,"man/cat8","qmail-newu.0",auto_uido,auto_gidq,0644); | ||
| 228 | c(auto_qmail,"man/man8","qmail-pw2u.8",auto_uido,auto_gidq,0644); | ||
| 229 | c(auto_qmail,"man/cat8","qmail-pw2u.0",auto_uido,auto_gidq,0644); | ||
| 230 | c(auto_qmail,"man/man8","qmail-qread.8",auto_uido,auto_gidq,0644); | ||
| 231 | c(auto_qmail,"man/cat8","qmail-qread.0",auto_uido,auto_gidq,0644); | ||
| 232 | c(auto_qmail,"man/man8","qmail-qstat.8",auto_uido,auto_gidq,0644); | ||
| 233 | c(auto_qmail,"man/cat8","qmail-qstat.0",auto_uido,auto_gidq,0644); | ||
| 234 | c(auto_qmail,"man/man8","qmail-tcpok.8",auto_uido,auto_gidq,0644); | ||
| 235 | c(auto_qmail,"man/cat8","qmail-tcpok.0",auto_uido,auto_gidq,0644); | ||
| 236 | c(auto_qmail,"man/man8","qmail-tcpto.8",auto_uido,auto_gidq,0644); | ||
| 237 | c(auto_qmail,"man/cat8","qmail-tcpto.0",auto_uido,auto_gidq,0644); | ||
| 238 | c(auto_qmail,"man/man8","qmail-pop3d.8",auto_uido,auto_gidq,0644); | ||
| 239 | c(auto_qmail,"man/cat8","qmail-pop3d.0",auto_uido,auto_gidq,0644); | ||
| 240 | c(auto_qmail,"man/man8","qmail-popup.8",auto_uido,auto_gidq,0644); | ||
| 241 | c(auto_qmail,"man/cat8","qmail-popup.0",auto_uido,auto_gidq,0644); | ||
| 242 | c(auto_qmail,"man/man8","qmail-qmqpc.8",auto_uido,auto_gidq,0644); | ||
| 243 | c(auto_qmail,"man/cat8","qmail-qmqpc.0",auto_uido,auto_gidq,0644); | ||
| 244 | c(auto_qmail,"man/man8","qmail-qmqpd.8",auto_uido,auto_gidq,0644); | ||
| 245 | c(auto_qmail,"man/cat8","qmail-qmqpd.0",auto_uido,auto_gidq,0644); | ||
| 246 | c(auto_qmail,"man/man8","qmail-qmtpd.8",auto_uido,auto_gidq,0644); | ||
| 247 | c(auto_qmail,"man/cat8","qmail-qmtpd.0",auto_uido,auto_gidq,0644); | ||
| 248 | c(auto_qmail,"man/man8","qmail-smtpd.8",auto_uido,auto_gidq,0644); | ||
| 249 | c(auto_qmail,"man/cat8","qmail-smtpd.0",auto_uido,auto_gidq,0644); | ||
| 250 | c(auto_qmail,"man/man8","qmail-command.8",auto_uido,auto_gidq,0644); | ||
| 251 | c(auto_qmail,"man/cat8","qmail-command.0",auto_uido,auto_gidq,0644); | ||
| 252 | } | ||
diff --git a/home+df.sh b/home+df.sh new file mode 100644 index 0000000..7885cdf --- /dev/null +++ b/home+df.sh | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | # Using splogger to send the log through syslog. | ||
| 4 | # Using dot-forward to support sendmail-style ~/.forward files. | ||
| 5 | # Using qmail-local to deliver messages to ~/Mailbox by default. | ||
| 6 | |||
| 7 | exec env - PATH="QMAIL/bin:$PATH" \ | ||
| 8 | qmail-start '|dot-forward .forward | ||
| 9 | ./Mailbox' splogger qmail | ||
| @@ -0,0 +1,7 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | # Using splogger to send the log through syslog. | ||
| 4 | # Using qmail-local to deliver messages to ~/Mailbox by default. | ||
| 5 | |||
| 6 | exec env - PATH="QMAIL/bin:$PATH" \ | ||
| 7 | qmail-start ./Mailbox splogger qmail | ||
diff --git a/hostname.c b/hostname.c new file mode 100644 index 0000000..39c7f87 --- /dev/null +++ b/hostname.c | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "subfd.h" | ||
| 3 | #include "readwrite.h" | ||
| 4 | #include "exit.h" | ||
| 5 | |||
| 6 | char host[256]; | ||
| 7 | |||
| 8 | void main() | ||
| 9 | { | ||
| 10 | host[0] = 0; /* sigh */ | ||
| 11 | gethostname(host,sizeof(host)); | ||
| 12 | host[sizeof(host) - 1] = 0; | ||
| 13 | substdio_puts(subfdoutsmall,host); | ||
| 14 | substdio_puts(subfdoutsmall,"\n"); | ||
| 15 | substdio_flush(subfdoutsmall); | ||
| 16 | _exit(0); | ||
| 17 | } | ||
diff --git a/idedit.c b/idedit.c new file mode 100644 index 0000000..e6747b5 --- /dev/null +++ b/idedit.c | |||
| @@ -0,0 +1,147 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <pwd.h> | ||
| 3 | #include <grp.h> | ||
| 4 | #include "readwrite.h" | ||
| 5 | #include "exit.h" | ||
| 6 | #include "scan.h" | ||
| 7 | #include "fmt.h" | ||
| 8 | #include "strerr.h" | ||
| 9 | #include "open.h" | ||
| 10 | #include "seek.h" | ||
| 11 | #include "fork.h" | ||
| 12 | |||
| 13 | #define FATAL "idedit: fatal: " | ||
| 14 | #define WARNING "idedit: warning: " | ||
| 15 | |||
| 16 | int fd; | ||
| 17 | |||
| 18 | void byte(pos,value) | ||
| 19 | char *pos; | ||
| 20 | unsigned int value; | ||
| 21 | { | ||
| 22 | unsigned long u; | ||
| 23 | unsigned char ch; | ||
| 24 | |||
| 25 | if (pos[scan_ulong(pos,&u)]) return; | ||
| 26 | |||
| 27 | if (seek_set(fd,(seek_pos) u) == -1) | ||
| 28 | strerr_die2sys(111,FATAL,"unable to seek: "); | ||
| 29 | |||
| 30 | ch = value; | ||
| 31 | if (write(fd,&ch,1) != 1) | ||
| 32 | strerr_die2sys(111,FATAL,"unable to write: "); | ||
| 33 | } | ||
| 34 | |||
| 35 | char *args[10]; | ||
| 36 | |||
| 37 | void run() | ||
| 38 | { | ||
| 39 | int pid; | ||
| 40 | int wstat; | ||
| 41 | |||
| 42 | pid = fork(); | ||
| 43 | if (pid == -1) | ||
| 44 | strerr_die2sys(111,FATAL,"unable to fork: "); | ||
| 45 | |||
| 46 | if (pid == 0) { | ||
| 47 | execv(*args,args); | ||
| 48 | strerr_die4sys(111,WARNING,"unable to run ",*args,": "); | ||
| 49 | } | ||
| 50 | |||
| 51 | if (wait_pid(&wstat,pid) != pid) | ||
| 52 | strerr_die2sys(111,FATAL,"waitpid surprise"); | ||
| 53 | } | ||
| 54 | |||
| 55 | void u(account,group,home,pos0,pos1,pos2,pos3) | ||
| 56 | char *account; | ||
| 57 | char *group; | ||
| 58 | char *home; | ||
| 59 | char *pos0; | ||
| 60 | char *pos1; | ||
| 61 | char *pos2; | ||
| 62 | char *pos3; | ||
| 63 | { | ||
| 64 | struct passwd *pw; | ||
| 65 | unsigned int value; | ||
| 66 | |||
| 67 | pw = getpwnam(account); | ||
| 68 | |||
| 69 | if (!pw && group) { | ||
| 70 | args[0] = "add-account"; | ||
| 71 | args[1] = account; | ||
| 72 | args[2] = group; | ||
| 73 | args[3] = home; | ||
| 74 | args[4] = 0; | ||
| 75 | run(); | ||
| 76 | pw = getpwnam(account); | ||
| 77 | } | ||
| 78 | |||
| 79 | if (!pw) | ||
| 80 | strerr_die3x(111,FATAL,"unable to find uid for ",account); | ||
| 81 | |||
| 82 | value = pw->pw_uid; | ||
| 83 | byte(pos0,value); value >>= 8; | ||
| 84 | byte(pos1,value); value >>= 8; | ||
| 85 | byte(pos2,value); value >>= 8; | ||
| 86 | byte(pos3,value); value >>= 8; | ||
| 87 | if (value) | ||
| 88 | strerr_die3x(111,FATAL,"excessively large uid for ",account); | ||
| 89 | } | ||
| 90 | |||
| 91 | void g(group,pos0,pos1,pos2,pos3) | ||
| 92 | char *group; | ||
| 93 | char *pos0; | ||
| 94 | char *pos1; | ||
| 95 | char *pos2; | ||
| 96 | char *pos3; | ||
| 97 | { | ||
| 98 | struct group *gr; | ||
| 99 | unsigned int value; | ||
| 100 | |||
| 101 | gr = getgrnam(group); | ||
| 102 | |||
| 103 | if (!gr) { | ||
| 104 | args[0] = "add-group"; | ||
| 105 | args[1] = group; | ||
| 106 | args[2] = 0; | ||
| 107 | run(); | ||
| 108 | gr = getgrnam(group); | ||
| 109 | } | ||
| 110 | |||
| 111 | if (!gr) | ||
| 112 | strerr_die3x(111,FATAL,"unable to find gid for ",group); | ||
| 113 | |||
| 114 | value = gr->gr_gid; | ||
| 115 | byte(pos0,value); value >>= 8; | ||
| 116 | byte(pos1,value); value >>= 8; | ||
| 117 | byte(pos2,value); value >>= 8; | ||
| 118 | byte(pos3,value); value >>= 8; | ||
| 119 | if (value) | ||
| 120 | strerr_die3x(111,FATAL,"excessively large gid for ",group); | ||
| 121 | } | ||
| 122 | |||
| 123 | void main(argc,argv) | ||
| 124 | int argc; | ||
| 125 | char **argv; | ||
| 126 | { | ||
| 127 | if (argc < 42) _exit(100); | ||
| 128 | |||
| 129 | fd = open_write(argv[1]); | ||
| 130 | if (fd == -1) strerr_die4sys(111,FATAL,"unable to open ",argv[1],": "); | ||
| 131 | |||
| 132 | g("qmail",argv[34],argv[35],argv[36],argv[37]); | ||
| 133 | g("nofiles",argv[38],argv[39],argv[40],argv[41]); | ||
| 134 | |||
| 135 | u("root",(char *) 0,"/",argv[14],argv[15],argv[16],argv[17]); | ||
| 136 | |||
| 137 | u("qmaild","nofiles","/var/qmail",argv[6],argv[7],argv[8],argv[9]); | ||
| 138 | u("qmaill","nofiles","/var/qmail",argv[10],argv[11],argv[12],argv[13]); | ||
| 139 | u("qmailp","nofiles","/var/qmail",argv[18],argv[19],argv[20],argv[21]); | ||
| 140 | u("alias","nofiles","/var/qmail/alias",argv[2],argv[3],argv[4],argv[5]); | ||
| 141 | |||
| 142 | u("qmailq","qmail","/var/qmail",argv[22],argv[23],argv[24],argv[25]); | ||
| 143 | u("qmailr","qmail","/var/qmail",argv[26],argv[27],argv[28],argv[29]); | ||
| 144 | u("qmails","qmail","/var/qmail",argv[30],argv[31],argv[32],argv[33]); | ||
| 145 | |||
| 146 | _exit(0); | ||
| 147 | } | ||
diff --git a/install-big.c b/install-big.c new file mode 100644 index 0000000..df813df --- /dev/null +++ b/install-big.c | |||
| @@ -0,0 +1,285 @@ | |||
| 1 | #include "auto_qmail.h" | ||
| 2 | #include "auto_split.h" | ||
| 3 | #include "auto_uids.h" | ||
| 4 | #include "fmt.h" | ||
| 5 | #include "fifo.h" | ||
| 6 | |||
| 7 | char buf[100 + FMT_ULONG]; | ||
| 8 | |||
| 9 | void dsplit(base,uid,mode) | ||
| 10 | char *base; /* must be under 100 bytes */ | ||
| 11 | int uid; | ||
| 12 | int mode; | ||
| 13 | { | ||
| 14 | char *x; | ||
| 15 | unsigned long i; | ||
| 16 | |||
| 17 | d(auto_qmail,base,uid,auto_gidq,mode); | ||
| 18 | |||
| 19 | for (i = 0;i < auto_split;++i) { | ||
| 20 | x = buf; | ||
| 21 | x += fmt_str(x,base); | ||
| 22 | x += fmt_str(x,"/"); | ||
| 23 | x += fmt_ulong(x,i); | ||
| 24 | *x = 0; | ||
| 25 | |||
| 26 | d(auto_qmail,buf,uid,auto_gidq,mode); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | void hier() | ||
| 31 | { | ||
| 32 | h(auto_qmail,auto_uido,auto_gidq,0755); | ||
| 33 | |||
| 34 | d(auto_qmail,"control",auto_uido,auto_gidq,0755); | ||
| 35 | d(auto_qmail,"users",auto_uido,auto_gidq,0755); | ||
| 36 | d(auto_qmail,"bin",auto_uido,auto_gidq,0755); | ||
| 37 | d(auto_qmail,"boot",auto_uido,auto_gidq,0755); | ||
| 38 | d(auto_qmail,"doc",auto_uido,auto_gidq,0755); | ||
| 39 | d(auto_qmail,"man",auto_uido,auto_gidq,0755); | ||
| 40 | d(auto_qmail,"man/cat1",auto_uido,auto_gidq,0755); | ||
| 41 | d(auto_qmail,"man/cat5",auto_uido,auto_gidq,0755); | ||
| 42 | d(auto_qmail,"man/cat7",auto_uido,auto_gidq,0755); | ||
| 43 | d(auto_qmail,"man/cat8",auto_uido,auto_gidq,0755); | ||
| 44 | d(auto_qmail,"man/man1",auto_uido,auto_gidq,0755); | ||
| 45 | d(auto_qmail,"man/man5",auto_uido,auto_gidq,0755); | ||
| 46 | d(auto_qmail,"man/man7",auto_uido,auto_gidq,0755); | ||
| 47 | d(auto_qmail,"man/man8",auto_uido,auto_gidq,0755); | ||
| 48 | |||
| 49 | d(auto_qmail,"alias",auto_uida,auto_gidq,02755); | ||
| 50 | |||
| 51 | d(auto_qmail,"queue",auto_uidq,auto_gidq,0750); | ||
| 52 | d(auto_qmail,"queue/pid",auto_uidq,auto_gidq,0700); | ||
| 53 | d(auto_qmail,"queue/intd",auto_uidq,auto_gidq,0700); | ||
| 54 | d(auto_qmail,"queue/todo",auto_uidq,auto_gidq,0750); | ||
| 55 | d(auto_qmail,"queue/bounce",auto_uids,auto_gidq,0700); | ||
| 56 | |||
| 57 | dsplit("queue/mess",auto_uidq,0750); | ||
| 58 | dsplit("queue/info",auto_uids,0700); | ||
| 59 | dsplit("queue/local",auto_uids,0700); | ||
| 60 | dsplit("queue/remote",auto_uids,0700); | ||
| 61 | |||
| 62 | d(auto_qmail,"queue/lock",auto_uidq,auto_gidq,0750); | ||
| 63 | z(auto_qmail,"queue/lock/tcpto",1024,auto_uidr,auto_gidq,0644); | ||
| 64 | z(auto_qmail,"queue/lock/sendmutex",0,auto_uids,auto_gidq,0600); | ||
| 65 | p(auto_qmail,"queue/lock/trigger",auto_uids,auto_gidq,0622); | ||
| 66 | |||
| 67 | c(auto_qmail,"boot","home",auto_uido,auto_gidq,0755); | ||
| 68 | c(auto_qmail,"boot","home+df",auto_uido,auto_gidq,0755); | ||
| 69 | c(auto_qmail,"boot","proc",auto_uido,auto_gidq,0755); | ||
| 70 | c(auto_qmail,"boot","proc+df",auto_uido,auto_gidq,0755); | ||
| 71 | c(auto_qmail,"boot","binm1",auto_uido,auto_gidq,0755); | ||
| 72 | c(auto_qmail,"boot","binm1+df",auto_uido,auto_gidq,0755); | ||
| 73 | c(auto_qmail,"boot","binm2",auto_uido,auto_gidq,0755); | ||
| 74 | c(auto_qmail,"boot","binm2+df",auto_uido,auto_gidq,0755); | ||
| 75 | c(auto_qmail,"boot","binm3",auto_uido,auto_gidq,0755); | ||
| 76 | c(auto_qmail,"boot","binm3+df",auto_uido,auto_gidq,0755); | ||
| 77 | |||
| 78 | c(auto_qmail,"doc","FAQ",auto_uido,auto_gidq,0644); | ||
| 79 | c(auto_qmail,"doc","UPGRADE",auto_uido,auto_gidq,0644); | ||
| 80 | c(auto_qmail,"doc","SENDMAIL",auto_uido,auto_gidq,0644); | ||
| 81 | c(auto_qmail,"doc","INSTALL",auto_uido,auto_gidq,0644); | ||
| 82 | c(auto_qmail,"doc","INSTALL.alias",auto_uido,auto_gidq,0644); | ||
| 83 | c(auto_qmail,"doc","INSTALL.ctl",auto_uido,auto_gidq,0644); | ||
| 84 | c(auto_qmail,"doc","INSTALL.ids",auto_uido,auto_gidq,0644); | ||
| 85 | c(auto_qmail,"doc","INSTALL.maildir",auto_uido,auto_gidq,0644); | ||
| 86 | c(auto_qmail,"doc","INSTALL.mbox",auto_uido,auto_gidq,0644); | ||
| 87 | c(auto_qmail,"doc","INSTALL.vsm",auto_uido,auto_gidq,0644); | ||
| 88 | c(auto_qmail,"doc","TEST.deliver",auto_uido,auto_gidq,0644); | ||
| 89 | c(auto_qmail,"doc","TEST.receive",auto_uido,auto_gidq,0644); | ||
| 90 | c(auto_qmail,"doc","REMOVE.sendmail",auto_uido,auto_gidq,0644); | ||
| 91 | c(auto_qmail,"doc","REMOVE.binmail",auto_uido,auto_gidq,0644); | ||
| 92 | c(auto_qmail,"doc","PIC.local2alias",auto_uido,auto_gidq,0644); | ||
| 93 | c(auto_qmail,"doc","PIC.local2ext",auto_uido,auto_gidq,0644); | ||
| 94 | c(auto_qmail,"doc","PIC.local2local",auto_uido,auto_gidq,0644); | ||
| 95 | c(auto_qmail,"doc","PIC.local2rem",auto_uido,auto_gidq,0644); | ||
| 96 | c(auto_qmail,"doc","PIC.local2virt",auto_uido,auto_gidq,0644); | ||
| 97 | c(auto_qmail,"doc","PIC.nullclient",auto_uido,auto_gidq,0644); | ||
| 98 | c(auto_qmail,"doc","PIC.relaybad",auto_uido,auto_gidq,0644); | ||
| 99 | c(auto_qmail,"doc","PIC.relaygood",auto_uido,auto_gidq,0644); | ||
| 100 | c(auto_qmail,"doc","PIC.rem2local",auto_uido,auto_gidq,0644); | ||
| 101 | |||
| 102 | c(auto_qmail,"bin","qmail-queue",auto_uidq,auto_gidq,04711); | ||
| 103 | c(auto_qmail,"bin","qmail-lspawn",auto_uido,auto_gidq,0700); | ||
| 104 | c(auto_qmail,"bin","qmail-start",auto_uido,auto_gidq,0700); | ||
| 105 | c(auto_qmail,"bin","qmail-getpw",auto_uido,auto_gidq,0711); | ||
| 106 | c(auto_qmail,"bin","qmail-local",auto_uido,auto_gidq,0711); | ||
| 107 | c(auto_qmail,"bin","qmail-remote",auto_uido,auto_gidq,0711); | ||
| 108 | c(auto_qmail,"bin","qmail-rspawn",auto_uido,auto_gidq,0711); | ||
| 109 | c(auto_qmail,"bin","qmail-clean",auto_uido,auto_gidq,0711); | ||
| 110 | c(auto_qmail,"bin","qmail-send",auto_uido,auto_gidq,0711); | ||
| 111 | c(auto_qmail,"bin","splogger",auto_uido,auto_gidq,0711); | ||
| 112 | c(auto_qmail,"bin","qmail-newu",auto_uido,auto_gidq,0700); | ||
| 113 | c(auto_qmail,"bin","qmail-newmrh",auto_uido,auto_gidq,0700); | ||
| 114 | c(auto_qmail,"bin","qmail-pw2u",auto_uido,auto_gidq,0711); | ||
| 115 | c(auto_qmail,"bin","qmail-inject",auto_uido,auto_gidq,0755); | ||
| 116 | c(auto_qmail,"bin","predate",auto_uido,auto_gidq,0755); | ||
| 117 | c(auto_qmail,"bin","datemail",auto_uido,auto_gidq,0755); | ||
| 118 | c(auto_qmail,"bin","mailsubj",auto_uido,auto_gidq,0755); | ||
| 119 | c(auto_qmail,"bin","qmail-showctl",auto_uido,auto_gidq,0755); | ||
| 120 | c(auto_qmail,"bin","qmail-qread",auto_uido,auto_gidq,0755); | ||
| 121 | c(auto_qmail,"bin","qmail-qstat",auto_uido,auto_gidq,0755); | ||
| 122 | c(auto_qmail,"bin","qmail-tcpto",auto_uido,auto_gidq,0755); | ||
| 123 | c(auto_qmail,"bin","qmail-tcpok",auto_uido,auto_gidq,0755); | ||
| 124 | c(auto_qmail,"bin","qmail-pop3d",auto_uido,auto_gidq,0755); | ||
| 125 | c(auto_qmail,"bin","qmail-popup",auto_uido,auto_gidq,0711); | ||
| 126 | c(auto_qmail,"bin","qmail-qmqpc",auto_uido,auto_gidq,0755); | ||
| 127 | c(auto_qmail,"bin","qmail-qmqpd",auto_uido,auto_gidq,0755); | ||
| 128 | c(auto_qmail,"bin","qmail-qmtpd",auto_uido,auto_gidq,0755); | ||
| 129 | c(auto_qmail,"bin","qmail-smtpd",auto_uido,auto_gidq,0755); | ||
| 130 | c(auto_qmail,"bin","sendmail",auto_uido,auto_gidq,0755); | ||
| 131 | c(auto_qmail,"bin","tcp-env",auto_uido,auto_gidq,0755); | ||
| 132 | c(auto_qmail,"bin","qreceipt",auto_uido,auto_gidq,0755); | ||
| 133 | c(auto_qmail,"bin","qsmhook",auto_uido,auto_gidq,0755); | ||
| 134 | c(auto_qmail,"bin","qbiff",auto_uido,auto_gidq,0755); | ||
| 135 | c(auto_qmail,"bin","forward",auto_uido,auto_gidq,0755); | ||
| 136 | c(auto_qmail,"bin","preline",auto_uido,auto_gidq,0755); | ||
| 137 | c(auto_qmail,"bin","condredirect",auto_uido,auto_gidq,0755); | ||
| 138 | c(auto_qmail,"bin","bouncesaying",auto_uido,auto_gidq,0755); | ||
| 139 | c(auto_qmail,"bin","except",auto_uido,auto_gidq,0755); | ||
| 140 | c(auto_qmail,"bin","maildirmake",auto_uido,auto_gidq,0755); | ||
| 141 | c(auto_qmail,"bin","maildir2mbox",auto_uido,auto_gidq,0755); | ||
| 142 | c(auto_qmail,"bin","maildirwatch",auto_uido,auto_gidq,0755); | ||
| 143 | c(auto_qmail,"bin","qail",auto_uido,auto_gidq,0755); | ||
| 144 | c(auto_qmail,"bin","elq",auto_uido,auto_gidq,0755); | ||
| 145 | c(auto_qmail,"bin","pinq",auto_uido,auto_gidq,0755); | ||
| 146 | |||
| 147 | c(auto_qmail,"man/man5","addresses.5",auto_uido,auto_gidq,0644); | ||
| 148 | c(auto_qmail,"man/cat5","addresses.0",auto_uido,auto_gidq,0644); | ||
| 149 | c(auto_qmail,"man/man5","envelopes.5",auto_uido,auto_gidq,0644); | ||
| 150 | c(auto_qmail,"man/cat5","envelopes.0",auto_uido,auto_gidq,0644); | ||
| 151 | c(auto_qmail,"man/man5","maildir.5",auto_uido,auto_gidq,0644); | ||
| 152 | c(auto_qmail,"man/cat5","maildir.0",auto_uido,auto_gidq,0644); | ||
| 153 | c(auto_qmail,"man/man5","mbox.5",auto_uido,auto_gidq,0644); | ||
| 154 | c(auto_qmail,"man/cat5","mbox.0",auto_uido,auto_gidq,0644); | ||
| 155 | c(auto_qmail,"man/man5","dot-qmail.5",auto_uido,auto_gidq,0644); | ||
| 156 | c(auto_qmail,"man/cat5","dot-qmail.0",auto_uido,auto_gidq,0644); | ||
| 157 | c(auto_qmail,"man/man5","qmail-control.5",auto_uido,auto_gidq,0644); | ||
| 158 | c(auto_qmail,"man/cat5","qmail-control.0",auto_uido,auto_gidq,0644); | ||
| 159 | c(auto_qmail,"man/man5","qmail-header.5",auto_uido,auto_gidq,0644); | ||
| 160 | c(auto_qmail,"man/cat5","qmail-header.0",auto_uido,auto_gidq,0644); | ||
| 161 | c(auto_qmail,"man/man5","qmail-log.5",auto_uido,auto_gidq,0644); | ||
| 162 | c(auto_qmail,"man/cat5","qmail-log.0",auto_uido,auto_gidq,0644); | ||
| 163 | c(auto_qmail,"man/man5","qmail-users.5",auto_uido,auto_gidq,0644); | ||
| 164 | c(auto_qmail,"man/cat5","qmail-users.0",auto_uido,auto_gidq,0644); | ||
| 165 | c(auto_qmail,"man/man5","tcp-environ.5",auto_uido,auto_gidq,0644); | ||
| 166 | c(auto_qmail,"man/cat5","tcp-environ.0",auto_uido,auto_gidq,0644); | ||
| 167 | |||
| 168 | c(auto_qmail,"man/man7","forgeries.7",auto_uido,auto_gidq,0644); | ||
| 169 | c(auto_qmail,"man/cat7","forgeries.0",auto_uido,auto_gidq,0644); | ||
| 170 | c(auto_qmail,"man/man7","qmail-limits.7",auto_uido,auto_gidq,0644); | ||
| 171 | c(auto_qmail,"man/cat7","qmail-limits.0",auto_uido,auto_gidq,0644); | ||
| 172 | c(auto_qmail,"man/man7","qmail.7",auto_uido,auto_gidq,0644); | ||
| 173 | c(auto_qmail,"man/cat7","qmail.0",auto_uido,auto_gidq,0644); | ||
| 174 | |||
| 175 | c(auto_qmail,"man/man1","forward.1",auto_uido,auto_gidq,0644); | ||
| 176 | c(auto_qmail,"man/cat1","forward.0",auto_uido,auto_gidq,0644); | ||
| 177 | c(auto_qmail,"man/man1","condredirect.1",auto_uido,auto_gidq,0644); | ||
| 178 | c(auto_qmail,"man/cat1","condredirect.0",auto_uido,auto_gidq,0644); | ||
| 179 | c(auto_qmail,"man/man1","bouncesaying.1",auto_uido,auto_gidq,0644); | ||
| 180 | c(auto_qmail,"man/cat1","bouncesaying.0",auto_uido,auto_gidq,0644); | ||
| 181 | c(auto_qmail,"man/man1","except.1",auto_uido,auto_gidq,0644); | ||
| 182 | c(auto_qmail,"man/cat1","except.0",auto_uido,auto_gidq,0644); | ||
| 183 | c(auto_qmail,"man/man1","maildirmake.1",auto_uido,auto_gidq,0644); | ||
| 184 | c(auto_qmail,"man/cat1","maildirmake.0",auto_uido,auto_gidq,0644); | ||
| 185 | c(auto_qmail,"man/man1","maildir2mbox.1",auto_uido,auto_gidq,0644); | ||
| 186 | c(auto_qmail,"man/cat1","maildir2mbox.0",auto_uido,auto_gidq,0644); | ||
| 187 | c(auto_qmail,"man/man1","maildirwatch.1",auto_uido,auto_gidq,0644); | ||
| 188 | c(auto_qmail,"man/cat1","maildirwatch.0",auto_uido,auto_gidq,0644); | ||
| 189 | c(auto_qmail,"man/man1","mailsubj.1",auto_uido,auto_gidq,0644); | ||
| 190 | c(auto_qmail,"man/cat1","mailsubj.0",auto_uido,auto_gidq,0644); | ||
| 191 | c(auto_qmail,"man/man1","qreceipt.1",auto_uido,auto_gidq,0644); | ||
| 192 | c(auto_qmail,"man/cat1","qreceipt.0",auto_uido,auto_gidq,0644); | ||
| 193 | c(auto_qmail,"man/man1","qbiff.1",auto_uido,auto_gidq,0644); | ||
| 194 | c(auto_qmail,"man/cat1","qbiff.0",auto_uido,auto_gidq,0644); | ||
| 195 | c(auto_qmail,"man/man1","preline.1",auto_uido,auto_gidq,0644); | ||
| 196 | c(auto_qmail,"man/cat1","preline.0",auto_uido,auto_gidq,0644); | ||
| 197 | c(auto_qmail,"man/man1","tcp-env.1",auto_uido,auto_gidq,0644); | ||
| 198 | c(auto_qmail,"man/cat1","tcp-env.0",auto_uido,auto_gidq,0644); | ||
| 199 | |||
| 200 | c(auto_qmail,"man/man8","qmail-local.8",auto_uido,auto_gidq,0644); | ||
| 201 | c(auto_qmail,"man/cat8","qmail-local.0",auto_uido,auto_gidq,0644); | ||
| 202 | c(auto_qmail,"man/man8","qmail-lspawn.8",auto_uido,auto_gidq,0644); | ||
| 203 | c(auto_qmail,"man/cat8","qmail-lspawn.0",auto_uido,auto_gidq,0644); | ||
| 204 | c(auto_qmail,"man/man8","qmail-getpw.8",auto_uido,auto_gidq,0644); | ||
| 205 | c(auto_qmail,"man/cat8","qmail-getpw.0",auto_uido,auto_gidq,0644); | ||
| 206 | c(auto_qmail,"man/man8","qmail-remote.8",auto_uido,auto_gidq,0644); | ||
| 207 | c(auto_qmail,"man/cat8","qmail-remote.0",auto_uido,auto_gidq,0644); | ||
| 208 | c(auto_qmail,"man/man8","qmail-rspawn.8",auto_uido,auto_gidq,0644); | ||
| 209 | c(auto_qmail,"man/cat8","qmail-rspawn.0",auto_uido,auto_gidq,0644); | ||
| 210 | c(auto_qmail,"man/man8","qmail-clean.8",auto_uido,auto_gidq,0644); | ||
| 211 | c(auto_qmail,"man/cat8","qmail-clean.0",auto_uido,auto_gidq,0644); | ||
| 212 | c(auto_qmail,"man/man8","qmail-send.8",auto_uido,auto_gidq,0644); | ||
| 213 | c(auto_qmail,"man/cat8","qmail-send.0",auto_uido,auto_gidq,0644); | ||
| 214 | c(auto_qmail,"man/man8","qmail-start.8",auto_uido,auto_gidq,0644); | ||
| 215 | c(auto_qmail,"man/cat8","qmail-start.0",auto_uido,auto_gidq,0644); | ||
| 216 | c(auto_qmail,"man/man8","splogger.8",auto_uido,auto_gidq,0644); | ||
| 217 | c(auto_qmail,"man/cat8","splogger.0",auto_uido,auto_gidq,0644); | ||
| 218 | c(auto_qmail,"man/man8","qmail-queue.8",auto_uido,auto_gidq,0644); | ||
| 219 | c(auto_qmail,"man/cat8","qmail-queue.0",auto_uido,auto_gidq,0644); | ||
| 220 | c(auto_qmail,"man/man8","qmail-inject.8",auto_uido,auto_gidq,0644); | ||
| 221 | c(auto_qmail,"man/cat8","qmail-inject.0",auto_uido,auto_gidq,0644); | ||
| 222 | c(auto_qmail,"man/man8","qmail-showctl.8",auto_uido,auto_gidq,0644); | ||
| 223 | c(auto_qmail,"man/cat8","qmail-showctl.0",auto_uido,auto_gidq,0644); | ||
| 224 | c(auto_qmail,"man/man8","qmail-newmrh.8",auto_uido,auto_gidq,0644); | ||
| 225 | c(auto_qmail,"man/cat8","qmail-newmrh.0",auto_uido,auto_gidq,0644); | ||
| 226 | c(auto_qmail,"man/man8","qmail-newu.8",auto_uido,auto_gidq,0644); | ||
| 227 | c(auto_qmail,"man/cat8","qmail-newu.0",auto_uido,auto_gidq,0644); | ||
| 228 | c(auto_qmail,"man/man8","qmail-pw2u.8",auto_uido,auto_gidq,0644); | ||
| 229 | c(auto_qmail,"man/cat8","qmail-pw2u.0",auto_uido,auto_gidq,0644); | ||
| 230 | c(auto_qmail,"man/man8","qmail-qread.8",auto_uido,auto_gidq,0644); | ||
| 231 | c(auto_qmail,"man/cat8","qmail-qread.0",auto_uido,auto_gidq,0644); | ||
| 232 | c(auto_qmail,"man/man8","qmail-qstat.8",auto_uido,auto_gidq,0644); | ||
| 233 | c(auto_qmail,"man/cat8","qmail-qstat.0",auto_uido,auto_gidq,0644); | ||
| 234 | c(auto_qmail,"man/man8","qmail-tcpok.8",auto_uido,auto_gidq,0644); | ||
| 235 | c(auto_qmail,"man/cat8","qmail-tcpok.0",auto_uido,auto_gidq,0644); | ||
| 236 | c(auto_qmail,"man/man8","qmail-tcpto.8",auto_uido,auto_gidq,0644); | ||
| 237 | c(auto_qmail,"man/cat8","qmail-tcpto.0",auto_uido,auto_gidq,0644); | ||
| 238 | c(auto_qmail,"man/man8","qmail-pop3d.8",auto_uido,auto_gidq,0644); | ||
| 239 | c(auto_qmail,"man/cat8","qmail-pop3d.0",auto_uido,auto_gidq,0644); | ||
| 240 | c(auto_qmail,"man/man8","qmail-popup.8",auto_uido,auto_gidq,0644); | ||
| 241 | c(auto_qmail,"man/cat8","qmail-popup.0",auto_uido,auto_gidq,0644); | ||
| 242 | c(auto_qmail,"man/man8","qmail-qmqpc.8",auto_uido,auto_gidq,0644); | ||
| 243 | c(auto_qmail,"man/cat8","qmail-qmqpc.0",auto_uido,auto_gidq,0644); | ||
| 244 | c(auto_qmail,"man/man8","qmail-qmqpd.8",auto_uido,auto_gidq,0644); | ||
| 245 | c(auto_qmail,"man/cat8","qmail-qmqpd.0",auto_uido,auto_gidq,0644); | ||
| 246 | c(auto_qmail,"man/man8","qmail-qmtpd.8",auto_uido,auto_gidq,0644); | ||
| 247 | c(auto_qmail,"man/cat8","qmail-qmtpd.0",auto_uido,auto_gidq,0644); | ||
| 248 | c(auto_qmail,"man/man8","qmail-smtpd.8",auto_uido,auto_gidq,0644); | ||
| 249 | c(auto_qmail,"man/cat8","qmail-smtpd.0",auto_uido,auto_gidq,0644); | ||
| 250 | c(auto_qmail,"man/man8","qmail-command.8",auto_uido,auto_gidq,0644); | ||
| 251 | c(auto_qmail,"man/cat8","qmail-command.0",auto_uido,auto_gidq,0644); | ||
| 252 | |||
| 253 | c(auto_qmail,"bin","dot-forward",auto_uido,auto_gidq,0755); | ||
| 254 | |||
| 255 | c(auto_qmail,"man/man1","dot-forward.1",auto_uido,auto_gidq,0644); | ||
| 256 | c(auto_qmail,"man/cat1","dot-forward.0",auto_uido,auto_gidq,0644); | ||
| 257 | |||
| 258 | d(auto_qmail,"doc/fastforward",auto_uido,auto_gidq,0755); | ||
| 259 | |||
| 260 | c(auto_qmail,"bin","fastforward",auto_uido,auto_gidq,0755); | ||
| 261 | c(auto_qmail,"bin","printforward",auto_uido,auto_gidq,0755); | ||
| 262 | c(auto_qmail,"bin","setforward",auto_uido,auto_gidq,0755); | ||
| 263 | c(auto_qmail,"bin","newaliases",auto_uido,auto_gidq,0755); | ||
| 264 | c(auto_qmail,"bin","printmaillist",auto_uido,auto_gidq,0755); | ||
| 265 | c(auto_qmail,"bin","setmaillist",auto_uido,auto_gidq,0755); | ||
| 266 | c(auto_qmail,"bin","newinclude",auto_uido,auto_gidq,0755); | ||
| 267 | |||
| 268 | c(auto_qmail,"doc/fastforward","ALIASES",auto_uido,auto_gidq,0644); | ||
| 269 | |||
| 270 | c(auto_qmail,"man/man1","fastforward.1",auto_uido,auto_gidq,0644); | ||
| 271 | c(auto_qmail,"man/man1","printforward.1",auto_uido,auto_gidq,0644); | ||
| 272 | c(auto_qmail,"man/man1","setforward.1",auto_uido,auto_gidq,0644); | ||
| 273 | c(auto_qmail,"man/man1","newaliases.1",auto_uido,auto_gidq,0644); | ||
| 274 | c(auto_qmail,"man/man1","printmaillist.1",auto_uido,auto_gidq,0644); | ||
| 275 | c(auto_qmail,"man/man1","setmaillist.1",auto_uido,auto_gidq,0644); | ||
| 276 | c(auto_qmail,"man/man1","newinclude.1",auto_uido,auto_gidq,0644); | ||
| 277 | |||
| 278 | c(auto_qmail,"man/cat1","fastforward.0",auto_uido,auto_gidq,0644); | ||
| 279 | c(auto_qmail,"man/cat1","printforward.0",auto_uido,auto_gidq,0644); | ||
| 280 | c(auto_qmail,"man/cat1","setforward.0",auto_uido,auto_gidq,0644); | ||
| 281 | c(auto_qmail,"man/cat1","newaliases.0",auto_uido,auto_gidq,0644); | ||
| 282 | c(auto_qmail,"man/cat1","printmaillist.0",auto_uido,auto_gidq,0644); | ||
| 283 | c(auto_qmail,"man/cat1","setmaillist.0",auto_uido,auto_gidq,0644); | ||
| 284 | c(auto_qmail,"man/cat1","newinclude.0",auto_uido,auto_gidq,0644); | ||
| 285 | } | ||
diff --git a/install.c b/install.c new file mode 100644 index 0000000..95034f2 --- /dev/null +++ b/install.c | |||
| @@ -0,0 +1,164 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "strerr.h" | ||
| 3 | #include "error.h" | ||
| 4 | #include "open.h" | ||
| 5 | #include "readwrite.h" | ||
| 6 | #include "exit.h" | ||
| 7 | |||
| 8 | extern void hier(); | ||
| 9 | |||
| 10 | #define FATAL "install: fatal: " | ||
| 11 | |||
| 12 | int fdsourcedir = -1; | ||
| 13 | |||
| 14 | void h(home,uid,gid,mode) | ||
| 15 | char *home; | ||
| 16 | int uid; | ||
| 17 | int gid; | ||
| 18 | int mode; | ||
| 19 | { | ||
| 20 | if (mkdir(home,0700) == -1) | ||
| 21 | if (errno != error_exist) | ||
| 22 | strerr_die4sys(111,FATAL,"unable to mkdir ",home,": "); | ||
| 23 | if (chown(home,uid,gid) == -1) | ||
| 24 | strerr_die4sys(111,FATAL,"unable to chown ",home,": "); | ||
| 25 | if (chmod(home,mode) == -1) | ||
| 26 | strerr_die4sys(111,FATAL,"unable to chmod ",home,": "); | ||
| 27 | } | ||
| 28 | |||
| 29 | void d(home,subdir,uid,gid,mode) | ||
| 30 | char *home; | ||
| 31 | char *subdir; | ||
| 32 | int uid; | ||
| 33 | int gid; | ||
| 34 | int mode; | ||
| 35 | { | ||
| 36 | if (chdir(home) == -1) | ||
| 37 | strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); | ||
| 38 | if (mkdir(subdir,0700) == -1) | ||
| 39 | if (errno != error_exist) | ||
| 40 | strerr_die6sys(111,FATAL,"unable to mkdir ",home,"/",subdir,": "); | ||
| 41 | if (chown(subdir,uid,gid) == -1) | ||
| 42 | strerr_die6sys(111,FATAL,"unable to chown ",home,"/",subdir,": "); | ||
| 43 | if (chmod(subdir,mode) == -1) | ||
| 44 | strerr_die6sys(111,FATAL,"unable to chmod ",home,"/",subdir,": "); | ||
| 45 | } | ||
| 46 | |||
| 47 | void p(home,fifo,uid,gid,mode) | ||
| 48 | char *home; | ||
| 49 | char *fifo; | ||
| 50 | int uid; | ||
| 51 | int gid; | ||
| 52 | int mode; | ||
| 53 | { | ||
| 54 | if (chdir(home) == -1) | ||
| 55 | strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); | ||
| 56 | if (fifo_make(fifo,0700) == -1) | ||
| 57 | if (errno != error_exist) | ||
| 58 | strerr_die6sys(111,FATAL,"unable to mkfifo ",home,"/",fifo,": "); | ||
| 59 | if (chown(fifo,uid,gid) == -1) | ||
| 60 | strerr_die6sys(111,FATAL,"unable to chown ",home,"/",fifo,": "); | ||
| 61 | if (chmod(fifo,mode) == -1) | ||
| 62 | strerr_die6sys(111,FATAL,"unable to chmod ",home,"/",fifo,": "); | ||
| 63 | } | ||
| 64 | |||
| 65 | char inbuf[SUBSTDIO_INSIZE]; | ||
| 66 | char outbuf[SUBSTDIO_OUTSIZE]; | ||
| 67 | substdio ssin; | ||
| 68 | substdio ssout; | ||
| 69 | |||
| 70 | void c(home,subdir,file,uid,gid,mode) | ||
| 71 | char *home; | ||
| 72 | char *subdir; | ||
| 73 | char *file; | ||
| 74 | int uid; | ||
| 75 | int gid; | ||
| 76 | int mode; | ||
| 77 | { | ||
| 78 | int fdin; | ||
| 79 | int fdout; | ||
| 80 | |||
| 81 | if (fchdir(fdsourcedir) == -1) | ||
| 82 | strerr_die2sys(111,FATAL,"unable to switch back to source directory: "); | ||
| 83 | |||
| 84 | fdin = open_read(file); | ||
| 85 | if (fdin == -1) | ||
| 86 | strerr_die4sys(111,FATAL,"unable to read ",file,": "); | ||
| 87 | substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof inbuf); | ||
| 88 | |||
| 89 | if (chdir(home) == -1) | ||
| 90 | strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); | ||
| 91 | if (chdir(subdir) == -1) | ||
| 92 | strerr_die6sys(111,FATAL,"unable to switch to ",home,"/",subdir,": "); | ||
| 93 | |||
| 94 | fdout = open_trunc(file); | ||
| 95 | if (fdout == -1) | ||
| 96 | strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); | ||
| 97 | substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof outbuf); | ||
| 98 | |||
| 99 | switch(substdio_copy(&ssout,&ssin)) { | ||
| 100 | case -2: | ||
| 101 | strerr_die4sys(111,FATAL,"unable to read ",file,": "); | ||
| 102 | case -3: | ||
| 103 | strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); | ||
| 104 | } | ||
| 105 | |||
| 106 | close(fdin); | ||
| 107 | if (substdio_flush(&ssout) == -1) | ||
| 108 | strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); | ||
| 109 | if (fsync(fdout) == -1) | ||
| 110 | strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); | ||
| 111 | if (close(fdout) == -1) /* NFS silliness */ | ||
| 112 | strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); | ||
| 113 | |||
| 114 | if (chown(file,uid,gid) == -1) | ||
| 115 | strerr_die6sys(111,FATAL,"unable to chown .../",subdir,"/",file,": "); | ||
| 116 | if (chmod(file,mode) == -1) | ||
| 117 | strerr_die6sys(111,FATAL,"unable to chmod .../",subdir,"/",file,": "); | ||
| 118 | } | ||
| 119 | |||
| 120 | void z(home,file,len,uid,gid,mode) | ||
| 121 | char *home; | ||
| 122 | char *file; | ||
| 123 | int len; | ||
| 124 | int uid; | ||
| 125 | int gid; | ||
| 126 | int mode; | ||
| 127 | { | ||
| 128 | int fdout; | ||
| 129 | |||
| 130 | if (chdir(home) == -1) | ||
| 131 | strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); | ||
| 132 | |||
| 133 | fdout = open_trunc(file); | ||
| 134 | if (fdout == -1) | ||
| 135 | strerr_die6sys(111,FATAL,"unable to write ",home,"/",file,": "); | ||
| 136 | substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof outbuf); | ||
| 137 | |||
| 138 | while (len-- > 0) | ||
| 139 | if (substdio_put(&ssout,"",1) == -1) | ||
| 140 | strerr_die6sys(111,FATAL,"unable to write ",home,"/",file,": "); | ||
| 141 | |||
| 142 | if (substdio_flush(&ssout) == -1) | ||
| 143 | strerr_die6sys(111,FATAL,"unable to write ",home,"/",file,": "); | ||
| 144 | if (fsync(fdout) == -1) | ||
| 145 | strerr_die6sys(111,FATAL,"unable to write ",home,"/",file,": "); | ||
| 146 | if (close(fdout) == -1) /* NFS silliness */ | ||
| 147 | strerr_die6sys(111,FATAL,"unable to write ",home,"/",file,": "); | ||
| 148 | |||
| 149 | if (chown(file,uid,gid) == -1) | ||
| 150 | strerr_die6sys(111,FATAL,"unable to chown ",home,"/",file,": "); | ||
| 151 | if (chmod(file,mode) == -1) | ||
| 152 | strerr_die6sys(111,FATAL,"unable to chmod ",home,"/",file,": "); | ||
| 153 | } | ||
| 154 | |||
| 155 | void main() | ||
| 156 | { | ||
| 157 | fdsourcedir = open_read("."); | ||
| 158 | if (fdsourcedir == -1) | ||
| 159 | strerr_die2sys(111,FATAL,"unable to open current directory: "); | ||
| 160 | |||
| 161 | umask(077); | ||
| 162 | hier(); | ||
| 163 | _exit(0); | ||
| 164 | } | ||
diff --git a/instcheck.c b/instcheck.c new file mode 100644 index 0000000..d41efda --- /dev/null +++ b/instcheck.c | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include "strerr.h" | ||
| 4 | #include "error.h" | ||
| 5 | #include "readwrite.h" | ||
| 6 | #include "exit.h" | ||
| 7 | |||
| 8 | extern void hier(); | ||
| 9 | |||
| 10 | #define FATAL "instcheck: fatal: " | ||
| 11 | #define WARNING "instcheck: warning: " | ||
| 12 | |||
| 13 | void perm(prefix1,prefix2,prefix3,file,type,uid,gid,mode) | ||
| 14 | char *prefix1; | ||
| 15 | char *prefix2; | ||
| 16 | char *prefix3; | ||
| 17 | char *file; | ||
| 18 | int type; | ||
| 19 | int uid; | ||
| 20 | int gid; | ||
| 21 | int mode; | ||
| 22 | { | ||
| 23 | struct stat st; | ||
| 24 | |||
| 25 | if (stat(file,&st) == -1) { | ||
| 26 | if (errno == error_noent) | ||
| 27 | strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," does not exist",0); | ||
| 28 | else | ||
| 29 | strerr_warn4(WARNING,"unable to stat .../",file,": ",&strerr_sys); | ||
| 30 | return; | ||
| 31 | } | ||
| 32 | |||
| 33 | if ((uid != -1) && (st.st_uid != uid)) | ||
| 34 | strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong owner",0); | ||
| 35 | if ((gid != -1) && (st.st_gid != gid)) | ||
| 36 | strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong group",0); | ||
| 37 | if ((st.st_mode & 07777) != mode) | ||
| 38 | strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong permissions",0); | ||
| 39 | if ((st.st_mode & S_IFMT) != type) | ||
| 40 | strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong type",0); | ||
| 41 | } | ||
| 42 | |||
| 43 | void h(home,uid,gid,mode) | ||
| 44 | char *home; | ||
| 45 | int uid; | ||
| 46 | int gid; | ||
| 47 | int mode; | ||
| 48 | { | ||
| 49 | perm("","","",home,S_IFDIR,uid,gid,mode); | ||
| 50 | } | ||
| 51 | |||
| 52 | void d(home,subdir,uid,gid,mode) | ||
| 53 | char *home; | ||
| 54 | char *subdir; | ||
| 55 | int uid; | ||
| 56 | int gid; | ||
| 57 | int mode; | ||
| 58 | { | ||
| 59 | if (chdir(home) == -1) | ||
| 60 | strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); | ||
| 61 | perm("",home,"/",subdir,S_IFDIR,uid,gid,mode); | ||
| 62 | } | ||
| 63 | |||
| 64 | void p(home,fifo,uid,gid,mode) | ||
| 65 | char *home; | ||
| 66 | char *fifo; | ||
| 67 | int uid; | ||
| 68 | int gid; | ||
| 69 | int mode; | ||
| 70 | { | ||
| 71 | if (chdir(home) == -1) | ||
| 72 | strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); | ||
| 73 | perm("",home,"/",fifo,S_IFIFO,uid,gid,mode); | ||
| 74 | } | ||
| 75 | |||
| 76 | void c(home,subdir,file,uid,gid,mode) | ||
| 77 | char *home; | ||
| 78 | char *subdir; | ||
| 79 | char *file; | ||
| 80 | int uid; | ||
| 81 | int gid; | ||
| 82 | int mode; | ||
| 83 | { | ||
| 84 | if (chdir(home) == -1) | ||
| 85 | strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); | ||
| 86 | if (chdir(subdir) == -1) | ||
| 87 | strerr_die6sys(111,FATAL,"unable to switch to ",home,"/",subdir,": "); | ||
| 88 | perm(".../",subdir,"/",file,S_IFREG,uid,gid,mode); | ||
| 89 | } | ||
| 90 | |||
| 91 | void z(home,file,len,uid,gid,mode) | ||
| 92 | char *home; | ||
| 93 | char *file; | ||
| 94 | int len; | ||
| 95 | int uid; | ||
| 96 | int gid; | ||
| 97 | int mode; | ||
| 98 | { | ||
| 99 | if (chdir(home) == -1) | ||
| 100 | strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); | ||
| 101 | perm("",home,"/",file,S_IFREG,uid,gid,mode); | ||
| 102 | } | ||
| 103 | |||
| 104 | void main() | ||
| 105 | { | ||
| 106 | hier(); | ||
| 107 | _exit(0); | ||
| 108 | } | ||
| @@ -0,0 +1,53 @@ | |||
| 1 | #include "fmt.h" | ||
| 2 | #include "scan.h" | ||
| 3 | #include "ip.h" | ||
| 4 | |||
| 5 | unsigned int ip_fmt(s,ip) | ||
| 6 | char *s; | ||
| 7 | struct ip_address *ip; | ||
| 8 | { | ||
| 9 | unsigned int len; | ||
| 10 | unsigned int i; | ||
| 11 | |||
| 12 | len = 0; | ||
| 13 | i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i; | ||
| 14 | i = fmt_str(s,"."); len += i; if (s) s += i; | ||
| 15 | i = fmt_ulong(s,(unsigned long) ip->d[1]); len += i; if (s) s += i; | ||
| 16 | i = fmt_str(s,"."); len += i; if (s) s += i; | ||
| 17 | i = fmt_ulong(s,(unsigned long) ip->d[2]); len += i; if (s) s += i; | ||
| 18 | i = fmt_str(s,"."); len += i; if (s) s += i; | ||
| 19 | i = fmt_ulong(s,(unsigned long) ip->d[3]); len += i; if (s) s += i; | ||
| 20 | return len; | ||
| 21 | } | ||
| 22 | |||
| 23 | unsigned int ip_scan(s,ip) | ||
| 24 | char *s; | ||
| 25 | struct ip_address *ip; | ||
| 26 | { | ||
| 27 | unsigned int i; | ||
| 28 | unsigned int len; | ||
| 29 | unsigned long u; | ||
| 30 | |||
| 31 | len = 0; | ||
| 32 | i = scan_ulong(s,&u); if (!i) return 0; ip->d[0] = u; s += i; len += i; | ||
| 33 | if (*s != '.') return 0; ++s; ++len; | ||
| 34 | i = scan_ulong(s,&u); if (!i) return 0; ip->d[1] = u; s += i; len += i; | ||
| 35 | if (*s != '.') return 0; ++s; ++len; | ||
| 36 | i = scan_ulong(s,&u); if (!i) return 0; ip->d[2] = u; s += i; len += i; | ||
| 37 | if (*s != '.') return 0; ++s; ++len; | ||
| 38 | i = scan_ulong(s,&u); if (!i) return 0; ip->d[3] = u; s += i; len += i; | ||
| 39 | return len; | ||
| 40 | } | ||
| 41 | |||
| 42 | unsigned int ip_scanbracket(s,ip) | ||
| 43 | char *s; | ||
| 44 | struct ip_address *ip; | ||
| 45 | { | ||
| 46 | unsigned int len; | ||
| 47 | |||
| 48 | if (*s != '[') return 0; | ||
| 49 | len = ip_scan(s + 1,ip); | ||
| 50 | if (!len) return 0; | ||
| 51 | if (s[len + 1] != ']') return 0; | ||
| 52 | return len + 2; | ||
| 53 | } | ||
| @@ -0,0 +1,11 @@ | |||
| 1 | #ifndef IP_H | ||
| 2 | #define IP_H | ||
| 3 | |||
| 4 | struct ip_address { unsigned char d[4]; } ; | ||
| 5 | |||
| 6 | extern unsigned int ip_fmt(); | ||
| 7 | #define IPFMT 19 | ||
| 8 | extern unsigned int ip_scan(); | ||
| 9 | extern unsigned int ip_scanbracket(); | ||
| 10 | |||
| 11 | #endif | ||
diff --git a/ipalloc.c b/ipalloc.c new file mode 100644 index 0000000..81792d5 --- /dev/null +++ b/ipalloc.c | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #include "alloc.h" | ||
| 2 | #include "gen_allocdefs.h" | ||
| 3 | #include "ip.h" | ||
| 4 | #include "ipalloc.h" | ||
| 5 | |||
| 6 | GEN_ALLOC_readyplus(ipalloc,struct ip_mx,ix,len,a,i,n,x,10,ipalloc_readyplus) | ||
| 7 | GEN_ALLOC_append(ipalloc,struct ip_mx,ix,len,a,i,n,x,10,ipalloc_readyplus,ipalloc_append) | ||
diff --git a/ipalloc.h b/ipalloc.h new file mode 100644 index 0000000..ad61475 --- /dev/null +++ b/ipalloc.h | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | #ifndef IPALLOC_H | ||
| 2 | #define IPALLOC_H | ||
| 3 | |||
| 4 | #include "ip.h" | ||
| 5 | |||
| 6 | struct ip_mx { struct ip_address ip; int pref; } ; | ||
| 7 | |||
| 8 | #include "gen_alloc.h" | ||
| 9 | |||
| 10 | GEN_ALLOC_typedef(ipalloc,struct ip_mx,ix,len,a) | ||
| 11 | extern int ipalloc_readyplus(); | ||
| 12 | extern int ipalloc_append(); | ||
| 13 | |||
| 14 | #endif | ||
| @@ -0,0 +1,95 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/param.h> | ||
| 3 | #include <sys/time.h> | ||
| 4 | #include <sys/ioctl.h> | ||
| 5 | #include <sys/socket.h> | ||
| 6 | #include <net/if.h> | ||
| 7 | #include <netinet/in.h> | ||
| 8 | #ifndef SIOCGIFCONF /* whatever works */ | ||
| 9 | #include <sys/sockio.h> | ||
| 10 | #endif | ||
| 11 | #include "hassalen.h" | ||
| 12 | #include "byte.h" | ||
| 13 | #include "ip.h" | ||
| 14 | #include "ipalloc.h" | ||
| 15 | #include "stralloc.h" | ||
| 16 | #include "ipme.h" | ||
| 17 | |||
| 18 | static int ipmeok = 0; | ||
| 19 | ipalloc ipme = {0}; | ||
| 20 | |||
| 21 | int ipme_is(ip) | ||
| 22 | struct ip_address *ip; | ||
| 23 | { | ||
| 24 | int i; | ||
| 25 | if (ipme_init() != 1) return -1; | ||
| 26 | for (i = 0;i < ipme.len;++i) | ||
| 27 | if (byte_equal(&ipme.ix[i].ip,4,ip)) | ||
| 28 | return 1; | ||
| 29 | return 0; | ||
| 30 | } | ||
| 31 | |||
| 32 | static stralloc buf = {0}; | ||
| 33 | |||
| 34 | int ipme_init() | ||
| 35 | { | ||
| 36 | struct ifconf ifc; | ||
| 37 | char *x; | ||
| 38 | struct ifreq *ifr; | ||
| 39 | struct sockaddr_in *sin; | ||
| 40 | int len; | ||
| 41 | int s; | ||
| 42 | struct ip_mx ix; | ||
| 43 | |||
| 44 | if (ipmeok) return 1; | ||
| 45 | if (!ipalloc_readyplus(&ipme,0)) return 0; | ||
| 46 | ipme.len = 0; | ||
| 47 | ix.pref = 0; | ||
| 48 | |||
| 49 | if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1) return -1; | ||
| 50 | |||
| 51 | len = 256; | ||
| 52 | for (;;) { | ||
| 53 | if (!stralloc_ready(&buf,len)) { close(s); return 0; } | ||
| 54 | buf.len = 0; | ||
| 55 | ifc.ifc_buf = buf.s; | ||
| 56 | ifc.ifc_len = len; | ||
| 57 | if (ioctl(s,SIOCGIFCONF,&ifc) >= 0) /* > is for System V */ | ||
| 58 | if (ifc.ifc_len + sizeof(*ifr) + 64 < len) { /* what a stupid interface */ | ||
| 59 | buf.len = ifc.ifc_len; | ||
| 60 | break; | ||
| 61 | } | ||
| 62 | if (len > 200000) { close(s); return -1; } | ||
| 63 | len += 100 + (len >> 2); | ||
| 64 | } | ||
| 65 | x = buf.s; | ||
| 66 | while (x < buf.s + buf.len) { | ||
| 67 | ifr = (struct ifreq *) x; | ||
| 68 | #ifdef HASSALEN | ||
| 69 | len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len; | ||
| 70 | if (len < sizeof(*ifr)) | ||
| 71 | len = sizeof(*ifr); | ||
| 72 | if (ifr->ifr_addr.sa_family == AF_INET) { | ||
| 73 | sin = (struct sockaddr_in *) &ifr->ifr_addr; | ||
| 74 | byte_copy(&ix.ip,4,&sin->sin_addr); | ||
| 75 | if (ioctl(s,SIOCGIFFLAGS,x) == 0) | ||
| 76 | if (ifr->ifr_flags & IFF_UP) | ||
| 77 | if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; } | ||
| 78 | } | ||
| 79 | #else | ||
| 80 | len = sizeof(*ifr); | ||
| 81 | if (ioctl(s,SIOCGIFFLAGS,x) == 0) | ||
| 82 | if (ifr->ifr_flags & IFF_UP) | ||
| 83 | if (ioctl(s,SIOCGIFADDR,x) == 0) | ||
| 84 | if (ifr->ifr_addr.sa_family == AF_INET) { | ||
| 85 | sin = (struct sockaddr_in *) &ifr->ifr_addr; | ||
| 86 | byte_copy(&ix.ip,4,&sin->sin_addr); | ||
| 87 | if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; } | ||
| 88 | } | ||
| 89 | #endif | ||
| 90 | x += len; | ||
| 91 | } | ||
| 92 | close(s); | ||
| 93 | ipmeok = 1; | ||
| 94 | return 1; | ||
| 95 | } | ||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef IPME_H | ||
| 2 | #define IPME_H | ||
| 3 | |||
| 4 | #include "ip.h" | ||
| 5 | #include "ipalloc.h" | ||
| 6 | |||
| 7 | extern ipalloc ipme; | ||
| 8 | |||
| 9 | extern int ipme_init(); | ||
| 10 | extern int ipme_is(); | ||
| 11 | |||
| 12 | #endif | ||
diff --git a/ipmeprint.c b/ipmeprint.c new file mode 100644 index 0000000..1ef56e3 --- /dev/null +++ b/ipmeprint.c | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | #include "subfd.h" | ||
| 2 | #include "substdio.h" | ||
| 3 | #include "ip.h" | ||
| 4 | #include "ipme.h" | ||
| 5 | #include "exit.h" | ||
| 6 | |||
| 7 | char temp[IPFMT]; | ||
| 8 | |||
| 9 | void main() | ||
| 10 | { | ||
| 11 | int j; | ||
| 12 | switch(ipme_init()) | ||
| 13 | { | ||
| 14 | case 0: substdio_putsflush(subfderr,"out of memory\n"); _exit(111); | ||
| 15 | case -1: substdio_putsflush(subfderr,"hard error\n"); _exit(100); | ||
| 16 | } | ||
| 17 | for (j = 0;j < ipme.len;++j) | ||
| 18 | { | ||
| 19 | substdio_put(subfdout,temp,ip_fmt(temp,&ipme.ix[j].ip)); | ||
| 20 | substdio_puts(subfdout,"\n"); | ||
| 21 | } | ||
| 22 | substdio_flush(subfdout); | ||
| 23 | _exit(0); | ||
| 24 | } | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef LOCK_H | ||
| 2 | #define LOCK_H | ||
| 3 | |||
| 4 | extern int lock_ex(); | ||
| 5 | extern int lock_un(); | ||
| 6 | extern int lock_exnb(); | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/lock_ex.c b/lock_ex.c new file mode 100644 index 0000000..a3351c9 --- /dev/null +++ b/lock_ex.c | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/file.h> | ||
| 3 | #include <fcntl.h> | ||
| 4 | #include "hasflock.h" | ||
| 5 | #include "lock.h" | ||
| 6 | |||
| 7 | #ifdef HASFLOCK | ||
| 8 | int lock_ex(fd) int fd; { return flock(fd,LOCK_EX); } | ||
| 9 | #else | ||
| 10 | int lock_ex(fd) int fd; { return lockf(fd,1,0); } | ||
| 11 | #endif | ||
diff --git a/lock_exnb.c b/lock_exnb.c new file mode 100644 index 0000000..5d2a14a --- /dev/null +++ b/lock_exnb.c | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/file.h> | ||
| 3 | #include <fcntl.h> | ||
| 4 | #include "hasflock.h" | ||
| 5 | #include "lock.h" | ||
| 6 | |||
| 7 | #ifdef HASFLOCK | ||
| 8 | int lock_exnb(fd) int fd; { return flock(fd,LOCK_EX | LOCK_NB); } | ||
| 9 | #else | ||
| 10 | int lock_exnb(fd) int fd; { return lockf(fd,2,0); } | ||
| 11 | #endif | ||
diff --git a/lock_un.c b/lock_un.c new file mode 100644 index 0000000..16e2f17 --- /dev/null +++ b/lock_un.c | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/file.h> | ||
| 3 | #include <fcntl.h> | ||
| 4 | #include "hasflock.h" | ||
| 5 | #include "lock.h" | ||
| 6 | |||
| 7 | #ifdef HASFLOCK | ||
| 8 | int lock_un(fd) int fd; { return flock(fd,LOCK_UN); } | ||
| 9 | #else | ||
| 10 | int lock_un(fd) int fd; { return lockf(fd,0,0); } | ||
| 11 | #endif | ||
diff --git a/maildir.5 b/maildir.5 new file mode 100644 index 0000000..5da9573 --- /dev/null +++ b/maildir.5 | |||
| @@ -0,0 +1,239 @@ | |||
| 1 | .TH maildir 5 | ||
| 2 | .SH "NAME" | ||
| 3 | maildir \- directory for incoming mail messages | ||
| 4 | .SH "INTRODUCTION" | ||
| 5 | .I maildir | ||
| 6 | is a structure for | ||
| 7 | directories of incoming mail messages. | ||
| 8 | It solves the reliability problems that plague | ||
| 9 | .I mbox | ||
| 10 | files and | ||
| 11 | .I mh | ||
| 12 | folders. | ||
| 13 | .SH "RELIABILITY ISSUES" | ||
| 14 | A machine may crash while it is delivering a message. | ||
| 15 | For both | ||
| 16 | .I mbox | ||
| 17 | files and | ||
| 18 | .I mh | ||
| 19 | folders this means that the message will be silently truncated. | ||
| 20 | Even worse: for | ||
| 21 | .I mbox | ||
| 22 | format, if the message is truncated in the middle of a line, | ||
| 23 | it will be silently joined to the next message. | ||
| 24 | The mail transport agent will try again later to deliver the message, | ||
| 25 | but it is unacceptable that a corrupted message should show up at all. | ||
| 26 | In | ||
| 27 | .IR maildir , | ||
| 28 | every message is guaranteed complete upon delivery. | ||
| 29 | |||
| 30 | A machine may have two programs simultaneously delivering mail | ||
| 31 | to the same user. | ||
| 32 | The | ||
| 33 | .I mbox | ||
| 34 | and | ||
| 35 | .I mh | ||
| 36 | formats require the programs to update a single central file. | ||
| 37 | If the programs do not use some locking mechanism, | ||
| 38 | the central file will be corrupted. | ||
| 39 | There are several | ||
| 40 | .I mbox | ||
| 41 | and | ||
| 42 | .I mh | ||
| 43 | locking mechanisms, | ||
| 44 | none of which work portably and reliably. | ||
| 45 | In contrast, in | ||
| 46 | .IR maildir , | ||
| 47 | no locks are ever necessary. | ||
| 48 | Different delivery processes never touch the same file. | ||
| 49 | |||
| 50 | A user may try to delete messages from his mailbox at the same | ||
| 51 | moment that the machine delivers a new message. | ||
| 52 | For | ||
| 53 | .I mbox | ||
| 54 | and | ||
| 55 | .I mh | ||
| 56 | formats, the user's mail-reading program must know | ||
| 57 | what locking mechanism the mail-delivery programs use. | ||
| 58 | In contrast, in | ||
| 59 | .IR maildir , | ||
| 60 | any delivered message | ||
| 61 | can be safely updated or deleted by a mail-reading program. | ||
| 62 | |||
| 63 | Many sites use Sun's | ||
| 64 | .B Network F\fPa\fBil\fPur\fBe System | ||
| 65 | (NFS), | ||
| 66 | presumably because the operating system vendor does not offer | ||
| 67 | anything else. | ||
| 68 | NFS exacerbates all of the above problems. | ||
| 69 | Some NFS implementations don't provide | ||
| 70 | .B any | ||
| 71 | reliable locking mechanism. | ||
| 72 | With | ||
| 73 | .I mbox | ||
| 74 | and | ||
| 75 | .I mh | ||
| 76 | formats, | ||
| 77 | if two machines deliver mail to the same user, | ||
| 78 | or if a user reads mail anywhere except the delivery machine, | ||
| 79 | the user's mail is at risk. | ||
| 80 | .I maildir | ||
| 81 | works without trouble over NFS. | ||
| 82 | .SH "THE MAILDIR STRUCTURE" | ||
| 83 | A directory in | ||
| 84 | .I maildir | ||
| 85 | format has three subdirectories, | ||
| 86 | all on the same filesystem: | ||
| 87 | .BR tmp , | ||
| 88 | .BR new , | ||
| 89 | and | ||
| 90 | .BR cur . | ||
| 91 | |||
| 92 | Each file in | ||
| 93 | .B new | ||
| 94 | is a newly delivered mail message. | ||
| 95 | The modification time of the file is the delivery date of the message. | ||
| 96 | The message is delivered | ||
| 97 | .I without | ||
| 98 | an extra UUCP-style | ||
| 99 | .B From_ | ||
| 100 | line, | ||
| 101 | .I without | ||
| 102 | any | ||
| 103 | .B >From | ||
| 104 | quoting, | ||
| 105 | and | ||
| 106 | .I without | ||
| 107 | an extra blank line at the end. | ||
| 108 | The message is normally in RFC 822 format, | ||
| 109 | starting with a | ||
| 110 | .B Return-Path | ||
| 111 | line and a | ||
| 112 | .B Delivered-To | ||
| 113 | line, | ||
| 114 | but it could contain arbitrary binary data. | ||
| 115 | It might not even end with a newline. | ||
| 116 | |||
| 117 | Files in | ||
| 118 | .B cur | ||
| 119 | are just like files in | ||
| 120 | .BR new . | ||
| 121 | The big difference is that files in | ||
| 122 | .B cur | ||
| 123 | are no longer new mail: | ||
| 124 | they have been seen by the user's mail-reading program. | ||
| 125 | .SH "HOW A MESSAGE IS DELIVERED" | ||
| 126 | The | ||
| 127 | .B tmp | ||
| 128 | directory is used to ensure reliable delivery, | ||
| 129 | as discussed here. | ||
| 130 | |||
| 131 | A program delivers a mail message in six steps. | ||
| 132 | First, it | ||
| 133 | .B chdir()\fPs | ||
| 134 | to the | ||
| 135 | .I maildir | ||
| 136 | directory. | ||
| 137 | Second, it | ||
| 138 | .B stat()s | ||
| 139 | the name | ||
| 140 | .BR tmp/\fItime.pid.host , | ||
| 141 | where | ||
| 142 | .I time | ||
| 143 | is the number of seconds since the beginning of 1970 GMT, | ||
| 144 | .I pid | ||
| 145 | is the program's process ID, | ||
| 146 | and | ||
| 147 | .I host | ||
| 148 | is the host name. | ||
| 149 | Third, if | ||
| 150 | .B stat() | ||
| 151 | returned anything other than ENOENT, | ||
| 152 | the program sleeps for two seconds, updates | ||
| 153 | .IR time , | ||
| 154 | and tries the | ||
| 155 | .B stat() | ||
| 156 | again, a limited number of times. | ||
| 157 | Fourth, the program | ||
| 158 | creates | ||
| 159 | .BR tmp/\fItime.pid.host . | ||
| 160 | Fifth, the program | ||
| 161 | .I NFS-writes | ||
| 162 | the message to the file. | ||
| 163 | Sixth, the program | ||
| 164 | .BR link() s | ||
| 165 | the file to | ||
| 166 | .BR new/\fItime.pid.host . | ||
| 167 | At that instant the message has been successfully delivered. | ||
| 168 | |||
| 169 | The delivery program is required to start a 24-hour timer before | ||
| 170 | creating | ||
| 171 | .BR tmp/\fItime.pid.host , | ||
| 172 | and to abort the delivery | ||
| 173 | if the timer expires. | ||
| 174 | Upon error, timeout, or normal completion, | ||
| 175 | the delivery program may attempt to | ||
| 176 | .B unlink() | ||
| 177 | .BR tmp/\fItime.pid.host . | ||
| 178 | |||
| 179 | .I NFS-writing | ||
| 180 | means | ||
| 181 | (1) as usual, checking the number of bytes returned from each | ||
| 182 | .B write() | ||
| 183 | call; | ||
| 184 | (2) calling | ||
| 185 | .B fsync() | ||
| 186 | and checking its return value; | ||
| 187 | (3) calling | ||
| 188 | .B close() | ||
| 189 | and checking its return value. | ||
| 190 | (Standard NFS implementations handle | ||
| 191 | .B fsync() | ||
| 192 | incorrectly | ||
| 193 | but make up for it by abusing | ||
| 194 | .BR close() .) | ||
| 195 | .SH "HOW A MESSAGE IS READ" | ||
| 196 | A mail reader operates as follows. | ||
| 197 | |||
| 198 | It looks through the | ||
| 199 | .B new | ||
| 200 | directory for new messages. | ||
| 201 | Say there is a new message, | ||
| 202 | .BR new/\fIunique . | ||
| 203 | The reader may freely display the contents of | ||
| 204 | .BR new/\fIunique , | ||
| 205 | delete | ||
| 206 | .BR new/\fIunique , | ||
| 207 | or rename | ||
| 208 | .B new/\fIunique | ||
| 209 | as | ||
| 210 | .BR cur/\fIunique:info . | ||
| 211 | See | ||
| 212 | .B http://pobox.com/~djb/proto/maildir.html | ||
| 213 | for the meaning of | ||
| 214 | .IR info . | ||
| 215 | |||
| 216 | The reader is also expected to look through the | ||
| 217 | .B tmp | ||
| 218 | directory and to clean up any old files found there. | ||
| 219 | A file in | ||
| 220 | .B tmp | ||
| 221 | may be safely removed if it | ||
| 222 | has not been accessed in 36 hours. | ||
| 223 | |||
| 224 | It is a good idea for readers to skip all filenames in | ||
| 225 | .B new | ||
| 226 | and | ||
| 227 | .B cur | ||
| 228 | starting with a dot. | ||
| 229 | Other than this, readers should not attempt to parse filenames. | ||
| 230 | .SH "ENVIRONMENT VARIABLES" | ||
| 231 | Mail readers supporting | ||
| 232 | .I maildir | ||
| 233 | use the | ||
| 234 | .B MAILDIR | ||
| 235 | environment variable | ||
| 236 | as the name of the user's primary mail directory. | ||
| 237 | .SH "SEE ALSO" | ||
| 238 | mbox(5), | ||
| 239 | qmail-local(8) | ||
diff --git a/maildir.c b/maildir.c new file mode 100644 index 0000000..efbd3d4 --- /dev/null +++ b/maildir.c | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include "prioq.h" | ||
| 4 | #include "env.h" | ||
| 5 | #include "stralloc.h" | ||
| 6 | #include "direntry.h" | ||
| 7 | #include "datetime.h" | ||
| 8 | #include "now.h" | ||
| 9 | #include "str.h" | ||
| 10 | #include "maildir.h" | ||
| 11 | |||
| 12 | struct strerr maildir_chdir_err; | ||
| 13 | struct strerr maildir_scan_err; | ||
| 14 | |||
| 15 | int maildir_chdir() | ||
| 16 | { | ||
| 17 | char *maildir; | ||
| 18 | maildir = env_get("MAILDIR"); | ||
| 19 | if (!maildir) | ||
| 20 | STRERR(-1,maildir_chdir_err,"MAILDIR not set") | ||
| 21 | if (chdir(maildir) == -1) | ||
| 22 | STRERR_SYS3(-1,maildir_chdir_err,"unable to chdir to ",maildir,": ") | ||
| 23 | return 0; | ||
| 24 | } | ||
| 25 | |||
| 26 | void maildir_clean(tmpname) | ||
| 27 | stralloc *tmpname; | ||
| 28 | { | ||
| 29 | DIR *dir; | ||
| 30 | direntry *d; | ||
| 31 | datetime_sec time; | ||
| 32 | struct stat st; | ||
| 33 | |||
| 34 | time = now(); | ||
| 35 | |||
| 36 | dir = opendir("tmp"); | ||
| 37 | if (!dir) return; | ||
| 38 | |||
| 39 | while (d = readdir(dir)) | ||
| 40 | { | ||
| 41 | if (d->d_name[0] == '.') continue; | ||
| 42 | if (!stralloc_copys(tmpname,"tmp/")) break; | ||
| 43 | if (!stralloc_cats(tmpname,d->d_name)) break; | ||
| 44 | if (!stralloc_0(tmpname)) break; | ||
| 45 | if (stat(tmpname->s,&st) == 0) | ||
| 46 | if (time > st.st_atime + 129600) | ||
| 47 | unlink(tmpname->s); | ||
| 48 | } | ||
| 49 | closedir(dir); | ||
| 50 | } | ||
| 51 | |||
| 52 | static int append(pq,filenames,subdir,time) | ||
| 53 | prioq *pq; | ||
| 54 | stralloc *filenames; | ||
| 55 | char *subdir; | ||
| 56 | datetime_sec time; | ||
| 57 | { | ||
| 58 | DIR *dir; | ||
| 59 | direntry *d; | ||
| 60 | struct prioq_elt pe; | ||
| 61 | unsigned int pos; | ||
| 62 | struct stat st; | ||
| 63 | |||
| 64 | dir = opendir(subdir); | ||
| 65 | if (!dir) | ||
| 66 | STRERR_SYS3(-1,maildir_scan_err,"unable to scan $MAILDIR/",subdir,": ") | ||
| 67 | |||
| 68 | while (d = readdir(dir)) | ||
| 69 | { | ||
| 70 | if (d->d_name[0] == '.') continue; | ||
| 71 | pos = filenames->len; | ||
| 72 | if (!stralloc_cats(filenames,subdir)) break; | ||
| 73 | if (!stralloc_cats(filenames,"/")) break; | ||
| 74 | if (!stralloc_cats(filenames,d->d_name)) break; | ||
| 75 | if (!stralloc_0(filenames)) break; | ||
| 76 | if (stat(filenames->s + pos,&st) == 0) | ||
| 77 | if (st.st_mtime < time) /* don't want to mix up the order */ | ||
| 78 | { | ||
| 79 | pe.dt = st.st_mtime; | ||
| 80 | pe.id = pos; | ||
| 81 | if (!prioq_insert(pq,&pe)) break; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | closedir(dir); | ||
| 86 | if (d) STRERR_SYS3(-1,maildir_scan_err,"unable to read $MAILDIR/",subdir,": ") | ||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | int maildir_scan(pq,filenames,flagnew,flagcur) | ||
| 91 | prioq *pq; | ||
| 92 | stralloc *filenames; | ||
| 93 | int flagnew; | ||
| 94 | int flagcur; | ||
| 95 | { | ||
| 96 | struct prioq_elt pe; | ||
| 97 | datetime_sec time; | ||
| 98 | int r; | ||
| 99 | |||
| 100 | if (!stralloc_copys(filenames,"")) return 0; | ||
| 101 | while (prioq_min(pq,&pe)) prioq_delmin(pq); | ||
| 102 | |||
| 103 | time = now(); | ||
| 104 | |||
| 105 | if (flagnew) if (append(pq,filenames,"new",time) == -1) return -1; | ||
| 106 | if (flagcur) if (append(pq,filenames,"cur",time) == -1) return -1; | ||
| 107 | return 0; | ||
| 108 | } | ||
diff --git a/maildir.h b/maildir.h new file mode 100644 index 0000000..7dd8826 --- /dev/null +++ b/maildir.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef MAILDIR_H | ||
| 2 | #define MAILDIR_H | ||
| 3 | |||
| 4 | #include "strerr.h" | ||
| 5 | extern struct strerr maildir_chdir_err; | ||
| 6 | extern struct strerr maildir_scan_err; | ||
| 7 | |||
| 8 | extern int maildir_chdir(); | ||
| 9 | extern void maildir_clean(); | ||
| 10 | extern int maildir_scan(); | ||
| 11 | |||
| 12 | #endif | ||
diff --git a/maildir2mbox.1 b/maildir2mbox.1 new file mode 100644 index 0000000..31423d9 --- /dev/null +++ b/maildir2mbox.1 | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | .TH maildir2mbox 1 | ||
| 2 | .SH NAME | ||
| 3 | maildir2mbox \- move mail from a maildir to an mbox | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B maildir2mbox | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B maildir2mbox | ||
| 8 | moves mail from a | ||
| 9 | .IR maildir -format | ||
| 10 | directory to an | ||
| 11 | .IR mbox -format | ||
| 12 | file. | ||
| 13 | |||
| 14 | You must supply three environment variables to | ||
| 15 | .BR maildir2mbox : | ||
| 16 | .B MAILDIR | ||
| 17 | is the name of your | ||
| 18 | .I maildir | ||
| 19 | directory; | ||
| 20 | .B MAIL | ||
| 21 | is the name of your | ||
| 22 | .I mbox | ||
| 23 | file; | ||
| 24 | and | ||
| 25 | .B MAILTMP | ||
| 26 | is a temporary file that | ||
| 27 | .B maildir2mbox | ||
| 28 | can overwrite. | ||
| 29 | .B MAILTMP | ||
| 30 | and | ||
| 31 | .B MAIL | ||
| 32 | must be on the same filesystem. | ||
| 33 | |||
| 34 | .B maildir2mbox | ||
| 35 | is reliable: | ||
| 36 | it will not remove messages | ||
| 37 | from | ||
| 38 | .B MAILDIR | ||
| 39 | until the messages have been successfully appended to | ||
| 40 | .BR MAIL . | ||
| 41 | |||
| 42 | .B maildir2mbox | ||
| 43 | locks | ||
| 44 | .B MAIL | ||
| 45 | to protect against simultaneous access by a mail reader. | ||
| 46 | This locking system does not protect against simultaneous access | ||
| 47 | by another | ||
| 48 | .BR maildir2mbox ; | ||
| 49 | you should run only one | ||
| 50 | .B maildir2mbox | ||
| 51 | at a time. | ||
| 52 | .SH "SEE ALSO" | ||
| 53 | maildir(5) | ||
diff --git a/maildir2mbox.c b/maildir2mbox.c new file mode 100644 index 0000000..7364441 --- /dev/null +++ b/maildir2mbox.c | |||
| @@ -0,0 +1,162 @@ | |||
| 1 | #include "readwrite.h" | ||
| 2 | #include "prioq.h" | ||
| 3 | #include "env.h" | ||
| 4 | #include "stralloc.h" | ||
| 5 | #include "subfd.h" | ||
| 6 | #include "substdio.h" | ||
| 7 | #include "getln.h" | ||
| 8 | #include "error.h" | ||
| 9 | #include "open.h" | ||
| 10 | #include "lock.h" | ||
| 11 | #include "gfrom.h" | ||
| 12 | #include "str.h" | ||
| 13 | #include "exit.h" | ||
| 14 | #include "myctime.h" | ||
| 15 | #include "maildir.h" | ||
| 16 | |||
| 17 | char *mbox; | ||
| 18 | char *mboxtmp; | ||
| 19 | |||
| 20 | stralloc filenames = {0}; | ||
| 21 | prioq pq = {0}; | ||
| 22 | prioq pq2 = {0}; | ||
| 23 | |||
| 24 | stralloc line = {0}; | ||
| 25 | |||
| 26 | stralloc ufline = {0}; | ||
| 27 | |||
| 28 | char inbuf[SUBSTDIO_INSIZE]; | ||
| 29 | char outbuf[SUBSTDIO_OUTSIZE]; | ||
| 30 | |||
| 31 | #define FATAL "maildir2mbox: fatal: " | ||
| 32 | #define WARNING "maildir2mbox: warning: " | ||
| 33 | |||
| 34 | void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); } | ||
| 35 | |||
| 36 | void main() | ||
| 37 | { | ||
| 38 | substdio ssin; | ||
| 39 | substdio ssout; | ||
| 40 | struct prioq_elt pe; | ||
| 41 | int fdoldmbox; | ||
| 42 | int fdnewmbox; | ||
| 43 | int fd; | ||
| 44 | int match; | ||
| 45 | int fdlock; | ||
| 46 | |||
| 47 | umask(077); | ||
| 48 | |||
| 49 | mbox = env_get("MAIL"); | ||
| 50 | if (!mbox) strerr_die2x(111,FATAL,"MAIL not set"); | ||
| 51 | mboxtmp = env_get("MAILTMP"); | ||
| 52 | if (!mboxtmp) strerr_die2x(111,FATAL,"MAILTMP not set"); | ||
| 53 | |||
| 54 | if (maildir_chdir() == -1) | ||
| 55 | strerr_die1(111,FATAL,&maildir_chdir_err); | ||
| 56 | maildir_clean(&filenames); | ||
| 57 | if (maildir_scan(&pq,&filenames,1,1) == -1) | ||
| 58 | strerr_die1(111,FATAL,&maildir_scan_err); | ||
| 59 | |||
| 60 | if (!prioq_min(&pq,&pe)) _exit(0); /* nothing new */ | ||
| 61 | |||
| 62 | fdlock = open_append(mbox); | ||
| 63 | if (fdlock == -1) | ||
| 64 | strerr_die4sys(111,FATAL,"unable to lock ",mbox,": "); | ||
| 65 | if (lock_ex(fdlock) == -1) | ||
| 66 | strerr_die4sys(111,FATAL,"unable to lock ",mbox,": "); | ||
| 67 | |||
| 68 | fdoldmbox = open_read(mbox); | ||
| 69 | if (fdoldmbox == -1) | ||
| 70 | strerr_die4sys(111,FATAL,"unable to read ",mbox,": "); | ||
| 71 | |||
| 72 | fdnewmbox = open_trunc(mboxtmp); | ||
| 73 | if (fdnewmbox == -1) | ||
| 74 | strerr_die4sys(111,FATAL,"unable to create ",mboxtmp,": "); | ||
| 75 | |||
| 76 | substdio_fdbuf(&ssin,read,fdoldmbox,inbuf,sizeof(inbuf)); | ||
| 77 | substdio_fdbuf(&ssout,write,fdnewmbox,outbuf,sizeof(outbuf)); | ||
| 78 | |||
| 79 | switch(substdio_copy(&ssout,&ssin)) | ||
| 80 | { | ||
| 81 | case -2: strerr_die4sys(111,FATAL,"unable to read ",mbox,": "); | ||
| 82 | case -3: strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); | ||
| 83 | } | ||
| 84 | |||
| 85 | while (prioq_min(&pq,&pe)) | ||
| 86 | { | ||
| 87 | prioq_delmin(&pq); | ||
| 88 | if (!prioq_insert(&pq2,&pe)) die_nomem(); | ||
| 89 | |||
| 90 | fd = open_read(filenames.s + pe.id); | ||
| 91 | if (fd == -1) | ||
| 92 | strerr_die4sys(111,FATAL,"unable to read $MAILDIR/",filenames.s + pe.id,": "); | ||
| 93 | substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); | ||
| 94 | |||
| 95 | if (getln(&ssin,&line,&match,'\n') != 0) | ||
| 96 | strerr_die4sys(111,FATAL,"unable to read $MAILDIR/",filenames.s + pe.id,": "); | ||
| 97 | |||
| 98 | if (!stralloc_copys(&ufline,"From XXX ")) die_nomem(); | ||
| 99 | if (match) | ||
| 100 | if (stralloc_starts(&line,"Return-Path: <")) | ||
| 101 | { | ||
| 102 | if (line.s[14] == '>') | ||
| 103 | { | ||
| 104 | if (!stralloc_copys(&ufline,"From MAILER-DAEMON ")) die_nomem(); | ||
| 105 | } | ||
| 106 | else | ||
| 107 | { | ||
| 108 | int i; | ||
| 109 | if (!stralloc_ready(&ufline,line.len)) die_nomem(); | ||
| 110 | if (!stralloc_copys(&ufline,"From ")) die_nomem(); | ||
| 111 | for (i = 14;i < line.len - 2;++i) | ||
| 112 | if ((line.s[i] == ' ') || (line.s[i] == '\t')) | ||
| 113 | ufline.s[ufline.len++] = '-'; | ||
| 114 | else | ||
| 115 | ufline.s[ufline.len++] = line.s[i]; | ||
| 116 | if (!stralloc_cats(&ufline," ")) die_nomem(); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | if (!stralloc_cats(&ufline,myctime(pe.dt))) die_nomem(); | ||
| 120 | if (substdio_put(&ssout,ufline.s,ufline.len) == -1) | ||
| 121 | strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); | ||
| 122 | |||
| 123 | while (match && line.len) | ||
| 124 | { | ||
| 125 | if (gfrom(line.s,line.len)) | ||
| 126 | if (substdio_puts(&ssout,">") == -1) | ||
| 127 | strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); | ||
| 128 | if (substdio_put(&ssout,line.s,line.len) == -1) | ||
| 129 | strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); | ||
| 130 | if (!match) | ||
| 131 | { | ||
| 132 | if (substdio_puts(&ssout,"\n") == -1) | ||
| 133 | strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); | ||
| 134 | break; | ||
| 135 | } | ||
| 136 | if (getln(&ssin,&line,&match,'\n') != 0) | ||
| 137 | strerr_die4sys(111,FATAL,"unable to read $MAILDIR/",filenames.s + pe.id,": "); | ||
| 138 | } | ||
| 139 | if (substdio_puts(&ssout,"\n")) | ||
| 140 | strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); | ||
| 141 | |||
| 142 | close(fd); | ||
| 143 | } | ||
| 144 | |||
| 145 | if (substdio_flush(&ssout) == -1) | ||
| 146 | strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); | ||
| 147 | if (fsync(fdnewmbox) == -1) | ||
| 148 | strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); | ||
| 149 | if (close(fdnewmbox) == -1) /* NFS dorks */ | ||
| 150 | strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); | ||
| 151 | if (rename(mboxtmp,mbox) == -1) | ||
| 152 | strerr_die6(111,FATAL,"unable to move ",mboxtmp," to ",mbox,": ",&strerr_sys); | ||
| 153 | |||
| 154 | while (prioq_min(&pq2,&pe)) | ||
| 155 | { | ||
| 156 | prioq_delmin(&pq2); | ||
| 157 | if (unlink(filenames.s + pe.id) == -1) | ||
| 158 | strerr_warn4(WARNING,"$MAILDIR/",filenames.s + pe.id," will be delivered twice; unable to unlink: ",&strerr_sys); | ||
| 159 | } | ||
| 160 | |||
| 161 | _exit(0); | ||
| 162 | } | ||
diff --git a/maildirmake.1 b/maildirmake.1 new file mode 100644 index 0000000..e5bd042 --- /dev/null +++ b/maildirmake.1 | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | .TH maildirmake 1 | ||
| 2 | .SH NAME | ||
| 3 | maildirmake \- create a maildir for incoming mail | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B maildirmake | ||
| 6 | .I dir | ||
| 7 | .SH DESCRIPTION | ||
| 8 | .B maildirmake | ||
| 9 | makes a new directory, | ||
| 10 | .IR dir , | ||
| 11 | in | ||
| 12 | .B maildir | ||
| 13 | format. | ||
| 14 | .SH "SEE ALSO" | ||
| 15 | maildir(5) | ||
diff --git a/maildirmake.c b/maildirmake.c new file mode 100644 index 0000000..9863fef --- /dev/null +++ b/maildirmake.c | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | #include "strerr.h" | ||
| 2 | #include "exit.h" | ||
| 3 | |||
| 4 | #define FATAL "maildirmake: fatal: " | ||
| 5 | |||
| 6 | void main(argc,argv) | ||
| 7 | int argc; | ||
| 8 | char **argv; | ||
| 9 | { | ||
| 10 | umask(077); | ||
| 11 | if (!argv[1]) | ||
| 12 | strerr_die1x(100,"maildirmake: usage: maildirmake name"); | ||
| 13 | if (mkdir(argv[1],0700) == -1) | ||
| 14 | strerr_die4sys(111,FATAL,"unable to mkdir ",argv[1],": "); | ||
| 15 | if (chdir(argv[1]) == -1) | ||
| 16 | strerr_die4sys(111,FATAL,"unable to chdir to ",argv[1],": "); | ||
| 17 | if (mkdir("tmp",0700) == -1) | ||
| 18 | strerr_die4sys(111,FATAL,"unable to mkdir ",argv[1],"/tmp: "); | ||
| 19 | if (mkdir("new",0700) == -1) | ||
| 20 | strerr_die4sys(111,FATAL,"unable to mkdir ",argv[1],"/new: "); | ||
| 21 | if (mkdir("cur",0700) == -1) | ||
| 22 | strerr_die4sys(111,FATAL,"unable to mkdir ",argv[1],"/cur: "); | ||
| 23 | _exit(0); | ||
| 24 | } | ||
diff --git a/maildirwatch.1 b/maildirwatch.1 new file mode 100644 index 0000000..d1d70a0 --- /dev/null +++ b/maildirwatch.1 | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | .TH maildirwatch 1 | ||
| 2 | .SH NAME | ||
| 3 | maildirwatch \- look for new mail in a maildir | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B maildirwatch | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B maildirwatch | ||
| 8 | watches your | ||
| 9 | .I maildir | ||
| 10 | for new mail. | ||
| 11 | You must supply a | ||
| 12 | .B MAILDIR | ||
| 13 | environment variable | ||
| 14 | with the name of your | ||
| 15 | .I maildir | ||
| 16 | directory. | ||
| 17 | |||
| 18 | .B maildirwatch | ||
| 19 | prints a new mail summary twice per minute. | ||
| 20 | It is designed to run inside a (VT100-compatible) window; | ||
| 21 | it clears the window before each summary. | ||
| 22 | .SH "SEE ALSO" | ||
| 23 | maildir(5) | ||
diff --git a/maildirwatch.c b/maildirwatch.c new file mode 100644 index 0000000..40d8322 --- /dev/null +++ b/maildirwatch.c | |||
| @@ -0,0 +1,125 @@ | |||
| 1 | #include "getln.h" | ||
| 2 | #include "substdio.h" | ||
| 3 | #include "subfd.h" | ||
| 4 | #include "prioq.h" | ||
| 5 | #include "stralloc.h" | ||
| 6 | #include "str.h" | ||
| 7 | #include "exit.h" | ||
| 8 | #include "hfield.h" | ||
| 9 | #include "readwrite.h" | ||
| 10 | #include "open.h" | ||
| 11 | #include "headerbody.h" | ||
| 12 | #include "maildir.h" | ||
| 13 | |||
| 14 | #define FATAL "maildirwatch: fatal: " | ||
| 15 | |||
| 16 | void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); } | ||
| 17 | |||
| 18 | stralloc recipient = {0}; | ||
| 19 | stralloc sender = {0}; | ||
| 20 | stralloc fromline = {0}; | ||
| 21 | stralloc text = {0}; | ||
| 22 | |||
| 23 | void addtext(s,n) char *s; int n; | ||
| 24 | { | ||
| 25 | if (!stralloc_catb(&text,s,n)) die_nomem(); | ||
| 26 | if (text.len > 158) text.len = 158; | ||
| 27 | } | ||
| 28 | void dobody(h) stralloc *h; { addtext(h->s,h->len); } | ||
| 29 | void doheader(h) stralloc *h; | ||
| 30 | { | ||
| 31 | int i; | ||
| 32 | switch(hfield_known(h->s,h->len)) | ||
| 33 | { | ||
| 34 | case H_SUBJECT: | ||
| 35 | i = hfield_skipname(h->s,h->len); | ||
| 36 | addtext(h->s + i,h->len - i); | ||
| 37 | break; | ||
| 38 | case H_DELIVEREDTO: | ||
| 39 | i = hfield_skipname(h->s,h->len); | ||
| 40 | if (i < h->len) | ||
| 41 | if (!stralloc_copyb(&recipient,h->s + i,h->len - i - 1)) die_nomem(); | ||
| 42 | break; | ||
| 43 | case H_RETURNPATH: | ||
| 44 | i = hfield_skipname(h->s,h->len); | ||
| 45 | if (i < h->len) | ||
| 46 | if (!stralloc_copyb(&sender,h->s + i,h->len - i - 1)) die_nomem(); | ||
| 47 | break; | ||
| 48 | case H_FROM: | ||
| 49 | if (!stralloc_copyb(&fromline,h->s,h->len - 1)) die_nomem(); | ||
| 50 | break; | ||
| 51 | } | ||
| 52 | } | ||
| 53 | void finishheader() { ; } | ||
| 54 | |||
| 55 | stralloc filenames = {0}; | ||
| 56 | prioq pq = {0}; | ||
| 57 | |||
| 58 | char inbuf[SUBSTDIO_INSIZE]; | ||
| 59 | substdio ssin; | ||
| 60 | |||
| 61 | void main() | ||
| 62 | { | ||
| 63 | struct prioq_elt pe; | ||
| 64 | int fd; | ||
| 65 | int i; | ||
| 66 | |||
| 67 | if (maildir_chdir() == -1) | ||
| 68 | strerr_die1(111,FATAL,&maildir_chdir_err); | ||
| 69 | |||
| 70 | for (;;) | ||
| 71 | { | ||
| 72 | maildir_clean(&filenames); | ||
| 73 | if (maildir_scan(&pq,&filenames,1,0) == -1) | ||
| 74 | strerr_die1(111,FATAL,&maildir_scan_err); | ||
| 75 | |||
| 76 | substdio_putsflush(subfdout,"\033[;H\033[;J"); | ||
| 77 | |||
| 78 | while (prioq_min(&pq,&pe)) | ||
| 79 | { | ||
| 80 | prioq_delmin(&pq); | ||
| 81 | |||
| 82 | fd = open_read(filenames.s + pe.id); | ||
| 83 | if (fd == -1) continue; | ||
| 84 | substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); | ||
| 85 | |||
| 86 | if (!stralloc_copys(&sender,"?")) die_nomem(); | ||
| 87 | if (!stralloc_copys(&recipient,"?")) die_nomem(); | ||
| 88 | if (!stralloc_copys(&fromline,"")) die_nomem(); | ||
| 89 | if (!stralloc_copys(&text,"")) die_nomem(); | ||
| 90 | if (headerbody(&ssin,doheader,finishheader,dobody) == -1) | ||
| 91 | strerr_die2x(111,FATAL,"trouble reading new message"); | ||
| 92 | |||
| 93 | for (i = 0;i < fromline.len;++i) | ||
| 94 | if ((fromline.s[i] < 32) || (fromline.s[i] > 126)) | ||
| 95 | fromline.s[i] = '/'; | ||
| 96 | for (i = 0;i < sender.len;++i) | ||
| 97 | if ((sender.s[i] < 32) || (sender.s[i] > 126)) | ||
| 98 | sender.s[i] = '?'; | ||
| 99 | for (i = 0;i < recipient.len;++i) | ||
| 100 | if ((recipient.s[i] < 32) || (recipient.s[i] > 126)) | ||
| 101 | recipient.s[i] = '?'; | ||
| 102 | for (i = 0;i < text.len;++i) | ||
| 103 | if ((text.s[i] < 32) || (text.s[i] > 126)) | ||
| 104 | text.s[i] = '/'; | ||
| 105 | substdio_puts(subfdout,"FROM "); | ||
| 106 | substdio_put(subfdout,sender.s,sender.len); | ||
| 107 | substdio_puts(subfdout," TO <"); | ||
| 108 | substdio_put(subfdout,recipient.s,recipient.len); | ||
| 109 | substdio_puts(subfdout,">\n"); | ||
| 110 | if (fromline.len) | ||
| 111 | { | ||
| 112 | substdio_puts(subfdout,"\033[1m"); | ||
| 113 | substdio_put(subfdout,fromline.s,fromline.len); | ||
| 114 | substdio_puts(subfdout,"\033[0m\n"); | ||
| 115 | } | ||
| 116 | substdio_put(subfdout,text.s,text.len); | ||
| 117 | substdio_puts(subfdout,"\n\n"); | ||
| 118 | |||
| 119 | close(fd); | ||
| 120 | } | ||
| 121 | |||
| 122 | substdio_flush(subfdout); | ||
| 123 | sleep(30); | ||
| 124 | } | ||
| 125 | } | ||
diff --git a/mailsubj.1 b/mailsubj.1 new file mode 100644 index 0000000..687b8e8 --- /dev/null +++ b/mailsubj.1 | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | .TH mailsubj 1 | ||
| 2 | .SH NAME | ||
| 3 | mailsubj \- send a mail message with a subject line | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B mailsubj | ||
| 6 | .I subject | ||
| 7 | .I recip ... | ||
| 8 | .SH DESCRIPTION | ||
| 9 | .B mailsubj | ||
| 10 | inserts | ||
| 11 | .I subject | ||
| 12 | and the list of | ||
| 13 | .IR recip s | ||
| 14 | into a mail message: | ||
| 15 | |||
| 16 | .EX | ||
| 17 | Subject: subject | ||
| 18 | .br | ||
| 19 | To: recip ... | ||
| 20 | .br | ||
| 21 | |||
| 22 | .br | ||
| 23 | body | ||
| 24 | .EE | ||
| 25 | |||
| 26 | .B mailsubj | ||
| 27 | reads the body of the message from its standard input. | ||
| 28 | Then it sends the message. | ||
| 29 | |||
| 30 | Note that | ||
| 31 | .I subject | ||
| 32 | and | ||
| 33 | .I recip | ||
| 34 | must be quoted properly for the message header. | ||
| 35 | .SH "SEE ALSO" | ||
| 36 | addresses(5), | ||
| 37 | qmail-header(8), | ||
| 38 | qmail-inject(8) | ||
diff --git a/mailsubj.sh b/mailsubj.sh new file mode 100644 index 0000000..a93d3f4 --- /dev/null +++ b/mailsubj.sh | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | subject="$1" | ||
| 2 | shift | ||
| 3 | ( echo Subject: "$subject" | ||
| 4 | echo To: ${1+"$@"} | ||
| 5 | echo '' | ||
| 6 | cat | ||
| 7 | ) | QMAIL/bin/qmail-inject | ||
diff --git a/make-compile.sh b/make-compile.sh new file mode 100644 index 0000000..a1eb501 --- /dev/null +++ b/make-compile.sh | |||
| @@ -0,0 +1 @@ | |||
| echo exec "$CC" -c '${1+"$@"}' | |||
diff --git a/make-load.sh b/make-load.sh new file mode 100644 index 0000000..de07d2e --- /dev/null +++ b/make-load.sh | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | echo 'main="$1"; shift' | ||
| 2 | echo exec "$LD" '-o "$main" "$main".o ${1+"$@"}' | ||
diff --git a/make-makelib.sh b/make-makelib.sh new file mode 100644 index 0000000..d6b7c8c --- /dev/null +++ b/make-makelib.sh | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | echo 'main="$1"; shift' | ||
| 2 | echo 'rm -f "$main"' | ||
| 3 | echo 'ar cr "$main" ${1+"$@"}' | ||
| 4 | |||
| 5 | case "$1" in | ||
| 6 | sunos-5.*) ;; | ||
| 7 | unix_sv*) ;; | ||
| 8 | irix64-*) ;; | ||
| 9 | irix-*) ;; | ||
| 10 | dgux-*) ;; | ||
| 11 | hp-ux-*) ;; | ||
| 12 | sco*) ;; | ||
| 13 | *) | ||
| 14 | echo 'ranlib "$main"' | ||
| 15 | ;; | ||
| 16 | esac | ||
| @@ -0,0 +1,235 @@ | |||
| 1 | .TH mbox 5 | ||
| 2 | .SH "NAME" | ||
| 3 | mbox \- file containing mail messages | ||
| 4 | .SH "INTRODUCTION" | ||
| 5 | The most common format for storage of mail messages is | ||
| 6 | .I mbox | ||
| 7 | format. | ||
| 8 | An | ||
| 9 | .I mbox | ||
| 10 | is a single file containing zero or more mail messages. | ||
| 11 | .SH "MESSAGE FORMAT" | ||
| 12 | A message encoded in | ||
| 13 | .I mbox | ||
| 14 | format begins with a | ||
| 15 | .B From_ | ||
| 16 | line, continues with a series of | ||
| 17 | .B \fRnon-\fBFrom_ | ||
| 18 | lines, | ||
| 19 | and ends with a blank line. | ||
| 20 | A | ||
| 21 | .B From_ | ||
| 22 | line means any line that begins with the characters | ||
| 23 | F, r, o, m, space: | ||
| 24 | |||
| 25 | .EX | ||
| 26 | From god@heaven.af.mil Sat Jan 3 01:05:34 1996 | ||
| 27 | .br | ||
| 28 | Return-Path: <god@heaven.af.mil> | ||
| 29 | .br | ||
| 30 | Delivered-To: djb@silverton.berkeley.edu | ||
| 31 | .br | ||
| 32 | Date: 3 Jan 1996 01:05:34 -0000 | ||
| 33 | .br | ||
| 34 | From: God <god@heaven.af.mil> | ||
| 35 | .br | ||
| 36 | To: djb@silverton.berkeley.edu (D. J. Bernstein) | ||
| 37 | .br | ||
| 38 | |||
| 39 | .br | ||
| 40 | How's that mail system project coming along? | ||
| 41 | .br | ||
| 42 | |||
| 43 | .EE | ||
| 44 | |||
| 45 | The final line is a completely blank line (no spaces or tabs). | ||
| 46 | Notice that blank lines may also appear elsewhere in the message. | ||
| 47 | |||
| 48 | The | ||
| 49 | .B From_ | ||
| 50 | line always looks like | ||
| 51 | .B From | ||
| 52 | .I envsender | ||
| 53 | .I date | ||
| 54 | .IR moreinfo . | ||
| 55 | .I envsender | ||
| 56 | is one word, without spaces or tabs; | ||
| 57 | it is usually the envelope sender of the message. | ||
| 58 | .I date | ||
| 59 | is the delivery date of the message. | ||
| 60 | It always contains exactly 24 characters in | ||
| 61 | .B asctime | ||
| 62 | format. | ||
| 63 | .I moreinfo | ||
| 64 | is optional; it may contain arbitrary information. | ||
| 65 | |||
| 66 | Between the | ||
| 67 | .B From_ | ||
| 68 | line and the blank line is a message in RFC 822 format, | ||
| 69 | as described in | ||
| 70 | .BR qmail-header(5) , | ||
| 71 | subject to | ||
| 72 | .B >From quoting | ||
| 73 | as described below. | ||
| 74 | .SH "HOW A MESSAGE IS DELIVERED" | ||
| 75 | Here is how a program appends a message to an | ||
| 76 | .I mbox | ||
| 77 | file. | ||
| 78 | |||
| 79 | It first creates a | ||
| 80 | .B From_ | ||
| 81 | line given the message's envelope sender and the current date. | ||
| 82 | If the envelope sender is empty (i.e., if this is a bounce message), | ||
| 83 | the program uses | ||
| 84 | .B MAILER-DAEMON | ||
| 85 | instead. | ||
| 86 | If the envelope sender contains spaces, tabs, or newlines, | ||
| 87 | the program replaces them with hyphens. | ||
| 88 | |||
| 89 | The program then copies the message, applying | ||
| 90 | .B >From quoting | ||
| 91 | to each line. | ||
| 92 | .B >From quoting | ||
| 93 | ensures that the resulting lines are not | ||
| 94 | .B From_ | ||
| 95 | lines: | ||
| 96 | the program prepends a | ||
| 97 | .B > | ||
| 98 | to any | ||
| 99 | .B From_ | ||
| 100 | line, | ||
| 101 | .B >From_ | ||
| 102 | line, | ||
| 103 | .B >>From_ | ||
| 104 | line, | ||
| 105 | .B >>>From_ | ||
| 106 | line, | ||
| 107 | etc. | ||
| 108 | |||
| 109 | Finally the program appends a blank line to the message. | ||
| 110 | If the last line of the message was a partial line, | ||
| 111 | it writes two newlines; | ||
| 112 | otherwise it writes one. | ||
| 113 | .SH "HOW A MESSAGE IS READ" | ||
| 114 | A reader scans through an | ||
| 115 | .I mbox | ||
| 116 | file looking for | ||
| 117 | .B From_ | ||
| 118 | lines. | ||
| 119 | Any | ||
| 120 | .B From_ | ||
| 121 | line marks the beginning of a message. | ||
| 122 | The reader should not attempt to take advantage of the fact that every | ||
| 123 | .B From_ | ||
| 124 | line (past the beginning of the file) | ||
| 125 | is preceded by a blank line. | ||
| 126 | |||
| 127 | Once the reader finds a message, | ||
| 128 | it extracts a (possibly corrupted) envelope sender | ||
| 129 | and delivery date out of the | ||
| 130 | .B From_ | ||
| 131 | line. | ||
| 132 | It then reads until the next | ||
| 133 | .B From_ | ||
| 134 | line or end of file, whichever comes first. | ||
| 135 | It strips off the final blank line | ||
| 136 | and | ||
| 137 | deletes the | ||
| 138 | quoting of | ||
| 139 | .B >From_ | ||
| 140 | lines and | ||
| 141 | .B >>From_ | ||
| 142 | lines and so on. | ||
| 143 | The result is an RFC 822 message. | ||
| 144 | .SH "COMMON MBOX VARIANTS" | ||
| 145 | There are many variants of | ||
| 146 | .I mbox | ||
| 147 | format. | ||
| 148 | The variant described above is | ||
| 149 | .I mboxrd | ||
| 150 | format, popularized by Rahul Dhesi in June 1995. | ||
| 151 | |||
| 152 | The original | ||
| 153 | .I mboxo | ||
| 154 | format quotes only | ||
| 155 | .B From_ | ||
| 156 | lines, not | ||
| 157 | .B >From_ | ||
| 158 | lines. | ||
| 159 | As a result it is impossible to tell whether | ||
| 160 | |||
| 161 | .EX | ||
| 162 | From: djb@silverton.berkeley.edu (D. J. Bernstein) | ||
| 163 | .br | ||
| 164 | To: god@heaven.af.mil | ||
| 165 | .br | ||
| 166 | |||
| 167 | .br | ||
| 168 | >From now through August I'll be doing beta testing. | ||
| 169 | .br | ||
| 170 | Thanks for your interest. | ||
| 171 | .EE | ||
| 172 | |||
| 173 | was quoted in the original message. | ||
| 174 | An | ||
| 175 | .I mboxrd | ||
| 176 | reader will always strip off the quoting. | ||
| 177 | |||
| 178 | .I mboxcl | ||
| 179 | format is like | ||
| 180 | .I mboxo | ||
| 181 | format, but includes a Content-Length field with the | ||
| 182 | number of bytes in the message. | ||
| 183 | .I mboxcl2 | ||
| 184 | format is like | ||
| 185 | .I mboxcl | ||
| 186 | but has no | ||
| 187 | .B >From | ||
| 188 | quoting. | ||
| 189 | These formats are used by SVR4 mailers. | ||
| 190 | .I mboxcl2 | ||
| 191 | cannot be read safely by | ||
| 192 | .I mboxrd | ||
| 193 | readers. | ||
| 194 | .SH "UNSPECIFIED DETAILS" | ||
| 195 | There are many locking mechanisms for | ||
| 196 | .I mbox | ||
| 197 | files. | ||
| 198 | .B qmail-local | ||
| 199 | always uses | ||
| 200 | .B flock | ||
| 201 | on systems that have it, otherwise | ||
| 202 | .BR lockf . | ||
| 203 | |||
| 204 | The delivery date in a | ||
| 205 | .B From_ | ||
| 206 | line does not specify a time zone. | ||
| 207 | .B qmail-local | ||
| 208 | always creates the delivery date in GMT | ||
| 209 | so that | ||
| 210 | .I mbox | ||
| 211 | files can be safely transported from one time zone to another. | ||
| 212 | |||
| 213 | If the mtime on a nonempty | ||
| 214 | .I mbox | ||
| 215 | file is greater than the atime, | ||
| 216 | the file has new mail. | ||
| 217 | If the mtime is smaller than the atime, | ||
| 218 | the new mail has been read. | ||
| 219 | If the atime equals the mtime, | ||
| 220 | there is no way to tell whether the file has new mail, | ||
| 221 | since | ||
| 222 | .B qmail-local | ||
| 223 | takes much less than a second to run. | ||
| 224 | One solution is for a mail reader to artificially set the | ||
| 225 | atime to the mtime plus 1. | ||
| 226 | Then the file has new mail if and only if the atime is | ||
| 227 | less than or equal to the mtime. | ||
| 228 | |||
| 229 | Some mail readers place | ||
| 230 | .B Status | ||
| 231 | fields in each message to indicate which messages have been read. | ||
| 232 | .SH "SEE ALSO" | ||
| 233 | maildir(5), | ||
| 234 | qmail-header(5), | ||
| 235 | qmail-local(8) | ||
diff --git a/myctime.c b/myctime.c new file mode 100644 index 0000000..5003c39 --- /dev/null +++ b/myctime.c | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | #include "datetime.h" | ||
| 2 | #include "fmt.h" | ||
| 3 | #include "myctime.h" | ||
| 4 | |||
| 5 | static char *daytab[7] = { | ||
| 6 | "Sun","Mon","Tue","Wed","Thu","Fri","Sat" | ||
| 7 | }; | ||
| 8 | static char *montab[12] = { | ||
| 9 | "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" | ||
| 10 | }; | ||
| 11 | |||
| 12 | static char result[30]; | ||
| 13 | |||
| 14 | char *myctime(t) | ||
| 15 | datetime_sec t; | ||
| 16 | { | ||
| 17 | struct datetime dt; | ||
| 18 | unsigned int len; | ||
| 19 | datetime_tai(&dt,t); | ||
| 20 | len = 0; | ||
| 21 | len += fmt_str(result + len,daytab[dt.wday]); | ||
| 22 | result[len++] = ' '; | ||
| 23 | len += fmt_str(result + len,montab[dt.mon]); | ||
| 24 | result[len++] = ' '; | ||
| 25 | len += fmt_uint0(result + len,dt.mday,2); | ||
| 26 | result[len++] = ' '; | ||
| 27 | len += fmt_uint0(result + len,dt.hour,2); | ||
| 28 | result[len++] = ':'; | ||
| 29 | len += fmt_uint0(result + len,dt.min,2); | ||
| 30 | result[len++] = ':'; | ||
| 31 | len += fmt_uint0(result + len,dt.sec,2); | ||
| 32 | result[len++] = ' '; | ||
| 33 | len += fmt_uint(result + len,1900 + dt.year); | ||
| 34 | result[len++] = '\n'; | ||
| 35 | result[len++] = 0; | ||
| 36 | return result; | ||
| 37 | } | ||
diff --git a/myctime.h b/myctime.h new file mode 100644 index 0000000..ec1d03c --- /dev/null +++ b/myctime.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef MYCTIME_H | ||
| 2 | #define MYCTIME_H | ||
| 3 | |||
| 4 | extern char *myctime(); | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/ndelay.c b/ndelay.c new file mode 100644 index 0000000..438d1d8 --- /dev/null +++ b/ndelay.c | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <fcntl.h> | ||
| 3 | #include "ndelay.h" | ||
| 4 | |||
| 5 | #ifndef O_NONBLOCK | ||
| 6 | #define O_NONBLOCK O_NDELAY | ||
| 7 | #endif | ||
| 8 | |||
| 9 | int ndelay_on(fd) | ||
| 10 | int fd; | ||
| 11 | { | ||
| 12 | return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NONBLOCK); | ||
| 13 | } | ||
diff --git a/ndelay.h b/ndelay.h new file mode 100644 index 0000000..68c6bce --- /dev/null +++ b/ndelay.h | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef NDELAY_H | ||
| 2 | #define NDELAY_H | ||
| 3 | |||
| 4 | extern int ndelay_on(); | ||
| 5 | extern int ndelay_off(); | ||
| 6 | |||
| 7 | #endif | ||
diff --git a/ndelay_off.c b/ndelay_off.c new file mode 100644 index 0000000..86f8fbf --- /dev/null +++ b/ndelay_off.c | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <fcntl.h> | ||
| 3 | #include "ndelay.h" | ||
| 4 | |||
| 5 | #ifndef O_NONBLOCK | ||
| 6 | #define O_NONBLOCK O_NDELAY | ||
| 7 | #endif | ||
| 8 | |||
| 9 | int ndelay_off(fd) | ||
| 10 | int fd; | ||
| 11 | { | ||
| 12 | return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) & ~O_NONBLOCK); | ||
| 13 | } | ||
diff --git a/newfield.c b/newfield.c new file mode 100644 index 0000000..78d6bb8 --- /dev/null +++ b/newfield.c | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | #include "fmt.h" | ||
| 2 | #include "datetime.h" | ||
| 3 | #include "stralloc.h" | ||
| 4 | #include "date822fmt.h" | ||
| 5 | #include "newfield.h" | ||
| 6 | |||
| 7 | /* "Date: 26 Sep 1995 04:46:53 -0000\n" */ | ||
| 8 | stralloc newfield_date = {0}; | ||
| 9 | /* "Message-ID: <19950926044653.12345.qmail@silverton.berkeley.edu>\n" */ | ||
| 10 | stralloc newfield_msgid = {0}; | ||
| 11 | |||
| 12 | static unsigned int datefmt(s,when) | ||
| 13 | char *s; | ||
| 14 | datetime_sec when; | ||
| 15 | { | ||
| 16 | unsigned int i; | ||
| 17 | unsigned int len; | ||
| 18 | struct datetime dt; | ||
| 19 | datetime_tai(&dt,when); | ||
| 20 | len = 0; | ||
| 21 | i = fmt_str(s,"Date: "); len += i; if (s) s += i; | ||
| 22 | i = date822fmt(s,&dt); len += i; if (s) s += i; | ||
| 23 | return len; | ||
| 24 | } | ||
| 25 | |||
| 26 | static unsigned int msgidfmt(s,idhost,idhostlen,when) | ||
| 27 | char *s; | ||
| 28 | char *idhost; | ||
| 29 | int idhostlen; | ||
| 30 | datetime_sec when; | ||
| 31 | { | ||
| 32 | unsigned int i; | ||
| 33 | unsigned int len; | ||
| 34 | struct datetime dt; | ||
| 35 | datetime_tai(&dt,when); | ||
| 36 | len = 0; | ||
| 37 | i = fmt_str(s,"Message-ID: <"); len += i; if (s) s += i; | ||
| 38 | i = fmt_uint(s,dt.year + 1900); len += i; if (s) s += i; | ||
| 39 | i = fmt_uint0(s,dt.mon + 1,2); len += i; if (s) s += i; | ||
| 40 | i = fmt_uint0(s,dt.mday,2); len += i; if (s) s += i; | ||
| 41 | i = fmt_uint0(s,dt.hour,2); len += i; if (s) s += i; | ||
| 42 | i = fmt_uint0(s,dt.min,2); len += i; if (s) s += i; | ||
| 43 | i = fmt_uint0(s,dt.sec,2); len += i; if (s) s += i; | ||
| 44 | i = fmt_str(s,"."); len += i; if (s) s += i; | ||
| 45 | i = fmt_uint(s,getpid()); len += i; if (s) s += i; | ||
| 46 | i = fmt_str(s,".qmail@"); len += i; if (s) s += i; | ||
| 47 | i = fmt_strn(s,idhost,idhostlen); len += i; if (s) s += i; | ||
| 48 | i = fmt_str(s,">\n"); len += i; if (s) s += i; | ||
| 49 | return len; | ||
| 50 | } | ||
| 51 | |||
| 52 | int newfield_datemake(when) | ||
| 53 | datetime_sec when; | ||
| 54 | { | ||
| 55 | if (!stralloc_ready(&newfield_date,datefmt(FMT_LEN,when))) return 0; | ||
| 56 | newfield_date.len = datefmt(newfield_date.s,when); | ||
| 57 | return 1; | ||
| 58 | } | ||
| 59 | |||
| 60 | int newfield_msgidmake(idhost,idhostlen,when) | ||
| 61 | char *idhost; | ||
| 62 | int idhostlen; | ||
| 63 | datetime_sec when; | ||
| 64 | { | ||
| 65 | if (!stralloc_ready(&newfield_msgid,msgidfmt(FMT_LEN,idhost,idhostlen,when))) return 0; | ||
| 66 | newfield_msgid.len = msgidfmt(newfield_msgid.s,idhost,idhostlen,when); | ||
| 67 | return 1; | ||
| 68 | } | ||
diff --git a/newfield.h b/newfield.h new file mode 100644 index 0000000..a51352a --- /dev/null +++ b/newfield.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef NEWFIELD_H | ||
| 2 | #define NEWFIELD_H | ||
| 3 | |||
| 4 | #include "stralloc.h" | ||
| 5 | |||
| 6 | extern stralloc newfield_date; | ||
| 7 | extern int newfield_datemake(); | ||
| 8 | |||
| 9 | extern stralloc newfield_msgid; | ||
| 10 | extern int newfield_msgidmake(); | ||
| 11 | |||
| 12 | #endif | ||
| @@ -0,0 +1,14 @@ | |||
| 1 | .TH now 3 | ||
| 2 | .SH NAME | ||
| 3 | now \- get current time, in seconds | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <now.h> | ||
| 6 | |||
| 7 | datetime_sec \fBnow\fP(); | ||
| 8 | .SH DESCRIPTION | ||
| 9 | .B now | ||
| 10 | returns the number of real-time seconds that have elapsed | ||
| 11 | since the end of 1969 TAI. | ||
| 12 | .SH "SEE ALSO" | ||
| 13 | datetime(3), | ||
| 14 | time(3) | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | #include <time.h> | ||
| 2 | #include "datetime.h" | ||
| 3 | #include "now.h" | ||
| 4 | |||
| 5 | datetime_sec now() | ||
| 6 | { | ||
| 7 | return time((long *) 0); | ||
| 8 | } | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef NOW_H | ||
| 2 | #define NOW_H | ||
| 3 | |||
| 4 | #include "datetime.h" | ||
| 5 | |||
| 6 | extern datetime_sec now(); | ||
| 7 | |||
| 8 | #endif | ||
| @@ -0,0 +1,10 @@ | |||
| 1 | #ifndef OPEN_H | ||
| 2 | #define OPEN_H | ||
| 3 | |||
| 4 | extern int open_read(); | ||
| 5 | extern int open_excl(); | ||
| 6 | extern int open_append(); | ||
| 7 | extern int open_trunc(); | ||
| 8 | extern int open_write(); | ||
| 9 | |||
| 10 | #endif | ||
diff --git a/open_append.c b/open_append.c new file mode 100644 index 0000000..93a0862 --- /dev/null +++ b/open_append.c | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <fcntl.h> | ||
| 3 | #include "open.h" | ||
| 4 | |||
| 5 | int open_append(fn) char *fn; | ||
| 6 | { return open(fn,O_WRONLY | O_NDELAY | O_APPEND | O_CREAT,0600); } | ||
diff --git a/open_excl.c b/open_excl.c new file mode 100644 index 0000000..887e7c8 --- /dev/null +++ b/open_excl.c | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <fcntl.h> | ||
| 3 | #include "open.h" | ||
| 4 | |||
| 5 | int open_excl(fn) char *fn; | ||
| 6 | { return open(fn,O_WRONLY | O_EXCL | O_CREAT,0644); } | ||
diff --git a/open_read.c b/open_read.c new file mode 100644 index 0000000..f503e48 --- /dev/null +++ b/open_read.c | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <fcntl.h> | ||
| 3 | #include "open.h" | ||
| 4 | |||
| 5 | int open_read(fn) char *fn; | ||
| 6 | { return open(fn,O_RDONLY | O_NDELAY); } | ||
diff --git a/open_trunc.c b/open_trunc.c new file mode 100644 index 0000000..e275085 --- /dev/null +++ b/open_trunc.c | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <fcntl.h> | ||
| 3 | #include "open.h" | ||
| 4 | |||
| 5 | int open_trunc(fn) char *fn; | ||
| 6 | { return open(fn,O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT,0644); } | ||
diff --git a/open_write.c b/open_write.c new file mode 100644 index 0000000..dcdcb95 --- /dev/null +++ b/open_write.c | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <fcntl.h> | ||
| 3 | #include "open.h" | ||
| 4 | |||
| 5 | int open_write(fn) char *fn; | ||
| 6 | { return open(fn,O_WRONLY | O_NDELAY); } | ||
| @@ -0,0 +1 @@ | |||
| QMAIL/bin/maildir2mbox && exec pine ${1+"$@"} | |||
diff --git a/predate.c b/predate.c new file mode 100644 index 0000000..9648f6e --- /dev/null +++ b/predate.c | |||
| @@ -0,0 +1,116 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <time.h> | ||
| 3 | #include "datetime.h" | ||
| 4 | #include "fork.h" | ||
| 5 | #include "wait.h" | ||
| 6 | #include "fd.h" | ||
| 7 | #include "fmt.h" | ||
| 8 | #include "strerr.h" | ||
| 9 | #include "substdio.h" | ||
| 10 | #include "subfd.h" | ||
| 11 | #include "readwrite.h" | ||
| 12 | #include "exit.h" | ||
| 13 | |||
| 14 | #define FATAL "predate: fatal: " | ||
| 15 | |||
| 16 | static char *montab[12] = { | ||
| 17 | "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" | ||
| 18 | }; | ||
| 19 | |||
| 20 | char num[FMT_ULONG]; | ||
| 21 | char outbuf[1024]; | ||
| 22 | |||
| 23 | void main(argc,argv) | ||
| 24 | int argc; | ||
| 25 | char **argv; | ||
| 26 | { | ||
| 27 | time_t now; | ||
| 28 | struct tm *tm; | ||
| 29 | struct datetime dt; | ||
| 30 | datetime_sec utc; | ||
| 31 | datetime_sec local; | ||
| 32 | int minutes; | ||
| 33 | int pi[2]; | ||
| 34 | substdio ss; | ||
| 35 | int wstat; | ||
| 36 | int pid; | ||
| 37 | |||
| 38 | sig_pipeignore(); | ||
| 39 | |||
| 40 | if (!argv[1]) | ||
| 41 | strerr_die1x(100,"predate: usage: predate child"); | ||
| 42 | |||
| 43 | if (pipe(pi) == -1) | ||
| 44 | strerr_die2sys(111,FATAL,"unable to create pipe: "); | ||
| 45 | |||
| 46 | switch(pid = fork()) { | ||
| 47 | case -1: | ||
| 48 | strerr_die2sys(111,FATAL,"unable to fork: "); | ||
| 49 | case 0: | ||
| 50 | close(pi[1]); | ||
| 51 | if (fd_move(0,pi[0]) == -1) | ||
| 52 | strerr_die2sys(111,FATAL,"unable to set up fds: "); | ||
| 53 | sig_pipedefault(); | ||
| 54 | execvp(argv[1],argv + 1); | ||
| 55 | strerr_die4sys(111,FATAL,"unable to run ",argv[1],": "); | ||
| 56 | } | ||
| 57 | close(pi[0]); | ||
| 58 | substdio_fdbuf(&ss,write,pi[1],outbuf,sizeof(outbuf)); | ||
| 59 | |||
| 60 | time(&now); | ||
| 61 | |||
| 62 | tm = gmtime(&now); | ||
| 63 | dt.year = tm->tm_year; | ||
| 64 | dt.mon = tm->tm_mon; | ||
| 65 | dt.mday = tm->tm_mday; | ||
| 66 | dt.hour = tm->tm_hour; | ||
| 67 | dt.min = tm->tm_min; | ||
| 68 | dt.sec = tm->tm_sec; | ||
| 69 | utc = datetime_untai(&dt); /* utc == now, if gmtime ignores leap seconds */ | ||
| 70 | |||
| 71 | tm = localtime(&now); | ||
| 72 | dt.year = tm->tm_year; | ||
| 73 | dt.mon = tm->tm_mon; | ||
| 74 | dt.mday = tm->tm_mday; | ||
| 75 | dt.hour = tm->tm_hour; | ||
| 76 | dt.min = tm->tm_min; | ||
| 77 | dt.sec = tm->tm_sec; | ||
| 78 | local = datetime_untai(&dt); | ||
| 79 | |||
| 80 | substdio_puts(&ss,"Date: "); | ||
| 81 | substdio_put(&ss,num,fmt_uint(num,dt.mday)); | ||
| 82 | substdio_puts(&ss," "); | ||
| 83 | substdio_puts(&ss,montab[dt.mon]); | ||
| 84 | substdio_puts(&ss," "); | ||
| 85 | substdio_put(&ss,num,fmt_uint(num,dt.year + 1900)); | ||
| 86 | substdio_puts(&ss," "); | ||
| 87 | substdio_put(&ss,num,fmt_uint0(num,dt.hour,2)); | ||
| 88 | substdio_puts(&ss,":"); | ||
| 89 | substdio_put(&ss,num,fmt_uint0(num,dt.min,2)); | ||
| 90 | substdio_puts(&ss,":"); | ||
| 91 | substdio_put(&ss,num,fmt_uint0(num,dt.sec,2)); | ||
| 92 | |||
| 93 | if (local < utc) { | ||
| 94 | minutes = (utc - local + 30) / 60; | ||
| 95 | substdio_puts(&ss," -"); | ||
| 96 | substdio_put(&ss,num,fmt_uint0(num,minutes / 60,2)); | ||
| 97 | substdio_put(&ss,num,fmt_uint0(num,minutes % 60,2)); | ||
| 98 | } | ||
| 99 | else { | ||
| 100 | minutes = (local - utc + 30) / 60; | ||
| 101 | substdio_puts(&ss," +"); | ||
| 102 | substdio_put(&ss,num,fmt_uint0(num,minutes / 60,2)); | ||
| 103 | substdio_put(&ss,num,fmt_uint0(num,minutes % 60,2)); | ||
| 104 | } | ||
| 105 | |||
| 106 | substdio_puts(&ss,"\n"); | ||
| 107 | substdio_copy(&ss,subfdin); | ||
| 108 | substdio_flush(&ss); | ||
| 109 | close(pi[1]); | ||
| 110 | |||
| 111 | if (wait_pid(&wstat,pid) == -1) | ||
| 112 | strerr_die2sys(111,FATAL,"wait failed: "); | ||
| 113 | if (wait_crashed(wstat)) | ||
| 114 | strerr_die2x(111,FATAL,"child crashed"); | ||
| 115 | _exit(wait_exitcode(wstat)); | ||
| 116 | } | ||
diff --git a/preline.1 b/preline.1 new file mode 100644 index 0000000..69a757c --- /dev/null +++ b/preline.1 | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | .TH preline 1 | ||
| 2 | .SH NAME | ||
| 3 | preline \- prepend lines to message | ||
| 4 | .SH SYNOPSIS | ||
| 5 | in | ||
| 6 | .BR .qmail\fIext : | ||
| 7 | .B | preline \fIcommand | ||
| 8 | .SH DESCRIPTION | ||
| 9 | .B preline | ||
| 10 | feeds each incoming mail message through | ||
| 11 | .IR command . | ||
| 12 | At the top of each message it inserts | ||
| 13 | a UUCP-style | ||
| 14 | .B From_ | ||
| 15 | line, a | ||
| 16 | .B Return-Path | ||
| 17 | line, and a | ||
| 18 | .B Delivered-To | ||
| 19 | line. | ||
| 20 | |||
| 21 | .B preline | ||
| 22 | is useful for | ||
| 23 | .B procmail | ||
| 24 | and | ||
| 25 | ELM's | ||
| 26 | .BR filter , | ||
| 27 | which | ||
| 28 | do not understand the | ||
| 29 | .B qmail-command | ||
| 30 | environment variables. | ||
| 31 | .SH OPTIONS | ||
| 32 | .TP | ||
| 33 | .B \-d | ||
| 34 | Do not include the | ||
| 35 | .B Delivered-To | ||
| 36 | line. You should use this option when the | ||
| 37 | recipient of the incoming mail message is actually under remote control, | ||
| 38 | but was sent here through | ||
| 39 | .B control/virtualdomains | ||
| 40 | for manual routing. | ||
| 41 | .TP | ||
| 42 | .B \-f | ||
| 43 | Do not include the | ||
| 44 | .B From_ | ||
| 45 | line. You should use this option except for | ||
| 46 | .IR command s | ||
| 47 | that create | ||
| 48 | .I mbox | ||
| 49 | files. | ||
| 50 | .TP | ||
| 51 | .B \-r | ||
| 52 | Do not include the | ||
| 53 | .B Return-Path | ||
| 54 | line. | ||
| 55 | .SH "SEE ALSO" | ||
| 56 | mbox(5), | ||
| 57 | qmail-command(8) | ||
diff --git a/preline.c b/preline.c new file mode 100644 index 0000000..1a4cef8 --- /dev/null +++ b/preline.c | |||
| @@ -0,0 +1,90 @@ | |||
| 1 | #include "fd.h" | ||
| 2 | #include "sgetopt.h" | ||
| 3 | #include "readwrite.h" | ||
| 4 | #include "strerr.h" | ||
| 5 | #include "substdio.h" | ||
| 6 | #include "exit.h" | ||
| 7 | #include "fork.h" | ||
| 8 | #include "wait.h" | ||
| 9 | #include "env.h" | ||
| 10 | #include "sig.h" | ||
| 11 | #include "error.h" | ||
| 12 | |||
| 13 | #define FATAL "preline: fatal: " | ||
| 14 | |||
| 15 | void die_usage() | ||
| 16 | { | ||
| 17 | strerr_die1x(100,"preline: usage: preline cmd [ arg ... ]"); | ||
| 18 | } | ||
| 19 | |||
| 20 | int flagufline = 1; char *ufline; | ||
| 21 | int flagrpline = 1; char *rpline; | ||
| 22 | int flagdtline = 1; char *dtline; | ||
| 23 | |||
| 24 | char outbuf[SUBSTDIO_OUTSIZE]; | ||
| 25 | char inbuf[SUBSTDIO_INSIZE]; | ||
| 26 | substdio ssout = SUBSTDIO_FDBUF(write,1,outbuf,sizeof outbuf); | ||
| 27 | substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf); | ||
| 28 | |||
| 29 | void main(argc,argv) | ||
| 30 | int argc; | ||
| 31 | char **argv; | ||
| 32 | { | ||
| 33 | int opt; | ||
| 34 | int pi[2]; | ||
| 35 | int pid; | ||
| 36 | int wstat; | ||
| 37 | |||
| 38 | sig_pipeignore(); | ||
| 39 | |||
| 40 | if (!(ufline = env_get("UFLINE"))) die_usage(); | ||
| 41 | if (!(rpline = env_get("RPLINE"))) die_usage(); | ||
| 42 | if (!(dtline = env_get("DTLINE"))) die_usage(); | ||
| 43 | |||
| 44 | while ((opt = getopt(argc,argv,"frdFRD")) != opteof) | ||
| 45 | switch(opt) { | ||
| 46 | case 'f': flagufline = 0; break; | ||
| 47 | case 'r': flagrpline = 0; break; | ||
| 48 | case 'd': flagdtline = 0; break; | ||
| 49 | case 'F': flagufline = 1; break; | ||
| 50 | case 'R': flagrpline = 1; break; | ||
| 51 | case 'D': flagdtline = 1; break; | ||
| 52 | default: die_usage(); | ||
| 53 | } | ||
| 54 | argc -= optind; | ||
| 55 | argv += optind; | ||
| 56 | if (!*argv) die_usage(); | ||
| 57 | |||
| 58 | if (pipe(pi) == -1) | ||
| 59 | strerr_die2sys(111,FATAL,"unable to create pipe: "); | ||
| 60 | |||
| 61 | pid = fork(); | ||
| 62 | if (pid == -1) | ||
| 63 | strerr_die2sys(111,FATAL,"unable to fork: "); | ||
| 64 | |||
| 65 | if (pid == 0) { | ||
| 66 | close(pi[1]); | ||
| 67 | if (fd_move(0,pi[0]) == -1) | ||
| 68 | strerr_die2sys(111,FATAL,"unable to set up fds: "); | ||
| 69 | sig_pipedefault(); | ||
| 70 | execvp(*argv,argv); | ||
| 71 | strerr_die4sys(error_temp(errno) ? 111 : 100,FATAL,"unable to run ",*argv,": "); | ||
| 72 | } | ||
| 73 | close(pi[0]); | ||
| 74 | if (fd_move(1,pi[1]) == -1) | ||
| 75 | strerr_die2sys(111,FATAL,"unable to set up fds: "); | ||
| 76 | |||
| 77 | if (flagufline) substdio_bputs(&ssout,ufline); | ||
| 78 | if (flagrpline) substdio_bputs(&ssout,rpline); | ||
| 79 | if (flagdtline) substdio_bputs(&ssout,dtline); | ||
| 80 | if (substdio_copy(&ssout,&ssin) != 0) | ||
| 81 | strerr_die2sys(111,FATAL,"unable to copy input: "); | ||
| 82 | substdio_flush(&ssout); | ||
| 83 | close(1); | ||
| 84 | |||
| 85 | if (wait_pid(&wstat,pid) == -1) | ||
| 86 | strerr_die2sys(111,FATAL,"wait failed: "); | ||
| 87 | if (wait_crashed(wstat)) | ||
| 88 | strerr_die2x(111,FATAL,"child crashed"); | ||
| 89 | _exit(wait_exitcode(wstat)); | ||
| 90 | } | ||
| @@ -0,0 +1,58 @@ | |||
| 1 | #include "alloc.h" | ||
| 2 | #include "gen_allocdefs.h" | ||
| 3 | #include "prioq.h" | ||
| 4 | |||
| 5 | GEN_ALLOC_readyplus(prioq,struct prioq_elt,p,len,a,i,n,x,100,prioq_readyplus) | ||
| 6 | |||
| 7 | int prioq_insert(pq,pe) | ||
| 8 | prioq *pq; | ||
| 9 | struct prioq_elt *pe; | ||
| 10 | { | ||
| 11 | int i; | ||
| 12 | int j; | ||
| 13 | if (!prioq_readyplus(pq,1)) return 0; | ||
| 14 | j = pq->len++; | ||
| 15 | while (j) | ||
| 16 | { | ||
| 17 | i = (j - 1)/2; | ||
| 18 | if (pq->p[i].dt <= pe->dt) break; | ||
| 19 | pq->p[j] = pq->p[i]; | ||
| 20 | j = i; | ||
| 21 | } | ||
| 22 | pq->p[j] = *pe; | ||
| 23 | return 1; | ||
| 24 | } | ||
| 25 | |||
| 26 | int prioq_min(pq,pe) | ||
| 27 | prioq *pq; | ||
| 28 | struct prioq_elt *pe; | ||
| 29 | { | ||
| 30 | if (!pq->p) return 0; | ||
| 31 | if (!pq->len) return 0; | ||
| 32 | *pe = pq->p[0]; | ||
| 33 | return 1; | ||
| 34 | } | ||
| 35 | |||
| 36 | void prioq_delmin(pq) | ||
| 37 | prioq *pq; | ||
| 38 | { | ||
| 39 | int i; | ||
| 40 | int j; | ||
| 41 | int n; | ||
| 42 | if (!pq->p) return; | ||
| 43 | n = pq->len; | ||
| 44 | if (!n) return; | ||
| 45 | i = 0; | ||
| 46 | --n; | ||
| 47 | for (;;) | ||
| 48 | { | ||
| 49 | j = i + i + 2; | ||
| 50 | if (j > n) break; | ||
| 51 | if (pq->p[j - 1].dt <= pq->p[j].dt) --j; | ||
| 52 | if (pq->p[n].dt <= pq->p[j].dt) break; | ||
| 53 | pq->p[i] = pq->p[j]; | ||
| 54 | i = j; | ||
| 55 | } | ||
| 56 | pq->p[i] = pq->p[n]; | ||
| 57 | pq->len = n; | ||
| 58 | } | ||
| @@ -0,0 +1,15 @@ | |||
| 1 | #ifndef PRIOQ_H | ||
| 2 | #define PRIOQ_H | ||
| 3 | |||
| 4 | #include "datetime.h" | ||
| 5 | #include "gen_alloc.h" | ||
| 6 | |||
| 7 | struct prioq_elt { datetime_sec dt; unsigned long id; } ; | ||
| 8 | |||
| 9 | GEN_ALLOC_typedef(prioq,struct prioq_elt,p,len,a) | ||
| 10 | |||
| 11 | extern int prioq_insert(); | ||
| 12 | extern int prioq_min(); | ||
| 13 | extern void prioq_delmin(); | ||
| 14 | |||
| 15 | #endif | ||
diff --git a/proc+df.sh b/proc+df.sh new file mode 100644 index 0000000..eb9e92c --- /dev/null +++ b/proc+df.sh | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | # Using splogger to send the log through syslog. | ||
| 4 | # Using dot-forward to support sendmail-style ~/.forward files. | ||
| 5 | # Using procmail to deliver messages to /var/spool/mail/$USER by default. | ||
| 6 | |||
| 7 | exec env - PATH="QMAIL/bin:$PATH" \ | ||
| 8 | qmail-start '|dot-forward .forward | ||
| 9 | |preline procmail' splogger qmail | ||
| @@ -0,0 +1,7 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | # Using splogger to send the log through syslog. | ||
| 4 | # Using procmail to deliver messages to /var/spool/mail/$USER by default. | ||
| 5 | |||
| 6 | exec env - PATH="QMAIL/bin:$PATH" \ | ||
| 7 | qmail-start '|preline procmail' splogger qmail | ||
| @@ -0,0 +1,21 @@ | |||
| 1 | #include "hasshsgr.h" | ||
| 2 | #include "prot.h" | ||
| 3 | |||
| 4 | /* XXX: there are more portability problems here waiting to leap out at me */ | ||
| 5 | |||
| 6 | int prot_gid(gid) int gid; | ||
| 7 | { | ||
| 8 | #ifdef HASSHORTSETGROUPS | ||
| 9 | short x[2]; | ||
| 10 | x[0] = gid; x[1] = 73; /* catch errors */ | ||
| 11 | if (setgroups(1,x) == -1) return -1; | ||
| 12 | #else | ||
| 13 | if (setgroups(1,&gid) == -1) return -1; | ||
| 14 | #endif | ||
| 15 | return setgid(gid); /* _should_ be redundant, but on some systems it isn't */ | ||
| 16 | } | ||
| 17 | |||
| 18 | int prot_uid(uid) int uid; | ||
| 19 | { | ||
| 20 | return setuid(uid); | ||
| 21 | } | ||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef PROT_H | ||
| 2 | #define PROT_H | ||
| 3 | |||
| 4 | extern int prot_gid(); | ||
| 5 | extern int prot_uid(); | ||
| 6 | |||
| 7 | #endif | ||
| @@ -0,0 +1 @@ | |||
| QMAIL/bin/maildir2mbox && exec Mail ${1+"$@"} | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | .TH qbiff 1 | ||
| 2 | .SH NAME | ||
| 3 | qbiff \- announce new mail the moment it arrives | ||
| 4 | .SH SYNOPSIS | ||
| 5 | in | ||
| 6 | .BR .qmail : | ||
| 7 | .B |qbiff | ||
| 8 | .SH DESCRIPTION | ||
| 9 | .B qbiff | ||
| 10 | writes a message to your screen | ||
| 11 | whenever a new mail message is delivered, | ||
| 12 | if you ran | ||
| 13 | .B biff y | ||
| 14 | after logging in. | ||
| 15 | |||
| 16 | .B WARNING: | ||
| 17 | If you create a | ||
| 18 | .B .qmail | ||
| 19 | file to enable | ||
| 20 | .BR qbiff , | ||
| 21 | make sure to also add a line specifying delivery to your normal mailbox. | ||
| 22 | For example: | ||
| 23 | |||
| 24 | .EX | ||
| 25 | /home/joe/Mailbox | ||
| 26 | .br | ||
| 27 | |qbiff | ||
| 28 | .EE | ||
| 29 | .SH "SEE ALSO" | ||
| 30 | biff(1), | ||
| 31 | dot-qmail(5) | ||
| @@ -0,0 +1,113 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include <utmp.h> | ||
| 4 | #ifndef UTMP_FILE | ||
| 5 | #ifdef _PATH_UTMP | ||
| 6 | #define UTMP_FILE _PATH_UTMP | ||
| 7 | #else | ||
| 8 | #define UTMP_FILE "/etc/utmp" | ||
| 9 | #endif | ||
| 10 | #endif | ||
| 11 | #include "readwrite.h" | ||
| 12 | #include "stralloc.h" | ||
| 13 | #include "substdio.h" | ||
| 14 | #include "subfd.h" | ||
| 15 | #include "open.h" | ||
| 16 | #include "byte.h" | ||
| 17 | #include "str.h" | ||
| 18 | #include "headerbody.h" | ||
| 19 | #include "hfield.h" | ||
| 20 | #include "env.h" | ||
| 21 | #include "exit.h" | ||
| 22 | |||
| 23 | substdio ssutmp; | ||
| 24 | char bufutmp[sizeof(struct utmp) * 16]; | ||
| 25 | int fdutmp; | ||
| 26 | substdio sstty; | ||
| 27 | char buftty[1024]; | ||
| 28 | int fdtty; | ||
| 29 | |||
| 30 | struct utmp ut; | ||
| 31 | char line[sizeof(ut.ut_line) + 1]; | ||
| 32 | stralloc woof = {0}; | ||
| 33 | stralloc tofrom = {0}; | ||
| 34 | stralloc text = {0}; | ||
| 35 | |||
| 36 | void doit(s,n) char *s; int n; | ||
| 37 | { | ||
| 38 | if (!stralloc_catb(&text,s,n)) _exit(0); | ||
| 39 | if (text.len > 78) text.len = 78; | ||
| 40 | } | ||
| 41 | void dobody(h) stralloc *h; { doit(h->s,h->len); } | ||
| 42 | void doheader(h) stralloc *h; | ||
| 43 | { | ||
| 44 | int i; | ||
| 45 | if (hfield_known(h->s,h->len) == H_SUBJECT) | ||
| 46 | { | ||
| 47 | i = hfield_skipname(h->s,h->len); | ||
| 48 | doit(h->s + i,h->len - i); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | void finishheader() { ; } | ||
| 52 | |||
| 53 | void main() | ||
| 54 | { | ||
| 55 | char *user; | ||
| 56 | char *sender; | ||
| 57 | char *userext; | ||
| 58 | struct stat st; | ||
| 59 | int i; | ||
| 60 | |||
| 61 | if (chdir("/dev") == -1) _exit(0); | ||
| 62 | |||
| 63 | if (!(user = env_get("USER"))) _exit(0); | ||
| 64 | if (!(sender = env_get("SENDER"))) _exit(0); | ||
| 65 | if (!(userext = env_get("LOCAL"))) _exit(0); | ||
| 66 | if (str_len(user) > sizeof(ut.ut_name)) _exit(0); | ||
| 67 | |||
| 68 | if (!stralloc_copys(&tofrom,"*** TO <")) _exit(0); | ||
| 69 | if (!stralloc_cats(&tofrom,userext)) _exit(0); | ||
| 70 | if (!stralloc_cats(&tofrom,"> FROM <")) _exit(0); | ||
| 71 | if (!stralloc_cats(&tofrom,sender)) _exit(0); | ||
| 72 | if (!stralloc_cats(&tofrom,">")) _exit(0); | ||
| 73 | |||
| 74 | for (i = 0;i < tofrom.len;++i) | ||
| 75 | if ((tofrom.s[i] < 32) || (tofrom.s[i] > 126)) | ||
| 76 | tofrom.s[i] = '_'; | ||
| 77 | |||
| 78 | if (!stralloc_copys(&text," ")) _exit(0); | ||
| 79 | if (headerbody(subfdin,doheader,finishheader,dobody) == -1) _exit(0); | ||
| 80 | |||
| 81 | for (i = 0;i < text.len;++i) | ||
| 82 | if ((text.s[i] < 32) || (text.s[i] > 126)) | ||
| 83 | text.s[i] = '/'; | ||
| 84 | |||
| 85 | if (!stralloc_copys(&woof,"\015\n\007")) _exit(0); | ||
| 86 | if (!stralloc_cat(&woof,&tofrom)) _exit(0); | ||
| 87 | if (!stralloc_cats(&woof,"\015\n")) _exit(0); | ||
| 88 | if (!stralloc_cat(&woof,&text)) _exit(0); | ||
| 89 | if (!stralloc_cats(&woof,"\015\n")) _exit(0); | ||
| 90 | |||
| 91 | fdutmp = open_read(UTMP_FILE); | ||
| 92 | if (fdutmp == -1) _exit(0); | ||
| 93 | substdio_fdbuf(&ssutmp,read,fdutmp,bufutmp,sizeof(bufutmp)); | ||
| 94 | |||
| 95 | while (substdio_get(&ssutmp,&ut,sizeof(ut)) == sizeof(ut)) | ||
| 96 | if (!str_diffn(ut.ut_name,user,sizeof(ut.ut_name))) | ||
| 97 | { | ||
| 98 | byte_copy(line,sizeof(ut.ut_line),ut.ut_line); | ||
| 99 | line[sizeof(ut.ut_line)] = 0; | ||
| 100 | if (line[0] == '/') continue; | ||
| 101 | if (!line[0]) continue; | ||
| 102 | if (line[str_chr(line,'.')]) continue; | ||
| 103 | fdtty = open_append(line); | ||
| 104 | if (fdtty == -1) continue; | ||
| 105 | if (fstat(fdtty,&st) == -1) { close(fdtty); continue; } | ||
| 106 | if (!(st.st_mode & 0100)) { close(fdtty); continue; } | ||
| 107 | if (st.st_uid != getuid()) { close(fdtty); continue; } | ||
| 108 | substdio_fdbuf(&sstty,write,fdtty,buftty,sizeof(buftty)); | ||
| 109 | substdio_putflush(&sstty,woof.s,woof.len); | ||
| 110 | close(fdtty); | ||
| 111 | } | ||
| 112 | _exit(0); | ||
| 113 | } | ||
| @@ -0,0 +1,18 @@ | |||
| 1 | #ifndef QLX_H | ||
| 2 | #define QLX_H | ||
| 3 | |||
| 4 | /* 0, 111, 100 are qmail-local success, soft, hard */ | ||
| 5 | |||
| 6 | #define QLX_USAGE 112 | ||
| 7 | #define QLX_BUG 101 | ||
| 8 | #define QLX_ROOT 113 | ||
| 9 | #define QLX_NFS 115 | ||
| 10 | #define QLX_NOALIAS 116 | ||
| 11 | #define QLX_CDB 117 | ||
| 12 | #define QLX_SYS 118 | ||
| 13 | #define QLX_NOMEM 119 | ||
| 14 | #define QLX_EXECSOFT 120 | ||
| 15 | #define QLX_EXECPW 121 | ||
| 16 | #define QLX_EXECHARD 126 | ||
| 17 | |||
| 18 | #endif | ||
diff --git a/qmail-clean.8 b/qmail-clean.8 new file mode 100644 index 0000000..41795c6 --- /dev/null +++ b/qmail-clean.8 | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | .TH qmail-clean 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-clean \- clean up the queue directory | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-clean | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B qmail-clean | ||
| 8 | reads a cleanup command from descriptor 0, | ||
| 9 | performs the cleanup, | ||
| 10 | prints the results to descriptor 1, | ||
| 11 | and repeats. | ||
| 12 | .SH "SEE ALSO" | ||
| 13 | qmail-send(8) | ||
diff --git a/qmail-clean.c b/qmail-clean.c new file mode 100644 index 0000000..7539007 --- /dev/null +++ b/qmail-clean.c | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include "readwrite.h" | ||
| 4 | #include "sig.h" | ||
| 5 | #include "now.h" | ||
| 6 | #include "str.h" | ||
| 7 | #include "direntry.h" | ||
| 8 | #include "getln.h" | ||
| 9 | #include "stralloc.h" | ||
| 10 | #include "substdio.h" | ||
| 11 | #include "subfd.h" | ||
| 12 | #include "byte.h" | ||
| 13 | #include "scan.h" | ||
| 14 | #include "fmt.h" | ||
| 15 | #include "error.h" | ||
| 16 | #include "exit.h" | ||
| 17 | #include "fmtqfn.h" | ||
| 18 | #include "auto_qmail.h" | ||
| 19 | |||
| 20 | #define OSSIFIED 129600 /* see qmail-send.c */ | ||
| 21 | |||
| 22 | stralloc line = {0}; | ||
| 23 | |||
| 24 | void cleanuppid() | ||
| 25 | { | ||
| 26 | DIR *dir; | ||
| 27 | direntry *d; | ||
| 28 | struct stat st; | ||
| 29 | datetime_sec time; | ||
| 30 | |||
| 31 | time = now(); | ||
| 32 | dir = opendir("pid"); | ||
| 33 | if (!dir) return; | ||
| 34 | while (d = readdir(dir)) | ||
| 35 | { | ||
| 36 | if (str_equal(d->d_name,".")) continue; | ||
| 37 | if (str_equal(d->d_name,"..")) continue; | ||
| 38 | if (!stralloc_copys(&line,"pid/")) continue; | ||
| 39 | if (!stralloc_cats(&line,d->d_name)) continue; | ||
| 40 | if (!stralloc_0(&line)) continue; | ||
| 41 | if (stat(line.s,&st) == -1) continue; | ||
| 42 | if (time < st.st_atime + OSSIFIED) continue; | ||
| 43 | unlink(line.s); | ||
| 44 | } | ||
| 45 | closedir(dir); | ||
| 46 | } | ||
| 47 | |||
| 48 | char fnbuf[FMTQFN]; | ||
| 49 | |||
| 50 | void respond(s) char *s; { if (substdio_putflush(subfdoutsmall,s,1) == -1) _exit(100); } | ||
| 51 | |||
| 52 | void main() | ||
| 53 | { | ||
| 54 | int i; | ||
| 55 | int match; | ||
| 56 | int cleanuploop; | ||
| 57 | unsigned long id; | ||
| 58 | |||
| 59 | if (chdir(auto_qmail) == -1) _exit(111); | ||
| 60 | if (chdir("queue") == -1) _exit(111); | ||
| 61 | |||
| 62 | sig_pipeignore(); | ||
| 63 | |||
| 64 | if (!stralloc_ready(&line,200)) _exit(111); | ||
| 65 | |||
| 66 | cleanuploop = 0; | ||
| 67 | |||
| 68 | for (;;) | ||
| 69 | { | ||
| 70 | if (cleanuploop) --cleanuploop; else { cleanuppid(); cleanuploop = 30; } | ||
| 71 | if (getln(subfdinsmall,&line,&match,'\0') == -1) break; | ||
| 72 | if (!match) break; | ||
| 73 | if (line.len < 7) { respond("x"); continue; } | ||
| 74 | if (line.len > 100) { respond("x"); continue; } | ||
| 75 | if (line.s[line.len - 1]) { respond("x"); continue; } /* impossible */ | ||
| 76 | for (i = 5;i < line.len - 1;++i) | ||
| 77 | if ((unsigned char) (line.s[i] - '0') > 9) | ||
| 78 | { respond("x"); continue; } | ||
| 79 | if (!scan_ulong(line.s + 5,&id)) { respond("x"); continue; } | ||
| 80 | if (byte_equal(line.s,5,"foop/")) | ||
| 81 | { | ||
| 82 | #define U(prefix,flag) fmtqfn(fnbuf,prefix,id,flag); \ | ||
| 83 | if (unlink(fnbuf) == -1) if (errno != error_noent) { respond("!"); continue; } | ||
| 84 | U("intd/",0) | ||
| 85 | U("mess/",1) | ||
| 86 | respond("+"); | ||
| 87 | } | ||
| 88 | else if (byte_equal(line.s,4,"todo/")) | ||
| 89 | { | ||
| 90 | U("intd/",0) | ||
| 91 | U("todo/",0) | ||
| 92 | respond("+"); | ||
| 93 | } | ||
| 94 | else | ||
| 95 | respond("x"); | ||
| 96 | } | ||
| 97 | _exit(0); | ||
| 98 | } | ||
diff --git a/qmail-command.8 b/qmail-command.8 new file mode 100644 index 0000000..ad46377 --- /dev/null +++ b/qmail-command.8 | |||
| @@ -0,0 +1,149 @@ | |||
| 1 | .TH qmail-command 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-command \- user-specified mail delivery program | ||
| 4 | .SH SYNOPSIS | ||
| 5 | in | ||
| 6 | .BR .qmail\fIext : | ||
| 7 | .B |\fIcommand | ||
| 8 | .SH DESCRIPTION | ||
| 9 | .B qmail-local | ||
| 10 | will, upon your request, | ||
| 11 | feed each incoming mail message through a program of your choice. | ||
| 12 | |||
| 13 | When a mail message arrives, | ||
| 14 | .B qmail-local | ||
| 15 | runs | ||
| 16 | .B sh -c \fIcommand | ||
| 17 | in your home directory. | ||
| 18 | It makes the message available on | ||
| 19 | .IR command 's | ||
| 20 | standard input. | ||
| 21 | |||
| 22 | .B WARNING: | ||
| 23 | The mail message does not begin with | ||
| 24 | .BR qmail-local 's | ||
| 25 | usual | ||
| 26 | .B Return-Path | ||
| 27 | and | ||
| 28 | .B Delivered-To | ||
| 29 | lines. | ||
| 30 | |||
| 31 | Note that | ||
| 32 | .B qmail-local | ||
| 33 | uses the same file descriptor for every delivery | ||
| 34 | in your | ||
| 35 | .B .qmail | ||
| 36 | file, so it is not safe for | ||
| 37 | .I command | ||
| 38 | to fork a child that | ||
| 39 | reads the message in the background while the parent exits. | ||
| 40 | .SH "EXIT CODES" | ||
| 41 | .IR command 's | ||
| 42 | exit codes are interpreted as follows: | ||
| 43 | 0 means that the delivery was successful; | ||
| 44 | 99 means that the delivery was successful, | ||
| 45 | but that | ||
| 46 | .B qmail-local | ||
| 47 | should ignore all further delivery instructions; | ||
| 48 | 100 means that the delivery failed permanently (hard error); | ||
| 49 | 111 means that the delivery failed but should be tried again | ||
| 50 | in a little while (soft error). | ||
| 51 | |||
| 52 | Currently 64, 65, 70, 76, 77, 78, and 112 are considered hard errors, | ||
| 53 | and all other codes are considered soft errors, | ||
| 54 | but | ||
| 55 | .I command | ||
| 56 | should avoid relying on this. | ||
| 57 | .SH "ENVIRONMENT VARIABLES" | ||
| 58 | .B qmail-local | ||
| 59 | supplies several useful environment variables to | ||
| 60 | .IR command . | ||
| 61 | .B WARNING: | ||
| 62 | These environment variables are not quoted. | ||
| 63 | They may contain special characters. | ||
| 64 | They are under the control of a possibly malicious remote user. | ||
| 65 | |||
| 66 | .B SENDER | ||
| 67 | is the envelope sender address. | ||
| 68 | .B NEWSENDER | ||
| 69 | is the forwarding envelope sender address, | ||
| 70 | as described in | ||
| 71 | .BR dot-qmail(5) . | ||
| 72 | .B RECIPIENT | ||
| 73 | is the envelope recipient address, | ||
| 74 | .IR local@domain . | ||
| 75 | .B USER | ||
| 76 | is | ||
| 77 | .IR user . | ||
| 78 | .B HOME | ||
| 79 | is your home directory, | ||
| 80 | .IR homedir . | ||
| 81 | .B HOST | ||
| 82 | is the | ||
| 83 | .I domain | ||
| 84 | part of the recipient address. | ||
| 85 | .B LOCAL | ||
| 86 | is the | ||
| 87 | .I local | ||
| 88 | part. | ||
| 89 | .B EXT | ||
| 90 | is the | ||
| 91 | address extension, | ||
| 92 | .IR ext . | ||
| 93 | |||
| 94 | .B HOST2 | ||
| 95 | is the portion of | ||
| 96 | .B HOST | ||
| 97 | preceding the last dot; | ||
| 98 | .B HOST3 | ||
| 99 | is the portion of | ||
| 100 | .B HOST | ||
| 101 | preceding the second-to-last dot; | ||
| 102 | .B HOST4 | ||
| 103 | is the portion of | ||
| 104 | .B HOST | ||
| 105 | preceding the third-to-last dot. | ||
| 106 | |||
| 107 | .B EXT2 | ||
| 108 | is the portion of | ||
| 109 | .B EXT | ||
| 110 | following the first dash; | ||
| 111 | .B EXT3 | ||
| 112 | is the portion | ||
| 113 | following the second dash; | ||
| 114 | .B EXT4 | ||
| 115 | is the portion | ||
| 116 | following the third dash. | ||
| 117 | .B DEFAULT | ||
| 118 | is the portion | ||
| 119 | corresponding to the | ||
| 120 | .B default | ||
| 121 | part of the | ||
| 122 | .BR .qmail\- ... | ||
| 123 | file name; | ||
| 124 | .B DEFAULT | ||
| 125 | is not set if | ||
| 126 | the file name does not end with | ||
| 127 | .BR default . | ||
| 128 | |||
| 129 | .B DTLINE | ||
| 130 | and | ||
| 131 | .B RPLINE | ||
| 132 | are the usual | ||
| 133 | .B Delivered-To | ||
| 134 | and | ||
| 135 | .B Return-Path | ||
| 136 | lines, | ||
| 137 | including newlines. | ||
| 138 | .B UFLINE | ||
| 139 | is the UUCP-style | ||
| 140 | .B From_ | ||
| 141 | line that | ||
| 142 | .B qmail-local | ||
| 143 | adds to | ||
| 144 | .IR mbox -format | ||
| 145 | files. | ||
| 146 | .SH "SEE ALSO" | ||
| 147 | dot-qmail(5), | ||
| 148 | envelopes(5), | ||
| 149 | qmail-local(8) | ||
diff --git a/qmail-control.9 b/qmail-control.9 new file mode 100644 index 0000000..503ce93 --- /dev/null +++ b/qmail-control.9 | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | .TH qmail-control 5 | ||
| 2 | .SH "NAME" | ||
| 3 | qmail-control \- qmail configuration files | ||
| 4 | .SH "INTRODUCTION" | ||
| 5 | You can change the behavior of the | ||
| 6 | .B qmail | ||
| 7 | system by modifying | ||
| 8 | .BR qmail 's | ||
| 9 | .I control files | ||
| 10 | in | ||
| 11 | .BR QMAILHOME/control . | ||
| 12 | |||
| 13 | .B qmail | ||
| 14 | can survive with just one control file, | ||
| 15 | .IR me , | ||
| 16 | containing the | ||
| 17 | fully-qualified name of the current host. | ||
| 18 | This file is used as the default for | ||
| 19 | other hostname-related control files. | ||
| 20 | |||
| 21 | Comments are allowed | ||
| 22 | in | ||
| 23 | .IR badmailfrom , | ||
| 24 | .IR locals , | ||
| 25 | .IR percenthack , | ||
| 26 | .IR qmqpservers , | ||
| 27 | .IR rcpthosts , | ||
| 28 | .IR smtproutes , | ||
| 29 | and | ||
| 30 | .IR virtualdomains . | ||
| 31 | Trailing spaces and tabs are allowed in any control file. | ||
| 32 | |||
| 33 | The following table lists all control files | ||
| 34 | other than | ||
| 35 | .IR me . | ||
| 36 | See the corresponding man pages for further details. | ||
| 37 | |||
| 38 | .RS | ||
| 39 | .nf | ||
| 40 | .ta 5c 10c | ||
| 41 | control default used by | ||
| 42 | |||
| 43 | .I badmailfrom \fR(none) \fRqmail-smtpd | ||
| 44 | .I bouncefrom \fRMAILER-DAEMON \fRqmail-send | ||
| 45 | .I bouncehost \fIme \fRqmail-send | ||
| 46 | .I concurrencylocal \fR10 \fRqmail-send | ||
| 47 | .I concurrencyremote \fR20 \fRqmail-send | ||
| 48 | .I defaultdomain \fIme \fRqmail-inject | ||
| 49 | .I defaulthost \fIme \fRqmail-inject | ||
| 50 | .I databytes \fR0 \fRqmail-smtpd | ||
| 51 | .I doublebouncehost \fIme \fRqmail-send | ||
| 52 | .I doublebounceto \fRpostmaster \fRqmail-send | ||
| 53 | .I envnoathost \fIme \fRqmail-send | ||
| 54 | .I helohost \fIme \fRqmail-remote | ||
| 55 | .I idhost \fIme \fRqmail-inject | ||
| 56 | .I localiphost \fIme \fRqmail-smtpd | ||
| 57 | .I locals \fIme \fRqmail-send | ||
| 58 | .I morercpthosts \fR(none) \fRqmail-smtpd | ||
| 59 | .I percenthack \fR(none) \fRqmail-send | ||
| 60 | .I plusdomain \fIme \fRqmail-inject | ||
| 61 | .I qmqpservers \fR(none) \fRqmail-qmqpc | ||
| 62 | .I queuelifetime \fR604800 \fRqmail-send | ||
| 63 | .I rcpthosts \fR(none) \fRqmail-smtpd | ||
| 64 | .I smtpgreeting \fIme \fRqmail-smtpd | ||
| 65 | .I smtproutes \fR(none) \fRqmail-remote | ||
| 66 | .I timeoutconnect \fR60 \fRqmail-remote | ||
| 67 | .I timeoutremote \fR1200 \fRqmail-remote | ||
| 68 | .I timeoutsmtpd \fR1200 \fRqmail-smtpd | ||
| 69 | .I virtualdomains \fR(none) \fRqmail-send | ||
| 70 | .fi | ||
| 71 | .RE | ||
| 72 | .SH "SEE ALSO" | ||
| 73 | qmail-inject(8), | ||
| 74 | qmail-qmqpc(8), | ||
| 75 | qmail-remote(8), | ||
| 76 | qmail-send(8), | ||
| 77 | qmail-showctl(8), | ||
| 78 | qmail-smtpd(8) | ||
diff --git a/qmail-getpw.9 b/qmail-getpw.9 new file mode 100644 index 0000000..0f12e1c --- /dev/null +++ b/qmail-getpw.9 | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | .TH qmail-getpw 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-getpw \- give addresses to users | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-getpw | ||
| 6 | .I local | ||
| 7 | .SH DESCRIPTION | ||
| 8 | In | ||
| 9 | .BR qmail , | ||
| 10 | each user controls a vast array of local addresses. | ||
| 11 | .B qmail-getpw | ||
| 12 | finds the user that controls a particular address, | ||
| 13 | .IR local . | ||
| 14 | It prints six pieces of information, | ||
| 15 | each terminated by NUL: | ||
| 16 | .IR user ; | ||
| 17 | .IR uid ; | ||
| 18 | .IR gid ; | ||
| 19 | .IR homedir ; | ||
| 20 | .IR dash ; | ||
| 21 | and | ||
| 22 | .IR ext . | ||
| 23 | The user's account name is | ||
| 24 | .IR user ; | ||
| 25 | the user's uid and gid in decimal are | ||
| 26 | .I uid | ||
| 27 | and | ||
| 28 | .IR gid ; | ||
| 29 | the user's home directory is | ||
| 30 | .IR homedir ; | ||
| 31 | and messages to | ||
| 32 | .I local | ||
| 33 | will be handled by | ||
| 34 | .IR homedir\fB/.qmail\fIdashext . | ||
| 35 | |||
| 36 | In case of trouble, | ||
| 37 | .B qmail-getpw | ||
| 38 | exits nonzero without printing anything. | ||
| 39 | |||
| 40 | .B WARNING: | ||
| 41 | The operating system's | ||
| 42 | .B getpwnam | ||
| 43 | function, which is at the heart of | ||
| 44 | .BR qmail-getpw , | ||
| 45 | is inherently unreliable: | ||
| 46 | it fails to distinguish between temporary errors and nonexistent users. | ||
| 47 | Future versions of | ||
| 48 | .B getpwnam | ||
| 49 | should return ETXTBSY to indicate temporary errors | ||
| 50 | and ESRCH to indicate nonexistent users. | ||
| 51 | .SH "RULES" | ||
| 52 | .B qmail-getpw | ||
| 53 | considers an account in | ||
| 54 | .B /etc/passwd | ||
| 55 | to be a user if | ||
| 56 | (1) the account has a nonzero uid, | ||
| 57 | (2) the account's home directory exists (and is visible to | ||
| 58 | .BR qmail-getpw ), | ||
| 59 | and | ||
| 60 | (3) the account owns its home directory. | ||
| 61 | .B qmail-getpw | ||
| 62 | ignores account names containing uppercase letters. | ||
| 63 | .B qmail-getpw | ||
| 64 | also assumes that all account names are shorter than 32 characters. | ||
| 65 | |||
| 66 | .B qmail-getpw | ||
| 67 | gives each user | ||
| 68 | control over the basic | ||
| 69 | .I user | ||
| 70 | address and | ||
| 71 | all addresses of the form | ||
| 72 | .IR user\fBBREAK\fIanything . | ||
| 73 | When | ||
| 74 | .I local | ||
| 75 | is | ||
| 76 | .IR user , | ||
| 77 | .I dash | ||
| 78 | and | ||
| 79 | .I ext | ||
| 80 | are both empty. | ||
| 81 | When | ||
| 82 | .I local | ||
| 83 | is | ||
| 84 | .IR user\fBBREAK\fIanything , | ||
| 85 | .I dash | ||
| 86 | is a hyphen and | ||
| 87 | .I ext | ||
| 88 | is | ||
| 89 | .IR anything . | ||
| 90 | .I user | ||
| 91 | may appear in any combination of uppercase and lowercase letters | ||
| 92 | at the front of | ||
| 93 | .IR local . | ||
| 94 | |||
| 95 | A catch-all user, | ||
| 96 | .BR alias , | ||
| 97 | controls all other addresses. | ||
| 98 | In this case | ||
| 99 | .I ext | ||
| 100 | is | ||
| 101 | .I local | ||
| 102 | and | ||
| 103 | .I dash | ||
| 104 | is a hyphen. | ||
| 105 | |||
| 106 | You can override all of | ||
| 107 | .BR qmail-getpw 's | ||
| 108 | decisions with the | ||
| 109 | .B qmail-users | ||
| 110 | mechanism, which is reliable, highly configurable, and much faster than | ||
| 111 | .BR qmail-getpw . | ||
| 112 | .SH "SEE ALSO" | ||
| 113 | qmail-users(5), | ||
| 114 | qmail-lspawn(8) | ||
diff --git a/qmail-getpw.c b/qmail-getpw.c new file mode 100644 index 0000000..128c682 --- /dev/null +++ b/qmail-getpw.c | |||
| @@ -0,0 +1,88 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include <pwd.h> | ||
| 4 | #include "readwrite.h" | ||
| 5 | #include "substdio.h" | ||
| 6 | #include "subfd.h" | ||
| 7 | #include "error.h" | ||
| 8 | #include "exit.h" | ||
| 9 | #include "byte.h" | ||
| 10 | #include "str.h" | ||
| 11 | #include "case.h" | ||
| 12 | #include "fmt.h" | ||
| 13 | #include "auto_usera.h" | ||
| 14 | #include "auto_break.h" | ||
| 15 | #include "qlx.h" | ||
| 16 | |||
| 17 | #define GETPW_USERLEN 32 | ||
| 18 | |||
| 19 | char *local; | ||
| 20 | struct passwd *pw; | ||
| 21 | char *dash; | ||
| 22 | char *extension; | ||
| 23 | |||
| 24 | int userext() | ||
| 25 | { | ||
| 26 | char username[GETPW_USERLEN]; | ||
| 27 | struct stat st; | ||
| 28 | |||
| 29 | extension = local + str_len(local); | ||
| 30 | for (;;) { | ||
| 31 | if (extension - local < sizeof(username)) | ||
| 32 | if (!*extension || (*extension == *auto_break)) { | ||
| 33 | byte_copy(username,extension - local,local); | ||
| 34 | username[extension - local] = 0; | ||
| 35 | case_lowers(username); | ||
| 36 | errno = 0; | ||
| 37 | pw = getpwnam(username); | ||
| 38 | if (errno == error_txtbsy) _exit(QLX_SYS); | ||
| 39 | if (pw) | ||
| 40 | if (pw->pw_uid) | ||
| 41 | if (stat(pw->pw_dir,&st) == 0) { | ||
| 42 | if (st.st_uid == pw->pw_uid) { | ||
| 43 | dash = ""; | ||
| 44 | if (*extension) { ++extension; dash = "-"; } | ||
| 45 | return 1; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | else | ||
| 49 | if (error_temp(errno)) _exit(QLX_NFS); | ||
| 50 | } | ||
| 51 | if (extension == local) return 0; | ||
| 52 | --extension; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | char num[FMT_ULONG]; | ||
| 57 | |||
| 58 | void main(argc,argv) | ||
| 59 | int argc; | ||
| 60 | char **argv; | ||
| 61 | { | ||
| 62 | local = argv[1]; | ||
| 63 | if (!local) _exit(100); | ||
| 64 | |||
| 65 | if (!userext()) { | ||
| 66 | extension = local; | ||
| 67 | dash = "-"; | ||
| 68 | pw = getpwnam(auto_usera); | ||
| 69 | } | ||
| 70 | |||
| 71 | if (!pw) _exit(QLX_NOALIAS); | ||
| 72 | |||
| 73 | substdio_puts(subfdoutsmall,pw->pw_name); | ||
| 74 | substdio_put(subfdoutsmall,"",1); | ||
| 75 | substdio_put(subfdoutsmall,num,fmt_ulong(num,(long) pw->pw_uid)); | ||
| 76 | substdio_put(subfdoutsmall,"",1); | ||
| 77 | substdio_put(subfdoutsmall,num,fmt_ulong(num,(long) pw->pw_gid)); | ||
| 78 | substdio_put(subfdoutsmall,"",1); | ||
| 79 | substdio_puts(subfdoutsmall,pw->pw_dir); | ||
| 80 | substdio_put(subfdoutsmall,"",1); | ||
| 81 | substdio_puts(subfdoutsmall,dash); | ||
| 82 | substdio_put(subfdoutsmall,"",1); | ||
| 83 | substdio_puts(subfdoutsmall,extension); | ||
| 84 | substdio_put(subfdoutsmall,"",1); | ||
| 85 | substdio_flush(subfdoutsmall); | ||
| 86 | |||
| 87 | _exit(0); | ||
| 88 | } | ||
diff --git a/qmail-header.5 b/qmail-header.5 new file mode 100644 index 0000000..d90323a --- /dev/null +++ b/qmail-header.5 | |||
| @@ -0,0 +1,332 @@ | |||
| 1 | .TH qmail-header 5 | ||
| 2 | .SH NAME | ||
| 3 | qmail-header \- format of a mail message | ||
| 4 | .SH OVERVIEW | ||
| 5 | At the top of every mail message is a | ||
| 6 | highly structured | ||
| 7 | .BR header . | ||
| 8 | Many programs expect the header to carry certain information, | ||
| 9 | as described below. | ||
| 10 | The main function of | ||
| 11 | .B qmail-inject | ||
| 12 | is to make sure that each outgoing message has an appropriate header. | ||
| 13 | |||
| 14 | For more detailed information, see | ||
| 15 | .BR http://pobox.com/~djb/proto/immhf.html . | ||
| 16 | .SH "MESSAGE STRUCTURE" | ||
| 17 | A message contains a series of | ||
| 18 | .I header fields\fR, | ||
| 19 | a blank line, | ||
| 20 | and a | ||
| 21 | .IR body : | ||
| 22 | |||
| 23 | .EX | ||
| 24 | Received: (qmail-queue invoked by uid 666); | ||
| 25 | .br | ||
| 26 | 30 Jul 1996 11:54:54 -0000 | ||
| 27 | .br | ||
| 28 | From: djb@silverton.berkeley.edu (D. J. Bernstein) | ||
| 29 | .br | ||
| 30 | To: fred@silverton.berkeley.edu | ||
| 31 | .br | ||
| 32 | Date: 30 Jul 1996 11:54:54 -0000 | ||
| 33 | .br | ||
| 34 | Subject: Go, Bears! | ||
| 35 | .br | ||
| 36 | |||
| 37 | .br | ||
| 38 | I've got money on this one. How about you? | ||
| 39 | .br | ||
| 40 | |||
| 41 | .br | ||
| 42 | ---Dan (this is the third line of the body) | ||
| 43 | .EE | ||
| 44 | |||
| 45 | Each header field has a | ||
| 46 | .IR name , | ||
| 47 | a colon, | ||
| 48 | some | ||
| 49 | .IR contents , | ||
| 50 | and a newline: | ||
| 51 | |||
| 52 | .EX | ||
| 53 | Subject: Go, Bears! | ||
| 54 | .EE | ||
| 55 | |||
| 56 | The field contents may be folded across several lines. | ||
| 57 | Each line past the first must begin with a space or tab: | ||
| 58 | |||
| 59 | .EX | ||
| 60 | Received: (qmail-queue invoked by uid 666); | ||
| 61 | .br | ||
| 62 | 30 Jul 1996 11:54:54 -0000 | ||
| 63 | .EE | ||
| 64 | |||
| 65 | The field name must not contain spaces, tabs, or colons. | ||
| 66 | Also, an empty field name is illegal. | ||
| 67 | .B qmail-inject | ||
| 68 | does not allow field names with unprintable characters. | ||
| 69 | |||
| 70 | Case is irrelevant in field names: | ||
| 71 | .B subject | ||
| 72 | and | ||
| 73 | .B SUBJECT | ||
| 74 | and | ||
| 75 | .B SuBjEcT | ||
| 76 | have the same meaning. | ||
| 77 | .SH "ADDRESS LISTS" | ||
| 78 | Certain fields, such as | ||
| 79 | .BR To , | ||
| 80 | contain | ||
| 81 | .I address lists\fR. | ||
| 82 | |||
| 83 | An address list contains some number of | ||
| 84 | .I addresses | ||
| 85 | or | ||
| 86 | .I address groups\fR, | ||
| 87 | separated by commas: | ||
| 88 | |||
| 89 | .EX | ||
| 90 | a@b, c@d (Somebody), A Person <e@f>, | ||
| 91 | .br | ||
| 92 | random group: g@h, i@j;, k@l | ||
| 93 | .EE | ||
| 94 | |||
| 95 | An | ||
| 96 | .I address group | ||
| 97 | has some text, a colon, a list of addresses, | ||
| 98 | and a semicolon: | ||
| 99 | |||
| 100 | .EX | ||
| 101 | random group: g@h, i@j; | ||
| 102 | .EE | ||
| 103 | |||
| 104 | An address can appear in several forms. | ||
| 105 | The most common form is | ||
| 106 | .IR box@host . | ||
| 107 | |||
| 108 | Every address must include a host name. | ||
| 109 | If | ||
| 110 | .B qmail-inject | ||
| 111 | sees a lone box name | ||
| 112 | it adds the | ||
| 113 | .I default host name\fR. | ||
| 114 | |||
| 115 | All host names should be fully qualified. | ||
| 116 | .B qmail-inject | ||
| 117 | appends the | ||
| 118 | .I default domain name | ||
| 119 | to any name without dots: | ||
| 120 | |||
| 121 | .EX | ||
| 122 | djb@silverton -> djb@silverton.berkeley.edu | ||
| 123 | .EE | ||
| 124 | |||
| 125 | It appends the | ||
| 126 | .I plus domain name | ||
| 127 | to any name | ||
| 128 | that ends with a plus sign: | ||
| 129 | |||
| 130 | .EX | ||
| 131 | eric@mammoth.cs+ -> eric@mammoth.cs.berkeley.edu | ||
| 132 | .EE | ||
| 133 | |||
| 134 | A host name may be a dotted-decimal address: | ||
| 135 | |||
| 136 | .EX | ||
| 137 | djb@[128.32.183.163] | ||
| 138 | .EE | ||
| 139 | |||
| 140 | RFC 822 allows mailbox names inside angle brackets | ||
| 141 | to include | ||
| 142 | .I source routes\fR, | ||
| 143 | but | ||
| 144 | .B qmail-inject | ||
| 145 | strips all source routes out of addresses. | ||
| 146 | .SH "SENDER ADDRESSES" | ||
| 147 | .B qmail-inject | ||
| 148 | looks for sender address lists in the following fields: | ||
| 149 | .BR Sender , | ||
| 150 | .BR From , | ||
| 151 | .BR Reply-To , | ||
| 152 | .BR Return-Path , | ||
| 153 | .BR Return-Receipt-To , | ||
| 154 | .BR Errors-To , | ||
| 155 | .BR Resent-Sender , | ||
| 156 | .BR Resent-From , | ||
| 157 | .BR Resent-Reply-To . | ||
| 158 | |||
| 159 | If there is no | ||
| 160 | .B From | ||
| 161 | field, | ||
| 162 | .B qmail-inject | ||
| 163 | adds a new | ||
| 164 | .B From | ||
| 165 | field with the name of the user invoking | ||
| 166 | .B qmail-inject. | ||
| 167 | |||
| 168 | RFC 822 requires that certain sender fields contain | ||
| 169 | only a single address, but | ||
| 170 | .B qmail-inject | ||
| 171 | does not enforce this restriction. | ||
| 172 | .SH "RECIPIENT ADDRESSES" | ||
| 173 | .B qmail-inject | ||
| 174 | looks for recipient address lists in the following fields: | ||
| 175 | .BR To , | ||
| 176 | .BR Cc , | ||
| 177 | .BR Bcc , | ||
| 178 | .BR Apparently-To , | ||
| 179 | .BR Resent-To , | ||
| 180 | .BR Resent-Cc , | ||
| 181 | .BR Resent-Bcc . | ||
| 182 | |||
| 183 | Every message must contain at least one | ||
| 184 | .B To | ||
| 185 | or | ||
| 186 | .B Cc | ||
| 187 | or | ||
| 188 | .BR Bcc . | ||
| 189 | .B qmail-inject | ||
| 190 | deletes any | ||
| 191 | .B Bcc | ||
| 192 | field. | ||
| 193 | If there is no | ||
| 194 | .B To | ||
| 195 | or | ||
| 196 | .B Cc | ||
| 197 | field, | ||
| 198 | .B qmail-inject | ||
| 199 | adds a line | ||
| 200 | |||
| 201 | .EX | ||
| 202 | Cc: recipient list not shown: ; | ||
| 203 | .EE | ||
| 204 | |||
| 205 | This complies with RFC 822; | ||
| 206 | it also works around some strange | ||
| 207 | .B sendmail | ||
| 208 | behavior, in case the message is passed through | ||
| 209 | .B sendmail | ||
| 210 | on another machine. | ||
| 211 | .SH STAMPS | ||
| 212 | Every message must contain a | ||
| 213 | .B Date | ||
| 214 | field, with the date in a strict format defined by RFC 822. | ||
| 215 | If necessary | ||
| 216 | .B qmail-inject | ||
| 217 | creates a new | ||
| 218 | .B Date | ||
| 219 | field with the current date (in GMT). | ||
| 220 | |||
| 221 | Every message should contain a | ||
| 222 | .B Message-Id | ||
| 223 | field. | ||
| 224 | The field contents are a unique worldwide identifier for this message. | ||
| 225 | If necessary | ||
| 226 | .B qmail-inject | ||
| 227 | creates a new | ||
| 228 | .B Message-Id | ||
| 229 | field. | ||
| 230 | |||
| 231 | Another important field is | ||
| 232 | .BR Received . | ||
| 233 | Every time the message is sent from one system to another, | ||
| 234 | a new | ||
| 235 | .B Received | ||
| 236 | field is added to the top of the message. | ||
| 237 | .B qmail-inject | ||
| 238 | does not create any | ||
| 239 | .B Received | ||
| 240 | fields. | ||
| 241 | .SH "RESENT MESSAGES" | ||
| 242 | A message is | ||
| 243 | .I resent | ||
| 244 | if it contains any of the following fields: | ||
| 245 | .BR Resent-Sender , | ||
| 246 | .BR Resent-From , | ||
| 247 | .BR Resent-Reply-To , | ||
| 248 | .BR Resent-To , | ||
| 249 | .BR Resent-Cc , | ||
| 250 | .BR Resent-Bcc , | ||
| 251 | .BR Resent-Date , | ||
| 252 | .BR Resent-Message-ID . | ||
| 253 | |||
| 254 | If a message is resent, | ||
| 255 | .B qmail-inject | ||
| 256 | changes its behavior as follows. | ||
| 257 | |||
| 258 | It deletes any | ||
| 259 | .B Resent-Bcc | ||
| 260 | field (as well as any | ||
| 261 | .B Bcc | ||
| 262 | field); | ||
| 263 | if there are no | ||
| 264 | .B Resent-To | ||
| 265 | or | ||
| 266 | .B Resent-Cc | ||
| 267 | fields, | ||
| 268 | .B qmail-inject | ||
| 269 | adds an appropriate | ||
| 270 | .B Resent-Cc | ||
| 271 | line. | ||
| 272 | It does | ||
| 273 | .I not | ||
| 274 | add a | ||
| 275 | .B Cc | ||
| 276 | line, | ||
| 277 | even if neither | ||
| 278 | .B To | ||
| 279 | nor | ||
| 280 | .B Cc | ||
| 281 | is present. | ||
| 282 | |||
| 283 | If there is no | ||
| 284 | .B Resent-From | ||
| 285 | field, | ||
| 286 | .B qmail-inject | ||
| 287 | adds a new | ||
| 288 | .B Resent-From | ||
| 289 | field. | ||
| 290 | It does | ||
| 291 | .I not | ||
| 292 | add a new | ||
| 293 | .B From | ||
| 294 | field. | ||
| 295 | |||
| 296 | .B qmail-inject | ||
| 297 | adds | ||
| 298 | .B Resent-Date | ||
| 299 | if one is not already present; | ||
| 300 | same for | ||
| 301 | .BR Resent-Message-Id . | ||
| 302 | It does | ||
| 303 | .I not | ||
| 304 | add new | ||
| 305 | .B Date | ||
| 306 | or | ||
| 307 | .B Message-Id | ||
| 308 | fields. | ||
| 309 | .SH "OTHER FEATURES" | ||
| 310 | Addresses are separated by commas, not spaces. | ||
| 311 | When | ||
| 312 | .B qmail-inject | ||
| 313 | sees an illegal space, | ||
| 314 | it inserts a comma: | ||
| 315 | |||
| 316 | .EX | ||
| 317 | djb fred -> djb, fred | ||
| 318 | .EE | ||
| 319 | |||
| 320 | .B qmail-inject | ||
| 321 | removes all | ||
| 322 | .B Return-Path | ||
| 323 | header fields. | ||
| 324 | |||
| 325 | .B qmail-inject | ||
| 326 | also removes any | ||
| 327 | .B Content-Length | ||
| 328 | fields. | ||
| 329 | .SH "SEE ALSO" | ||
| 330 | addresses(5), | ||
| 331 | envelopes(5), | ||
| 332 | qmail-inject(8) | ||
diff --git a/qmail-inject.8 b/qmail-inject.8 new file mode 100644 index 0000000..59e11a7 --- /dev/null +++ b/qmail-inject.8 | |||
| @@ -0,0 +1,309 @@ | |||
| 1 | .TH qmail-inject 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-inject \- preprocess and send a mail message | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-inject | ||
| 6 | [ | ||
| 7 | .B \-nNaAhH | ||
| 8 | ] [ | ||
| 9 | .B \-f\fIsender | ||
| 10 | ] [ | ||
| 11 | .I recip ... | ||
| 12 | ] | ||
| 13 | .SH DESCRIPTION | ||
| 14 | .B qmail-inject | ||
| 15 | reads a mail message from its standard input, | ||
| 16 | adds appropriate information to the message header, | ||
| 17 | and invokes | ||
| 18 | .B qmail-queue | ||
| 19 | to send the message | ||
| 20 | to one or more recipients. | ||
| 21 | |||
| 22 | See | ||
| 23 | .B qmail-header(5) | ||
| 24 | for information on how | ||
| 25 | .B qmail-inject | ||
| 26 | rewrites header fields. | ||
| 27 | |||
| 28 | .B qmail-inject | ||
| 29 | normally exits 0. | ||
| 30 | It exits 100 if it was invoked improperly | ||
| 31 | or if there is a severe syntax error in the message. | ||
| 32 | It exits 111 for temporary errors. | ||
| 33 | .SH "ENVIRONMENT VARIABLES" | ||
| 34 | For the convenience of users who do not run | ||
| 35 | .B qmail-inject | ||
| 36 | directly, | ||
| 37 | .B qmail-inject | ||
| 38 | takes many options through environment variables. | ||
| 39 | |||
| 40 | The user name in the | ||
| 41 | .B From | ||
| 42 | header field is set by | ||
| 43 | .BR QMAILUSER , | ||
| 44 | .BR MAILUSER , | ||
| 45 | .BR USER , | ||
| 46 | or | ||
| 47 | .BR LOGNAME , | ||
| 48 | whichever comes first. | ||
| 49 | |||
| 50 | The host name is normally set by the | ||
| 51 | .I defaulthost | ||
| 52 | control | ||
| 53 | but can be overridden with | ||
| 54 | .B QMAILHOST | ||
| 55 | or | ||
| 56 | .BR MAILHOST . | ||
| 57 | |||
| 58 | The personal name is | ||
| 59 | .BR QMAILNAME , | ||
| 60 | .BR MAILNAME , | ||
| 61 | or | ||
| 62 | .BR NAME . | ||
| 63 | |||
| 64 | The default envelope sender address is the same as the | ||
| 65 | default | ||
| 66 | .B From | ||
| 67 | address, | ||
| 68 | but it can be overridden with | ||
| 69 | .B QMAILSUSER | ||
| 70 | and | ||
| 71 | .BR QMAILSHOST . | ||
| 72 | It may also be modified by the | ||
| 73 | .B r | ||
| 74 | and | ||
| 75 | .B m | ||
| 76 | letters described below. | ||
| 77 | Bounces will be sent to this address. | ||
| 78 | |||
| 79 | If | ||
| 80 | .B QMAILMFTFILE | ||
| 81 | is set, | ||
| 82 | .B qmail-inject | ||
| 83 | reads a list of mailing list addresses, | ||
| 84 | one per line, | ||
| 85 | from that file. | ||
| 86 | If To+Cc includes one of those addresses (without regard to case), | ||
| 87 | .B qmail-inject | ||
| 88 | adds a Mail-Followup-To field | ||
| 89 | with all the To+Cc addresses. | ||
| 90 | .B qmail-inject | ||
| 91 | does not add Mail-Followup-To | ||
| 92 | to a message that already has one. | ||
| 93 | |||
| 94 | The | ||
| 95 | .B QMAILINJECT | ||
| 96 | environment variable | ||
| 97 | can contain any of the following letters: | ||
| 98 | .TP | ||
| 99 | .B c | ||
| 100 | Use address-comment style for the | ||
| 101 | .B From | ||
| 102 | field. | ||
| 103 | Normally | ||
| 104 | .B qmail-inject | ||
| 105 | uses name-address style. | ||
| 106 | .TP | ||
| 107 | .B s | ||
| 108 | Do not look at any incoming | ||
| 109 | .B Return-Path | ||
| 110 | field. | ||
| 111 | Normally, if | ||
| 112 | .B Return-Path | ||
| 113 | is supplied, it sets the envelope sender address, | ||
| 114 | overriding all environment variables. | ||
| 115 | .B Return-Path | ||
| 116 | is deleted in any case. | ||
| 117 | .TP | ||
| 118 | .B f | ||
| 119 | Delete any incoming | ||
| 120 | .B From | ||
| 121 | field. | ||
| 122 | Normally, if | ||
| 123 | .B From | ||
| 124 | is supplied, it overrides the usual | ||
| 125 | .B From | ||
| 126 | field created by | ||
| 127 | .BR qmail-inject . | ||
| 128 | .TP | ||
| 129 | .B i | ||
| 130 | Delete any incoming | ||
| 131 | .B Message-ID | ||
| 132 | field. | ||
| 133 | Normally, if | ||
| 134 | .B Message-ID | ||
| 135 | is supplied, it overrides the usual | ||
| 136 | .B Message-ID | ||
| 137 | field created by | ||
| 138 | .BR qmail-inject . | ||
| 139 | .TP | ||
| 140 | .B r | ||
| 141 | Use a per-recipient VERP. | ||
| 142 | .B qmail-inject | ||
| 143 | will append each recipient address to the envelope sender | ||
| 144 | of the copy going to that recipient. | ||
| 145 | .TP | ||
| 146 | .B m | ||
| 147 | Use a per-message VERP. | ||
| 148 | .B qmail-inject | ||
| 149 | will append the current date and process ID to the envelope sender. | ||
| 150 | .SH OPTIONS | ||
| 151 | .TP | ||
| 152 | .B \-a | ||
| 153 | Send the message to all addresses given as | ||
| 154 | .I recip | ||
| 155 | arguments; | ||
| 156 | do not use header recipient addresses. | ||
| 157 | .TP | ||
| 158 | .B \-h | ||
| 159 | Send the message to all header recipient addresses. | ||
| 160 | For non-forwarded messages, this means | ||
| 161 | the addresses listed under | ||
| 162 | .BR To , | ||
| 163 | .BR Cc , | ||
| 164 | .BR Bcc , | ||
| 165 | .BR Apparently-To . | ||
| 166 | For forwarded messages, this means | ||
| 167 | the addresses listed under | ||
| 168 | .BR Resent-To , | ||
| 169 | .BR Resent-Cc , | ||
| 170 | .BR Resent-Bcc . | ||
| 171 | Do not use any | ||
| 172 | .I recip | ||
| 173 | arguments. | ||
| 174 | .TP | ||
| 175 | .B \-A | ||
| 176 | (Default.) | ||
| 177 | Send the message to all addresses given as | ||
| 178 | .I recip | ||
| 179 | arguments. | ||
| 180 | If no | ||
| 181 | .I recip | ||
| 182 | arguments are supplied, | ||
| 183 | send the message to all header recipient addresses. | ||
| 184 | .TP | ||
| 185 | .B \-H | ||
| 186 | Send the message to all header recipient addresses, | ||
| 187 | and to all addresses given as | ||
| 188 | .I recip | ||
| 189 | arguments. | ||
| 190 | .TP | ||
| 191 | .B \-f\fIsender | ||
| 192 | Pass | ||
| 193 | .I sender | ||
| 194 | to | ||
| 195 | .B qmail-queue | ||
| 196 | as the envelope sender address. | ||
| 197 | This overrides | ||
| 198 | .B Return-Path | ||
| 199 | and all environment variables. | ||
| 200 | .TP | ||
| 201 | .B \-N | ||
| 202 | (Default.) | ||
| 203 | Feed the resulting message to | ||
| 204 | .BR qmail-queue . | ||
| 205 | .TP | ||
| 206 | .B \-n | ||
| 207 | Print the message rather than feeding it to | ||
| 208 | .BR qmail-queue . | ||
| 209 | .SH "CONTROL FILES" | ||
| 210 | .TP 5 | ||
| 211 | .I defaultdomain | ||
| 212 | Default domain name. | ||
| 213 | Default: | ||
| 214 | .IR me , | ||
| 215 | if that is supplied; | ||
| 216 | otherwise the literal name | ||
| 217 | .BR defaultdomain , | ||
| 218 | which is probably not what you want. | ||
| 219 | .B qmail-inject | ||
| 220 | adds this name to any host name without dots, | ||
| 221 | including | ||
| 222 | .I defaulthost | ||
| 223 | if | ||
| 224 | .I defaulthost | ||
| 225 | does not have dots. | ||
| 226 | (Exception: see | ||
| 227 | .IR plusdomain .) | ||
| 228 | |||
| 229 | The | ||
| 230 | .B QMAILDEFAULTDOMAIN | ||
| 231 | environment variable | ||
| 232 | overrides | ||
| 233 | .IR defaultdomain . | ||
| 234 | .TP 5 | ||
| 235 | .I defaulthost | ||
| 236 | Default host name. | ||
| 237 | Default: | ||
| 238 | .IR me , | ||
| 239 | if that is supplied; | ||
| 240 | otherwise the literal name | ||
| 241 | .BR defaulthost , | ||
| 242 | which is probably not what you want. | ||
| 243 | .B qmail-inject | ||
| 244 | adds this name to any address without a host name. | ||
| 245 | .I defaulthost | ||
| 246 | need not be the current host's name. | ||
| 247 | For example, | ||
| 248 | you may prefer that outgoing mail show | ||
| 249 | just your domain name. | ||
| 250 | |||
| 251 | The | ||
| 252 | .B QMAILDEFAULTHOST | ||
| 253 | environment variable overrides | ||
| 254 | .IR defaulthost . | ||
| 255 | .TP 5 | ||
| 256 | .I idhost | ||
| 257 | Host name for Message-IDs. | ||
| 258 | Default: | ||
| 259 | .IR me , | ||
| 260 | if that is supplied; | ||
| 261 | otherwise the literal name | ||
| 262 | .BR idhost , | ||
| 263 | which is certainly not what you want. | ||
| 264 | .I idhost | ||
| 265 | need not be the current host's name. | ||
| 266 | For example, you may prefer to use fake | ||
| 267 | host names in Message-IDs. | ||
| 268 | However, | ||
| 269 | .I idhost | ||
| 270 | must be a fully-qualified name within your domain, | ||
| 271 | and each host in your domain should use a different | ||
| 272 | .IR idhost . | ||
| 273 | |||
| 274 | The | ||
| 275 | .B QMAILIDHOST | ||
| 276 | environment variable overrides | ||
| 277 | .IR idhost . | ||
| 278 | .TP 5 | ||
| 279 | .I plusdomain | ||
| 280 | Plus domain name. | ||
| 281 | Default: | ||
| 282 | .IR me , | ||
| 283 | if that is supplied; | ||
| 284 | otherwise the literal name | ||
| 285 | .BR plusdomain , | ||
| 286 | which is probably not what you want. | ||
| 287 | .B qmail-inject | ||
| 288 | adds this name to any host name that ends with a plus sign, | ||
| 289 | including | ||
| 290 | .I defaulthost | ||
| 291 | if | ||
| 292 | .I defaulthost | ||
| 293 | ends with a plus sign. | ||
| 294 | If a host name does not have dots but ends with a plus sign, | ||
| 295 | .B qmail-inject | ||
| 296 | uses | ||
| 297 | .IR plusdomain , | ||
| 298 | not | ||
| 299 | .IR defaultdomain . | ||
| 300 | |||
| 301 | The | ||
| 302 | .B QMAILPLUSDOMAIN | ||
| 303 | environment variable overrides | ||
| 304 | .IR plusdomain . | ||
| 305 | .SH "SEE ALSO" | ||
| 306 | addresses(5), | ||
| 307 | qmail-control(5), | ||
| 308 | qmail-header(5), | ||
| 309 | qmail-queue(8) | ||
diff --git a/qmail-inject.c b/qmail-inject.c new file mode 100644 index 0000000..753c18a --- /dev/null +++ b/qmail-inject.c | |||
| @@ -0,0 +1,773 @@ | |||
| 1 | #include "sig.h" | ||
| 2 | #include "substdio.h" | ||
| 3 | #include "stralloc.h" | ||
| 4 | #include "subfd.h" | ||
| 5 | #include "sgetopt.h" | ||
| 6 | #include "getln.h" | ||
| 7 | #include "alloc.h" | ||
| 8 | #include "str.h" | ||
| 9 | #include "fmt.h" | ||
| 10 | #include "hfield.h" | ||
| 11 | #include "token822.h" | ||
| 12 | #include "control.h" | ||
| 13 | #include "env.h" | ||
| 14 | #include "gen_alloc.h" | ||
| 15 | #include "gen_allocdefs.h" | ||
| 16 | #include "error.h" | ||
| 17 | #include "qmail.h" | ||
| 18 | #include "now.h" | ||
| 19 | #include "exit.h" | ||
| 20 | #include "quote.h" | ||
| 21 | #include "headerbody.h" | ||
| 22 | #include "auto_qmail.h" | ||
| 23 | #include "newfield.h" | ||
| 24 | #include "constmap.h" | ||
| 25 | |||
| 26 | #define LINELEN 80 | ||
| 27 | |||
| 28 | datetime_sec starttime; | ||
| 29 | |||
| 30 | char *qmopts; | ||
| 31 | int flagdeletesender = 0; | ||
| 32 | int flagdeletefrom = 0; | ||
| 33 | int flagdeletemessid = 0; | ||
| 34 | int flagnamecomment = 0; | ||
| 35 | int flaghackmess = 0; | ||
| 36 | int flaghackrecip = 0; | ||
| 37 | char *mailhost; | ||
| 38 | char *mailuser; | ||
| 39 | int mailusertokentype; | ||
| 40 | char *mailrhost; | ||
| 41 | char *mailruser; | ||
| 42 | |||
| 43 | stralloc control_idhost = {0}; | ||
| 44 | stralloc control_defaultdomain = {0}; | ||
| 45 | stralloc control_defaulthost = {0}; | ||
| 46 | stralloc control_plusdomain = {0}; | ||
| 47 | |||
| 48 | stralloc sender = {0}; | ||
| 49 | stralloc envsbuf = {0}; | ||
| 50 | token822_alloc envs = {0}; | ||
| 51 | int flagrh; | ||
| 52 | |||
| 53 | int flagqueue; | ||
| 54 | struct qmail qqt; | ||
| 55 | |||
| 56 | void put(s,len) char *s; int len; | ||
| 57 | { if (flagqueue) qmail_put(&qqt,s,len); else substdio_put(subfdout,s,len); } | ||
| 58 | void puts(s) char *s; { put(s,str_len(s)); } | ||
| 59 | |||
| 60 | void perm() { _exit(100); } | ||
| 61 | void temp() { _exit(111); } | ||
| 62 | void die_nomem() { | ||
| 63 | substdio_putsflush(subfderr,"qmail-inject: fatal: out of memory\n"); temp(); } | ||
| 64 | void die_invalid(sa) stralloc *sa; { | ||
| 65 | substdio_putsflush(subfderr,"qmail-inject: fatal: invalid header field: "); | ||
| 66 | substdio_putflush(subfderr,sa->s,sa->len); perm(); } | ||
| 67 | void die_qqt() { | ||
| 68 | substdio_putsflush(subfderr,"qmail-inject: fatal: unable to run qmail-queue\n"); temp(); } | ||
| 69 | void die_chdir() { | ||
| 70 | substdio_putsflush(subfderr,"qmail-inject: fatal: internal bug\n"); temp(); } | ||
| 71 | void die_read() { | ||
| 72 | if (errno == error_nomem) die_nomem(); | ||
| 73 | substdio_putsflush(subfderr,"qmail-inject: fatal: read error\n"); temp(); } | ||
| 74 | void doordie(sa,r) stralloc *sa; int r; { | ||
| 75 | if (r == 1) return; if (r == -1) die_nomem(); | ||
| 76 | substdio_putsflush(subfderr,"qmail-inject: fatal: unable to parse this line:\n"); | ||
| 77 | substdio_putflush(subfderr,sa->s,sa->len); perm(); } | ||
| 78 | |||
| 79 | GEN_ALLOC_typedef(saa,stralloc,sa,len,a) | ||
| 80 | GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus) | ||
| 81 | |||
| 82 | static stralloc sauninit = {0}; | ||
| 83 | |||
| 84 | saa savedh = {0}; | ||
| 85 | saa hrlist = {0}; | ||
| 86 | saa tocclist = {0}; | ||
| 87 | saa hrrlist = {0}; | ||
| 88 | saa reciplist = {0}; | ||
| 89 | int flagresent; | ||
| 90 | |||
| 91 | void exitnicely() | ||
| 92 | { | ||
| 93 | char *qqx; | ||
| 94 | |||
| 95 | if (!flagqueue) substdio_flush(subfdout); | ||
| 96 | |||
| 97 | if (flagqueue) | ||
| 98 | { | ||
| 99 | int i; | ||
| 100 | |||
| 101 | if (!stralloc_0(&sender)) die_nomem(); | ||
| 102 | qmail_from(&qqt,sender.s); | ||
| 103 | |||
| 104 | for (i = 0;i < reciplist.len;++i) | ||
| 105 | { | ||
| 106 | if (!stralloc_0(&reciplist.sa[i])) die_nomem(); | ||
| 107 | qmail_to(&qqt,reciplist.sa[i].s); | ||
| 108 | } | ||
| 109 | if (flagrh) | ||
| 110 | if (flagresent) | ||
| 111 | for (i = 0;i < hrrlist.len;++i) | ||
| 112 | { | ||
| 113 | if (!stralloc_0(&hrrlist.sa[i])) die_nomem(); | ||
| 114 | qmail_to(&qqt,hrrlist.sa[i].s); | ||
| 115 | } | ||
| 116 | else | ||
| 117 | for (i = 0;i < hrlist.len;++i) | ||
| 118 | { | ||
| 119 | if (!stralloc_0(&hrlist.sa[i])) die_nomem(); | ||
| 120 | qmail_to(&qqt,hrlist.sa[i].s); | ||
| 121 | } | ||
| 122 | |||
| 123 | qqx = qmail_close(&qqt); | ||
| 124 | if (*qqx) | ||
| 125 | if (*qqx == 'D') { | ||
| 126 | substdio_puts(subfderr,"qmail-inject: fatal: "); | ||
| 127 | substdio_puts(subfderr,qqx + 1); | ||
| 128 | substdio_puts(subfderr,"\n"); | ||
| 129 | substdio_flush(subfderr); | ||
| 130 | perm(); | ||
| 131 | } | ||
| 132 | else { | ||
| 133 | substdio_puts(subfderr,"qmail-inject: fatal: "); | ||
| 134 | substdio_puts(subfderr,qqx + 1); | ||
| 135 | substdio_puts(subfderr,"\n"); | ||
| 136 | substdio_flush(subfderr); | ||
| 137 | temp(); | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | _exit(0); | ||
| 142 | } | ||
| 143 | |||
| 144 | void savedh_append(h) | ||
| 145 | stralloc *h; | ||
| 146 | { | ||
| 147 | if (!saa_readyplus(&savedh,1)) die_nomem(); | ||
| 148 | savedh.sa[savedh.len] = sauninit; | ||
| 149 | if (!stralloc_copy(savedh.sa + savedh.len,h)) die_nomem(); | ||
| 150 | ++savedh.len; | ||
| 151 | } | ||
| 152 | |||
| 153 | void savedh_print() | ||
| 154 | { | ||
| 155 | int i; | ||
| 156 | |||
| 157 | for (i = 0;i < savedh.len;++i) | ||
| 158 | put(savedh.sa[i].s,savedh.sa[i].len); | ||
| 159 | } | ||
| 160 | |||
| 161 | stralloc defaultdomainbuf = {0}; | ||
| 162 | token822_alloc defaultdomain = {0}; | ||
| 163 | stralloc defaulthostbuf = {0}; | ||
| 164 | token822_alloc defaulthost = {0}; | ||
| 165 | stralloc plusdomainbuf = {0}; | ||
| 166 | token822_alloc plusdomain = {0}; | ||
| 167 | |||
| 168 | void rwroute(addr) | ||
| 169 | token822_alloc *addr; | ||
| 170 | { | ||
| 171 | if (addr->t[addr->len - 1].type == TOKEN822_AT) | ||
| 172 | while (addr->len) | ||
| 173 | if (addr->t[--addr->len].type == TOKEN822_COLON) | ||
| 174 | return; | ||
| 175 | } | ||
| 176 | |||
| 177 | void rwextraat(addr) | ||
| 178 | token822_alloc *addr; | ||
| 179 | { | ||
| 180 | int i; | ||
| 181 | if (addr->t[0].type == TOKEN822_AT) | ||
| 182 | { | ||
| 183 | --addr->len; | ||
| 184 | for (i = 0;i < addr->len;++i) | ||
| 185 | addr->t[i] = addr->t[i + 1]; | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | void rwextradot(addr) | ||
| 190 | token822_alloc *addr; | ||
| 191 | { | ||
| 192 | int i; | ||
| 193 | if (addr->t[0].type == TOKEN822_DOT) | ||
| 194 | { | ||
| 195 | --addr->len; | ||
| 196 | for (i = 0;i < addr->len;++i) | ||
| 197 | addr->t[i] = addr->t[i + 1]; | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | void rwnoat(addr) | ||
| 202 | token822_alloc *addr; | ||
| 203 | { | ||
| 204 | int i; | ||
| 205 | int shift; | ||
| 206 | |||
| 207 | for (i = 0;i < addr->len;++i) | ||
| 208 | if (addr->t[i].type == TOKEN822_AT) | ||
| 209 | return; | ||
| 210 | shift = defaulthost.len; | ||
| 211 | if (!token822_readyplus(addr,shift)) die_nomem(); | ||
| 212 | for (i = addr->len - 1;i >= 0;--i) | ||
| 213 | addr->t[i + shift] = addr->t[i]; | ||
| 214 | addr->len += shift; | ||
| 215 | for (i = 0;i < shift;++i) | ||
| 216 | addr->t[i] = defaulthost.t[shift - 1 - i]; | ||
| 217 | } | ||
| 218 | |||
| 219 | void rwnodot(addr) | ||
| 220 | token822_alloc *addr; | ||
| 221 | { | ||
| 222 | int i; | ||
| 223 | int shift; | ||
| 224 | for (i = 0;i < addr->len;++i) | ||
| 225 | { | ||
| 226 | if (addr->t[i].type == TOKEN822_DOT) | ||
| 227 | return; | ||
| 228 | if (addr->t[i].type == TOKEN822_AT) | ||
| 229 | break; | ||
| 230 | } | ||
| 231 | for (i = 0;i < addr->len;++i) | ||
| 232 | { | ||
| 233 | if (addr->t[i].type == TOKEN822_LITERAL) | ||
| 234 | return; | ||
| 235 | if (addr->t[i].type == TOKEN822_AT) | ||
| 236 | break; | ||
| 237 | } | ||
| 238 | shift = defaultdomain.len; | ||
| 239 | if (!token822_readyplus(addr,shift)) die_nomem(); | ||
| 240 | for (i = addr->len - 1;i >= 0;--i) | ||
| 241 | addr->t[i + shift] = addr->t[i]; | ||
| 242 | addr->len += shift; | ||
| 243 | for (i = 0;i < shift;++i) | ||
| 244 | addr->t[i] = defaultdomain.t[shift - 1 - i]; | ||
| 245 | } | ||
| 246 | |||
| 247 | void rwplus(addr) | ||
| 248 | token822_alloc *addr; | ||
| 249 | { | ||
| 250 | int i; | ||
| 251 | int shift; | ||
| 252 | |||
| 253 | if (addr->t[0].type != TOKEN822_ATOM) return; | ||
| 254 | if (!addr->t[0].slen) return; | ||
| 255 | if (addr->t[0].s[addr->t[0].slen - 1] != '+') return; | ||
| 256 | |||
| 257 | --addr->t[0].slen; /* remove + */ | ||
| 258 | |||
| 259 | shift = plusdomain.len; | ||
| 260 | if (!token822_readyplus(addr,shift)) die_nomem(); | ||
| 261 | for (i = addr->len - 1;i >= 0;--i) | ||
| 262 | addr->t[i + shift] = addr->t[i]; | ||
| 263 | addr->len += shift; | ||
| 264 | for (i = 0;i < shift;++i) | ||
| 265 | addr->t[i] = plusdomain.t[shift - 1 - i]; | ||
| 266 | } | ||
| 267 | |||
| 268 | void rwgeneric(addr) | ||
| 269 | token822_alloc *addr; | ||
| 270 | { | ||
| 271 | if (!addr->len) return; /* don't rewrite <> */ | ||
| 272 | if (addr->len >= 2) | ||
| 273 | if (addr->t[1].type == TOKEN822_AT) | ||
| 274 | if (addr->t[0].type == TOKEN822_LITERAL) | ||
| 275 | if (!addr->t[0].slen) /* don't rewrite <foo@[]> */ | ||
| 276 | return; | ||
| 277 | rwroute(addr); | ||
| 278 | if (!addr->len) return; /* <@foo:> -> <> */ | ||
| 279 | rwextradot(addr); | ||
| 280 | if (!addr->len) return; /* <.> -> <> */ | ||
| 281 | rwextraat(addr); | ||
| 282 | if (!addr->len) return; /* <@> -> <> */ | ||
| 283 | rwnoat(addr); | ||
| 284 | rwplus(addr); | ||
| 285 | rwnodot(addr); | ||
| 286 | } | ||
| 287 | |||
| 288 | int setreturn(addr) | ||
| 289 | token822_alloc *addr; | ||
| 290 | { | ||
| 291 | if (!sender.s) | ||
| 292 | { | ||
| 293 | token822_reverse(addr); | ||
| 294 | if (token822_unquote(&sender,addr) != 1) die_nomem(); | ||
| 295 | if (flaghackrecip) | ||
| 296 | if (!stralloc_cats(&sender,"-@[]")) die_nomem(); | ||
| 297 | token822_reverse(addr); | ||
| 298 | } | ||
| 299 | return 1; | ||
| 300 | } | ||
| 301 | |||
| 302 | int rwreturn(addr) | ||
| 303 | token822_alloc *addr; | ||
| 304 | { | ||
| 305 | rwgeneric(addr); | ||
| 306 | setreturn(addr); | ||
| 307 | return 1; | ||
| 308 | } | ||
| 309 | |||
| 310 | int rwsender(addr) | ||
| 311 | token822_alloc *addr; | ||
| 312 | { | ||
| 313 | rwgeneric(addr); | ||
| 314 | return 1; | ||
| 315 | } | ||
| 316 | |||
| 317 | void rwappend(addr,xl) | ||
| 318 | token822_alloc *addr; | ||
| 319 | saa *xl; | ||
| 320 | { | ||
| 321 | token822_reverse(addr); | ||
| 322 | if (!saa_readyplus(xl,1)) die_nomem(); | ||
| 323 | xl->sa[xl->len] = sauninit; | ||
| 324 | if (token822_unquote(&xl->sa[xl->len],addr) != 1) die_nomem(); | ||
| 325 | ++xl->len; | ||
| 326 | token822_reverse(addr); | ||
| 327 | } | ||
| 328 | |||
| 329 | int rwhrr(addr) token822_alloc *addr; | ||
| 330 | { rwgeneric(addr); rwappend(addr,&hrrlist); return 1; } | ||
| 331 | int rwhr(addr) token822_alloc *addr; | ||
| 332 | { rwgeneric(addr); rwappend(addr,&hrlist); return 1; } | ||
| 333 | int rwtocc(addr) token822_alloc *addr; | ||
| 334 | { rwgeneric(addr); rwappend(addr,&hrlist); rwappend(addr,&tocclist); return 1; } | ||
| 335 | |||
| 336 | int htypeseen[H_NUM]; | ||
| 337 | stralloc hfbuf = {0}; | ||
| 338 | token822_alloc hfin = {0}; | ||
| 339 | token822_alloc hfrewrite = {0}; | ||
| 340 | token822_alloc hfaddr = {0}; | ||
| 341 | |||
| 342 | void doheaderfield(h) | ||
| 343 | stralloc *h; | ||
| 344 | { | ||
| 345 | int htype; | ||
| 346 | int (*rw)() = 0; | ||
| 347 | |||
| 348 | htype = hfield_known(h->s,h->len); | ||
| 349 | if (flagdeletefrom) if (htype == H_FROM) return; | ||
| 350 | if (flagdeletemessid) if (htype == H_MESSAGEID) return; | ||
| 351 | if (flagdeletesender) if (htype == H_RETURNPATH) return; | ||
| 352 | |||
| 353 | if (htype) | ||
| 354 | htypeseen[htype] = 1; | ||
| 355 | else | ||
| 356 | if (!hfield_valid(h->s,h->len)) | ||
| 357 | die_invalid(h); | ||
| 358 | |||
| 359 | switch(htype) { | ||
| 360 | case H_TO: case H_CC: | ||
| 361 | rw = rwtocc; break; | ||
| 362 | case H_BCC: case H_APPARENTLYTO: | ||
| 363 | rw = rwhr; break; | ||
| 364 | case H_R_TO: case H_R_CC: case H_R_BCC: | ||
| 365 | rw = rwhrr; break; | ||
| 366 | case H_RETURNPATH: | ||
| 367 | rw = rwreturn; break; | ||
| 368 | case H_SENDER: case H_FROM: case H_REPLYTO: | ||
| 369 | case H_RETURNRECEIPTTO: case H_ERRORSTO: | ||
| 370 | case H_R_SENDER: case H_R_FROM: case H_R_REPLYTO: | ||
| 371 | rw = rwsender; break; | ||
| 372 | } | ||
| 373 | |||
| 374 | if (rw) { | ||
| 375 | doordie(h,token822_parse(&hfin,h,&hfbuf)); | ||
| 376 | doordie(h,token822_addrlist(&hfrewrite,&hfaddr,&hfin,rw)); | ||
| 377 | if (token822_unparse(h,&hfrewrite,LINELEN) != 1) | ||
| 378 | die_nomem(); | ||
| 379 | } | ||
| 380 | |||
| 381 | if (htype == H_BCC) return; | ||
| 382 | if (htype == H_R_BCC) return; | ||
| 383 | if (htype == H_RETURNPATH) return; | ||
| 384 | if (htype == H_CONTENTLENGTH) return; /* some things are just too stupid */ | ||
| 385 | savedh_append(h); | ||
| 386 | } | ||
| 387 | |||
| 388 | void dobody(h) | ||
| 389 | stralloc *h; | ||
| 390 | { | ||
| 391 | put(h->s,h->len); | ||
| 392 | } | ||
| 393 | |||
| 394 | stralloc torecip = {0}; | ||
| 395 | token822_alloc tr = {0}; | ||
| 396 | |||
| 397 | void dorecip(s) | ||
| 398 | char *s; | ||
| 399 | { | ||
| 400 | if (!quote2(&torecip,s)) die_nomem(); | ||
| 401 | switch(token822_parse(&tr,&torecip,&hfbuf)) | ||
| 402 | { | ||
| 403 | case -1: die_nomem(); | ||
| 404 | case 0: | ||
| 405 | substdio_puts(subfderr,"qmail-inject: fatal: unable to parse address: "); | ||
| 406 | substdio_puts(subfderr,s); | ||
| 407 | substdio_putsflush(subfderr,"\n"); | ||
| 408 | perm(); | ||
| 409 | } | ||
| 410 | token822_reverse(&tr); | ||
| 411 | rwgeneric(&tr); | ||
| 412 | rwappend(&tr,&reciplist); | ||
| 413 | } | ||
| 414 | |||
| 415 | stralloc defaultfrom = {0}; | ||
| 416 | token822_alloc df = {0}; | ||
| 417 | |||
| 418 | void defaultfrommake() | ||
| 419 | { | ||
| 420 | char *fullname; | ||
| 421 | fullname = env_get("QMAILNAME"); | ||
| 422 | if (!fullname) fullname = env_get("MAILNAME"); | ||
| 423 | if (!fullname) fullname = env_get("NAME"); | ||
| 424 | if (!token822_ready(&df,20)) die_nomem(); | ||
| 425 | df.len = 0; | ||
| 426 | df.t[df.len].type = TOKEN822_ATOM; | ||
| 427 | df.t[df.len].s = "From"; | ||
| 428 | df.t[df.len].slen = 4; | ||
| 429 | ++df.len; | ||
| 430 | df.t[df.len].type = TOKEN822_COLON; | ||
| 431 | ++df.len; | ||
| 432 | if (fullname && !flagnamecomment) | ||
| 433 | { | ||
| 434 | df.t[df.len].type = TOKEN822_QUOTE; | ||
| 435 | df.t[df.len].s = fullname; | ||
| 436 | df.t[df.len].slen = str_len(fullname); | ||
| 437 | ++df.len; | ||
| 438 | df.t[df.len].type = TOKEN822_LEFT; | ||
| 439 | ++df.len; | ||
| 440 | } | ||
| 441 | df.t[df.len].type = mailusertokentype; | ||
| 442 | df.t[df.len].s = mailuser; | ||
| 443 | df.t[df.len].slen = str_len(mailuser); | ||
| 444 | ++df.len; | ||
| 445 | if (mailhost) | ||
| 446 | { | ||
| 447 | df.t[df.len].type = TOKEN822_AT; | ||
| 448 | ++df.len; | ||
| 449 | df.t[df.len].type = TOKEN822_ATOM; | ||
| 450 | df.t[df.len].s = mailhost; | ||
| 451 | df.t[df.len].slen = str_len(mailhost); | ||
| 452 | ++df.len; | ||
| 453 | } | ||
| 454 | if (fullname && !flagnamecomment) | ||
| 455 | { | ||
| 456 | df.t[df.len].type = TOKEN822_RIGHT; | ||
| 457 | ++df.len; | ||
| 458 | } | ||
| 459 | if (fullname && flagnamecomment) | ||
| 460 | { | ||
| 461 | df.t[df.len].type = TOKEN822_COMMENT; | ||
| 462 | df.t[df.len].s = fullname; | ||
| 463 | df.t[df.len].slen = str_len(fullname); | ||
| 464 | ++df.len; | ||
| 465 | } | ||
| 466 | if (token822_unparse(&defaultfrom,&df,LINELEN) != 1) die_nomem(); | ||
| 467 | doordie(&defaultfrom,token822_parse(&df,&defaultfrom,&hfbuf)); | ||
| 468 | doordie(&defaultfrom,token822_addrlist(&hfrewrite,&hfaddr,&df,rwsender)); | ||
| 469 | if (token822_unparse(&defaultfrom,&hfrewrite,LINELEN) != 1) die_nomem(); | ||
| 470 | } | ||
| 471 | |||
| 472 | stralloc defaultreturnpath = {0}; | ||
| 473 | token822_alloc drp = {0}; | ||
| 474 | stralloc hackedruser = {0}; | ||
| 475 | char strnum[FMT_ULONG]; | ||
| 476 | |||
| 477 | void dodefaultreturnpath() | ||
| 478 | { | ||
| 479 | if (!stralloc_copys(&hackedruser,mailruser)) die_nomem(); | ||
| 480 | if (flaghackmess) | ||
| 481 | { | ||
| 482 | if (!stralloc_cats(&hackedruser,"-")) die_nomem(); | ||
| 483 | if (!stralloc_catb(&hackedruser,strnum,fmt_ulong(strnum,(unsigned long) starttime))) die_nomem(); | ||
| 484 | if (!stralloc_cats(&hackedruser,".")) die_nomem(); | ||
| 485 | if (!stralloc_catb(&hackedruser,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem(); | ||
| 486 | } | ||
| 487 | if (flaghackrecip) | ||
| 488 | if (!stralloc_cats(&hackedruser,"-")) die_nomem(); | ||
| 489 | if (!token822_ready(&drp,10)) die_nomem(); | ||
| 490 | drp.len = 0; | ||
| 491 | drp.t[drp.len].type = TOKEN822_ATOM; | ||
| 492 | drp.t[drp.len].s = "Return-Path"; | ||
| 493 | drp.t[drp.len].slen = 11; | ||
| 494 | ++drp.len; | ||
| 495 | drp.t[drp.len].type = TOKEN822_COLON; | ||
| 496 | ++drp.len; | ||
| 497 | drp.t[drp.len].type = TOKEN822_QUOTE; | ||
| 498 | drp.t[drp.len].s = hackedruser.s; | ||
| 499 | drp.t[drp.len].slen = hackedruser.len; | ||
| 500 | ++drp.len; | ||
| 501 | if (mailrhost) | ||
| 502 | { | ||
| 503 | drp.t[drp.len].type = TOKEN822_AT; | ||
| 504 | ++drp.len; | ||
| 505 | drp.t[drp.len].type = TOKEN822_ATOM; | ||
| 506 | drp.t[drp.len].s = mailrhost; | ||
| 507 | drp.t[drp.len].slen = str_len(mailrhost); | ||
| 508 | ++drp.len; | ||
| 509 | } | ||
| 510 | if (token822_unparse(&defaultreturnpath,&drp,LINELEN) != 1) die_nomem(); | ||
| 511 | doordie(&defaultreturnpath,token822_parse(&drp,&defaultreturnpath,&hfbuf)); | ||
| 512 | doordie(&defaultreturnpath | ||
| 513 | ,token822_addrlist(&hfrewrite,&hfaddr,&drp,rwreturn)); | ||
| 514 | if (token822_unparse(&defaultreturnpath,&hfrewrite,LINELEN) != 1) die_nomem(); | ||
| 515 | } | ||
| 516 | |||
| 517 | int flagmft = 0; | ||
| 518 | stralloc mft = {0}; | ||
| 519 | struct constmap mapmft; | ||
| 520 | |||
| 521 | void mft_init() | ||
| 522 | { | ||
| 523 | char *x; | ||
| 524 | int r; | ||
| 525 | |||
| 526 | x = env_get("QMAILMFTFILE"); | ||
| 527 | if (!x) return; | ||
| 528 | |||
| 529 | r = control_readfile(&mft,x,0); | ||
| 530 | if (r == -1) die_read(); /*XXX*/ | ||
| 531 | if (!r) return; | ||
| 532 | |||
| 533 | if (!constmap_init(&mapmft,mft.s,mft.len,0)) die_nomem(); | ||
| 534 | flagmft = 1; | ||
| 535 | } | ||
| 536 | |||
| 537 | void finishmft() | ||
| 538 | { | ||
| 539 | int i; | ||
| 540 | static stralloc sa = {0}; | ||
| 541 | static stralloc sa2 = {0}; | ||
| 542 | |||
| 543 | if (!flagmft) return; | ||
| 544 | if (htypeseen[H_MAILFOLLOWUPTO]) return; | ||
| 545 | |||
| 546 | for (i = 0;i < tocclist.len;++i) | ||
| 547 | if (constmap(&mapmft,tocclist.sa[i].s,tocclist.sa[i].len)) | ||
| 548 | break; | ||
| 549 | |||
| 550 | if (i == tocclist.len) return; | ||
| 551 | |||
| 552 | puts("Mail-Followup-To: "); | ||
| 553 | i = tocclist.len; | ||
| 554 | while (i--) { | ||
| 555 | if (!stralloc_copy(&sa,&tocclist.sa[i])) die_nomem(); | ||
| 556 | if (!stralloc_0(&sa)) die_nomem(); | ||
| 557 | if (!quote2(&sa2,sa.s)) die_nomem(); | ||
| 558 | put(sa2.s,sa2.len); | ||
| 559 | if (i) puts(",\n "); | ||
| 560 | } | ||
| 561 | puts("\n"); | ||
| 562 | } | ||
| 563 | |||
| 564 | void finishheader() | ||
| 565 | { | ||
| 566 | flagresent = | ||
| 567 | htypeseen[H_R_SENDER] || htypeseen[H_R_FROM] || htypeseen[H_R_REPLYTO] | ||
| 568 | || htypeseen[H_R_TO] || htypeseen[H_R_CC] || htypeseen[H_R_BCC] | ||
| 569 | || htypeseen[H_R_DATE] || htypeseen[H_R_MESSAGEID]; | ||
| 570 | |||
| 571 | if (!sender.s) | ||
| 572 | dodefaultreturnpath(); | ||
| 573 | |||
| 574 | if (!flagqueue) | ||
| 575 | { | ||
| 576 | static stralloc sa = {0}; | ||
| 577 | static stralloc sa2 = {0}; | ||
| 578 | |||
| 579 | if (!stralloc_copy(&sa,&sender)) die_nomem(); | ||
| 580 | if (!stralloc_0(&sa)) die_nomem(); | ||
| 581 | if (!quote2(&sa2,sa.s)) die_nomem(); | ||
| 582 | |||
| 583 | puts("Return-Path: <"); | ||
| 584 | put(sa2.s,sa2.len); | ||
| 585 | puts(">\n"); | ||
| 586 | } | ||
| 587 | |||
| 588 | /* could check at this point whether there are any recipients */ | ||
| 589 | if (flagqueue) | ||
| 590 | if (qmail_open(&qqt) == -1) die_qqt(); | ||
| 591 | |||
| 592 | if (flagresent) | ||
| 593 | { | ||
| 594 | if (!htypeseen[H_R_DATE]) | ||
| 595 | { | ||
| 596 | if (!newfield_datemake(starttime)) die_nomem(); | ||
| 597 | puts("Resent-"); | ||
| 598 | put(newfield_date.s,newfield_date.len); | ||
| 599 | } | ||
| 600 | if (!htypeseen[H_R_MESSAGEID]) | ||
| 601 | { | ||
| 602 | if (!newfield_msgidmake(control_idhost.s,control_idhost.len,starttime)) die_nomem(); | ||
| 603 | puts("Resent-"); | ||
| 604 | put(newfield_msgid.s,newfield_msgid.len); | ||
| 605 | } | ||
| 606 | if (!htypeseen[H_R_FROM]) | ||
| 607 | { | ||
| 608 | defaultfrommake(); | ||
| 609 | puts("Resent-"); | ||
| 610 | put(defaultfrom.s,defaultfrom.len); | ||
| 611 | } | ||
| 612 | if (!htypeseen[H_R_TO] && !htypeseen[H_R_CC]) | ||
| 613 | puts("Resent-Cc: recipient list not shown: ;\n"); | ||
| 614 | } | ||
| 615 | else | ||
| 616 | { | ||
| 617 | if (!htypeseen[H_DATE]) | ||
| 618 | { | ||
| 619 | if (!newfield_datemake(starttime)) die_nomem(); | ||
| 620 | put(newfield_date.s,newfield_date.len); | ||
| 621 | } | ||
| 622 | if (!htypeseen[H_MESSAGEID]) | ||
| 623 | { | ||
| 624 | if (!newfield_msgidmake(control_idhost.s,control_idhost.len,starttime)) die_nomem(); | ||
| 625 | put(newfield_msgid.s,newfield_msgid.len); | ||
| 626 | } | ||
| 627 | if (!htypeseen[H_FROM]) | ||
| 628 | { | ||
| 629 | defaultfrommake(); | ||
| 630 | put(defaultfrom.s,defaultfrom.len); | ||
| 631 | } | ||
| 632 | if (!htypeseen[H_TO] && !htypeseen[H_CC]) | ||
| 633 | puts("Cc: recipient list not shown: ;\n"); | ||
| 634 | finishmft(); | ||
| 635 | } | ||
| 636 | |||
| 637 | savedh_print(); | ||
| 638 | } | ||
| 639 | |||
| 640 | void getcontrols() | ||
| 641 | { | ||
| 642 | static stralloc sa = {0}; | ||
| 643 | char *x; | ||
| 644 | |||
| 645 | mft_init(); | ||
| 646 | |||
| 647 | if (chdir(auto_qmail) == -1) die_chdir(); | ||
| 648 | if (control_init() == -1) die_read(); | ||
| 649 | |||
| 650 | if (control_rldef(&control_defaultdomain,"control/defaultdomain",1,"defaultdomain") != 1) | ||
| 651 | die_read(); | ||
| 652 | x = env_get("QMAILDEFAULTDOMAIN"); | ||
| 653 | if (x) if (!stralloc_copys(&control_defaultdomain,x)) die_nomem(); | ||
| 654 | if (!stralloc_copys(&sa,".")) die_nomem(); | ||
| 655 | if (!stralloc_cat(&sa,&control_defaultdomain)) die_nomem(); | ||
| 656 | doordie(&sa,token822_parse(&defaultdomain,&sa,&defaultdomainbuf)); | ||
| 657 | |||
| 658 | if (control_rldef(&control_defaulthost,"control/defaulthost",1,"defaulthost") != 1) | ||
| 659 | die_read(); | ||
| 660 | x = env_get("QMAILDEFAULTHOST"); | ||
| 661 | if (x) if (!stralloc_copys(&control_defaulthost,x)) die_nomem(); | ||
| 662 | if (!stralloc_copys(&sa,"@")) die_nomem(); | ||
| 663 | if (!stralloc_cat(&sa,&control_defaulthost)) die_nomem(); | ||
| 664 | doordie(&sa,token822_parse(&defaulthost,&sa,&defaulthostbuf)); | ||
| 665 | |||
| 666 | if (control_rldef(&control_plusdomain,"control/plusdomain",1,"plusdomain") != 1) | ||
| 667 | die_read(); | ||
| 668 | x = env_get("QMAILPLUSDOMAIN"); | ||
| 669 | if (x) if (!stralloc_copys(&control_plusdomain,x)) die_nomem(); | ||
| 670 | if (!stralloc_copys(&sa,".")) die_nomem(); | ||
| 671 | if (!stralloc_cat(&sa,&control_plusdomain)) die_nomem(); | ||
| 672 | doordie(&sa,token822_parse(&plusdomain,&sa,&plusdomainbuf)); | ||
| 673 | |||
| 674 | if (control_rldef(&control_idhost,"control/idhost",1,"idhost") != 1) | ||
| 675 | die_read(); | ||
| 676 | x = env_get("QMAILIDHOST"); | ||
| 677 | if (x) if (!stralloc_copys(&control_idhost,x)) die_nomem(); | ||
| 678 | } | ||
| 679 | |||
| 680 | #define RECIP_DEFAULT 1 | ||
| 681 | #define RECIP_ARGS 2 | ||
| 682 | #define RECIP_HEADER 3 | ||
| 683 | #define RECIP_AH 4 | ||
| 684 | |||
| 685 | void main(argc,argv) | ||
| 686 | int argc; | ||
| 687 | char **argv; | ||
| 688 | { | ||
| 689 | int i; | ||
| 690 | int opt; | ||
| 691 | int recipstrategy; | ||
| 692 | |||
| 693 | sig_pipeignore(); | ||
| 694 | |||
| 695 | starttime = now(); | ||
| 696 | |||
| 697 | qmopts = env_get("QMAILINJECT"); | ||
| 698 | if (qmopts) | ||
| 699 | while (*qmopts) | ||
| 700 | switch(*qmopts++) | ||
| 701 | { | ||
| 702 | case 'c': flagnamecomment = 1; break; | ||
| 703 | case 's': flagdeletesender = 1; break; | ||
| 704 | case 'f': flagdeletefrom = 1; break; | ||
| 705 | case 'i': flagdeletemessid = 1; break; | ||
| 706 | case 'r': flaghackrecip = 1; break; | ||
| 707 | case 'm': flaghackmess = 1; break; | ||
| 708 | } | ||
| 709 | |||
| 710 | mailhost = env_get("QMAILHOST"); | ||
| 711 | if (!mailhost) mailhost = env_get("MAILHOST"); | ||
| 712 | mailrhost = env_get("QMAILSHOST"); | ||
| 713 | if (!mailrhost) mailrhost = mailhost; | ||
| 714 | |||
| 715 | mailuser = env_get("QMAILUSER"); | ||
| 716 | if (!mailuser) mailuser = env_get("MAILUSER"); | ||
| 717 | if (!mailuser) mailuser = env_get("USER"); | ||
| 718 | if (!mailuser) mailuser = env_get("LOGNAME"); | ||
| 719 | if (!mailuser) mailuser = "anonymous"; | ||
| 720 | mailusertokentype = TOKEN822_ATOM; | ||
| 721 | if (quote_need(mailuser,str_len(mailuser))) mailusertokentype = TOKEN822_QUOTE; | ||
| 722 | mailruser = env_get("QMAILSUSER"); | ||
| 723 | if (!mailruser) mailruser = mailuser; | ||
| 724 | |||
| 725 | for (i = 0;i < H_NUM;++i) htypeseen[i] = 0; | ||
| 726 | |||
| 727 | recipstrategy = RECIP_DEFAULT; | ||
| 728 | flagqueue = 1; | ||
| 729 | |||
| 730 | getcontrols(); | ||
| 731 | |||
| 732 | if (!saa_readyplus(&hrlist,1)) die_nomem(); | ||
| 733 | if (!saa_readyplus(&tocclist,1)) die_nomem(); | ||
| 734 | if (!saa_readyplus(&hrrlist,1)) die_nomem(); | ||
| 735 | if (!saa_readyplus(&reciplist,1)) die_nomem(); | ||
| 736 | |||
| 737 | while ((opt = getopt(argc,argv,"aAhHnNf:")) != opteof) | ||
| 738 | switch(opt) | ||
| 739 | { | ||
| 740 | case 'a': recipstrategy = RECIP_ARGS; break; | ||
| 741 | case 'A': recipstrategy = RECIP_DEFAULT; break; | ||
| 742 | case 'h': recipstrategy = RECIP_HEADER; break; | ||
| 743 | case 'H': recipstrategy = RECIP_AH; break; | ||
| 744 | case 'n': flagqueue = 0; break; | ||
| 745 | case 'N': flagqueue = 1; break; | ||
| 746 | case 'f': | ||
| 747 | if (!quote2(&sender,optarg)) die_nomem(); | ||
| 748 | doordie(&sender,token822_parse(&envs,&sender,&envsbuf)); | ||
| 749 | token822_reverse(&envs); | ||
| 750 | rwgeneric(&envs); | ||
| 751 | token822_reverse(&envs); | ||
| 752 | if (token822_unquote(&sender,&envs) != 1) die_nomem(); | ||
| 753 | break; | ||
| 754 | case '?': | ||
| 755 | default: | ||
| 756 | perm(); | ||
| 757 | } | ||
| 758 | argc -= optind; | ||
| 759 | argv += optind; | ||
| 760 | |||
| 761 | if (recipstrategy == RECIP_DEFAULT) | ||
| 762 | recipstrategy = (*argv ? RECIP_ARGS : RECIP_HEADER); | ||
| 763 | |||
| 764 | if (recipstrategy != RECIP_HEADER) | ||
| 765 | while (*argv) | ||
| 766 | dorecip(*argv++); | ||
| 767 | |||
| 768 | flagrh = (recipstrategy != RECIP_ARGS); | ||
| 769 | |||
| 770 | if (headerbody(subfdin,doheaderfield,finishheader,dobody) == -1) | ||
| 771 | die_read(); | ||
| 772 | exitnicely(); | ||
| 773 | } | ||
diff --git a/qmail-limits.9 b/qmail-limits.9 new file mode 100644 index 0000000..dca5426 --- /dev/null +++ b/qmail-limits.9 | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | .TH qmail-limits 7 | ||
| 2 | .SH "NAME" | ||
| 3 | qmail-limits \- artificial limits in the qmail system | ||
| 4 | .SH "DESCRIPTION" | ||
| 5 | The | ||
| 6 | .B qmail | ||
| 7 | system is able to handle messages of any size, | ||
| 8 | addresses of any size, mailing lists of any size, and so on, | ||
| 9 | except as limited by the available memory and disk space. | ||
| 10 | |||
| 11 | However, it imposes certain artificial limits: | ||
| 12 | .TP 5 | ||
| 13 | 1. | ||
| 14 | .B qmail-lspawn | ||
| 15 | silently limits the number of simultaneous local deliveries to SPAWN. | ||
| 16 | .B qmail-rspawn | ||
| 17 | silently limits the number of simultaneous remote deliveries to SPAWN. | ||
| 18 | .TP 5 | ||
| 19 | 2. | ||
| 20 | .B qmail-queue | ||
| 21 | rejects any message with an envelope address longer than 1000 characters. | ||
| 22 | .TP 5 | ||
| 23 | 3. | ||
| 24 | .B qmail-lspawn | ||
| 25 | truncates any overly long error report from a delivery program. | ||
| 26 | It appends a note saying that it did so. | ||
| 27 | .SH "SEE ALSO" | ||
| 28 | qmail-lspawn(8), | ||
| 29 | qmail-queue(8), | ||
| 30 | qmail-rspawn(8) | ||
diff --git a/qmail-local.8 b/qmail-local.8 new file mode 100644 index 0000000..c047697 --- /dev/null +++ b/qmail-local.8 | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | .TH qmail-local 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-local \- deliver or forward a mail message | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-local | ||
| 6 | [ | ||
| 7 | .B \-nN | ||
| 8 | ] | ||
| 9 | .I user | ||
| 10 | .I homedir | ||
| 11 | .I local | ||
| 12 | .I dash | ||
| 13 | .I ext | ||
| 14 | .I domain | ||
| 15 | .I sender | ||
| 16 | .I defaultdelivery | ||
| 17 | .SH DESCRIPTION | ||
| 18 | .B qmail-local | ||
| 19 | reads a mail message | ||
| 20 | and delivers it to | ||
| 21 | .I user | ||
| 22 | by the procedure described in | ||
| 23 | .BR dot-qmail(5) . | ||
| 24 | |||
| 25 | The message's envelope recipient is | ||
| 26 | .IR local@domain . | ||
| 27 | .B qmail-local | ||
| 28 | records | ||
| 29 | .I local@domain | ||
| 30 | in a new | ||
| 31 | .B Delivered-To | ||
| 32 | header field. | ||
| 33 | If exactly the same | ||
| 34 | .B Delivered-To: \fIlocal@domain | ||
| 35 | already appears in the header, | ||
| 36 | .B qmail-local | ||
| 37 | bounces the message, | ||
| 38 | to prevent mail forwarding loops. | ||
| 39 | |||
| 40 | The message's envelope sender is | ||
| 41 | .IR sender . | ||
| 42 | .B qmail-local | ||
| 43 | records | ||
| 44 | .I sender | ||
| 45 | in a new | ||
| 46 | .B Return-Path | ||
| 47 | header field. | ||
| 48 | |||
| 49 | .I homedir | ||
| 50 | is the user's home directory. | ||
| 51 | It must be an absolute directory name. | ||
| 52 | |||
| 53 | .I dash | ||
| 54 | and | ||
| 55 | .I ext | ||
| 56 | identify the | ||
| 57 | .B .qmail\fIdashext | ||
| 58 | file used by | ||
| 59 | .BR qmail-local ; | ||
| 60 | see | ||
| 61 | .BR dot-qmail(5) . | ||
| 62 | Normally | ||
| 63 | .I dash | ||
| 64 | is either empty or a lone hyphen. | ||
| 65 | If it is empty, | ||
| 66 | .B qmail-local | ||
| 67 | treats a nonexistent | ||
| 68 | .B .qmail\fIext | ||
| 69 | the same way as an empty | ||
| 70 | .BR .qmail\fIext : | ||
| 71 | namely, following the delivery instructions in | ||
| 72 | .IR defaultdelivery . | ||
| 73 | |||
| 74 | The standard input for | ||
| 75 | .B qmail-local | ||
| 76 | must be a seekable file, | ||
| 77 | so that | ||
| 78 | .B qmail-local | ||
| 79 | can read it more than once. | ||
| 80 | .SH "OPTIONS" | ||
| 81 | .TP | ||
| 82 | .B \-n | ||
| 83 | Instead of reading and delivering the message, | ||
| 84 | print a description of the delivery instructions. | ||
| 85 | .TP | ||
| 86 | .B \-N | ||
| 87 | (Default.) Read and deliver the message. | ||
| 88 | .SH "EXIT CODES" | ||
| 89 | 0 if the delivery is completely successful; | ||
| 90 | nonzero if any delivery instruction failed. | ||
| 91 | Exit code 111 | ||
| 92 | indicates temporary failure. | ||
| 93 | .SH "SEE ALSO" | ||
| 94 | dot-qmail(5), | ||
| 95 | envelopes(5), | ||
| 96 | qmail-command(8), | ||
| 97 | qmail-queue(8), | ||
| 98 | qmail-send(8), | ||
| 99 | qmail-lspawn(8) | ||
diff --git a/qmail-local.c b/qmail-local.c new file mode 100644 index 0000000..cd01602 --- /dev/null +++ b/qmail-local.c | |||
| @@ -0,0 +1,698 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include "readwrite.h" | ||
| 4 | #include "sig.h" | ||
| 5 | #include "env.h" | ||
| 6 | #include "byte.h" | ||
| 7 | #include "exit.h" | ||
| 8 | #include "fork.h" | ||
| 9 | #include "open.h" | ||
| 10 | #include "wait.h" | ||
| 11 | #include "lock.h" | ||
| 12 | #include "seek.h" | ||
| 13 | #include "substdio.h" | ||
| 14 | #include "getln.h" | ||
| 15 | #include "strerr.h" | ||
| 16 | #include "subfd.h" | ||
| 17 | #include "sgetopt.h" | ||
| 18 | #include "alloc.h" | ||
| 19 | #include "error.h" | ||
| 20 | #include "stralloc.h" | ||
| 21 | #include "fmt.h" | ||
| 22 | #include "str.h" | ||
| 23 | #include "now.h" | ||
| 24 | #include "case.h" | ||
| 25 | #include "quote.h" | ||
| 26 | #include "qmail.h" | ||
| 27 | #include "slurpclose.h" | ||
| 28 | #include "myctime.h" | ||
| 29 | #include "gfrom.h" | ||
| 30 | #include "auto_patrn.h" | ||
| 31 | |||
| 32 | void usage() { strerr_die1x(100,"qmail-local: usage: qmail-local [ -nN ] user homedir local dash ext domain sender aliasempty"); } | ||
| 33 | |||
| 34 | void temp_nomem() { strerr_die1x(111,"Out of memory. (#4.3.0)"); } | ||
| 35 | void temp_rewind() { strerr_die1x(111,"Unable to rewind message. (#4.3.0)"); } | ||
| 36 | void temp_childcrashed() { strerr_die1x(111,"Aack, child crashed. (#4.3.0)"); } | ||
| 37 | void temp_fork() { strerr_die3x(111,"Unable to fork: ",error_str(errno),". (#4.3.0)"); } | ||
| 38 | void temp_read() { strerr_die3x(111,"Unable to read message: ",error_str(errno),". (#4.3.0)"); } | ||
| 39 | void temp_slowlock() | ||
| 40 | { strerr_die1x(111,"File has been locked for 30 seconds straight. (#4.3.0)"); } | ||
| 41 | void temp_qmail(fn) char *fn; | ||
| 42 | { strerr_die5x(111,"Unable to open ",fn,": ",error_str(errno),". (#4.3.0)"); } | ||
| 43 | |||
| 44 | int flagdoit; | ||
| 45 | int flag99; | ||
| 46 | |||
| 47 | char *user; | ||
| 48 | char *homedir; | ||
| 49 | char *local; | ||
| 50 | char *dash; | ||
| 51 | char *ext; | ||
| 52 | char *host; | ||
| 53 | char *sender; | ||
| 54 | char *aliasempty; | ||
| 55 | |||
| 56 | stralloc safeext = {0}; | ||
| 57 | stralloc ufline = {0}; | ||
| 58 | stralloc rpline = {0}; | ||
| 59 | stralloc envrecip = {0}; | ||
| 60 | stralloc dtline = {0}; | ||
| 61 | stralloc qme = {0}; | ||
| 62 | stralloc ueo = {0}; | ||
| 63 | stralloc cmds = {0}; | ||
| 64 | stralloc messline = {0}; | ||
| 65 | stralloc foo = {0}; | ||
| 66 | |||
| 67 | char buf[1024]; | ||
| 68 | char outbuf[1024]; | ||
| 69 | |||
| 70 | /* child process */ | ||
| 71 | |||
| 72 | char fntmptph[80 + FMT_ULONG * 2]; | ||
| 73 | char fnnewtph[80 + FMT_ULONG * 2]; | ||
| 74 | void tryunlinktmp() { unlink(fntmptph); } | ||
| 75 | void sigalrm() { tryunlinktmp(); _exit(3); } | ||
| 76 | |||
| 77 | void maildir_child(dir) | ||
| 78 | char *dir; | ||
| 79 | { | ||
| 80 | unsigned long pid; | ||
| 81 | unsigned long time; | ||
| 82 | char host[64]; | ||
| 83 | char *s; | ||
| 84 | int loop; | ||
| 85 | struct stat st; | ||
| 86 | int fd; | ||
| 87 | substdio ss; | ||
| 88 | substdio ssout; | ||
| 89 | |||
| 90 | sig_alarmcatch(sigalrm); | ||
| 91 | if (chdir(dir) == -1) { if (error_temp(errno)) _exit(1); _exit(2); } | ||
| 92 | pid = getpid(); | ||
| 93 | host[0] = 0; | ||
| 94 | gethostname(host,sizeof(host)); | ||
| 95 | for (loop = 0;;++loop) | ||
| 96 | { | ||
| 97 | time = now(); | ||
| 98 | s = fntmptph; | ||
| 99 | s += fmt_str(s,"tmp/"); | ||
| 100 | s += fmt_ulong(s,time); *s++ = '.'; | ||
| 101 | s += fmt_ulong(s,pid); *s++ = '.'; | ||
| 102 | s += fmt_strn(s,host,sizeof(host)); *s++ = 0; | ||
| 103 | if (stat(fntmptph,&st) == -1) if (errno == error_noent) break; | ||
| 104 | /* really should never get to this point */ | ||
| 105 | if (loop == 2) _exit(1); | ||
| 106 | sleep(2); | ||
| 107 | } | ||
| 108 | str_copy(fnnewtph,fntmptph); | ||
| 109 | byte_copy(fnnewtph,3,"new"); | ||
| 110 | |||
| 111 | alarm(86400); | ||
| 112 | fd = open_excl(fntmptph); | ||
| 113 | if (fd == -1) _exit(1); | ||
| 114 | |||
| 115 | substdio_fdbuf(&ss,read,0,buf,sizeof(buf)); | ||
| 116 | substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf)); | ||
| 117 | if (substdio_put(&ssout,rpline.s,rpline.len) == -1) goto fail; | ||
| 118 | if (substdio_put(&ssout,dtline.s,dtline.len) == -1) goto fail; | ||
| 119 | |||
| 120 | switch(substdio_copy(&ssout,&ss)) | ||
| 121 | { | ||
| 122 | case -2: tryunlinktmp(); _exit(4); | ||
| 123 | case -3: goto fail; | ||
| 124 | } | ||
| 125 | |||
| 126 | if (substdio_flush(&ssout) == -1) goto fail; | ||
| 127 | if (fsync(fd) == -1) goto fail; | ||
| 128 | if (close(fd) == -1) goto fail; /* NFS dorks */ | ||
| 129 | |||
| 130 | if (link(fntmptph,fnnewtph) == -1) goto fail; | ||
| 131 | /* if it was error_exist, almost certainly successful; i hate NFS */ | ||
| 132 | tryunlinktmp(); _exit(0); | ||
| 133 | |||
| 134 | fail: tryunlinktmp(); _exit(1); | ||
| 135 | } | ||
| 136 | |||
| 137 | /* end child process */ | ||
| 138 | |||
| 139 | void maildir(fn) | ||
| 140 | char *fn; | ||
| 141 | { | ||
| 142 | int child; | ||
| 143 | int wstat; | ||
| 144 | |||
| 145 | if (seek_begin(0) == -1) temp_rewind(); | ||
| 146 | |||
| 147 | switch(child = fork()) | ||
| 148 | { | ||
| 149 | case -1: | ||
| 150 | temp_fork(); | ||
| 151 | case 0: | ||
| 152 | maildir_child(fn); | ||
| 153 | _exit(111); | ||
| 154 | } | ||
| 155 | |||
| 156 | wait_pid(&wstat,child); | ||
| 157 | if (wait_crashed(wstat)) | ||
| 158 | temp_childcrashed(); | ||
| 159 | switch(wait_exitcode(wstat)) | ||
| 160 | { | ||
| 161 | case 0: break; | ||
| 162 | case 2: strerr_die1x(111,"Unable to chdir to maildir. (#4.2.1)"); | ||
| 163 | case 3: strerr_die1x(111,"Timeout on maildir delivery. (#4.3.0)"); | ||
| 164 | case 4: strerr_die1x(111,"Unable to read message. (#4.3.0)"); | ||
| 165 | default: strerr_die1x(111,"Temporary error on maildir delivery. (#4.3.0)"); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | void mailfile(fn) | ||
| 170 | char *fn; | ||
| 171 | { | ||
| 172 | int fd; | ||
| 173 | substdio ss; | ||
| 174 | substdio ssout; | ||
| 175 | int match; | ||
| 176 | seek_pos pos; | ||
| 177 | int flaglocked; | ||
| 178 | |||
| 179 | if (seek_begin(0) == -1) temp_rewind(); | ||
| 180 | |||
| 181 | fd = open_append(fn); | ||
| 182 | if (fd == -1) | ||
| 183 | strerr_die5x(111,"Unable to open ",fn,": ",error_str(errno),". (#4.2.1)"); | ||
| 184 | |||
| 185 | sig_alarmcatch(temp_slowlock); | ||
| 186 | alarm(30); | ||
| 187 | flaglocked = (lock_ex(fd) != -1); | ||
| 188 | alarm(0); | ||
| 189 | sig_alarmdefault(); | ||
| 190 | |||
| 191 | seek_end(fd); | ||
| 192 | pos = seek_cur(fd); | ||
| 193 | |||
| 194 | substdio_fdbuf(&ss,read,0,buf,sizeof(buf)); | ||
| 195 | substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf)); | ||
| 196 | if (substdio_put(&ssout,ufline.s,ufline.len)) goto writeerrs; | ||
| 197 | if (substdio_put(&ssout,rpline.s,rpline.len)) goto writeerrs; | ||
| 198 | if (substdio_put(&ssout,dtline.s,dtline.len)) goto writeerrs; | ||
| 199 | for (;;) | ||
| 200 | { | ||
| 201 | if (getln(&ss,&messline,&match,'\n') != 0) | ||
| 202 | { | ||
| 203 | strerr_warn3("Unable to read message: ",error_str(errno),". (#4.3.0)",0); | ||
| 204 | if (flaglocked) seek_trunc(fd,pos); close(fd); | ||
| 205 | _exit(111); | ||
| 206 | } | ||
| 207 | if (!match && !messline.len) break; | ||
| 208 | if (gfrom(messline.s,messline.len)) | ||
| 209 | if (substdio_bput(&ssout,">",1)) goto writeerrs; | ||
| 210 | if (substdio_bput(&ssout,messline.s,messline.len)) goto writeerrs; | ||
| 211 | if (!match) | ||
| 212 | { | ||
| 213 | if (substdio_bputs(&ssout,"\n")) goto writeerrs; | ||
| 214 | break; | ||
| 215 | } | ||
| 216 | } | ||
| 217 | if (substdio_bputs(&ssout,"\n")) goto writeerrs; | ||
| 218 | if (substdio_flush(&ssout)) goto writeerrs; | ||
| 219 | if (fsync(fd) == -1) goto writeerrs; | ||
| 220 | close(fd); | ||
| 221 | return; | ||
| 222 | |||
| 223 | writeerrs: | ||
| 224 | strerr_warn5("Unable to write ",fn,": ",error_str(errno),". (#4.3.0)",0); | ||
| 225 | if (flaglocked) seek_trunc(fd,pos); | ||
| 226 | close(fd); | ||
| 227 | _exit(111); | ||
| 228 | } | ||
| 229 | |||
| 230 | void mailprogram(prog) | ||
| 231 | char *prog; | ||
| 232 | { | ||
| 233 | int child; | ||
| 234 | char *(args[4]); | ||
| 235 | int wstat; | ||
| 236 | |||
| 237 | if (seek_begin(0) == -1) temp_rewind(); | ||
| 238 | |||
| 239 | switch(child = fork()) | ||
| 240 | { | ||
| 241 | case -1: | ||
| 242 | temp_fork(); | ||
| 243 | case 0: | ||
| 244 | args[0] = "/bin/sh"; args[1] = "-c"; args[2] = prog; args[3] = 0; | ||
| 245 | sig_pipedefault(); | ||
| 246 | execv(*args,args); | ||
| 247 | strerr_die3x(111,"Unable to run /bin/sh: ",error_str(errno),". (#4.3.0)"); | ||
| 248 | } | ||
| 249 | |||
| 250 | wait_pid(&wstat,child); | ||
| 251 | if (wait_crashed(wstat)) | ||
| 252 | temp_childcrashed(); | ||
| 253 | switch(wait_exitcode(wstat)) | ||
| 254 | { | ||
| 255 | case 100: | ||
| 256 | case 64: case 65: case 70: case 76: case 77: case 78: case 112: _exit(100); | ||
| 257 | case 0: break; | ||
| 258 | case 99: flag99 = 1; break; | ||
| 259 | default: _exit(111); | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | unsigned long mailforward_qp = 0; | ||
| 264 | |||
| 265 | void mailforward(recips) | ||
| 266 | char **recips; | ||
| 267 | { | ||
| 268 | struct qmail qqt; | ||
| 269 | char *qqx; | ||
| 270 | substdio ss; | ||
| 271 | int match; | ||
| 272 | |||
| 273 | if (seek_begin(0) == -1) temp_rewind(); | ||
| 274 | substdio_fdbuf(&ss,read,0,buf,sizeof(buf)); | ||
| 275 | |||
| 276 | if (qmail_open(&qqt) == -1) temp_fork(); | ||
| 277 | mailforward_qp = qmail_qp(&qqt); | ||
| 278 | qmail_put(&qqt,dtline.s,dtline.len); | ||
| 279 | do | ||
| 280 | { | ||
| 281 | if (getln(&ss,&messline,&match,'\n') != 0) { qmail_fail(&qqt); break; } | ||
| 282 | qmail_put(&qqt,messline.s,messline.len); | ||
| 283 | } | ||
| 284 | while (match); | ||
| 285 | qmail_from(&qqt,ueo.s); | ||
| 286 | while (*recips) qmail_to(&qqt,*recips++); | ||
| 287 | qqx = qmail_close(&qqt); | ||
| 288 | if (!*qqx) return; | ||
| 289 | strerr_die3x(*qqx == 'D' ? 100 : 111,"Unable to forward message: ",qqx + 1,"."); | ||
| 290 | } | ||
| 291 | |||
| 292 | void bouncexf() | ||
| 293 | { | ||
| 294 | int match; | ||
| 295 | substdio ss; | ||
| 296 | |||
| 297 | if (seek_begin(0) == -1) temp_rewind(); | ||
| 298 | substdio_fdbuf(&ss,read,0,buf,sizeof(buf)); | ||
| 299 | for (;;) | ||
| 300 | { | ||
| 301 | if (getln(&ss,&messline,&match,'\n') != 0) temp_read(); | ||
| 302 | if (!match) break; | ||
| 303 | if (messline.len <= 1) | ||
| 304 | break; | ||
| 305 | if (messline.len == dtline.len) | ||
| 306 | if (!str_diffn(messline.s,dtline.s,dtline.len)) | ||
| 307 | strerr_die1x(100,"This message is looping: it already has my Delivered-To line. (#5.4.6)"); | ||
| 308 | } | ||
| 309 | } | ||
| 310 | |||
| 311 | void checkhome() | ||
| 312 | { | ||
| 313 | struct stat st; | ||
| 314 | |||
| 315 | if (stat(".",&st) == -1) | ||
| 316 | strerr_die3x(111,"Unable to stat home directory: ",error_str(errno),". (#4.3.0)"); | ||
| 317 | if (st.st_mode & auto_patrn) | ||
| 318 | strerr_die1x(111,"Uh-oh: home directory is writable. (#4.7.0)"); | ||
| 319 | if (st.st_mode & 01000) | ||
| 320 | if (flagdoit) | ||
| 321 | strerr_die1x(111,"Home directory is sticky: user is editing his .qmail file. (#4.2.1)"); | ||
| 322 | else | ||
| 323 | strerr_warn1("Warning: home directory is sticky.",0); | ||
| 324 | } | ||
| 325 | |||
| 326 | int qmeox(dashowner) | ||
| 327 | char *dashowner; | ||
| 328 | { | ||
| 329 | struct stat st; | ||
| 330 | |||
| 331 | if (!stralloc_copys(&qme,".qmail")) temp_nomem(); | ||
| 332 | if (!stralloc_cats(&qme,dash)) temp_nomem(); | ||
| 333 | if (!stralloc_cat(&qme,&safeext)) temp_nomem(); | ||
| 334 | if (!stralloc_cats(&qme,dashowner)) temp_nomem(); | ||
| 335 | if (!stralloc_0(&qme)) temp_nomem(); | ||
| 336 | if (stat(qme.s,&st) == -1) | ||
| 337 | { | ||
| 338 | if (error_temp(errno)) temp_qmail(qme.s); | ||
| 339 | return -1; | ||
| 340 | } | ||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | |||
| 344 | int qmeexists(fd,cutable) | ||
| 345 | int *fd; | ||
| 346 | int *cutable; | ||
| 347 | { | ||
| 348 | struct stat st; | ||
| 349 | |||
| 350 | if (!stralloc_0(&qme)) temp_nomem(); | ||
| 351 | |||
| 352 | *fd = open_read(qme.s); | ||
| 353 | if (*fd == -1) { | ||
| 354 | if (error_temp(errno)) temp_qmail(qme.s); | ||
| 355 | if (errno == error_perm) temp_qmail(qme.s); | ||
| 356 | if (errno == error_acces) temp_qmail(qme.s); | ||
| 357 | return 0; | ||
| 358 | } | ||
| 359 | |||
| 360 | if (fstat(*fd,&st) == -1) temp_qmail(qme.s); | ||
| 361 | if ((st.st_mode & S_IFMT) == S_IFREG) { | ||
| 362 | if (st.st_mode & auto_patrn) | ||
| 363 | strerr_die1x(111,"Uh-oh: .qmail file is writable. (#4.7.0)"); | ||
| 364 | *cutable = !!(st.st_mode & 0100); | ||
| 365 | return 1; | ||
| 366 | } | ||
| 367 | close(*fd); | ||
| 368 | return 0; | ||
| 369 | } | ||
| 370 | |||
| 371 | /* "" "": "" */ | ||
| 372 | /* "-/" "": "-/" "-/default" */ | ||
| 373 | /* "-/" "a": "-/a" "-/default" */ | ||
| 374 | /* "-/" "a-": "-/a-" "-/a-default" "-/default" */ | ||
| 375 | /* "-/" "a-b": "-/a-b" "-/a-default" "-/default" */ | ||
| 376 | /* "-/" "a-b-": "-/a-b-" "-/a-b-default" "-/a-default" "-/default" */ | ||
| 377 | /* "-/" "a-b-c": "-/a-b-c" "-/a-b-default" "-/a-default" "-/default" */ | ||
| 378 | |||
| 379 | void qmesearch(fd,cutable) | ||
| 380 | int *fd; | ||
| 381 | int *cutable; | ||
| 382 | { | ||
| 383 | int i; | ||
| 384 | |||
| 385 | if (!stralloc_copys(&qme,".qmail")) temp_nomem(); | ||
| 386 | if (!stralloc_cats(&qme,dash)) temp_nomem(); | ||
| 387 | if (!stralloc_cat(&qme,&safeext)) temp_nomem(); | ||
| 388 | if (qmeexists(fd,cutable)) { | ||
| 389 | if (safeext.len >= 7) { | ||
| 390 | i = safeext.len - 7; | ||
| 391 | if (!byte_diff("default",7,safeext.s + i)) | ||
| 392 | if (i <= str_len(ext)) /* paranoia */ | ||
| 393 | if (!env_put2("DEFAULT",ext + i)) temp_nomem(); | ||
| 394 | } | ||
| 395 | return; | ||
| 396 | } | ||
| 397 | |||
| 398 | for (i = safeext.len;i >= 0;--i) | ||
| 399 | if (!i || (safeext.s[i - 1] == '-')) { | ||
| 400 | if (!stralloc_copys(&qme,".qmail")) temp_nomem(); | ||
| 401 | if (!stralloc_cats(&qme,dash)) temp_nomem(); | ||
| 402 | if (!stralloc_catb(&qme,safeext.s,i)) temp_nomem(); | ||
| 403 | if (!stralloc_cats(&qme,"default")) temp_nomem(); | ||
| 404 | if (qmeexists(fd,cutable)) { | ||
| 405 | if (i <= str_len(ext)) /* paranoia */ | ||
| 406 | if (!env_put2("DEFAULT",ext + i)) temp_nomem(); | ||
| 407 | return; | ||
| 408 | } | ||
| 409 | } | ||
| 410 | |||
| 411 | *fd = -1; | ||
| 412 | } | ||
| 413 | |||
| 414 | unsigned long count_file = 0; | ||
| 415 | unsigned long count_forward = 0; | ||
| 416 | unsigned long count_program = 0; | ||
| 417 | char count_buf[FMT_ULONG]; | ||
| 418 | |||
| 419 | void count_print() | ||
| 420 | { | ||
| 421 | substdio_puts(subfdoutsmall,"did "); | ||
| 422 | substdio_put(subfdoutsmall,count_buf,fmt_ulong(count_buf,count_file)); | ||
| 423 | substdio_puts(subfdoutsmall,"+"); | ||
| 424 | substdio_put(subfdoutsmall,count_buf,fmt_ulong(count_buf,count_forward)); | ||
| 425 | substdio_puts(subfdoutsmall,"+"); | ||
| 426 | substdio_put(subfdoutsmall,count_buf,fmt_ulong(count_buf,count_program)); | ||
| 427 | substdio_puts(subfdoutsmall,"\n"); | ||
| 428 | if (mailforward_qp) | ||
| 429 | { | ||
| 430 | substdio_puts(subfdoutsmall,"qp "); | ||
| 431 | substdio_put(subfdoutsmall,count_buf,fmt_ulong(count_buf,mailforward_qp)); | ||
| 432 | substdio_puts(subfdoutsmall,"\n"); | ||
| 433 | } | ||
| 434 | substdio_flush(subfdoutsmall); | ||
| 435 | } | ||
| 436 | |||
| 437 | void sayit(type,cmd,len) | ||
| 438 | char *type; | ||
| 439 | char *cmd; | ||
| 440 | int len; | ||
| 441 | { | ||
| 442 | substdio_puts(subfdoutsmall,type); | ||
| 443 | substdio_put(subfdoutsmall,cmd,len); | ||
| 444 | substdio_putsflush(subfdoutsmall,"\n"); | ||
| 445 | } | ||
| 446 | |||
| 447 | void main(argc,argv) | ||
| 448 | int argc; | ||
| 449 | char **argv; | ||
| 450 | { | ||
| 451 | int opt; | ||
| 452 | int i; | ||
| 453 | int j; | ||
| 454 | int k; | ||
| 455 | int fd; | ||
| 456 | int numforward; | ||
| 457 | char **recips; | ||
| 458 | datetime_sec starttime; | ||
| 459 | int flagforwardonly; | ||
| 460 | char *x; | ||
| 461 | |||
| 462 | umask(077); | ||
| 463 | sig_pipeignore(); | ||
| 464 | |||
| 465 | if (!env_init()) temp_nomem(); | ||
| 466 | |||
| 467 | flagdoit = 1; | ||
| 468 | while ((opt = getopt(argc,argv,"nN")) != opteof) | ||
| 469 | switch(opt) | ||
| 470 | { | ||
| 471 | case 'n': flagdoit = 0; break; | ||
| 472 | case 'N': flagdoit = 1; break; | ||
| 473 | default: | ||
| 474 | usage(); | ||
| 475 | } | ||
| 476 | argc -= optind; | ||
| 477 | argv += optind; | ||
| 478 | |||
| 479 | if (!(user = *argv++)) usage(); | ||
| 480 | if (!(homedir = *argv++)) usage(); | ||
| 481 | if (!(local = *argv++)) usage(); | ||
| 482 | if (!(dash = *argv++)) usage(); | ||
| 483 | if (!(ext = *argv++)) usage(); | ||
| 484 | if (!(host = *argv++)) usage(); | ||
| 485 | if (!(sender = *argv++)) usage(); | ||
| 486 | if (!(aliasempty = *argv++)) usage(); | ||
| 487 | if (*argv) usage(); | ||
| 488 | |||
| 489 | if (homedir[0] != '/') usage(); | ||
| 490 | if (chdir(homedir) == -1) | ||
| 491 | strerr_die5x(111,"Unable to switch to ",homedir,": ",error_str(errno),". (#4.3.0)"); | ||
| 492 | checkhome(); | ||
| 493 | |||
| 494 | if (!env_put2("HOST",host)) temp_nomem(); | ||
| 495 | if (!env_put2("HOME",homedir)) temp_nomem(); | ||
| 496 | if (!env_put2("USER",user)) temp_nomem(); | ||
| 497 | if (!env_put2("LOCAL",local)) temp_nomem(); | ||
| 498 | |||
| 499 | if (!stralloc_copys(&envrecip,local)) temp_nomem(); | ||
| 500 | if (!stralloc_cats(&envrecip,"@")) temp_nomem(); | ||
| 501 | if (!stralloc_cats(&envrecip,host)) temp_nomem(); | ||
| 502 | |||
| 503 | if (!stralloc_copy(&foo,&envrecip)) temp_nomem(); | ||
| 504 | if (!stralloc_0(&foo)) temp_nomem(); | ||
| 505 | if (!env_put2("RECIPIENT",foo.s)) temp_nomem(); | ||
| 506 | |||
| 507 | if (!stralloc_copys(&dtline,"Delivered-To: ")) temp_nomem(); | ||
| 508 | if (!stralloc_cat(&dtline,&envrecip)) temp_nomem(); | ||
| 509 | for (i = 0;i < dtline.len;++i) if (dtline.s[i] == '\n') dtline.s[i] = '_'; | ||
| 510 | if (!stralloc_cats(&dtline,"\n")) temp_nomem(); | ||
| 511 | |||
| 512 | if (!stralloc_copy(&foo,&dtline)) temp_nomem(); | ||
| 513 | if (!stralloc_0(&foo)) temp_nomem(); | ||
| 514 | if (!env_put2("DTLINE",foo.s)) temp_nomem(); | ||
| 515 | |||
| 516 | if (flagdoit) | ||
| 517 | bouncexf(); | ||
| 518 | |||
| 519 | if (!env_put2("SENDER",sender)) temp_nomem(); | ||
| 520 | |||
| 521 | if (!quote2(&foo,sender)) temp_nomem(); | ||
| 522 | if (!stralloc_copys(&rpline,"Return-Path: <")) temp_nomem(); | ||
| 523 | if (!stralloc_cat(&rpline,&foo)) temp_nomem(); | ||
| 524 | for (i = 0;i < rpline.len;++i) if (rpline.s[i] == '\n') rpline.s[i] = '_'; | ||
| 525 | if (!stralloc_cats(&rpline,">\n")) temp_nomem(); | ||
| 526 | |||
| 527 | if (!stralloc_copy(&foo,&rpline)) temp_nomem(); | ||
| 528 | if (!stralloc_0(&foo)) temp_nomem(); | ||
| 529 | if (!env_put2("RPLINE",foo.s)) temp_nomem(); | ||
| 530 | |||
| 531 | if (!stralloc_copys(&ufline,"From ")) temp_nomem(); | ||
| 532 | if (*sender) | ||
| 533 | { | ||
| 534 | int len; int i; char ch; | ||
| 535 | |||
| 536 | len = str_len(sender); | ||
| 537 | if (!stralloc_readyplus(&ufline,len)) temp_nomem(); | ||
| 538 | for (i = 0;i < len;++i) | ||
| 539 | { | ||
| 540 | ch = sender[i]; | ||
| 541 | if ((ch == ' ') || (ch == '\t') || (ch == '\n')) ch = '-'; | ||
| 542 | ufline.s[ufline.len + i] = ch; | ||
| 543 | } | ||
| 544 | ufline.len += len; | ||
| 545 | } | ||
| 546 | else | ||
| 547 | if (!stralloc_cats(&ufline,"MAILER-DAEMON")) temp_nomem(); | ||
| 548 | if (!stralloc_cats(&ufline," ")) temp_nomem(); | ||
| 549 | starttime = now(); | ||
| 550 | if (!stralloc_cats(&ufline,myctime(starttime))) temp_nomem(); | ||
| 551 | |||
| 552 | if (!stralloc_copy(&foo,&ufline)) temp_nomem(); | ||
| 553 | if (!stralloc_0(&foo)) temp_nomem(); | ||
| 554 | if (!env_put2("UFLINE",foo.s)) temp_nomem(); | ||
| 555 | |||
| 556 | x = ext; | ||
| 557 | if (!env_put2("EXT",x)) temp_nomem(); | ||
| 558 | x += str_chr(x,'-'); if (*x) ++x; | ||
| 559 | if (!env_put2("EXT2",x)) temp_nomem(); | ||
| 560 | x += str_chr(x,'-'); if (*x) ++x; | ||
| 561 | if (!env_put2("EXT3",x)) temp_nomem(); | ||
| 562 | x += str_chr(x,'-'); if (*x) ++x; | ||
| 563 | if (!env_put2("EXT4",x)) temp_nomem(); | ||
| 564 | |||
| 565 | if (!stralloc_copys(&safeext,ext)) temp_nomem(); | ||
| 566 | case_lowerb(safeext.s,safeext.len); | ||
| 567 | for (i = 0;i < safeext.len;++i) | ||
| 568 | if (safeext.s[i] == '.') | ||
| 569 | safeext.s[i] = ':'; | ||
| 570 | |||
| 571 | i = str_len(host); | ||
| 572 | i = byte_rchr(host,i,'.'); | ||
| 573 | if (!stralloc_copyb(&foo,host,i)) temp_nomem(); | ||
| 574 | if (!stralloc_0(&foo)) temp_nomem(); | ||
| 575 | if (!env_put2("HOST2",foo.s)) temp_nomem(); | ||
| 576 | i = byte_rchr(host,i,'.'); | ||
| 577 | if (!stralloc_copyb(&foo,host,i)) temp_nomem(); | ||
| 578 | if (!stralloc_0(&foo)) temp_nomem(); | ||
| 579 | if (!env_put2("HOST3",foo.s)) temp_nomem(); | ||
| 580 | i = byte_rchr(host,i,'.'); | ||
| 581 | if (!stralloc_copyb(&foo,host,i)) temp_nomem(); | ||
| 582 | if (!stralloc_0(&foo)) temp_nomem(); | ||
| 583 | if (!env_put2("HOST4",foo.s)) temp_nomem(); | ||
| 584 | |||
| 585 | flagforwardonly = 0; | ||
| 586 | qmesearch(&fd,&flagforwardonly); | ||
| 587 | if (fd == -1) | ||
| 588 | if (*dash) | ||
| 589 | strerr_die1x(100,"Sorry, no mailbox here by that name. (#5.1.1)"); | ||
| 590 | |||
| 591 | if (!stralloc_copys(&ueo,sender)) temp_nomem(); | ||
| 592 | if (str_diff(sender,"")) | ||
| 593 | if (str_diff(sender,"#@[]")) | ||
| 594 | if (qmeox("-owner") == 0) | ||
| 595 | { | ||
| 596 | if (qmeox("-owner-default") == 0) | ||
| 597 | { | ||
| 598 | if (!stralloc_copys(&ueo,local)) temp_nomem(); | ||
| 599 | if (!stralloc_cats(&ueo,"-owner-@")) temp_nomem(); | ||
| 600 | if (!stralloc_cats(&ueo,host)) temp_nomem(); | ||
| 601 | if (!stralloc_cats(&ueo,"-@[]")) temp_nomem(); | ||
| 602 | } | ||
| 603 | else | ||
| 604 | { | ||
| 605 | if (!stralloc_copys(&ueo,local)) temp_nomem(); | ||
| 606 | if (!stralloc_cats(&ueo,"-owner@")) temp_nomem(); | ||
| 607 | if (!stralloc_cats(&ueo,host)) temp_nomem(); | ||
| 608 | } | ||
| 609 | } | ||
| 610 | if (!stralloc_0(&ueo)) temp_nomem(); | ||
| 611 | if (!env_put2("NEWSENDER",ueo.s)) temp_nomem(); | ||
| 612 | |||
| 613 | if (!stralloc_ready(&cmds,0)) temp_nomem(); | ||
| 614 | cmds.len = 0; | ||
| 615 | if (fd != -1) | ||
| 616 | if (slurpclose(fd,&cmds,256) == -1) temp_nomem(); | ||
| 617 | |||
| 618 | if (!cmds.len) | ||
| 619 | { | ||
| 620 | if (!stralloc_copys(&cmds,aliasempty)) temp_nomem(); | ||
| 621 | flagforwardonly = 0; | ||
| 622 | } | ||
| 623 | if (!cmds.len || (cmds.s[cmds.len - 1] != '\n')) | ||
| 624 | if (!stralloc_cats(&cmds,"\n")) temp_nomem(); | ||
| 625 | |||
| 626 | numforward = 0; | ||
| 627 | i = 0; | ||
| 628 | for (j = 0;j < cmds.len;++j) | ||
| 629 | if (cmds.s[j] == '\n') | ||
| 630 | { | ||
| 631 | switch(cmds.s[i]) { case '#': case '.': case '/': case '|': break; | ||
| 632 | default: ++numforward; } | ||
| 633 | i = j + 1; | ||
| 634 | } | ||
| 635 | |||
| 636 | recips = (char **) alloc((numforward + 1) * sizeof(char *)); | ||
| 637 | if (!recips) temp_nomem(); | ||
| 638 | numforward = 0; | ||
| 639 | |||
| 640 | flag99 = 0; | ||
| 641 | |||
| 642 | i = 0; | ||
| 643 | for (j = 0;j < cmds.len;++j) | ||
| 644 | if (cmds.s[j] == '\n') | ||
| 645 | { | ||
| 646 | cmds.s[j] = 0; | ||
| 647 | k = j; | ||
| 648 | while ((k > i) && (cmds.s[k - 1] == ' ') || (cmds.s[k - 1] == '\t')) | ||
| 649 | cmds.s[--k] = 0; | ||
| 650 | switch(cmds.s[i]) | ||
| 651 | { | ||
| 652 | case 0: /* k == i */ | ||
| 653 | if (i) break; | ||
| 654 | strerr_die1x(111,"Uh-oh: first line of .qmail file is blank. (#4.2.1)"); | ||
| 655 | case '#': | ||
| 656 | break; | ||
| 657 | case '.': | ||
| 658 | case '/': | ||
| 659 | ++count_file; | ||
| 660 | if (flagforwardonly) strerr_die1x(111,"Uh-oh: .qmail has file delivery but has x bit set. (#4.7.0)"); | ||
| 661 | if (cmds.s[k - 1] == '/') | ||
| 662 | if (flagdoit) maildir(cmds.s + i); | ||
| 663 | else sayit("maildir ",cmds.s + i,k - i); | ||
| 664 | else | ||
| 665 | if (flagdoit) mailfile(cmds.s + i); | ||
| 666 | else sayit("mbox ",cmds.s + i,k - i); | ||
| 667 | break; | ||
| 668 | case '|': | ||
| 669 | ++count_program; | ||
| 670 | if (flagforwardonly) strerr_die1x(111,"Uh-oh: .qmail has prog delivery but has x bit set. (#4.7.0)"); | ||
| 671 | if (flagdoit) mailprogram(cmds.s + i + 1); | ||
| 672 | else sayit("program ",cmds.s + i + 1,k - i - 1); | ||
| 673 | break; | ||
| 674 | case '+': | ||
| 675 | if (str_equal(cmds.s + i + 1,"list")) | ||
| 676 | flagforwardonly = 1; | ||
| 677 | break; | ||
| 678 | case '&': | ||
| 679 | ++i; | ||
| 680 | default: | ||
| 681 | ++count_forward; | ||
| 682 | if (flagdoit) recips[numforward++] = cmds.s + i; | ||
| 683 | else sayit("forward ",cmds.s + i,k - i); | ||
| 684 | break; | ||
| 685 | } | ||
| 686 | i = j + 1; | ||
| 687 | if (flag99) break; | ||
| 688 | } | ||
| 689 | |||
| 690 | if (numforward) if (flagdoit) | ||
| 691 | { | ||
| 692 | recips[numforward] = 0; | ||
| 693 | mailforward(recips); | ||
| 694 | } | ||
| 695 | |||
| 696 | count_print(); | ||
| 697 | _exit(0); | ||
| 698 | } | ||
diff --git a/qmail-log.5 b/qmail-log.5 new file mode 100644 index 0000000..98cef63 --- /dev/null +++ b/qmail-log.5 | |||
| @@ -0,0 +1,261 @@ | |||
| 1 | .TH qmail-log 5 | ||
| 2 | .SH NAME | ||
| 3 | qmail-log \- the qmail activity record | ||
| 4 | .SH DESCRIPTION | ||
| 5 | .B qmail-send | ||
| 6 | prints a series of lines describing its activities. | ||
| 7 | Each possible line is described below. | ||
| 8 | .SH "STATUS" | ||
| 9 | .TP | ||
| 10 | .B status: local \fIl\fB/\fIL\fB remote \fIr\fB/\fIR\fB ... | ||
| 11 | .B qmail-send | ||
| 12 | is waiting for | ||
| 13 | .I l | ||
| 14 | local deliveries | ||
| 15 | and | ||
| 16 | .I r | ||
| 17 | remote deliveries. | ||
| 18 | The concurrency limits are | ||
| 19 | .I L | ||
| 20 | and | ||
| 21 | .IR R . | ||
| 22 | .TP | ||
| 23 | .B status: exiting | ||
| 24 | .B qmail-send | ||
| 25 | is done. | ||
| 26 | .SH "FATAL PROBLEMS" | ||
| 27 | .TP | ||
| 28 | .B alert: cannot start: ... | ||
| 29 | .B qmail-send | ||
| 30 | is unable to prepare itself for delivering messages; | ||
| 31 | it is giving up. | ||
| 32 | This normally indicates a serious configuration error, | ||
| 33 | but it can be caused by a temporary lack of resources. | ||
| 34 | .TP | ||
| 35 | .B alert: oh no! lost ... | ||
| 36 | One of the other daemons has died. | ||
| 37 | .B qmail-send | ||
| 38 | will exit as soon as possible. | ||
| 39 | .SH "SERIOUS PROBLEMS" | ||
| 40 | .TP | ||
| 41 | .B alert: unable to append to bounce message... | ||
| 42 | .B qmail-send | ||
| 43 | is unable to record a permanent failure, | ||
| 44 | usually because the disk is full. | ||
| 45 | This is a very serious problem; | ||
| 46 | .B qmail-send | ||
| 47 | cannot proceed without recording the results. | ||
| 48 | It will try again in ten seconds. | ||
| 49 | .TP | ||
| 50 | .B alert: out of memory... | ||
| 51 | .B qmail-send | ||
| 52 | tried to allocate more memory and failed. | ||
| 53 | It will try again in ten seconds. | ||
| 54 | .TP | ||
| 55 | .B alert: unable to opendir... | ||
| 56 | .B qmail-send | ||
| 57 | is having trouble reading a file list from disk, | ||
| 58 | usually because the system's file descriptor table is full, | ||
| 59 | but possibly because permissions are set incorrectly. | ||
| 60 | It will try again in ten seconds. | ||
| 61 | .TP | ||
| 62 | .B alert: unable to switch back... | ||
| 63 | .B qmail-send | ||
| 64 | was sent SIGHUP, | ||
| 65 | and it is unable to reenter the queue directory. | ||
| 66 | This is a very serious problem; | ||
| 67 | .B qmail-send | ||
| 68 | cannot proceed outside the queue directory. | ||
| 69 | It will try again in ten seconds. | ||
| 70 | .TP | ||
| 71 | .B alert: unable to reread... | ||
| 72 | .B qmail-send | ||
| 73 | was sent SIGHUP, | ||
| 74 | but it is unable to read the new controls. | ||
| 75 | It will continue operating with the original controls. | ||
| 76 | .SH "MESSAGES" | ||
| 77 | .TP | ||
| 78 | .B new msg \fIm\fB | ||
| 79 | .B qmail-send | ||
| 80 | is going to preprocess a queued message. | ||
| 81 | The message number, | ||
| 82 | .IR m , | ||
| 83 | is its disk inode number. | ||
| 84 | After a message is removed from the queue, | ||
| 85 | its number can be reused immediately. | ||
| 86 | .TP | ||
| 87 | .B info msg \fIm\fB: bytes \fIb\fB from <\fIs\fB> qp \fIq\fB uid \fIu\fB | ||
| 88 | Message | ||
| 89 | .I m | ||
| 90 | contains | ||
| 91 | .I b | ||
| 92 | bytes; | ||
| 93 | its envelope sender is | ||
| 94 | .IR s ; | ||
| 95 | it was queued by a user with user ID | ||
| 96 | .IR u . | ||
| 97 | .I q | ||
| 98 | is a long-term queue identifier, | ||
| 99 | the process ID of the | ||
| 100 | .B qmail-queue | ||
| 101 | that queued the message. | ||
| 102 | .TP | ||
| 103 | .B bounce msg \fIm\fB qp \fIq\fB | ||
| 104 | Message | ||
| 105 | .I m | ||
| 106 | had some delivery failures. | ||
| 107 | The long-term queue identifier of the bounce (or double-bounce) message | ||
| 108 | is | ||
| 109 | .IR q . | ||
| 110 | .TP | ||
| 111 | .B triple bounce: discarding ... | ||
| 112 | Message | ||
| 113 | .I m | ||
| 114 | had some delivery failures, | ||
| 115 | but it is already a double-bounce message, | ||
| 116 | so it must be thrown away. | ||
| 117 | Triple-bounce messages do not exist. | ||
| 118 | .TP | ||
| 119 | .B end msg \fIm\fB | ||
| 120 | .B qmail-send | ||
| 121 | is about to remove | ||
| 122 | message | ||
| 123 | .I m | ||
| 124 | from the queue. | ||
| 125 | .SH "DELIVERIES" | ||
| 126 | .TP | ||
| 127 | .B starting delivery \fId\fB: msg \fIm\fB to ... | ||
| 128 | .B qmail-send | ||
| 129 | is telling | ||
| 130 | .B qmail-lspawn | ||
| 131 | or | ||
| 132 | .B qmail-rspawn | ||
| 133 | to deliver message | ||
| 134 | .I m | ||
| 135 | to one recipient. | ||
| 136 | The delivery number, | ||
| 137 | .IR d , | ||
| 138 | starts at 1 and increases by 1 for each new delivery. | ||
| 139 | .TP | ||
| 140 | .B delivery \fId\fB: success: ... | ||
| 141 | Delivery | ||
| 142 | .I d | ||
| 143 | was successful. | ||
| 144 | .TP | ||
| 145 | .B delivery \fId\fB: failure: ... | ||
| 146 | Delivery | ||
| 147 | .I d | ||
| 148 | failed permanently. | ||
| 149 | The message will bounce. | ||
| 150 | .TP | ||
| 151 | .B delivery \fId\fB: deferral: ... | ||
| 152 | Delivery | ||
| 153 | .I d | ||
| 154 | failed temporarily. | ||
| 155 | This recipient will be retried later. | ||
| 156 | .TP | ||
| 157 | .B delivery \fId\fB: report mangled, will defer | ||
| 158 | There is a serious bug in | ||
| 159 | .B qmail-lspawn | ||
| 160 | or | ||
| 161 | .BR qmail-rspawn . | ||
| 162 | This recipient will be retried later. | ||
| 163 | .SH "WARNINGS" | ||
| 164 | .TP | ||
| 165 | .B internal error: delivery report out of range | ||
| 166 | .B qmail-lspawn | ||
| 167 | or | ||
| 168 | .B qmail-rspawn | ||
| 169 | has supplied a report on a nonexistent delivery. | ||
| 170 | This is a serious bug. | ||
| 171 | .TP | ||
| 172 | .B qmail-clean unable to clean up ... | ||
| 173 | For some reason | ||
| 174 | .B qmail-clean | ||
| 175 | is unable to remove the indicated file. | ||
| 176 | It will try again later. | ||
| 177 | .TP | ||
| 178 | .B trouble fsyncing ... | ||
| 179 | .B qmail-send | ||
| 180 | was unable to write to disk the results of preprocessing a queued message. | ||
| 181 | It will try again later. | ||
| 182 | .TP | ||
| 183 | .B trouble in select | ||
| 184 | There is an operating system bug. | ||
| 185 | .TP | ||
| 186 | .B trouble injecting bounce message... | ||
| 187 | .B qmail-send | ||
| 188 | was unable to queue a bounce message, | ||
| 189 | usually because the disk is full. | ||
| 190 | It will try again later. | ||
| 191 | .TP | ||
| 192 | .B trouble marking ... | ||
| 193 | .B qmail-send | ||
| 194 | was unable to record the result of a successful or permanently | ||
| 195 | unsuccessful delivery. | ||
| 196 | This means that the delivery will be tried again later. | ||
| 197 | .TP | ||
| 198 | .B trouble opening ... | ||
| 199 | .B qmail-send | ||
| 200 | was unable to open the list of local or remote recipients | ||
| 201 | for a message. | ||
| 202 | It will try again later. | ||
| 203 | .TP | ||
| 204 | .B trouble reading ... | ||
| 205 | Either | ||
| 206 | .B qmail-send | ||
| 207 | is unable to read a recipient list, | ||
| 208 | or it is unable to read the envelope of a queued | ||
| 209 | message, or it is out of memory. | ||
| 210 | Whatever it was doing, it will try again later. | ||
| 211 | .TP | ||
| 212 | .B trouble writing to ... | ||
| 213 | .B qmail-send | ||
| 214 | was unable to preprocess a queued message, | ||
| 215 | usually because the disk is full. | ||
| 216 | It will try again later. | ||
| 217 | .TP | ||
| 218 | .B unable to create ... | ||
| 219 | .B qmail-send | ||
| 220 | was unable to preprocess a queued message, | ||
| 221 | usually because the disk is out of inodes. | ||
| 222 | It will try again later. | ||
| 223 | .TP | ||
| 224 | .B unable to open ... | ||
| 225 | .B qmail-send | ||
| 226 | is unable to read the envelope of a queued message | ||
| 227 | for preprocessing. | ||
| 228 | It will try again later. | ||
| 229 | .TP | ||
| 230 | .B unable to start qmail-queue... | ||
| 231 | .B qmail-send | ||
| 232 | is unable to queue a bounce message, | ||
| 233 | usually because the machine is almost out of memory. | ||
| 234 | It will try again later. | ||
| 235 | .TP | ||
| 236 | .B unable to stat ... | ||
| 237 | .B qmail-send | ||
| 238 | is unable to obtain information about a file that should exist. | ||
| 239 | It will try again later. | ||
| 240 | .TP | ||
| 241 | .B unable to unlink ... | ||
| 242 | .B qmail-send | ||
| 243 | is unable to remove a file. | ||
| 244 | It will try again later. | ||
| 245 | .TP | ||
| 246 | .B unable to utime ... | ||
| 247 | .B qmail-send | ||
| 248 | is about to exit, | ||
| 249 | and it is unable to record on disk | ||
| 250 | the next scheduled delivery time for a message. | ||
| 251 | The message will be retried as soon as | ||
| 252 | .B qmail-send | ||
| 253 | is restarted. | ||
| 254 | .TP | ||
| 255 | .B unknown record type in ... | ||
| 256 | There is a serious bug in either | ||
| 257 | .B qmail-queue | ||
| 258 | or | ||
| 259 | .BR qmail-send . | ||
| 260 | .SH "SEE ALSO" | ||
| 261 | qmail-send(8) | ||
diff --git a/qmail-lspawn.8 b/qmail-lspawn.8 new file mode 100644 index 0000000..da01741 --- /dev/null +++ b/qmail-lspawn.8 | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | .TH qmail-lspawn 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-lspawn \- schedule local deliveries | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-lspawn | ||
| 6 | .I defaultdelivery | ||
| 7 | .SH DESCRIPTION | ||
| 8 | .B qmail-lspawn | ||
| 9 | reads a series of local delivery commands from descriptor 0, | ||
| 10 | invokes | ||
| 11 | .B qmail-local | ||
| 12 | to perform the deliveries, | ||
| 13 | and prints the results to descriptor 1. | ||
| 14 | It passes | ||
| 15 | .I defaultdelivery | ||
| 16 | to | ||
| 17 | .B qmail-local | ||
| 18 | as the default delivery instruction. | ||
| 19 | |||
| 20 | .B qmail-lspawn | ||
| 21 | invokes | ||
| 22 | .B qmail-local | ||
| 23 | asynchronously, | ||
| 24 | so the results may not be in the same order as the commands. | ||
| 25 | |||
| 26 | For each recipient address, | ||
| 27 | .B qmail-lspawn | ||
| 28 | finds out which local user controls that address. | ||
| 29 | It first checks the | ||
| 30 | .B qmail-users | ||
| 31 | mechanism; if the address is not listed there, it invokes | ||
| 32 | .BR qmail-getpw . | ||
| 33 | .B qmail-lspawn | ||
| 34 | then runs | ||
| 35 | .B qmail-local | ||
| 36 | under the user's uid and gid. | ||
| 37 | It does not set up any supplementary groups. | ||
| 38 | |||
| 39 | .B qmail-lspawn | ||
| 40 | treats an empty mailbox name as a trash address. | ||
| 41 | .SH "SEE ALSO" | ||
| 42 | envelopes(5), | ||
| 43 | qmail-users(5), | ||
| 44 | qmail-getpw(8), | ||
| 45 | qmail-send(8), | ||
| 46 | qmail-local(8) | ||
diff --git a/qmail-lspawn.c b/qmail-lspawn.c new file mode 100644 index 0000000..5109cc3 --- /dev/null +++ b/qmail-lspawn.c | |||
| @@ -0,0 +1,234 @@ | |||
| 1 | #include "fd.h" | ||
| 2 | #include "wait.h" | ||
| 3 | #include "prot.h" | ||
| 4 | #include "substdio.h" | ||
| 5 | #include "stralloc.h" | ||
| 6 | #include "scan.h" | ||
| 7 | #include "exit.h" | ||
| 8 | #include "fork.h" | ||
| 9 | #include "error.h" | ||
| 10 | #include "cdb.h" | ||
| 11 | #include "case.h" | ||
| 12 | #include "slurpclose.h" | ||
| 13 | #include "auto_qmail.h" | ||
| 14 | #include "auto_uids.h" | ||
| 15 | #include "qlx.h" | ||
| 16 | |||
| 17 | char *aliasempty; | ||
| 18 | |||
| 19 | void initialize(argc,argv) | ||
| 20 | int argc; | ||
| 21 | char **argv; | ||
| 22 | { | ||
| 23 | aliasempty = argv[1]; | ||
| 24 | if (!aliasempty) _exit(100); | ||
| 25 | } | ||
| 26 | |||
| 27 | int truncreport = 3000; | ||
| 28 | |||
| 29 | void report(ss,wstat,s,len) | ||
| 30 | substdio *ss; | ||
| 31 | int wstat; | ||
| 32 | char *s; | ||
| 33 | int len; | ||
| 34 | { | ||
| 35 | int i; | ||
| 36 | if (wait_crashed(wstat)) | ||
| 37 | { substdio_puts(ss,"Zqmail-local crashed.\n"); return; } | ||
| 38 | switch(wait_exitcode(wstat)) | ||
| 39 | { | ||
| 40 | case QLX_CDB: | ||
| 41 | substdio_puts(ss,"ZTrouble reading users/cdb in qmail-lspawn.\n"); return; | ||
| 42 | case QLX_NOMEM: | ||
| 43 | substdio_puts(ss,"ZOut of memory in qmail-lspawn.\n"); return; | ||
| 44 | case QLX_SYS: | ||
| 45 | substdio_puts(ss,"ZTemporary failure in qmail-lspawn.\n"); return; | ||
| 46 | case QLX_NOALIAS: | ||
| 47 | substdio_puts(ss,"ZUnable to find alias user!\n"); return; | ||
| 48 | case QLX_ROOT: | ||
| 49 | substdio_puts(ss,"ZNot allowed to perform deliveries as root.\n"); return; | ||
| 50 | case QLX_USAGE: | ||
| 51 | substdio_puts(ss,"ZInternal qmail-lspawn bug.\n"); return; | ||
| 52 | case QLX_NFS: | ||
| 53 | substdio_puts(ss,"ZNFS failure in qmail-local.\n"); return; | ||
| 54 | case QLX_EXECHARD: | ||
| 55 | substdio_puts(ss,"DUnable to run qmail-local.\n"); return; | ||
| 56 | case QLX_EXECSOFT: | ||
| 57 | substdio_puts(ss,"ZUnable to run qmail-local.\n"); return; | ||
| 58 | case QLX_EXECPW: | ||
| 59 | substdio_puts(ss,"ZUnable to run qmail-getpw.\n"); return; | ||
| 60 | case 111: case 71: case 74: case 75: | ||
| 61 | substdio_put(ss,"Z",1); break; | ||
| 62 | case 0: | ||
| 63 | substdio_put(ss,"K",1); break; | ||
| 64 | case 100: | ||
| 65 | default: | ||
| 66 | substdio_put(ss,"D",1); break; | ||
| 67 | } | ||
| 68 | |||
| 69 | for (i = 0;i < len;++i) if (!s[i]) break; | ||
| 70 | substdio_put(ss,s,i); | ||
| 71 | } | ||
| 72 | |||
| 73 | stralloc lower = {0}; | ||
| 74 | stralloc nughde = {0}; | ||
| 75 | stralloc wildchars = {0}; | ||
| 76 | |||
| 77 | void nughde_get(local) | ||
| 78 | char *local; | ||
| 79 | { | ||
| 80 | char *(args[3]); | ||
| 81 | int pi[2]; | ||
| 82 | int gpwpid; | ||
| 83 | int gpwstat; | ||
| 84 | int r; | ||
| 85 | int fd; | ||
| 86 | int flagwild; | ||
| 87 | |||
| 88 | if (!stralloc_copys(&lower,"!")) _exit(QLX_NOMEM); | ||
| 89 | if (!stralloc_cats(&lower,local)) _exit(QLX_NOMEM); | ||
| 90 | if (!stralloc_0(&lower)) _exit(QLX_NOMEM); | ||
| 91 | case_lowerb(lower.s,lower.len); | ||
| 92 | |||
| 93 | if (!stralloc_copys(&nughde,"")) _exit(QLX_NOMEM); | ||
| 94 | |||
| 95 | fd = open_read("users/cdb"); | ||
| 96 | if (fd == -1) | ||
| 97 | if (errno != error_noent) | ||
| 98 | _exit(QLX_CDB); | ||
| 99 | |||
| 100 | if (fd != -1) | ||
| 101 | { | ||
| 102 | uint32 dlen; | ||
| 103 | unsigned int i; | ||
| 104 | |||
| 105 | r = cdb_seek(fd,"",0,&dlen); | ||
| 106 | if (r != 1) _exit(QLX_CDB); | ||
| 107 | if (!stralloc_ready(&wildchars,(unsigned int) dlen)) _exit(QLX_NOMEM); | ||
| 108 | wildchars.len = dlen; | ||
| 109 | if (cdb_bread(fd,wildchars.s,wildchars.len) == -1) _exit(QLX_CDB); | ||
| 110 | |||
| 111 | i = lower.len; | ||
| 112 | flagwild = 0; | ||
| 113 | |||
| 114 | do | ||
| 115 | { | ||
| 116 | /* i > 0 */ | ||
| 117 | if (!flagwild || (i == 1) || (byte_chr(wildchars.s,wildchars.len,lower.s[i - 1]) < wildchars.len)) | ||
| 118 | { | ||
| 119 | r = cdb_seek(fd,lower.s,i,&dlen); | ||
| 120 | if (r == -1) _exit(QLX_CDB); | ||
| 121 | if (r == 1) | ||
| 122 | { | ||
| 123 | if (!stralloc_ready(&nughde,(unsigned int) dlen)) _exit(QLX_NOMEM); | ||
| 124 | nughde.len = dlen; | ||
| 125 | if (cdb_bread(fd,nughde.s,nughde.len) == -1) _exit(QLX_CDB); | ||
| 126 | if (flagwild) | ||
| 127 | if (!stralloc_cats(&nughde,local + i - 1)) _exit(QLX_NOMEM); | ||
| 128 | if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); | ||
| 129 | close(fd); | ||
| 130 | return; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | --i; | ||
| 134 | flagwild = 1; | ||
| 135 | } | ||
| 136 | while (i); | ||
| 137 | |||
| 138 | close(fd); | ||
| 139 | } | ||
| 140 | |||
| 141 | if (pipe(pi) == -1) _exit(QLX_SYS); | ||
| 142 | args[0] = "bin/qmail-getpw"; | ||
| 143 | args[1] = local; | ||
| 144 | args[2] = 0; | ||
| 145 | switch(gpwpid = vfork()) | ||
| 146 | { | ||
| 147 | case -1: | ||
| 148 | _exit(QLX_SYS); | ||
| 149 | case 0: | ||
| 150 | if (prot_gid(auto_gidn) == -1) _exit(QLX_USAGE); | ||
| 151 | if (prot_uid(auto_uidp) == -1) _exit(QLX_USAGE); | ||
| 152 | close(pi[0]); | ||
| 153 | if (fd_move(1,pi[1]) == -1) _exit(QLX_SYS); | ||
| 154 | execv(*args,args); | ||
| 155 | _exit(QLX_EXECPW); | ||
| 156 | } | ||
| 157 | close(pi[1]); | ||
| 158 | |||
| 159 | if (slurpclose(pi[0],&nughde,128) == -1) _exit(QLX_SYS); | ||
| 160 | |||
| 161 | if (wait_pid(&gpwstat,gpwpid) != -1) | ||
| 162 | { | ||
| 163 | if (wait_crashed(gpwstat)) _exit(QLX_SYS); | ||
| 164 | if (wait_exitcode(gpwstat) != 0) _exit(wait_exitcode(gpwstat)); | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | int spawn(fdmess,fdout,s,r,at) | ||
| 169 | int fdmess; int fdout; | ||
| 170 | char *s; char *r; int at; | ||
| 171 | { | ||
| 172 | int f; | ||
| 173 | |||
| 174 | if (!(f = fork())) | ||
| 175 | { | ||
| 176 | char *(args[11]); | ||
| 177 | unsigned long u; | ||
| 178 | int n; | ||
| 179 | int uid; | ||
| 180 | int gid; | ||
| 181 | char *x; | ||
| 182 | unsigned int xlen; | ||
| 183 | |||
| 184 | r[at] = 0; | ||
| 185 | if (!r[0]) _exit(0); /* <> */ | ||
| 186 | |||
| 187 | if (chdir(auto_qmail) == -1) _exit(QLX_USAGE); | ||
| 188 | |||
| 189 | nughde_get(r); | ||
| 190 | |||
| 191 | x = nughde.s; | ||
| 192 | xlen = nughde.len; | ||
| 193 | |||
| 194 | args[0] = "bin/qmail-local"; | ||
| 195 | args[1] = "--"; | ||
| 196 | args[2] = x; | ||
| 197 | n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n; | ||
| 198 | |||
| 199 | scan_ulong(x,&u); | ||
| 200 | uid = u; | ||
| 201 | n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n; | ||
| 202 | |||
| 203 | scan_ulong(x,&u); | ||
| 204 | gid = u; | ||
| 205 | n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n; | ||
| 206 | |||
| 207 | args[3] = x; | ||
| 208 | n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n; | ||
| 209 | |||
| 210 | args[4] = r; | ||
| 211 | args[5] = x; | ||
| 212 | n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n; | ||
| 213 | |||
| 214 | args[6] = x; | ||
| 215 | n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n; | ||
| 216 | |||
| 217 | args[7] = r + at + 1; | ||
| 218 | args[8] = s; | ||
| 219 | args[9] = aliasempty; | ||
| 220 | args[10] = 0; | ||
| 221 | |||
| 222 | if (fd_move(0,fdmess) == -1) _exit(QLX_SYS); | ||
| 223 | if (fd_move(1,fdout) == -1) _exit(QLX_SYS); | ||
| 224 | if (fd_copy(2,1) == -1) _exit(QLX_SYS); | ||
| 225 | if (prot_gid(gid) == -1) _exit(QLX_USAGE); | ||
| 226 | if (prot_uid(uid) == -1) _exit(QLX_USAGE); | ||
| 227 | if (!getuid()) _exit(QLX_ROOT); | ||
| 228 | |||
| 229 | execv(*args,args); | ||
| 230 | if (error_temp(errno)) _exit(QLX_EXECSOFT); | ||
| 231 | _exit(QLX_EXECHARD); | ||
| 232 | } | ||
| 233 | return f; | ||
| 234 | } | ||
diff --git a/qmail-newmrh.9 b/qmail-newmrh.9 new file mode 100644 index 0000000..2f02f10 --- /dev/null +++ b/qmail-newmrh.9 | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | .TH qmail-newmrh 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-newmrh \- prepare morercpthosts for qmail-smtpd | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-newmrh | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B qmail-newmrh | ||
| 8 | reads the instructions in | ||
| 9 | .B QMAILHOME/control/morercpthosts | ||
| 10 | and writes them into | ||
| 11 | .B QMAILHOME/control/morercpthosts.cdb | ||
| 12 | in a binary format suited | ||
| 13 | for quick access by | ||
| 14 | .BR qmail-smtpd . | ||
| 15 | |||
| 16 | If there is a problem with | ||
| 17 | .BR control/morercpthosts , | ||
| 18 | .B qmail-newmrh | ||
| 19 | complains and leaves | ||
| 20 | .B control/morercpthosts.cdb | ||
| 21 | alone. | ||
| 22 | |||
| 23 | .B qmail-newmrh | ||
| 24 | ensures that | ||
| 25 | .B control/morercpthosts.cdb | ||
| 26 | is updated atomically, | ||
| 27 | so | ||
| 28 | .B qmail-smtpd | ||
| 29 | never has to wait for | ||
| 30 | .B qmail-newmrh | ||
| 31 | to finish. | ||
| 32 | However, | ||
| 33 | .B qmail-newmrh | ||
| 34 | makes no attempt to protect against two simultaneous updates of | ||
| 35 | .BR control/morercpthosts.cdb . | ||
| 36 | |||
| 37 | The binary | ||
| 38 | .B control/morercpthosts.cdb | ||
| 39 | format is portable across machines. | ||
| 40 | .SH "SEE ALSO" | ||
| 41 | qmail-smtpd(8) | ||
diff --git a/qmail-newmrh.c b/qmail-newmrh.c new file mode 100644 index 0000000..25a4a10 --- /dev/null +++ b/qmail-newmrh.c | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | #include "strerr.h" | ||
| 2 | #include "stralloc.h" | ||
| 3 | #include "substdio.h" | ||
| 4 | #include "getln.h" | ||
| 5 | #include "exit.h" | ||
| 6 | #include "readwrite.h" | ||
| 7 | #include "open.h" | ||
| 8 | #include "auto_qmail.h" | ||
| 9 | #include "cdbmss.h" | ||
| 10 | |||
| 11 | #define FATAL "qmail-newmrh: fatal: " | ||
| 12 | |||
| 13 | void die_read() | ||
| 14 | { | ||
| 15 | strerr_die2sys(111,FATAL,"unable to read control/morercpthosts: "); | ||
| 16 | } | ||
| 17 | void die_write() | ||
| 18 | { | ||
| 19 | strerr_die2sys(111,FATAL,"unable to write to control/morercpthosts.tmp: "); | ||
| 20 | } | ||
| 21 | |||
| 22 | char inbuf[1024]; | ||
| 23 | substdio ssin; | ||
| 24 | |||
| 25 | int fd; | ||
| 26 | int fdtemp; | ||
| 27 | |||
| 28 | struct cdbmss cdbmss; | ||
| 29 | stralloc line = {0}; | ||
| 30 | int match; | ||
| 31 | |||
| 32 | void main() | ||
| 33 | { | ||
| 34 | umask(033); | ||
| 35 | if (chdir(auto_qmail) == -1) | ||
| 36 | strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": "); | ||
| 37 | |||
| 38 | fd = open_read("control/morercpthosts"); | ||
| 39 | if (fd == -1) die_read(); | ||
| 40 | |||
| 41 | substdio_fdbuf(&ssin,read,fd,inbuf,sizeof inbuf); | ||
| 42 | |||
| 43 | fdtemp = open_trunc("control/morercpthosts.tmp"); | ||
| 44 | if (fdtemp == -1) die_write(); | ||
| 45 | |||
| 46 | if (cdbmss_start(&cdbmss,fdtemp) == -1) die_write(); | ||
| 47 | |||
| 48 | for (;;) { | ||
| 49 | if (getln(&ssin,&line,&match,'\n') != 0) die_read(); | ||
| 50 | case_lowerb(line.s,line.len); | ||
| 51 | while (line.len) { | ||
| 52 | if (line.s[line.len - 1] == ' ') { --line.len; continue; } | ||
| 53 | if (line.s[line.len - 1] == '\n') { --line.len; continue; } | ||
| 54 | if (line.s[line.len - 1] == '\t') { --line.len; continue; } | ||
| 55 | if (line.s[0] != '#') | ||
| 56 | if (cdbmss_add(&cdbmss,line.s,line.len,"",0) == -1) | ||
| 57 | die_write(); | ||
| 58 | break; | ||
| 59 | } | ||
| 60 | if (!match) break; | ||
| 61 | } | ||
| 62 | |||
| 63 | if (cdbmss_finish(&cdbmss) == -1) die_write(); | ||
| 64 | if (fsync(fdtemp) == -1) die_write(); | ||
| 65 | if (close(fdtemp) == -1) die_write(); /* NFS stupidity */ | ||
| 66 | if (rename("control/morercpthosts.tmp","control/morercpthosts.cdb") == -1) | ||
| 67 | strerr_die2sys(111,FATAL,"unable to move control/morercpthosts.tmp to control/morercpthosts.cdb"); | ||
| 68 | |||
| 69 | _exit(0); | ||
| 70 | } | ||
diff --git a/qmail-newu.9 b/qmail-newu.9 new file mode 100644 index 0000000..12f1b3f --- /dev/null +++ b/qmail-newu.9 | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | .TH qmail-newu 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-newu \- prepare address assignments for qmail-lspawn | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-newu | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B qmail-newu | ||
| 8 | reads the assignments in | ||
| 9 | .B QMAILHOME/users/assign | ||
| 10 | and writes them into | ||
| 11 | .B QMAILHOME/users/cdb | ||
| 12 | in a binary format suited | ||
| 13 | for quick access by | ||
| 14 | .BR qmail-lspawn . | ||
| 15 | |||
| 16 | If there is a problem with | ||
| 17 | .BR users/assign , | ||
| 18 | .B qmail-newu | ||
| 19 | complains and leaves | ||
| 20 | .B users/cdb | ||
| 21 | alone. | ||
| 22 | |||
| 23 | .B qmail-newu | ||
| 24 | ensures that | ||
| 25 | .B users/cdb | ||
| 26 | is updated atomically, | ||
| 27 | so | ||
| 28 | .B qmail-lspawn | ||
| 29 | never has to wait for | ||
| 30 | .B qmail-newu | ||
| 31 | to finish. | ||
| 32 | However, | ||
| 33 | .B qmail-newu | ||
| 34 | makes no attempt to protect against two simultaneous updates of | ||
| 35 | .BR users/cdb . | ||
| 36 | |||
| 37 | The binary | ||
| 38 | .B users/cdb | ||
| 39 | format is portable across machines. | ||
| 40 | .SH "SEE ALSO" | ||
| 41 | qmail-users(5), | ||
| 42 | qmail-lspawn(8), | ||
| 43 | qmail-pw2u(8) | ||
diff --git a/qmail-newu.c b/qmail-newu.c new file mode 100644 index 0000000..1f9ecc3 --- /dev/null +++ b/qmail-newu.c | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | #include "stralloc.h" | ||
| 2 | #include "subfd.h" | ||
| 3 | #include "getln.h" | ||
| 4 | #include "substdio.h" | ||
| 5 | #include "cdbmss.h" | ||
| 6 | #include "exit.h" | ||
| 7 | #include "readwrite.h" | ||
| 8 | #include "open.h" | ||
| 9 | #include "error.h" | ||
| 10 | #include "case.h" | ||
| 11 | #include "auto_qmail.h" | ||
| 12 | |||
| 13 | void die_temp() { _exit(111); } | ||
| 14 | |||
| 15 | void die_chdir() | ||
| 16 | { | ||
| 17 | substdio_putsflush(subfderr,"qmail-newu: fatal: unable to chdir\n"); | ||
| 18 | die_temp(); | ||
| 19 | } | ||
| 20 | void die_nomem() | ||
| 21 | { | ||
| 22 | substdio_putsflush(subfderr,"qmail-newu: fatal: out of memory\n"); | ||
| 23 | die_temp(); | ||
| 24 | } | ||
| 25 | void die_opena() | ||
| 26 | { | ||
| 27 | substdio_putsflush(subfderr,"qmail-newu: fatal: unable to open users/assign\n"); | ||
| 28 | die_temp(); | ||
| 29 | } | ||
| 30 | void die_reada() | ||
| 31 | { | ||
| 32 | substdio_putsflush(subfderr,"qmail-newu: fatal: unable to read users/assign\n"); | ||
| 33 | die_temp(); | ||
| 34 | } | ||
| 35 | void die_format() | ||
| 36 | { | ||
| 37 | substdio_putsflush(subfderr,"qmail-newu: fatal: bad format in users/assign\n"); | ||
| 38 | die_temp(); | ||
| 39 | } | ||
| 40 | void die_opent() | ||
| 41 | { | ||
| 42 | substdio_putsflush(subfderr,"qmail-newu: fatal: unable to open users/cdb.tmp\n"); | ||
| 43 | die_temp(); | ||
| 44 | } | ||
| 45 | void die_writet() | ||
| 46 | { | ||
| 47 | substdio_putsflush(subfderr,"qmail-newu: fatal: unable to write users/cdb.tmp\n"); | ||
| 48 | die_temp(); | ||
| 49 | } | ||
| 50 | void die_rename() | ||
| 51 | { | ||
| 52 | substdio_putsflush(subfderr,"qmail-newu: fatal: unable to move users/cdb.tmp to users/cdb\n"); | ||
| 53 | die_temp(); | ||
| 54 | } | ||
| 55 | |||
| 56 | struct cdbmss cdbmss; | ||
| 57 | stralloc key = {0}; | ||
| 58 | stralloc data = {0}; | ||
| 59 | |||
| 60 | char inbuf[1024]; | ||
| 61 | substdio ssin; | ||
| 62 | |||
| 63 | int fd; | ||
| 64 | int fdtemp; | ||
| 65 | |||
| 66 | stralloc line = {0}; | ||
| 67 | int match; | ||
| 68 | |||
| 69 | stralloc wildchars = {0}; | ||
| 70 | |||
| 71 | void main() | ||
| 72 | { | ||
| 73 | int i; | ||
| 74 | int numcolons; | ||
| 75 | |||
| 76 | umask(033); | ||
| 77 | if (chdir(auto_qmail) == -1) die_chdir(); | ||
| 78 | |||
| 79 | fd = open_read("users/assign"); | ||
| 80 | if (fd == -1) die_opena(); | ||
| 81 | |||
| 82 | substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); | ||
| 83 | |||
| 84 | fdtemp = open_trunc("users/cdb.tmp"); | ||
| 85 | if (fdtemp == -1) die_opent(); | ||
| 86 | |||
| 87 | if (cdbmss_start(&cdbmss,fdtemp) == -1) die_writet(); | ||
| 88 | |||
| 89 | if (!stralloc_copys(&wildchars,"")) die_nomem(); | ||
| 90 | |||
| 91 | for (;;) { | ||
| 92 | if (getln(&ssin,&line,&match,'\n') != 0) die_reada(); | ||
| 93 | if (line.len && (line.s[0] == '.')) break; | ||
| 94 | if (!match) die_format(); | ||
| 95 | |||
| 96 | if (byte_chr(line.s,line.len,'\0') < line.len) die_format(); | ||
| 97 | i = byte_chr(line.s,line.len,':'); | ||
| 98 | if (i == line.len) die_format(); | ||
| 99 | if (i == 0) die_format(); | ||
| 100 | if (!stralloc_copys(&key,"!")) die_nomem(); | ||
| 101 | if (line.s[0] == '+') { | ||
| 102 | if (!stralloc_catb(&key,line.s + 1,i - 1)) die_nomem(); | ||
| 103 | case_lowerb(key.s,key.len); | ||
| 104 | if (i >= 2) | ||
| 105 | if (byte_chr(wildchars.s,wildchars.len,line.s[i - 1]) == wildchars.len) | ||
| 106 | if (!stralloc_append(&wildchars,line.s + i - 1)) die_nomem(); | ||
| 107 | } | ||
| 108 | else { | ||
| 109 | if (!stralloc_catb(&key,line.s + 1,i - 1)) die_nomem(); | ||
| 110 | if (!stralloc_0(&key)) die_nomem(); | ||
| 111 | case_lowerb(key.s,key.len); | ||
| 112 | } | ||
| 113 | |||
| 114 | if (!stralloc_copyb(&data,line.s + i + 1,line.len - i - 1)) die_nomem(); | ||
| 115 | |||
| 116 | numcolons = 0; | ||
| 117 | for (i = 0;i < data.len;++i) | ||
| 118 | if (data.s[i] == ':') { | ||
| 119 | data.s[i] = 0; | ||
| 120 | if (++numcolons == 6) | ||
| 121 | break; | ||
| 122 | } | ||
| 123 | if (numcolons < 6) die_format(); | ||
| 124 | data.len = i; | ||
| 125 | |||
| 126 | if (cdbmss_add(&cdbmss,key.s,key.len,data.s,data.len) == -1) die_writet(); | ||
| 127 | } | ||
| 128 | |||
| 129 | if (cdbmss_add(&cdbmss,"",0,wildchars.s,wildchars.len) == -1) die_writet(); | ||
| 130 | |||
| 131 | if (cdbmss_finish(&cdbmss) == -1) die_writet(); | ||
| 132 | if (fsync(fdtemp) == -1) die_writet(); | ||
| 133 | if (close(fdtemp) == -1) die_writet(); /* NFS stupidity */ | ||
| 134 | if (rename("users/cdb.tmp","users/cdb") == -1) die_rename(); | ||
| 135 | |||
| 136 | _exit(0); | ||
| 137 | } | ||
diff --git a/qmail-pop3d.8 b/qmail-pop3d.8 new file mode 100644 index 0000000..de6b2ba --- /dev/null +++ b/qmail-pop3d.8 | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | .TH qmail-pop3d 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-pop3d \- distribute mail via POP | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-pop3d | ||
| 6 | .I maildirname | ||
| 7 | .SH DESCRIPTION | ||
| 8 | .B qmail-pop3d | ||
| 9 | lets a user read and delete his mail through the network. | ||
| 10 | |||
| 11 | Mail is stored in a | ||
| 12 | .B maildir | ||
| 13 | called | ||
| 14 | .IR maildirname , | ||
| 15 | normally | ||
| 16 | .BR Maildir , | ||
| 17 | in the user's home directory. | ||
| 18 | |||
| 19 | .B qmail-pop3d | ||
| 20 | is normally invoked | ||
| 21 | under | ||
| 22 | .BR qmail-popup , | ||
| 23 | which reads a username and password, | ||
| 24 | and | ||
| 25 | .BR /bin/checkpassword , | ||
| 26 | which checks the password and sets up environment variables. | ||
| 27 | |||
| 28 | .B qmail-pop3d | ||
| 29 | has a 20-minute idle timeout. | ||
| 30 | |||
| 31 | .B qmail-pop3d | ||
| 32 | supports UIDL, TOP, and LAST. | ||
| 33 | |||
| 34 | .B qmail-pop3d | ||
| 35 | appends an extra blank line to every message | ||
| 36 | to work around serious bugs in certain clients. | ||
| 37 | |||
| 38 | .B qmail-pop3d | ||
| 39 | is based on a program contributed by Russ Nelson. | ||
| 40 | .SH "SEE ALSO" | ||
| 41 | maildir(5), | ||
| 42 | qmail-local(8), | ||
| 43 | qmail-popup(8) | ||
diff --git a/qmail-pop3d.c b/qmail-pop3d.c new file mode 100644 index 0000000..51976c2 --- /dev/null +++ b/qmail-pop3d.c | |||
| @@ -0,0 +1,305 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include "commands.h" | ||
| 4 | #include "sig.h" | ||
| 5 | #include "getln.h" | ||
| 6 | #include "stralloc.h" | ||
| 7 | #include "substdio.h" | ||
| 8 | #include "alloc.h" | ||
| 9 | #include "open.h" | ||
| 10 | #include "prioq.h" | ||
| 11 | #include "scan.h" | ||
| 12 | #include "fmt.h" | ||
| 13 | #include "str.h" | ||
| 14 | #include "exit.h" | ||
| 15 | #include "maildir.h" | ||
| 16 | #include "readwrite.h" | ||
| 17 | #include "timeoutread.h" | ||
| 18 | #include "timeoutwrite.h" | ||
| 19 | |||
| 20 | void die() { _exit(0); } | ||
| 21 | |||
| 22 | int saferead(fd,buf,len) int fd; char *buf; int len; | ||
| 23 | { | ||
| 24 | int r; | ||
| 25 | r = timeoutread(1200,fd,buf,len); | ||
| 26 | if (r <= 0) die(); | ||
| 27 | return r; | ||
| 28 | } | ||
| 29 | |||
| 30 | int safewrite(fd,buf,len) int fd; char *buf; int len; | ||
| 31 | { | ||
| 32 | int r; | ||
| 33 | r = timeoutwrite(1200,fd,buf,len); | ||
| 34 | if (r <= 0) die(); | ||
| 35 | return r; | ||
| 36 | } | ||
| 37 | |||
| 38 | char ssoutbuf[1024]; | ||
| 39 | substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf); | ||
| 40 | |||
| 41 | char ssinbuf[128]; | ||
| 42 | substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf); | ||
| 43 | |||
| 44 | void put(buf,len) char *buf; int len; | ||
| 45 | { | ||
| 46 | substdio_put(&ssout,buf,len); | ||
| 47 | } | ||
| 48 | void puts(s) char *s; | ||
| 49 | { | ||
| 50 | substdio_puts(&ssout,s); | ||
| 51 | } | ||
| 52 | void flush() | ||
| 53 | { | ||
| 54 | substdio_flush(&ssout); | ||
| 55 | } | ||
| 56 | void err(s) char *s; | ||
| 57 | { | ||
| 58 | puts("-ERR "); | ||
| 59 | puts(s); | ||
| 60 | puts("\r\n"); | ||
| 61 | flush(); | ||
| 62 | } | ||
| 63 | |||
| 64 | void die_nomem() { err("out of memory"); die(); } | ||
| 65 | void die_nomaildir() { err("this user has no $HOME/Maildir"); die(); } | ||
| 66 | void die_scan() { err("unable to scan $HOME/Maildir"); die(); } | ||
| 67 | |||
| 68 | void err_syntax() { err("syntax error"); } | ||
| 69 | void err_unimpl() { err("unimplemented"); } | ||
| 70 | void err_deleted() { err("already deleted"); } | ||
| 71 | void err_nozero() { err("messages are counted from 1"); } | ||
| 72 | void err_toobig() { err("not that many messages"); } | ||
| 73 | void err_nosuch() { err("unable to open that message"); } | ||
| 74 | void err_nounlink() { err("unable to unlink all deleted messages"); } | ||
| 75 | |||
| 76 | void okay() { puts("+OK \r\n"); flush(); } | ||
| 77 | |||
| 78 | void printfn(fn) char *fn; | ||
| 79 | { | ||
| 80 | fn += 4; | ||
| 81 | put(fn,str_chr(fn,':')); | ||
| 82 | } | ||
| 83 | |||
| 84 | char strnum[FMT_ULONG]; | ||
| 85 | stralloc line = {0}; | ||
| 86 | |||
| 87 | void blast(ssfrom,limit) | ||
| 88 | substdio *ssfrom; | ||
| 89 | unsigned long limit; | ||
| 90 | { | ||
| 91 | int match; | ||
| 92 | int inheaders = 1; | ||
| 93 | |||
| 94 | for (;;) { | ||
| 95 | if (getln(ssfrom,&line,&match,'\n') != 0) die(); | ||
| 96 | if (!match && !line.len) break; | ||
| 97 | if (match) --line.len; /* no way to pass this info over POP */ | ||
| 98 | if (limit) if (!inheaders) if (!--limit) break; | ||
| 99 | if (!line.len) | ||
| 100 | inheaders = 0; | ||
| 101 | else | ||
| 102 | if (line.s[0] == '.') | ||
| 103 | put(".",1); | ||
| 104 | put(line.s,line.len); | ||
| 105 | put("\r\n",2); | ||
| 106 | if (!match) break; | ||
| 107 | } | ||
| 108 | put("\r\n.\r\n",5); | ||
| 109 | flush(); | ||
| 110 | } | ||
| 111 | |||
| 112 | stralloc filenames = {0}; | ||
| 113 | prioq pq = {0}; | ||
| 114 | |||
| 115 | struct message { | ||
| 116 | int flagdeleted; | ||
| 117 | unsigned long size; | ||
| 118 | char *fn; | ||
| 119 | } *m; | ||
| 120 | int numm; | ||
| 121 | |||
| 122 | int last = 0; | ||
| 123 | |||
| 124 | void getlist() | ||
| 125 | { | ||
| 126 | struct prioq_elt pe; | ||
| 127 | struct stat st; | ||
| 128 | int i; | ||
| 129 | |||
| 130 | maildir_clean(&line); | ||
| 131 | if (maildir_scan(&pq,&filenames,1,1) == -1) die_scan(); | ||
| 132 | |||
| 133 | numm = pq.p ? pq.len : 0; | ||
| 134 | m = (struct message *) alloc(numm * sizeof(struct message)); | ||
| 135 | if (!m) die_nomem(); | ||
| 136 | |||
| 137 | for (i = 0;i < numm;++i) { | ||
| 138 | if (!prioq_min(&pq,&pe)) { numm = i; break; } | ||
| 139 | prioq_delmin(&pq); | ||
| 140 | m[i].fn = filenames.s + pe.id; | ||
| 141 | m[i].flagdeleted = 0; | ||
| 142 | if (stat(m[i].fn,&st) == -1) | ||
| 143 | m[i].size = 0; | ||
| 144 | else | ||
| 145 | m[i].size = st.st_size; | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | void pop3_stat() | ||
| 150 | { | ||
| 151 | int i; | ||
| 152 | unsigned long total; | ||
| 153 | |||
| 154 | total = 0; | ||
| 155 | for (i = 0;i < numm;++i) if (!m[i].flagdeleted) total += m[i].size; | ||
| 156 | puts("+OK "); | ||
| 157 | put(strnum,fmt_uint(strnum,numm)); | ||
| 158 | puts(" "); | ||
| 159 | put(strnum,fmt_ulong(strnum,total)); | ||
| 160 | puts("\r\n"); | ||
| 161 | flush(); | ||
| 162 | } | ||
| 163 | |||
| 164 | void pop3_rset() | ||
| 165 | { | ||
| 166 | int i; | ||
| 167 | for (i = 0;i < numm;++i) m[i].flagdeleted = 0; | ||
| 168 | last = 0; | ||
| 169 | okay(); | ||
| 170 | } | ||
| 171 | |||
| 172 | void pop3_last() | ||
| 173 | { | ||
| 174 | puts("+OK "); | ||
| 175 | put(strnum,fmt_uint(strnum,last)); | ||
| 176 | puts("\r\n"); | ||
| 177 | flush(); | ||
| 178 | } | ||
| 179 | |||
| 180 | void pop3_quit() | ||
| 181 | { | ||
| 182 | int i; | ||
| 183 | for (i = 0;i < numm;++i) | ||
| 184 | if (m[i].flagdeleted) { | ||
| 185 | if (unlink(m[i].fn) == -1) err_nounlink(); | ||
| 186 | } | ||
| 187 | else | ||
| 188 | if (str_start(m[i].fn,"new/")) { | ||
| 189 | if (!stralloc_copys(&line,"cur/")) die_nomem(); | ||
| 190 | if (!stralloc_cats(&line,m[i].fn + 4)) die_nomem(); | ||
| 191 | if (!stralloc_cats(&line,":2,")) die_nomem(); | ||
| 192 | if (!stralloc_0(&line)) die_nomem(); | ||
| 193 | rename(m[i].fn,line.s); /* if it fails, bummer */ | ||
| 194 | } | ||
| 195 | okay(); | ||
| 196 | die(); | ||
| 197 | } | ||
| 198 | |||
| 199 | int msgno(arg) char *arg; | ||
| 200 | { | ||
| 201 | unsigned long u; | ||
| 202 | if (!scan_ulong(arg,&u)) { err_syntax(); return -1; } | ||
| 203 | if (!u) { err_nozero(); return -1; } | ||
| 204 | --u; | ||
| 205 | if (u >= numm) { err_toobig(); return -1; } | ||
| 206 | if (m[u].flagdeleted) { err_deleted(); return -1; } | ||
| 207 | return u; | ||
| 208 | } | ||
| 209 | |||
| 210 | void pop3_dele(arg) char *arg; | ||
| 211 | { | ||
| 212 | int i; | ||
| 213 | i = msgno(arg); | ||
| 214 | if (i == -1) return; | ||
| 215 | m[i].flagdeleted = 1; | ||
| 216 | if (i + 1 > last) last = i + 1; | ||
| 217 | okay(); | ||
| 218 | } | ||
| 219 | |||
| 220 | void list(i,flaguidl) | ||
| 221 | int i; | ||
| 222 | int flaguidl; | ||
| 223 | { | ||
| 224 | put(strnum,fmt_uint(strnum,i + 1)); | ||
| 225 | puts(" "); | ||
| 226 | if (flaguidl) printfn(m[i].fn); | ||
| 227 | else put(strnum,fmt_ulong(strnum,m[i].size)); | ||
| 228 | puts("\r\n"); | ||
| 229 | } | ||
| 230 | |||
| 231 | void dolisting(arg,flaguidl) char *arg; int flaguidl; | ||
| 232 | { | ||
| 233 | unsigned int i; | ||
| 234 | if (*arg) { | ||
| 235 | i = msgno(arg); | ||
| 236 | if (i == -1) return; | ||
| 237 | puts("+OK "); | ||
| 238 | list(i,flaguidl); | ||
| 239 | } | ||
| 240 | else { | ||
| 241 | okay(); | ||
| 242 | for (i = 0;i < numm;++i) | ||
| 243 | if (!m[i].flagdeleted) | ||
| 244 | list(i,flaguidl); | ||
| 245 | puts(".\r\n"); | ||
| 246 | } | ||
| 247 | flush(); | ||
| 248 | } | ||
| 249 | |||
| 250 | void pop3_uidl(arg) char *arg; { dolisting(arg,1); } | ||
| 251 | void pop3_list(arg) char *arg; { dolisting(arg,0); } | ||
| 252 | |||
| 253 | substdio ssmsg; char ssmsgbuf[1024]; | ||
| 254 | |||
| 255 | void pop3_top(arg) char *arg; | ||
| 256 | { | ||
| 257 | int i; | ||
| 258 | unsigned long limit; | ||
| 259 | int fd; | ||
| 260 | |||
| 261 | i = msgno(arg); | ||
| 262 | if (i == -1) return; | ||
| 263 | |||
| 264 | arg += scan_ulong(arg,&limit); | ||
| 265 | while (*arg == ' ') ++arg; | ||
| 266 | if (scan_ulong(arg,&limit)) ++limit; else limit = 0; | ||
| 267 | |||
| 268 | fd = open_read(m[i].fn); | ||
| 269 | if (fd == -1) { err_nosuch(); return; } | ||
| 270 | okay(); | ||
| 271 | substdio_fdbuf(&ssmsg,read,fd,ssmsgbuf,sizeof(ssmsgbuf)); | ||
| 272 | blast(&ssmsg,limit); | ||
| 273 | close(fd); | ||
| 274 | } | ||
| 275 | |||
| 276 | struct commands pop3commands[] = { | ||
| 277 | { "quit", pop3_quit, 0 } | ||
| 278 | , { "stat", pop3_stat, 0 } | ||
| 279 | , { "list", pop3_list, 0 } | ||
| 280 | , { "uidl", pop3_uidl, 0 } | ||
| 281 | , { "dele", pop3_dele, 0 } | ||
| 282 | , { "retr", pop3_top, 0 } | ||
| 283 | , { "rset", pop3_rset, 0 } | ||
| 284 | , { "last", pop3_last, 0 } | ||
| 285 | , { "top", pop3_top, 0 } | ||
| 286 | , { "noop", okay, 0 } | ||
| 287 | , { 0, err_unimpl, 0 } | ||
| 288 | } ; | ||
| 289 | |||
| 290 | void main(argc,argv) | ||
| 291 | int argc; | ||
| 292 | char **argv; | ||
| 293 | { | ||
| 294 | sig_alarmcatch(die); | ||
| 295 | sig_pipeignore(); | ||
| 296 | |||
| 297 | if (!argv[1]) die_nomaildir(); | ||
| 298 | if (chdir(argv[1]) == -1) die_nomaildir(); | ||
| 299 | |||
| 300 | getlist(); | ||
| 301 | |||
| 302 | okay(); | ||
| 303 | commands(&ssin,pop3commands); | ||
| 304 | die(); | ||
| 305 | } | ||
diff --git a/qmail-popup.8 b/qmail-popup.8 new file mode 100644 index 0000000..95f01bc --- /dev/null +++ b/qmail-popup.8 | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | .TH qmail-popup 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-popup \- read a POP username and password | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-popup | ||
| 6 | .I hostname | ||
| 7 | .I subprogram | ||
| 8 | .SH DESCRIPTION | ||
| 9 | .B qmail-popup | ||
| 10 | reads a POP username and password from the network. | ||
| 11 | It then runs | ||
| 12 | .IR subprogram . | ||
| 13 | |||
| 14 | .B qmail-popup | ||
| 15 | is most commonly invoked from | ||
| 16 | .B inetd | ||
| 17 | as | ||
| 18 | |||
| 19 | .EX | ||
| 20 | qmail-popup CHANGEME checkpassword qmail-pop3d Maildir | ||
| 21 | .EE | ||
| 22 | |||
| 23 | with | ||
| 24 | CHANGEME | ||
| 25 | replaced by the fully qualified domain name of the local host. | ||
| 26 | |||
| 27 | .B qmail-popup | ||
| 28 | expects descriptor 0 to read from the network | ||
| 29 | and descriptor 1 to write to the network. | ||
| 30 | It reads a username and password from descriptor 0 | ||
| 31 | in POP's USER-PASS style or APOP style. | ||
| 32 | It invokes | ||
| 33 | .IR subprogram , | ||
| 34 | with the same descriptors 0 and 1; | ||
| 35 | descriptor 2 writing to the network; | ||
| 36 | and descriptor 3 reading the username, a 0 byte, the password, | ||
| 37 | another 0 byte, | ||
| 38 | an APOP timestamp derived from | ||
| 39 | .IR hostname , | ||
| 40 | and a final 0 byte. | ||
| 41 | .B qmail-popup | ||
| 42 | then waits for | ||
| 43 | .I subprogram | ||
| 44 | to finish. | ||
| 45 | It prints an error message if | ||
| 46 | .I subprogram | ||
| 47 | crashes or exits nonzero. | ||
| 48 | |||
| 49 | .B qmail-popup | ||
| 50 | should be used only within | ||
| 51 | a secure network. | ||
| 52 | Otherwise an eavesdropper can steal passwords. | ||
| 53 | Even if you use APOP, | ||
| 54 | an active attacker can still take over the connection | ||
| 55 | and wreak havoc. | ||
| 56 | |||
| 57 | .B qmail-popup | ||
| 58 | has a 20-minute idle timeout. | ||
| 59 | |||
| 60 | .B qmail-popup | ||
| 61 | is based on a program contributed by Russ Nelson. | ||
| 62 | .SH "SEE ALSO" | ||
| 63 | maildir(5), | ||
| 64 | qmail-local(8), | ||
| 65 | qmail-pop3d(8) | ||
diff --git a/qmail-popup.c b/qmail-popup.c new file mode 100644 index 0000000..fbcc99b --- /dev/null +++ b/qmail-popup.c | |||
| @@ -0,0 +1,183 @@ | |||
| 1 | #include "commands.h" | ||
| 2 | #include "fd.h" | ||
| 3 | #include "sig.h" | ||
| 4 | #include "stralloc.h" | ||
| 5 | #include "substdio.h" | ||
| 6 | #include "alloc.h" | ||
| 7 | #include "wait.h" | ||
| 8 | #include "str.h" | ||
| 9 | #include "byte.h" | ||
| 10 | #include "now.h" | ||
| 11 | #include "fmt.h" | ||
| 12 | #include "exit.h" | ||
| 13 | #include "readwrite.h" | ||
| 14 | #include "timeoutread.h" | ||
| 15 | #include "timeoutwrite.h" | ||
| 16 | |||
| 17 | void die() { _exit(1); } | ||
| 18 | |||
| 19 | int saferead(fd,buf,len) int fd; char *buf; int len; | ||
| 20 | { | ||
| 21 | int r; | ||
| 22 | r = timeoutread(1200,fd,buf,len); | ||
| 23 | if (r <= 0) die(); | ||
| 24 | return r; | ||
| 25 | } | ||
| 26 | |||
| 27 | int safewrite(fd,buf,len) int fd; char *buf; int len; | ||
| 28 | { | ||
| 29 | int r; | ||
| 30 | r = timeoutwrite(1200,fd,buf,len); | ||
| 31 | if (r <= 0) die(); | ||
| 32 | return r; | ||
| 33 | } | ||
| 34 | |||
| 35 | char ssoutbuf[128]; | ||
| 36 | substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf); | ||
| 37 | |||
| 38 | char ssinbuf[128]; | ||
| 39 | substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf); | ||
| 40 | |||
| 41 | void puts(s) char *s; | ||
| 42 | { | ||
| 43 | substdio_puts(&ssout,s); | ||
| 44 | } | ||
| 45 | void flush() | ||
| 46 | { | ||
| 47 | substdio_flush(&ssout); | ||
| 48 | } | ||
| 49 | void err(s) char *s; | ||
| 50 | { | ||
| 51 | puts("-ERR "); | ||
| 52 | puts(s); | ||
| 53 | puts("\r\n"); | ||
| 54 | flush(); | ||
| 55 | } | ||
| 56 | |||
| 57 | void die_usage() { err("usage: popup hostname subprogram"); die(); } | ||
| 58 | void die_nomem() { err("out of memory"); die(); } | ||
| 59 | void die_pipe() { err("unable to open pipe"); die(); } | ||
| 60 | void die_write() { err("unable to write pipe"); die(); } | ||
| 61 | void die_fork() { err("unable to fork"); die(); } | ||
| 62 | void die_childcrashed() { err("aack, child crashed"); } | ||
| 63 | void die_badauth() { err("authorization failed"); } | ||
| 64 | |||
| 65 | void err_syntax() { err("syntax error"); } | ||
| 66 | void err_wantuser() { err("USER first"); } | ||
| 67 | void err_authoriz() { err("authorization first"); } | ||
| 68 | |||
| 69 | void okay() { puts("+OK \r\n"); flush(); } | ||
| 70 | void pop3_quit() { okay(); die(); } | ||
| 71 | |||
| 72 | |||
| 73 | char unique[FMT_ULONG + FMT_ULONG + 3]; | ||
| 74 | char *hostname; | ||
| 75 | stralloc username = {0}; | ||
| 76 | int seenuser = 0; | ||
| 77 | char **childargs; | ||
| 78 | substdio ssup; | ||
| 79 | char upbuf[128]; | ||
| 80 | |||
| 81 | |||
| 82 | void doanddie(user,userlen,pass) | ||
| 83 | char *user; | ||
| 84 | unsigned int userlen; /* including 0 byte */ | ||
| 85 | char *pass; | ||
| 86 | { | ||
| 87 | int child; | ||
| 88 | int wstat; | ||
| 89 | int pi[2]; | ||
| 90 | |||
| 91 | if (fd_copy(2,1) == -1) die_pipe(); | ||
| 92 | close(3); | ||
| 93 | if (pipe(pi) == -1) die_pipe(); | ||
| 94 | if (pi[0] != 3) die_pipe(); | ||
| 95 | switch(child = fork()) { | ||
| 96 | case -1: | ||
| 97 | die_fork(); | ||
| 98 | case 0: | ||
| 99 | close(pi[1]); | ||
| 100 | sig_pipedefault(); | ||
| 101 | execvp(*childargs,childargs); | ||
| 102 | _exit(1); | ||
| 103 | } | ||
| 104 | close(pi[0]); | ||
| 105 | substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof upbuf); | ||
| 106 | if (substdio_put(&ssup,user,userlen) == -1) die_write(); | ||
| 107 | if (substdio_put(&ssup,pass,str_len(pass) + 1) == -1) die_write(); | ||
| 108 | if (substdio_puts(&ssup,"<") == -1) die_write(); | ||
| 109 | if (substdio_puts(&ssup,unique) == -1) die_write(); | ||
| 110 | if (substdio_puts(&ssup,hostname) == -1) die_write(); | ||
| 111 | if (substdio_put(&ssup,">",2) == -1) die_write(); | ||
| 112 | if (substdio_flush(&ssup) == -1) die_write(); | ||
| 113 | close(pi[1]); | ||
| 114 | byte_zero(pass,str_len(pass)); | ||
| 115 | byte_zero(upbuf,sizeof upbuf); | ||
| 116 | if (wait_pid(&wstat,child) == -1) die(); | ||
| 117 | if (wait_crashed(wstat)) die_childcrashed(); | ||
| 118 | if (wait_exitcode(wstat)) die_badauth(); | ||
| 119 | die(); | ||
| 120 | } | ||
| 121 | void pop3_greet() | ||
| 122 | { | ||
| 123 | char *s; | ||
| 124 | s = unique; | ||
| 125 | s += fmt_uint(s,getpid()); | ||
| 126 | *s++ = '.'; | ||
| 127 | s += fmt_ulong(s,(unsigned long) now()); | ||
| 128 | *s++ = '@'; | ||
| 129 | *s++ = 0; | ||
| 130 | puts("+OK <"); | ||
| 131 | puts(unique); | ||
| 132 | puts(hostname); | ||
| 133 | puts(">\r\n"); | ||
| 134 | flush(); | ||
| 135 | } | ||
| 136 | void pop3_user(arg) char *arg; | ||
| 137 | { | ||
| 138 | if (!*arg) { err_syntax(); return; } | ||
| 139 | okay(); | ||
| 140 | seenuser = 1; | ||
| 141 | if (!stralloc_copys(&username,arg)) die_nomem(); | ||
| 142 | if (!stralloc_0(&username)) die_nomem(); | ||
| 143 | } | ||
| 144 | void pop3_pass(arg) char *arg; | ||
| 145 | { | ||
| 146 | if (!seenuser) { err_wantuser(); return; } | ||
| 147 | if (!*arg) { err_syntax(); return; } | ||
| 148 | doanddie(username.s,username.len,arg); | ||
| 149 | } | ||
| 150 | void pop3_apop(arg) char *arg; | ||
| 151 | { | ||
| 152 | char *space; | ||
| 153 | space = arg + str_chr(arg,' '); | ||
| 154 | if (!*space) { err_syntax(); return; } | ||
| 155 | *space++ = 0; | ||
| 156 | doanddie(arg,space - arg,space); | ||
| 157 | } | ||
| 158 | |||
| 159 | struct commands pop3commands[] = { | ||
| 160 | { "user", pop3_user, 0 } | ||
| 161 | , { "pass", pop3_pass, 0 } | ||
| 162 | , { "apop", pop3_apop, 0 } | ||
| 163 | , { "quit", pop3_quit, 0 } | ||
| 164 | , { "noop", okay, 0 } | ||
| 165 | , { 0, err_authoriz, 0 } | ||
| 166 | } ; | ||
| 167 | |||
| 168 | void main(argc,argv) | ||
| 169 | int argc; | ||
| 170 | char **argv; | ||
| 171 | { | ||
| 172 | sig_alarmcatch(die); | ||
| 173 | sig_pipeignore(); | ||
| 174 | |||
| 175 | hostname = argv[1]; | ||
| 176 | if (!hostname) die_usage(); | ||
| 177 | childargs = argv + 2; | ||
| 178 | if (!*childargs) die_usage(); | ||
| 179 | |||
| 180 | pop3_greet(); | ||
| 181 | commands(&ssin,pop3commands); | ||
| 182 | die(); | ||
| 183 | } | ||
diff --git a/qmail-pw2u.9 b/qmail-pw2u.9 new file mode 100644 index 0000000..932cd4d --- /dev/null +++ b/qmail-pw2u.9 | |||
| @@ -0,0 +1,241 @@ | |||
| 1 | .TH qmail-pw2u 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-pw2u \- build address assignments from a passwd file | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-pw2u | ||
| 6 | [ | ||
| 7 | .B \-/ohHuUC | ||
| 8 | ] | ||
| 9 | [ | ||
| 10 | .B \-c\fIchar | ||
| 11 | ] | ||
| 12 | .SH DESCRIPTION | ||
| 13 | .B qmail-pw2u | ||
| 14 | reads a V7-format passwd file from standard input | ||
| 15 | and prints a | ||
| 16 | .BR qmail-users -format | ||
| 17 | assignment file. | ||
| 18 | |||
| 19 | A V7-format passwd file is a series of lines. | ||
| 20 | Each line has the format | ||
| 21 | |||
| 22 | .EX | ||
| 23 | user:password:uid:gid:gecos:home:shell | ||
| 24 | .EE | ||
| 25 | |||
| 26 | where | ||
| 27 | .I user | ||
| 28 | is an account name, | ||
| 29 | .I uid | ||
| 30 | and | ||
| 31 | .I gid | ||
| 32 | are the user id and group id of that account, | ||
| 33 | and | ||
| 34 | .I home | ||
| 35 | is the account's home directory. | ||
| 36 | .IR password , | ||
| 37 | .IR gecos , | ||
| 38 | and | ||
| 39 | .I shell | ||
| 40 | are ignored by | ||
| 41 | .BR qmail-pw2u . | ||
| 42 | |||
| 43 | If you put the output of | ||
| 44 | .B qmail-pw2u | ||
| 45 | into | ||
| 46 | .BR QMAILHOME/users/assign , | ||
| 47 | and then run | ||
| 48 | .BR qmail-newu , | ||
| 49 | .B qmail-lspawn | ||
| 50 | will obey the assignments printed by | ||
| 51 | .BR qmail-pw2u . | ||
| 52 | .B WARNING: | ||
| 53 | After changing any users, uids, gids, or home directories | ||
| 54 | in your passwd file, | ||
| 55 | you must run | ||
| 56 | .B qmail-pw2u | ||
| 57 | and | ||
| 58 | .B qmail-newu | ||
| 59 | again if you want | ||
| 60 | .B qmail-lspawn | ||
| 61 | to see the changes. | ||
| 62 | .SH RULES | ||
| 63 | By default, | ||
| 64 | .B qmail-pw2u | ||
| 65 | follows the same rules as | ||
| 66 | .BR qmail-getpw . | ||
| 67 | It skips | ||
| 68 | .I user | ||
| 69 | if (1) | ||
| 70 | .I uid | ||
| 71 | is zero, | ||
| 72 | (2) | ||
| 73 | .I home | ||
| 74 | does not exist, | ||
| 75 | (3) | ||
| 76 | .I user | ||
| 77 | does not own | ||
| 78 | .IR home , | ||
| 79 | or | ||
| 80 | (4) | ||
| 81 | .I user | ||
| 82 | contains uppercase letters. | ||
| 83 | It then gives each remaining | ||
| 84 | .I user | ||
| 85 | control over the basic | ||
| 86 | .I user | ||
| 87 | address and | ||
| 88 | all addresses of the form | ||
| 89 | .IR user\fBBREAK\fIanything . | ||
| 90 | A catch-all user, | ||
| 91 | .BR alias , | ||
| 92 | controls all other addresses. | ||
| 93 | |||
| 94 | You may change these rules by setting up files in | ||
| 95 | .BR QMAILHOME/users : | ||
| 96 | .TP | ||
| 97 | .B include | ||
| 98 | Allowed users, one per line. | ||
| 99 | If | ||
| 100 | .B include | ||
| 101 | exists, and | ||
| 102 | .I user | ||
| 103 | is not listed in | ||
| 104 | .BR include , | ||
| 105 | .I user | ||
| 106 | is ignored. | ||
| 107 | .TP | ||
| 108 | .B exclude | ||
| 109 | Ignored users, one per line. | ||
| 110 | If | ||
| 111 | .B exclude | ||
| 112 | exists, and | ||
| 113 | .I user | ||
| 114 | is listed in | ||
| 115 | .BR exclude , | ||
| 116 | .I user | ||
| 117 | is ignored. | ||
| 118 | .TP | ||
| 119 | .B mailnames | ||
| 120 | Replacement names for users. | ||
| 121 | Each line has the form | ||
| 122 | |||
| 123 | .EX | ||
| 124 | user:mailname1:mailname2:... | ||
| 125 | .EE | ||
| 126 | |||
| 127 | The addresses | ||
| 128 | .I mailname1 | ||
| 129 | and | ||
| 130 | .I mailname1\fBBREAK\fIext | ||
| 131 | and | ||
| 132 | .I mailname2 | ||
| 133 | and so on will be delivered | ||
| 134 | to | ||
| 135 | .IR user . | ||
| 136 | |||
| 137 | .B WARNING: | ||
| 138 | The addresses | ||
| 139 | .I user | ||
| 140 | and | ||
| 141 | .I user\fBBREAK\fIext | ||
| 142 | will not be delivered to | ||
| 143 | .I user | ||
| 144 | unless | ||
| 145 | .I user | ||
| 146 | is listed as one of the | ||
| 147 | .IR mailname s. | ||
| 148 | |||
| 149 | A line in | ||
| 150 | .B mailnames | ||
| 151 | is silently ignored if the user does not exist. | ||
| 152 | .TP | ||
| 153 | .B subusers | ||
| 154 | Extra addresses. | ||
| 155 | Each line has the form | ||
| 156 | |||
| 157 | .EX | ||
| 158 | sub:user:pre: | ||
| 159 | .EE | ||
| 160 | |||
| 161 | .I sub | ||
| 162 | will be handled by | ||
| 163 | .IR home\fB/.qmail\-\fIpre , | ||
| 164 | where | ||
| 165 | .I home | ||
| 166 | is | ||
| 167 | .IR user 's | ||
| 168 | home directory; | ||
| 169 | .I sub\fBBREAK\fIext | ||
| 170 | will be handled by | ||
| 171 | .IR home\fB/.qmail\-\fIpre\fB\-\fIext . | ||
| 172 | .TP | ||
| 173 | .B append | ||
| 174 | Extra assignments, | ||
| 175 | printed at the end of | ||
| 176 | .BR qmail-pw2u 's | ||
| 177 | output. | ||
| 178 | .SH OPTIONS | ||
| 179 | .TP | ||
| 180 | .B \-o | ||
| 181 | (Default.) | ||
| 182 | Skip | ||
| 183 | .I user | ||
| 184 | if | ||
| 185 | .I home | ||
| 186 | does not exist (or is not visible to | ||
| 187 | .BR qmail-pw2u ). | ||
| 188 | Skip | ||
| 189 | .I user | ||
| 190 | if | ||
| 191 | .I home | ||
| 192 | is not owned by | ||
| 193 | .IR user . | ||
| 194 | .TP | ||
| 195 | .B \-h | ||
| 196 | Stop if | ||
| 197 | .I home | ||
| 198 | does not exist. | ||
| 199 | This is appropriate if every user is supposed to have a home directory. | ||
| 200 | Skip | ||
| 201 | .I user | ||
| 202 | if | ||
| 203 | .I home | ||
| 204 | is not owned by | ||
| 205 | .IR user . | ||
| 206 | .TP | ||
| 207 | .B \-H | ||
| 208 | Do not check the existence or ownership of | ||
| 209 | .IR home . | ||
| 210 | .TP | ||
| 211 | .B \-U | ||
| 212 | (Default.) | ||
| 213 | Skip | ||
| 214 | .I user | ||
| 215 | if there are any uppercase letters in | ||
| 216 | .IR user . | ||
| 217 | .TP | ||
| 218 | .B \-u | ||
| 219 | Allow uppercase letters in | ||
| 220 | .IR user . | ||
| 221 | .TP | ||
| 222 | .B \-c\fIchar | ||
| 223 | Use | ||
| 224 | .I char | ||
| 225 | as the user-extension delimiter | ||
| 226 | in place of | ||
| 227 | .BR BREAK . | ||
| 228 | .TP | ||
| 229 | .B \-C | ||
| 230 | Disable the user-extension mechanism. | ||
| 231 | .TP | ||
| 232 | .B \-/ | ||
| 233 | Use | ||
| 234 | .IR home\fB/.qmail\-/ ... | ||
| 235 | instead of | ||
| 236 | .IR home\fB/.qmail\- ... | ||
| 237 | .SH "SEE ALSO" | ||
| 238 | qmail-users(5), | ||
| 239 | qmail-lspawn(8), | ||
| 240 | qmail-newu(8), | ||
| 241 | qmail-getpw(8) | ||
diff --git a/qmail-pw2u.c b/qmail-pw2u.c new file mode 100644 index 0000000..4146067 --- /dev/null +++ b/qmail-pw2u.c | |||
| @@ -0,0 +1,312 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include "substdio.h" | ||
| 4 | #include "readwrite.h" | ||
| 5 | #include "subfd.h" | ||
| 6 | #include "sgetopt.h" | ||
| 7 | #include "control.h" | ||
| 8 | #include "constmap.h" | ||
| 9 | #include "stralloc.h" | ||
| 10 | #include "fmt.h" | ||
| 11 | #include "str.h" | ||
| 12 | #include "scan.h" | ||
| 13 | #include "open.h" | ||
| 14 | #include "error.h" | ||
| 15 | #include "getln.h" | ||
| 16 | #include "auto_break.h" | ||
| 17 | #include "auto_qmail.h" | ||
| 18 | #include "auto_usera.h" | ||
| 19 | |||
| 20 | void die_chdir() | ||
| 21 | { | ||
| 22 | substdio_putsflush(subfderr,"qmail-pw2u: fatal: unable to chdir\n"); | ||
| 23 | _exit(111); | ||
| 24 | } | ||
| 25 | void die_nomem() | ||
| 26 | { | ||
| 27 | substdio_putsflush(subfderr,"qmail-pw2u: fatal: out of memory\n"); | ||
| 28 | _exit(111); | ||
| 29 | } | ||
| 30 | void die_read() | ||
| 31 | { | ||
| 32 | substdio_putsflush(subfderr,"qmail-pw2u: fatal: unable to read input\n"); | ||
| 33 | _exit(111); | ||
| 34 | } | ||
| 35 | void die_write() | ||
| 36 | { | ||
| 37 | substdio_putsflush(subfderr,"qmail-pw2u: fatal: unable to write output\n"); | ||
| 38 | _exit(111); | ||
| 39 | } | ||
| 40 | void die_control() | ||
| 41 | { | ||
| 42 | substdio_putsflush(subfderr,"qmail-pw2u: fatal: unable to read controls\n"); | ||
| 43 | _exit(111); | ||
| 44 | } | ||
| 45 | void die_alias() | ||
| 46 | { | ||
| 47 | substdio_puts(subfderr,"qmail-pw2u: fatal: unable to find "); | ||
| 48 | substdio_puts(subfderr,auto_usera); | ||
| 49 | substdio_puts(subfderr," user\n"); | ||
| 50 | substdio_flush(subfderr); | ||
| 51 | _exit(111); | ||
| 52 | } | ||
| 53 | void die_home(fn) char *fn; | ||
| 54 | { | ||
| 55 | substdio_puts(subfderr,"qmail-pw2u: fatal: unable to stat "); | ||
| 56 | substdio_puts(subfderr,fn); | ||
| 57 | substdio_puts(subfderr,"\n"); | ||
| 58 | substdio_flush(subfderr); | ||
| 59 | _exit(111); | ||
| 60 | } | ||
| 61 | void die_user(s,len) char *s; unsigned int len; | ||
| 62 | { | ||
| 63 | substdio_puts(subfderr,"qmail-pw2u: fatal: unable to find "); | ||
| 64 | substdio_put(subfderr,s,len); | ||
| 65 | substdio_puts(subfderr," user for subuser\n"); | ||
| 66 | substdio_flush(subfderr); | ||
| 67 | _exit(111); | ||
| 68 | } | ||
| 69 | |||
| 70 | char *dashcolon = "-:"; | ||
| 71 | int flagalias = 0; | ||
| 72 | int flagnoupper = 1; | ||
| 73 | int homestrategy = 2; | ||
| 74 | /* 2: skip if home does not exist; skip if home is not owned by user */ | ||
| 75 | /* 1: stop if home does not exist; skip if home is not owned by user */ | ||
| 76 | /* 0: don't worry about home */ | ||
| 77 | |||
| 78 | int okincl; stralloc incl = {0}; struct constmap mapincl; | ||
| 79 | int okexcl; stralloc excl = {0}; struct constmap mapexcl; | ||
| 80 | int okmana; stralloc mana = {0}; struct constmap mapmana; | ||
| 81 | |||
| 82 | stralloc allusers = {0}; struct constmap mapuser; | ||
| 83 | |||
| 84 | stralloc uugh = {0}; | ||
| 85 | stralloc user = {0}; | ||
| 86 | stralloc uidstr = {0}; | ||
| 87 | stralloc gidstr = {0}; | ||
| 88 | stralloc home = {0}; | ||
| 89 | unsigned long uid; | ||
| 90 | |||
| 91 | stralloc line = {0}; | ||
| 92 | |||
| 93 | void doaccount() | ||
| 94 | { | ||
| 95 | struct stat st; | ||
| 96 | int i; | ||
| 97 | char *mailnames; | ||
| 98 | char *x; | ||
| 99 | unsigned int xlen; | ||
| 100 | |||
| 101 | if (byte_chr(line.s,line.len,'\0') < line.len) return; | ||
| 102 | |||
| 103 | x = line.s; xlen = line.len; i = byte_chr(x,xlen,':'); if (i == xlen) return; | ||
| 104 | if (!stralloc_copyb(&user,x,i)) die_nomem(); | ||
| 105 | if (!stralloc_0(&user)) die_nomem(); | ||
| 106 | ++i; x += i; xlen -= i; i = byte_chr(x,xlen,':'); if (i == xlen) return; | ||
| 107 | ++i; x += i; xlen -= i; i = byte_chr(x,xlen,':'); if (i == xlen) return; | ||
| 108 | if (!stralloc_copyb(&uidstr,x,i)) die_nomem(); | ||
| 109 | if (!stralloc_0(&uidstr)) die_nomem(); | ||
| 110 | scan_ulong(uidstr.s,&uid); | ||
| 111 | ++i; x += i; xlen -= i; i = byte_chr(x,xlen,':'); if (i == xlen) return; | ||
| 112 | if (!stralloc_copyb(&gidstr,x,i)) die_nomem(); | ||
| 113 | if (!stralloc_0(&gidstr)) die_nomem(); | ||
| 114 | ++i; x += i; xlen -= i; i = byte_chr(x,xlen,':'); if (i == xlen) return; | ||
| 115 | ++i; x += i; xlen -= i; i = byte_chr(x,xlen,':'); if (i == xlen) return; | ||
| 116 | if (!stralloc_copyb(&home,x,i)) die_nomem(); | ||
| 117 | if (!stralloc_0(&home)) die_nomem(); | ||
| 118 | |||
| 119 | if (!uid) return; | ||
| 120 | if (flagnoupper) | ||
| 121 | for (i = 0;i < user.len;++i) | ||
| 122 | if ((user.s[i] >= 'A') && (user.s[i] <= 'Z')) | ||
| 123 | return; | ||
| 124 | if (okincl) | ||
| 125 | if (!constmap(&mapincl,user.s,user.len - 1)) | ||
| 126 | return; | ||
| 127 | if (okexcl) | ||
| 128 | if (constmap(&mapexcl,user.s,user.len - 1)) | ||
| 129 | return; | ||
| 130 | if (homestrategy) { | ||
| 131 | if (stat(home.s,&st) == -1) { | ||
| 132 | if (errno != error_noent) die_home(home.s); | ||
| 133 | if (homestrategy == 1) die_home(home.s); | ||
| 134 | return; | ||
| 135 | } | ||
| 136 | if (st.st_uid != uid) return; | ||
| 137 | } | ||
| 138 | |||
| 139 | if (!stralloc_copys(&uugh,":")) die_nomem(); | ||
| 140 | if (!stralloc_cats(&uugh,user.s)) die_nomem(); | ||
| 141 | if (!stralloc_cats(&uugh,":")) die_nomem(); | ||
| 142 | if (!stralloc_cats(&uugh,uidstr.s)) die_nomem(); | ||
| 143 | if (!stralloc_cats(&uugh,":")) die_nomem(); | ||
| 144 | if (!stralloc_cats(&uugh,gidstr.s)) die_nomem(); | ||
| 145 | if (!stralloc_cats(&uugh,":")) die_nomem(); | ||
| 146 | if (!stralloc_cats(&uugh,home.s)) die_nomem(); | ||
| 147 | if (!stralloc_cats(&uugh,":")) die_nomem(); | ||
| 148 | |||
| 149 | /* XXX: avoid recording in allusers unless sub actually needs it */ | ||
| 150 | if (!stralloc_cats(&allusers,user.s)) die_nomem(); | ||
| 151 | if (!stralloc_cats(&allusers,":")) die_nomem(); | ||
| 152 | if (!stralloc_catb(&allusers,uugh.s,uugh.len)) die_nomem(); | ||
| 153 | if (!stralloc_0(&allusers)) die_nomem(); | ||
| 154 | |||
| 155 | if (str_equal(user.s,auto_usera)) { | ||
| 156 | if (substdio_puts(subfdout,"+") == -1) die_write(); | ||
| 157 | if (substdio_put(subfdout,uugh.s,uugh.len) == -1) die_write(); | ||
| 158 | if (substdio_puts(subfdout,dashcolon) == -1) die_write(); | ||
| 159 | if (substdio_puts(subfdout,":\n") == -1) die_write(); | ||
| 160 | flagalias = 1; | ||
| 161 | } | ||
| 162 | |||
| 163 | mailnames = 0; | ||
| 164 | if (okmana) | ||
| 165 | mailnames = constmap(&mapmana,user.s,user.len - 1); | ||
| 166 | if (!mailnames) | ||
| 167 | mailnames = user.s; | ||
| 168 | |||
| 169 | for (;;) { | ||
| 170 | while (*mailnames == ':') ++mailnames; | ||
| 171 | if (!*mailnames) break; | ||
| 172 | |||
| 173 | i = str_chr(mailnames,':'); | ||
| 174 | |||
| 175 | if (substdio_puts(subfdout,"=") == -1) die_write(); | ||
| 176 | if (substdio_put(subfdout,mailnames,i) == -1) die_write(); | ||
| 177 | if (substdio_put(subfdout,uugh.s,uugh.len) == -1) die_write(); | ||
| 178 | if (substdio_puts(subfdout,"::\n") == -1) die_write(); | ||
| 179 | |||
| 180 | if (*auto_break) { | ||
| 181 | if (substdio_puts(subfdout,"+") == -1) die_write(); | ||
| 182 | if (substdio_put(subfdout,mailnames,i) == -1) die_write(); | ||
| 183 | if (substdio_put(subfdout,auto_break,1) == -1) die_write(); | ||
| 184 | if (substdio_put(subfdout,uugh.s,uugh.len) == -1) die_write(); | ||
| 185 | if (substdio_puts(subfdout,dashcolon) == -1) die_write(); | ||
| 186 | if (substdio_puts(subfdout,":\n") == -1) die_write(); | ||
| 187 | } | ||
| 188 | |||
| 189 | mailnames += i; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | stralloc sub = {0}; | ||
| 194 | |||
| 195 | void dosubuser() | ||
| 196 | { | ||
| 197 | int i; | ||
| 198 | char *x; | ||
| 199 | unsigned int xlen; | ||
| 200 | char *uugh; | ||
| 201 | |||
| 202 | x = line.s; xlen = line.len; i = byte_chr(x,xlen,':'); if (i == xlen) return; | ||
| 203 | if (!stralloc_copyb(&sub,x,i)) die_nomem(); | ||
| 204 | ++i; x += i; xlen -= i; i = byte_chr(x,xlen,':'); if (i == xlen) return; | ||
| 205 | uugh = constmap(&mapuser,x,i); | ||
| 206 | if (!uugh) die_user(x,i); | ||
| 207 | ++i; x += i; xlen -= i; i = byte_chr(x,xlen,':'); if (i == xlen) return; | ||
| 208 | |||
| 209 | if (substdio_puts(subfdout,"=") == -1) die_write(); | ||
| 210 | if (substdio_put(subfdout,sub.s,sub.len) == -1) die_write(); | ||
| 211 | if (substdio_puts(subfdout,uugh) == -1) die_write(); | ||
| 212 | if (substdio_puts(subfdout,dashcolon) == -1) die_write(); | ||
| 213 | if (substdio_put(subfdout,x,i) == -1) die_write(); | ||
| 214 | if (substdio_puts(subfdout,":\n") == -1) die_write(); | ||
| 215 | |||
| 216 | if (*auto_break) { | ||
| 217 | if (substdio_puts(subfdout,"+") == -1) die_write(); | ||
| 218 | if (substdio_put(subfdout,sub.s,sub.len) == -1) die_write(); | ||
| 219 | if (substdio_put(subfdout,auto_break,1) == -1) die_write(); | ||
| 220 | if (substdio_puts(subfdout,uugh) == -1) die_write(); | ||
| 221 | if (substdio_puts(subfdout,dashcolon) == -1) die_write(); | ||
| 222 | if (substdio_put(subfdout,x,i) == -1) die_write(); | ||
| 223 | if (substdio_puts(subfdout,"-:\n") == -1) die_write(); | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | int fd; | ||
| 228 | substdio ss; | ||
| 229 | char ssbuf[SUBSTDIO_INSIZE]; | ||
| 230 | |||
| 231 | void main(argc,argv) | ||
| 232 | int argc; | ||
| 233 | char **argv; | ||
| 234 | { | ||
| 235 | int opt; | ||
| 236 | int match; | ||
| 237 | |||
| 238 | while ((opt = getopt(argc,argv,"/ohHuUc:C")) != opteof) | ||
| 239 | switch(opt) { | ||
| 240 | case '/': dashcolon = "-/:"; break; | ||
| 241 | case 'o': homestrategy = 2; break; | ||
| 242 | case 'h': homestrategy = 1; break; | ||
| 243 | case 'H': homestrategy = 0; break; | ||
| 244 | case 'u': flagnoupper = 0; break; | ||
| 245 | case 'U': flagnoupper = 1; break; | ||
| 246 | case 'c': *auto_break = *optarg; break; | ||
| 247 | case 'C': *auto_break = 0; break; | ||
| 248 | case '?': | ||
| 249 | default: | ||
| 250 | _exit(100); | ||
| 251 | } | ||
| 252 | |||
| 253 | if (chdir(auto_qmail) == -1) die_chdir(); | ||
| 254 | |||
| 255 | /* no need for control_init() */ | ||
| 256 | |||
| 257 | okincl = control_readfile(&incl,"users/include",0); | ||
| 258 | if (okincl == -1) die_control(); | ||
| 259 | if (okincl) if (!constmap_init(&mapincl,incl.s,incl.len,0)) die_nomem(); | ||
| 260 | |||
| 261 | okexcl = control_readfile(&excl,"users/exclude",0); | ||
| 262 | if (okexcl == -1) die_control(); | ||
| 263 | if (okexcl) if (!constmap_init(&mapexcl,excl.s,excl.len,0)) die_nomem(); | ||
| 264 | |||
| 265 | okmana = control_readfile(&mana,"users/mailnames",0); | ||
| 266 | if (okmana == -1) die_control(); | ||
| 267 | if (okmana) if (!constmap_init(&mapmana,mana.s,mana.len,1)) die_nomem(); | ||
| 268 | |||
| 269 | if (!stralloc_copys(&allusers,"")) die_nomem(); | ||
| 270 | |||
| 271 | for (;;) { | ||
| 272 | if (getln(subfdin,&line,&match,'\n') == -1) die_read(); | ||
| 273 | doaccount(); | ||
| 274 | if (!match) break; | ||
| 275 | } | ||
| 276 | if (!flagalias) die_alias(); | ||
| 277 | |||
| 278 | fd = open_read("users/subusers"); | ||
| 279 | if (fd == -1) { | ||
| 280 | if (errno != error_noent) die_control(); | ||
| 281 | } | ||
| 282 | else { | ||
| 283 | substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); | ||
| 284 | |||
| 285 | if (!constmap_init(&mapuser,allusers.s,allusers.len,1)) die_nomem(); | ||
| 286 | |||
| 287 | for (;;) { | ||
| 288 | if (getln(&ss,&line,&match,'\n') == -1) die_read(); | ||
| 289 | dosubuser(); | ||
| 290 | if (!match) break; | ||
| 291 | } | ||
| 292 | |||
| 293 | close(fd); | ||
| 294 | } | ||
| 295 | |||
| 296 | fd = open_read("users/append"); | ||
| 297 | if (fd == -1) { | ||
| 298 | if (errno != error_noent) die_control(); | ||
| 299 | } | ||
| 300 | else { | ||
| 301 | substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); | ||
| 302 | for (;;) { | ||
| 303 | if (getln(&ss,&line,&match,'\n') == -1) die_read(); | ||
| 304 | if (substdio_put(subfdout,line.s,line.len) == -1) die_write(); | ||
| 305 | if (!match) break; | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | if (substdio_puts(subfdout,".\n") == -1) die_write(); | ||
| 310 | if (substdio_flush(subfdout) == -1) die_write(); | ||
| 311 | _exit(0); | ||
| 312 | } | ||
diff --git a/qmail-qmqpc.8 b/qmail-qmqpc.8 new file mode 100644 index 0000000..e11a15e --- /dev/null +++ b/qmail-qmqpc.8 | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | .TH qmail-qmqpc 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-qmqpc \- queue a mail message via QMQP | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-qmqpc | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B qmail-qmqpc | ||
| 8 | offers the same interface as | ||
| 9 | .BR qmail-queue , | ||
| 10 | but it gives the message to a QMQP server | ||
| 11 | instead of storing it locally. | ||
| 12 | |||
| 13 | In a | ||
| 14 | .B mini-qmail | ||
| 15 | installation, | ||
| 16 | .B qmail-queue | ||
| 17 | is replaced with a symbolic link to | ||
| 18 | .BR qmail-qmqpc . | ||
| 19 | .SH "CONTROL FILES" | ||
| 20 | .TP 5 | ||
| 21 | .I qmqpservers | ||
| 22 | IP addresses of QMQP servers, one address per line. | ||
| 23 | .B qmail-qmqpc | ||
| 24 | will try each address in turn until it establishes a QMQP connection | ||
| 25 | or runs out of addresses. | ||
| 26 | .SH "SEE ALSO" | ||
| 27 | qmail-control(5), | ||
| 28 | qmail-queue(8), | ||
| 29 | qmail-qmqpd(8) | ||
diff --git a/qmail-qmqpc.c b/qmail-qmqpc.c new file mode 100644 index 0000000..d5adf05 --- /dev/null +++ b/qmail-qmqpc.c | |||
| @@ -0,0 +1,159 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/socket.h> | ||
| 3 | #include <netinet/in.h> | ||
| 4 | #include <arpa/inet.h> | ||
| 5 | #include "substdio.h" | ||
| 6 | #include "getln.h" | ||
| 7 | #include "readwrite.h" | ||
| 8 | #include "exit.h" | ||
| 9 | #include "stralloc.h" | ||
| 10 | #include "slurpclose.h" | ||
| 11 | #include "error.h" | ||
| 12 | #include "sig.h" | ||
| 13 | #include "ip.h" | ||
| 14 | #include "timeoutconn.h" | ||
| 15 | #include "timeoutread.h" | ||
| 16 | #include "timeoutwrite.h" | ||
| 17 | #include "auto_qmail.h" | ||
| 18 | #include "control.h" | ||
| 19 | #include "fmt.h" | ||
| 20 | |||
| 21 | #define PORT_QMQP 628 | ||
| 22 | |||
| 23 | void die_success() { _exit(0); } | ||
| 24 | void die_perm() { _exit(31); } | ||
| 25 | void nomem() { _exit(51); } | ||
| 26 | void die_read() { if (errno == error_nomem) nomem(); _exit(54); } | ||
| 27 | void die_control() { _exit(55); } | ||
| 28 | void die_socket() { _exit(56); } | ||
| 29 | void die_home() { _exit(61); } | ||
| 30 | void die_temp() { _exit(71); } | ||
| 31 | void die_conn() { _exit(74); } | ||
| 32 | void die_format() { _exit(91); } | ||
| 33 | |||
| 34 | int lasterror = 55; | ||
| 35 | int qmqpfd; | ||
| 36 | |||
| 37 | int saferead(fd,buf,len) int fd; char *buf; int len; | ||
| 38 | { | ||
| 39 | int r; | ||
| 40 | r = timeoutread(60,qmqpfd,buf,len); | ||
| 41 | if (r <= 0) die_conn(); | ||
| 42 | return r; | ||
| 43 | } | ||
| 44 | int safewrite(fd,buf,len) int fd; char *buf; int len; | ||
| 45 | { | ||
| 46 | int r; | ||
| 47 | r = timeoutwrite(60,qmqpfd,buf,len); | ||
| 48 | if (r <= 0) die_conn(); | ||
| 49 | return r; | ||
| 50 | } | ||
| 51 | |||
| 52 | char buf[1024]; | ||
| 53 | substdio to = SUBSTDIO_FDBUF(safewrite,-1,buf,sizeof buf); | ||
| 54 | substdio from = SUBSTDIO_FDBUF(saferead,-1,buf,sizeof buf); | ||
| 55 | substdio envelope = SUBSTDIO_FDBUF(read,1,buf,sizeof buf); | ||
| 56 | /* WARNING: can use only one of these at a time! */ | ||
| 57 | |||
| 58 | stralloc beforemessage = {0}; | ||
| 59 | stralloc message = {0}; | ||
| 60 | stralloc aftermessage = {0}; | ||
| 61 | |||
| 62 | char strnum[FMT_ULONG]; | ||
| 63 | stralloc line = {0}; | ||
| 64 | |||
| 65 | void getmess() | ||
| 66 | { | ||
| 67 | int match; | ||
| 68 | |||
| 69 | if (slurpclose(0,&message,1024) == -1) die_read(); | ||
| 70 | |||
| 71 | strnum[fmt_ulong(strnum,(unsigned long) message.len)] = 0; | ||
| 72 | if (!stralloc_copys(&beforemessage,strnum)) nomem(); | ||
| 73 | if (!stralloc_cats(&beforemessage,":")) nomem(); | ||
| 74 | if (!stralloc_copys(&aftermessage,",")) nomem(); | ||
| 75 | |||
| 76 | if (getln(&envelope,&line,&match,'\0') == -1) die_read(); | ||
| 77 | if (!match) die_format(); | ||
| 78 | if (line.len < 2) die_format(); | ||
| 79 | if (line.s[0] != 'F') die_format(); | ||
| 80 | |||
| 81 | strnum[fmt_ulong(strnum,(unsigned long) line.len - 2)] = 0; | ||
| 82 | if (!stralloc_cats(&aftermessage,strnum)) nomem(); | ||
| 83 | if (!stralloc_cats(&aftermessage,":")) nomem(); | ||
| 84 | if (!stralloc_catb(&aftermessage,line.s + 1,line.len - 2)) nomem(); | ||
| 85 | if (!stralloc_cats(&aftermessage,",")) nomem(); | ||
| 86 | |||
| 87 | for (;;) { | ||
| 88 | if (getln(&envelope,&line,&match,'\0') == -1) die_read(); | ||
| 89 | if (!match) die_format(); | ||
| 90 | if (line.len < 2) break; | ||
| 91 | if (line.s[0] != 'T') die_format(); | ||
| 92 | |||
| 93 | strnum[fmt_ulong(strnum,(unsigned long) line.len - 2)] = 0; | ||
| 94 | if (!stralloc_cats(&aftermessage,strnum)) nomem(); | ||
| 95 | if (!stralloc_cats(&aftermessage,":")) nomem(); | ||
| 96 | if (!stralloc_catb(&aftermessage,line.s + 1,line.len - 2)) nomem(); | ||
| 97 | if (!stralloc_cats(&aftermessage,",")) nomem(); | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | void doit(server) | ||
| 102 | char *server; | ||
| 103 | { | ||
| 104 | struct ip_address ip; | ||
| 105 | char ch; | ||
| 106 | |||
| 107 | if (!ip_scan(server,&ip)) return; | ||
| 108 | |||
| 109 | qmqpfd = socket(AF_INET,SOCK_STREAM,0); | ||
| 110 | if (qmqpfd == -1) die_socket(); | ||
| 111 | |||
| 112 | if (timeoutconn(qmqpfd,&ip,PORT_QMQP,10) != 0) { | ||
| 113 | lasterror = 73; | ||
| 114 | if (errno == error_timeout) lasterror = 72; | ||
| 115 | close(qmqpfd); | ||
| 116 | return; | ||
| 117 | } | ||
| 118 | |||
| 119 | strnum[fmt_ulong(strnum,(unsigned long) (beforemessage.len + message.len + aftermessage.len))] = 0; | ||
| 120 | substdio_puts(&to,strnum); | ||
| 121 | substdio_puts(&to,":"); | ||
| 122 | substdio_put(&to,beforemessage.s,beforemessage.len); | ||
| 123 | substdio_put(&to,message.s,message.len); | ||
| 124 | substdio_put(&to,aftermessage.s,aftermessage.len); | ||
| 125 | substdio_puts(&to,","); | ||
| 126 | substdio_flush(&to); | ||
| 127 | |||
| 128 | for (;;) { | ||
| 129 | substdio_get(&from,&ch,1); | ||
| 130 | if (ch == 'K') die_success(); | ||
| 131 | if (ch == 'Z') die_temp(); | ||
| 132 | if (ch == 'D') die_perm(); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | stralloc servers = {0}; | ||
| 137 | |||
| 138 | main() | ||
| 139 | { | ||
| 140 | int i; | ||
| 141 | int j; | ||
| 142 | |||
| 143 | sig_pipeignore(); | ||
| 144 | |||
| 145 | if (chdir(auto_qmail) == -1) die_home(); | ||
| 146 | if (control_init() == -1) die_control(); | ||
| 147 | if (control_readfile(&servers,"control/qmqpservers",0) != 1) die_control(); | ||
| 148 | |||
| 149 | getmess(); | ||
| 150 | |||
| 151 | i = 0; | ||
| 152 | for (j = 0;j < servers.len;++j) | ||
| 153 | if (!servers.s[j]) { | ||
| 154 | doit(servers.s + i); | ||
| 155 | i = j + 1; | ||
| 156 | } | ||
| 157 | |||
| 158 | _exit(lasterror); | ||
| 159 | } | ||
diff --git a/qmail-qmqpd.8 b/qmail-qmqpd.8 new file mode 100644 index 0000000..5142dfa --- /dev/null +++ b/qmail-qmqpd.8 | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | .TH qmail-qmqpd 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-qmqpd \- receive mail via QMQP | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-qmqpd | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B qmail-qmqpd | ||
| 8 | receives mail messages via the Quick Mail Queueing Protocol (QMQP) | ||
| 9 | and invokes | ||
| 10 | .B qmail-queue | ||
| 11 | to deposit them into the outgoing queue. | ||
| 12 | .B qmail-qmqpd | ||
| 13 | must be supplied several environment variables; | ||
| 14 | see | ||
| 15 | .BR tcp-environ(5) . | ||
| 16 | |||
| 17 | .B qmail-qmqpd | ||
| 18 | will relay messages to any destination. | ||
| 19 | It should be invoked only for connections from preauthorized users. | ||
| 20 | .SH "SEE ALSO" | ||
| 21 | tcp-env(1), | ||
| 22 | tcpserver(1), | ||
| 23 | tcp-environ(5), | ||
| 24 | qmail-qmqpc(8), | ||
| 25 | qmail-queue(8) | ||
diff --git a/qmail-qmqpd.c b/qmail-qmqpd.c new file mode 100644 index 0000000..86cb284 --- /dev/null +++ b/qmail-qmqpd.c | |||
| @@ -0,0 +1,174 @@ | |||
| 1 | #include "auto_qmail.h" | ||
| 2 | #include "qmail.h" | ||
| 3 | #include "received.h" | ||
| 4 | #include "sig.h" | ||
| 5 | #include "substdio.h" | ||
| 6 | #include "readwrite.h" | ||
| 7 | #include "exit.h" | ||
| 8 | #include "now.h" | ||
| 9 | #include "fmt.h" | ||
| 10 | #include "env.h" | ||
| 11 | |||
| 12 | void resources() { _exit(111); } | ||
| 13 | |||
| 14 | int safewrite(fd,buf,len) int fd; char *buf; int len; | ||
| 15 | { | ||
| 16 | int r; | ||
| 17 | r = write(fd,buf,len); | ||
| 18 | if (r <= 0) _exit(0); | ||
| 19 | return r; | ||
| 20 | } | ||
| 21 | int saferead(fd,buf,len) int fd; char *buf; int len; | ||
| 22 | { | ||
| 23 | int r; | ||
| 24 | r = read(fd,buf,len); | ||
| 25 | if (r <= 0) _exit(0); | ||
| 26 | return r; | ||
| 27 | } | ||
| 28 | |||
| 29 | char ssinbuf[512]; | ||
| 30 | substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf); | ||
| 31 | char ssoutbuf[256]; | ||
| 32 | substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf); | ||
| 33 | |||
| 34 | unsigned long bytesleft = 100; | ||
| 35 | |||
| 36 | void getbyte(ch) | ||
| 37 | char *ch; | ||
| 38 | { | ||
| 39 | if (!bytesleft--) _exit(100); | ||
| 40 | substdio_get(&ssin,ch,1); | ||
| 41 | } | ||
| 42 | |||
| 43 | unsigned long getlen() | ||
| 44 | { | ||
| 45 | unsigned long len = 0; | ||
| 46 | char ch; | ||
| 47 | |||
| 48 | for (;;) { | ||
| 49 | getbyte(&ch); | ||
| 50 | if (ch == ':') return len; | ||
| 51 | if (len > 200000000) resources(); | ||
| 52 | len = 10 * len + (ch - '0'); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | void getcomma() | ||
| 57 | { | ||
| 58 | char ch; | ||
| 59 | getbyte(&ch); | ||
| 60 | if (ch != ',') _exit(100); | ||
| 61 | } | ||
| 62 | |||
| 63 | struct qmail qq; | ||
| 64 | |||
| 65 | void identify() | ||
| 66 | { | ||
| 67 | char *remotehost; | ||
| 68 | char *remoteinfo; | ||
| 69 | char *remoteip; | ||
| 70 | char *local; | ||
| 71 | |||
| 72 | remotehost = env_get("TCPREMOTEHOST"); | ||
| 73 | if (!remotehost) remotehost = "unknown"; | ||
| 74 | remoteinfo = env_get("TCPREMOTEINFO"); | ||
| 75 | remoteip = env_get("TCPREMOTEIP"); | ||
| 76 | if (!remoteip) remoteip = "unknown"; | ||
| 77 | local = env_get("TCPLOCALHOST"); | ||
| 78 | if (!local) local = env_get("TCPLOCALIP"); | ||
| 79 | if (!local) local = "unknown"; | ||
| 80 | |||
| 81 | received(&qq,"QMQP",local,remoteip,remotehost,remoteinfo,(char *) 0); | ||
| 82 | } | ||
| 83 | |||
| 84 | char buf[1000]; | ||
| 85 | char strnum[FMT_ULONG]; | ||
| 86 | |||
| 87 | int getbuf() | ||
| 88 | { | ||
| 89 | unsigned long len; | ||
| 90 | int i; | ||
| 91 | |||
| 92 | len = getlen(); | ||
| 93 | if (len >= 1000) { | ||
| 94 | for (i = 0;i < len;++i) getbyte(buf); | ||
| 95 | getcomma(); | ||
| 96 | buf[0] = 0; | ||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | for (i = 0;i < len;++i) getbyte(buf + i); | ||
| 101 | getcomma(); | ||
| 102 | buf[len] = 0; | ||
| 103 | return byte_chr(buf,len,'\0') == len; | ||
| 104 | } | ||
| 105 | |||
| 106 | int flagok = 1; | ||
| 107 | |||
| 108 | main() | ||
| 109 | { | ||
| 110 | char *result; | ||
| 111 | unsigned long qp; | ||
| 112 | unsigned long len; | ||
| 113 | char ch; | ||
| 114 | |||
| 115 | sig_pipeignore(); | ||
| 116 | sig_alarmcatch(resources); | ||
| 117 | alarm(3600); | ||
| 118 | |||
| 119 | bytesleft = getlen(); | ||
| 120 | |||
| 121 | len = getlen(); | ||
| 122 | |||
| 123 | if (chdir(auto_qmail) == -1) resources(); | ||
| 124 | if (qmail_open(&qq) == -1) resources(); | ||
| 125 | qp = qmail_qp(&qq); | ||
| 126 | identify(); | ||
| 127 | |||
| 128 | while (len > 0) { /* XXX: could speed this up */ | ||
| 129 | getbyte(&ch); | ||
| 130 | --len; | ||
| 131 | qmail_put(&qq,&ch,1); | ||
| 132 | } | ||
| 133 | getcomma(); | ||
| 134 | |||
| 135 | if (getbuf()) | ||
| 136 | qmail_from(&qq,buf); | ||
| 137 | else { | ||
| 138 | qmail_from(&qq,""); | ||
| 139 | qmail_fail(&qq); | ||
| 140 | flagok = 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | while (bytesleft) | ||
| 144 | if (getbuf()) | ||
| 145 | qmail_to(&qq,buf); | ||
| 146 | else { | ||
| 147 | qmail_fail(&qq); | ||
| 148 | flagok = 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | bytesleft = 1; | ||
| 152 | getcomma(); | ||
| 153 | |||
| 154 | result = qmail_close(&qq); | ||
| 155 | |||
| 156 | if (!*result) { | ||
| 157 | len = fmt_str(buf,"Kok "); | ||
| 158 | len += fmt_ulong(buf + len,(unsigned long) now()); | ||
| 159 | len += fmt_str(buf + len," qp "); | ||
| 160 | len += fmt_ulong(buf + len,qp); | ||
| 161 | buf[len] = 0; | ||
| 162 | result = buf; | ||
| 163 | } | ||
| 164 | |||
| 165 | if (!flagok) | ||
| 166 | result = "Dsorry, I can't accept addresses like that (#5.1.3)"; | ||
| 167 | |||
| 168 | substdio_put(&ssout,strnum,fmt_ulong(strnum,(unsigned long) str_len(result))); | ||
| 169 | substdio_puts(&ssout,":"); | ||
| 170 | substdio_puts(&ssout,result); | ||
| 171 | substdio_puts(&ssout,","); | ||
| 172 | substdio_flush(&ssout); | ||
| 173 | _exit(0); | ||
| 174 | } | ||
diff --git a/qmail-qmtpd.8 b/qmail-qmtpd.8 new file mode 100644 index 0000000..244fdbf --- /dev/null +++ b/qmail-qmtpd.8 | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | .TH qmail-qmtpd 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-qmtpd \- receive mail via QMTP | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-qmtpd | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B qmail-qmtpd | ||
| 8 | receives mail messages via the Quick Mail Transfer Protocol (QMTP) | ||
| 9 | and invokes | ||
| 10 | .B qmail-queue | ||
| 11 | to deposit them into the outgoing queue. | ||
| 12 | .B qmail-qmtpd | ||
| 13 | must be supplied several environment variables; | ||
| 14 | see | ||
| 15 | .BR tcp-environ(5) . | ||
| 16 | |||
| 17 | .B qmail-qmtpd | ||
| 18 | supports the | ||
| 19 | .IR rcpthosts , | ||
| 20 | .IR morercpthosts , | ||
| 21 | .BR RELAYCLIENT , | ||
| 22 | .IR databytes , | ||
| 23 | and | ||
| 24 | .B DATABYTES | ||
| 25 | mechanisms described in | ||
| 26 | .BR qmail-smtpd(8) . | ||
| 27 | .SH "SEE ALSO" | ||
| 28 | tcp-env(1), | ||
| 29 | tcp-environ(5), | ||
| 30 | qmail-control(5), | ||
| 31 | qmail-queue(8), | ||
| 32 | qmail-smtpd(8) | ||
diff --git a/qmail-qmtpd.c b/qmail-qmtpd.c new file mode 100644 index 0000000..df911a6 --- /dev/null +++ b/qmail-qmtpd.c | |||
| @@ -0,0 +1,268 @@ | |||
| 1 | #include "stralloc.h" | ||
| 2 | #include "substdio.h" | ||
| 3 | #include "qmail.h" | ||
| 4 | #include "now.h" | ||
| 5 | #include "str.h" | ||
| 6 | #include "fmt.h" | ||
| 7 | #include "env.h" | ||
| 8 | #include "sig.h" | ||
| 9 | #include "rcpthosts.h" | ||
| 10 | #include "auto_qmail.h" | ||
| 11 | #include "readwrite.h" | ||
| 12 | #include "control.h" | ||
| 13 | #include "received.h" | ||
| 14 | |||
| 15 | void badproto() { _exit(100); } | ||
| 16 | void resources() { _exit(111); } | ||
| 17 | |||
| 18 | int safewrite(fd,buf,len) int fd; char *buf; int len; | ||
| 19 | { | ||
| 20 | int r; | ||
| 21 | r = write(fd,buf,len); | ||
| 22 | if (r <= 0) _exit(0); | ||
| 23 | return r; | ||
| 24 | } | ||
| 25 | |||
| 26 | char ssoutbuf[256]; | ||
| 27 | substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf); | ||
| 28 | |||
| 29 | int saferead(fd,buf,len) int fd; char *buf; int len; | ||
| 30 | { | ||
| 31 | int r; | ||
| 32 | substdio_flush(&ssout); | ||
| 33 | r = read(fd,buf,len); | ||
| 34 | if (r <= 0) _exit(0); | ||
| 35 | return r; | ||
| 36 | } | ||
| 37 | |||
| 38 | char ssinbuf[512]; | ||
| 39 | substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf); | ||
| 40 | |||
| 41 | unsigned long getlen() | ||
| 42 | { | ||
| 43 | unsigned long len = 0; | ||
| 44 | char ch; | ||
| 45 | for (;;) { | ||
| 46 | substdio_get(&ssin,&ch,1); | ||
| 47 | if (ch == ':') return len; | ||
| 48 | if (len > 200000000) resources(); | ||
| 49 | len = 10 * len + (ch - '0'); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | void getcomma() | ||
| 54 | { | ||
| 55 | char ch; | ||
| 56 | substdio_get(&ssin,&ch,1); | ||
| 57 | if (ch != ',') badproto(); | ||
| 58 | } | ||
| 59 | |||
| 60 | unsigned int databytes = 0; | ||
| 61 | unsigned int bytestooverflow = 0; | ||
| 62 | struct qmail qq; | ||
| 63 | |||
| 64 | char buf[1000]; | ||
| 65 | char buf2[100]; | ||
| 66 | |||
| 67 | char *remotehost; | ||
| 68 | char *remoteinfo; | ||
| 69 | char *remoteip; | ||
| 70 | char *local; | ||
| 71 | |||
| 72 | stralloc failure = {0}; | ||
| 73 | |||
| 74 | char *relayclient; | ||
| 75 | int relayclientlen; | ||
| 76 | |||
| 77 | main() | ||
| 78 | { | ||
| 79 | char ch; | ||
| 80 | int i; | ||
| 81 | unsigned long biglen; | ||
| 82 | unsigned long len; | ||
| 83 | int flagdos; | ||
| 84 | int flagsenderok; | ||
| 85 | int flagbother; | ||
| 86 | unsigned long qp; | ||
| 87 | char *result; | ||
| 88 | char *x; | ||
| 89 | unsigned long u; | ||
| 90 | |||
| 91 | sig_pipeignore(); | ||
| 92 | sig_alarmcatch(resources); | ||
| 93 | alarm(3600); | ||
| 94 | |||
| 95 | if (chdir(auto_qmail) == -1) resources(); | ||
| 96 | |||
| 97 | if (control_init() == -1) resources(); | ||
| 98 | if (rcpthosts_init() == -1) resources(); | ||
| 99 | relayclient = env_get("RELAYCLIENT"); | ||
| 100 | relayclientlen = relayclient ? str_len(relayclient) : 0; | ||
| 101 | |||
| 102 | if (control_readint(&databytes,"control/databytes") == -1) resources(); | ||
| 103 | x = env_get("DATABYTES"); | ||
| 104 | if (x) { scan_ulong(x,&u); databytes = u; } | ||
| 105 | if (!(databytes + 1)) --databytes; | ||
| 106 | |||
| 107 | remotehost = env_get("TCPREMOTEHOST"); | ||
| 108 | if (!remotehost) remotehost = "unknown"; | ||
| 109 | remoteinfo = env_get("TCPREMOTEINFO"); | ||
| 110 | remoteip = env_get("TCPREMOTEIP"); | ||
| 111 | if (!remoteip) remoteip = "unknown"; | ||
| 112 | local = env_get("TCPLOCALHOST"); | ||
| 113 | if (!local) local = env_get("TCPLOCALIP"); | ||
| 114 | if (!local) local = "unknown"; | ||
| 115 | |||
| 116 | for (;;) { | ||
| 117 | if (!stralloc_copys(&failure,"")) resources(); | ||
| 118 | flagsenderok = 1; | ||
| 119 | |||
| 120 | len = getlen(); | ||
| 121 | if (len == 0) badproto(); | ||
| 122 | |||
| 123 | if (databytes) bytestooverflow = databytes + 1; | ||
| 124 | if (qmail_open(&qq) == -1) resources(); | ||
| 125 | qp = qmail_qp(&qq); | ||
| 126 | |||
| 127 | substdio_get(&ssin,&ch,1); | ||
| 128 | --len; | ||
| 129 | if (ch == 10) flagdos = 0; | ||
| 130 | else if (ch == 13) flagdos = 1; | ||
| 131 | else badproto(); | ||
| 132 | |||
| 133 | received(&qq,"QMTP",local,remoteip,remotehost,remoteinfo,(char *) 0); | ||
| 134 | |||
| 135 | /* XXX: check for loops? only if len is big? */ | ||
| 136 | |||
| 137 | if (flagdos) | ||
| 138 | while (len > 0) { | ||
| 139 | substdio_get(&ssin,&ch,1); | ||
| 140 | --len; | ||
| 141 | while ((ch == 13) && len) { | ||
| 142 | substdio_get(&ssin,&ch,1); | ||
| 143 | --len; | ||
| 144 | if (ch == 10) break; | ||
| 145 | if (bytestooverflow) if (!--bytestooverflow) qmail_fail(&qq); | ||
| 146 | qmail_put(&qq,"\015",1); | ||
| 147 | } | ||
| 148 | if (bytestooverflow) if (!--bytestooverflow) qmail_fail(&qq); | ||
| 149 | qmail_put(&qq,&ch,1); | ||
| 150 | } | ||
| 151 | else { | ||
| 152 | if (databytes) | ||
| 153 | if (len > databytes) { | ||
| 154 | bytestooverflow = 0; | ||
| 155 | qmail_fail(&qq); | ||
| 156 | } | ||
| 157 | while (len > 0) { /* XXX: could speed this up, obviously */ | ||
| 158 | substdio_get(&ssin,&ch,1); | ||
| 159 | --len; | ||
| 160 | qmail_put(&qq,&ch,1); | ||
| 161 | } | ||
| 162 | } | ||
| 163 | getcomma(); | ||
| 164 | |||
| 165 | len = getlen(); | ||
| 166 | |||
| 167 | if (len >= 1000) { | ||
| 168 | buf[0] = 0; | ||
| 169 | flagsenderok = 0; | ||
| 170 | for (i = 0;i < len;++i) | ||
| 171 | substdio_get(&ssin,&ch,1); | ||
| 172 | } | ||
| 173 | else { | ||
| 174 | for (i = 0;i < len;++i) { | ||
| 175 | substdio_get(&ssin,buf + i,1); | ||
| 176 | if (!buf[i]) flagsenderok = 0; | ||
| 177 | } | ||
| 178 | buf[len] = 0; | ||
| 179 | } | ||
| 180 | getcomma(); | ||
| 181 | |||
| 182 | flagbother = 0; | ||
| 183 | qmail_from(&qq,buf); | ||
| 184 | if (!flagsenderok) qmail_fail(&qq); | ||
| 185 | |||
| 186 | biglen = getlen(); | ||
| 187 | while (biglen > 0) { | ||
| 188 | if (!stralloc_append(&failure,"")) resources(); | ||
| 189 | |||
| 190 | len = 0; | ||
| 191 | for (;;) { | ||
| 192 | if (!biglen) badproto(); | ||
| 193 | substdio_get(&ssin,&ch,1); | ||
| 194 | --biglen; | ||
| 195 | if (ch == ':') break; | ||
| 196 | if (len > 200000000) resources(); | ||
| 197 | len = 10 * len + (ch - '0'); | ||
| 198 | } | ||
| 199 | if (len >= biglen) badproto(); | ||
| 200 | if (len + relayclientlen >= 1000) { | ||
| 201 | failure.s[failure.len - 1] = 'L'; | ||
| 202 | for (i = 0;i < len;++i) | ||
| 203 | substdio_get(&ssin,&ch,1); | ||
| 204 | } | ||
| 205 | else { | ||
| 206 | for (i = 0;i < len;++i) { | ||
| 207 | substdio_get(&ssin,buf + i,1); | ||
| 208 | if (!buf[i]) failure.s[failure.len - 1] = 'N'; | ||
| 209 | } | ||
| 210 | buf[len] = 0; | ||
| 211 | |||
| 212 | if (relayclient) | ||
| 213 | str_copy(buf + len,relayclient); | ||
| 214 | else | ||
| 215 | switch(rcpthosts(buf,len)) { | ||
| 216 | case -1: resources(); | ||
| 217 | case 0: failure.s[failure.len - 1] = 'D'; | ||
| 218 | } | ||
| 219 | |||
| 220 | if (!failure.s[failure.len - 1]) { | ||
| 221 | qmail_to(&qq,buf); | ||
| 222 | flagbother = 1; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | getcomma(); | ||
| 226 | biglen -= (len + 1); | ||
| 227 | } | ||
| 228 | getcomma(); | ||
| 229 | |||
| 230 | if (!flagbother) qmail_fail(&qq); | ||
| 231 | result = qmail_close(&qq); | ||
| 232 | if (!flagsenderok) result = "Dunacceptable sender (#5.1.7)"; | ||
| 233 | if (databytes) if (!bytestooverflow) result = "Dsorry, that message size exceeds my databytes limit (#5.3.4)"; | ||
| 234 | |||
| 235 | if (*result) | ||
| 236 | len = str_len(result); | ||
| 237 | else { | ||
| 238 | /* success! */ | ||
| 239 | len = 0; | ||
| 240 | len += fmt_str(buf2 + len,"Kok "); | ||
| 241 | len += fmt_ulong(buf2 + len,(unsigned long) now()); | ||
| 242 | len += fmt_str(buf2 + len," qp "); | ||
| 243 | len += fmt_ulong(buf2 + len,qp); | ||
| 244 | buf2[len] = 0; | ||
| 245 | result = buf2; | ||
| 246 | } | ||
| 247 | |||
| 248 | len = fmt_ulong(buf,len); | ||
| 249 | buf[len++] = ':'; | ||
| 250 | len += fmt_str(buf + len,result); | ||
| 251 | buf[len++] = ','; | ||
| 252 | |||
| 253 | for (i = 0;i < failure.len;++i) | ||
| 254 | switch(failure.s[i]) { | ||
| 255 | case 0: | ||
| 256 | substdio_put(&ssout,buf,len); | ||
| 257 | break; | ||
| 258 | case 'D': | ||
| 259 | substdio_puts(&ssout,"66:Dsorry, that domain isn't in my list of allowed rcpthosts (#5.7.1),"); | ||
| 260 | break; | ||
| 261 | default: | ||
| 262 | substdio_puts(&ssout,"46:Dsorry, I can't handle that recipient (#5.1.3),"); | ||
| 263 | break; | ||
| 264 | } | ||
| 265 | |||
| 266 | /* ssout will be flushed when we read from the network again */ | ||
| 267 | } | ||
| 268 | } | ||
diff --git a/qmail-qread.8 b/qmail-qread.8 new file mode 100644 index 0000000..a4c31ef --- /dev/null +++ b/qmail-qread.8 | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | .TH qmail-qread 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-qread \- list outgoing messages and recipients | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-qread | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B qmail-qread | ||
| 8 | scans the outgoing queue of messages. | ||
| 9 | For each message it prints various human-readable information, | ||
| 10 | including the date the message entered the queue, | ||
| 11 | the number of bytes in the message, | ||
| 12 | the message sender, | ||
| 13 | and all the recipients still under consideration. | ||
| 14 | |||
| 15 | .B qmail-qread | ||
| 16 | must be run either as | ||
| 17 | .B root | ||
| 18 | or with user id | ||
| 19 | .B qmails | ||
| 20 | and group id | ||
| 21 | .BR qmail . | ||
| 22 | .SH "SEE ALSO" | ||
| 23 | qmail-qstat(8), | ||
| 24 | qmail-send(8) | ||
diff --git a/qmail-qread.c b/qmail-qread.c new file mode 100644 index 0000000..8ec0fbd --- /dev/null +++ b/qmail-qread.c | |||
| @@ -0,0 +1,175 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include "stralloc.h" | ||
| 4 | #include "substdio.h" | ||
| 5 | #include "subfd.h" | ||
| 6 | #include "fmt.h" | ||
| 7 | #include "str.h" | ||
| 8 | #include "getln.h" | ||
| 9 | #include "fmtqfn.h" | ||
| 10 | #include "readsubdir.h" | ||
| 11 | #include "auto_qmail.h" | ||
| 12 | #include "open.h" | ||
| 13 | #include "datetime.h" | ||
| 14 | #include "date822fmt.h" | ||
| 15 | #include "readwrite.h" | ||
| 16 | #include "error.h" | ||
| 17 | #include "exit.h" | ||
| 18 | |||
| 19 | readsubdir rs; | ||
| 20 | |||
| 21 | void die(n) int n; { substdio_flush(subfdout); _exit(n); } | ||
| 22 | |||
| 23 | void warn(s1,s2) char *s1; char *s2; | ||
| 24 | { | ||
| 25 | char *x; | ||
| 26 | x = error_str(errno); | ||
| 27 | substdio_puts(subfdout,s1); | ||
| 28 | substdio_puts(subfdout,s2); | ||
| 29 | substdio_puts(subfdout,": "); | ||
| 30 | substdio_puts(subfdout,x); | ||
| 31 | substdio_puts(subfdout,"\n"); | ||
| 32 | } | ||
| 33 | |||
| 34 | void die_nomem() { substdio_puts(subfdout,"fatal: out of memory\n"); die(111); } | ||
| 35 | void die_chdir() { warn("fatal: unable to chdir",""); die(111); } | ||
| 36 | void die_opendir(fn) char *fn; { warn("fatal: unable to opendir ",fn); die(111); } | ||
| 37 | |||
| 38 | void err(id) unsigned long id; | ||
| 39 | { | ||
| 40 | char foo[FMT_ULONG]; | ||
| 41 | foo[fmt_ulong(foo,id)] = 0; | ||
| 42 | warn("warning: trouble with #",foo); | ||
| 43 | } | ||
| 44 | |||
| 45 | char fnmess[FMTQFN]; | ||
| 46 | char fninfo[FMTQFN]; | ||
| 47 | char fnlocal[FMTQFN]; | ||
| 48 | char fnremote[FMTQFN]; | ||
| 49 | char fnbounce[FMTQFN]; | ||
| 50 | |||
| 51 | char inbuf[1024]; | ||
| 52 | stralloc sender = {0}; | ||
| 53 | |||
| 54 | unsigned long id; | ||
| 55 | datetime_sec qtime; | ||
| 56 | int flagbounce; | ||
| 57 | unsigned long size; | ||
| 58 | |||
| 59 | unsigned int fmtstats(s) | ||
| 60 | char *s; | ||
| 61 | { | ||
| 62 | struct datetime dt; | ||
| 63 | unsigned int len; | ||
| 64 | unsigned int i; | ||
| 65 | |||
| 66 | len = 0; | ||
| 67 | datetime_tai(&dt,qtime); | ||
| 68 | i = date822fmt(s,&dt) - 7/*XXX*/; len += i; if (s) s += i; | ||
| 69 | i = fmt_str(s," GMT #"); len += i; if (s) s += i; | ||
| 70 | i = fmt_ulong(s,id); len += i; if (s) s += i; | ||
| 71 | i = fmt_str(s," "); len += i; if (s) s += i; | ||
| 72 | i = fmt_ulong(s,size); len += i; if (s) s += i; | ||
| 73 | i = fmt_str(s," <"); len += i; if (s) s += i; | ||
| 74 | i = fmt_str(s,sender.s + 1); len += i; if (s) s += i; | ||
| 75 | i = fmt_str(s,"> "); len += i; if (s) s += i; | ||
| 76 | if (flagbounce) | ||
| 77 | { | ||
| 78 | i = fmt_str(s," bouncing"); len += i; if (s) s += i; | ||
| 79 | } | ||
| 80 | |||
| 81 | return len; | ||
| 82 | } | ||
| 83 | |||
| 84 | stralloc stats = {0}; | ||
| 85 | |||
| 86 | void out(s,n) char *s; unsigned int n; | ||
| 87 | { | ||
| 88 | while (n > 0) | ||
| 89 | { | ||
| 90 | substdio_put(subfdout,((*s >= 32) && (*s <= 126)) ? s : "_",1); | ||
| 91 | --n; | ||
| 92 | ++s; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | void outs(s) char *s; { out(s,str_len(s)); } | ||
| 96 | void outok(s) char *s; { substdio_puts(subfdout,s); } | ||
| 97 | |||
| 98 | void putstats() | ||
| 99 | { | ||
| 100 | if (!stralloc_ready(&stats,fmtstats(FMT_LEN))) die_nomem(); | ||
| 101 | stats.len = fmtstats(stats.s); | ||
| 102 | out(stats.s,stats.len); | ||
| 103 | outok("\n"); | ||
| 104 | } | ||
| 105 | |||
| 106 | stralloc line = {0}; | ||
| 107 | |||
| 108 | void main() | ||
| 109 | { | ||
| 110 | int channel; | ||
| 111 | int match; | ||
| 112 | struct stat st; | ||
| 113 | int fd; | ||
| 114 | substdio ss; | ||
| 115 | int x; | ||
| 116 | |||
| 117 | if (chdir(auto_qmail) == -1) die_chdir(); | ||
| 118 | if (chdir("queue") == -1) die_chdir(); | ||
| 119 | readsubdir_init(&rs,"info",die_opendir); | ||
| 120 | |||
| 121 | while (x = readsubdir_next(&rs,&id)) | ||
| 122 | if (x > 0) | ||
| 123 | { | ||
| 124 | fmtqfn(fnmess,"mess/",id,1); | ||
| 125 | fmtqfn(fninfo,"info/",id,1); | ||
| 126 | fmtqfn(fnlocal,"local/",id,1); | ||
| 127 | fmtqfn(fnremote,"remote/",id,1); | ||
| 128 | fmtqfn(fnbounce,"bounce/",id,0); | ||
| 129 | |||
| 130 | if (stat(fnmess,&st) == -1) { err(id); continue; } | ||
| 131 | size = st.st_size; | ||
| 132 | flagbounce = !stat(fnbounce,&st); | ||
| 133 | |||
| 134 | fd = open_read(fninfo); | ||
| 135 | if (fd == -1) { err(id); continue; } | ||
| 136 | substdio_fdbuf(&ss,read,fd,inbuf,sizeof(inbuf)); | ||
| 137 | if (getln(&ss,&sender,&match,0) == -1) die_nomem(); | ||
| 138 | if (fstat(fd,&st) == -1) { close(fd); err(id); continue; } | ||
| 139 | close(fd); | ||
| 140 | qtime = st.st_mtime; | ||
| 141 | |||
| 142 | putstats(); | ||
| 143 | |||
| 144 | for (channel = 0;channel < 2;++channel) | ||
| 145 | { | ||
| 146 | fd = open_read(channel ? fnremote : fnlocal); | ||
| 147 | if (fd == -1) | ||
| 148 | { | ||
| 149 | if (errno != error_noent) | ||
| 150 | err(id); | ||
| 151 | } | ||
| 152 | else | ||
| 153 | { | ||
| 154 | for (;;) | ||
| 155 | { | ||
| 156 | if (getln(&ss,&line,&match,0) == -1) die_nomem(); | ||
| 157 | if (!match) break; | ||
| 158 | switch(line.s[0]) | ||
| 159 | { | ||
| 160 | case 'D': | ||
| 161 | outok(" done"); | ||
| 162 | case 'T': | ||
| 163 | outok(channel ? "\tremote\t" : "\tlocal\t"); | ||
| 164 | outs(line.s + 1); | ||
| 165 | outok("\n"); | ||
| 166 | break; | ||
| 167 | } | ||
| 168 | } | ||
| 169 | close(fd); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | die(0); | ||
| 175 | } | ||
diff --git a/qmail-qstat.8 b/qmail-qstat.8 new file mode 100644 index 0000000..3491e34 --- /dev/null +++ b/qmail-qstat.8 | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | .TH qmail-qstat 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-qstat \- summarize status of mail queue | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-qstat | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B qmail-qstat | ||
| 8 | gives a human-readable breakdown | ||
| 9 | of the number of messages at various spots in the mail queue. | ||
| 10 | |||
| 11 | .B qmail-qstat | ||
| 12 | must be run either as | ||
| 13 | .B root | ||
| 14 | or with group id | ||
| 15 | .BR qmail . | ||
| 16 | .SH "SEE ALSO" | ||
| 17 | qmail-qread(8), | ||
| 18 | qmail-send(8) | ||
diff --git a/qmail-qstat.sh b/qmail-qstat.sh new file mode 100644 index 0000000..26a6d3f --- /dev/null +++ b/qmail-qstat.sh | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | cd QMAIL | ||
| 2 | messdirs=`echo queue/mess/* | wc -w` | ||
| 3 | messfiles=`find queue/mess/* -print | wc -w` | ||
| 4 | tododirs=`echo queue/todo | wc -w` | ||
| 5 | todofiles=`find queue/todo -print | wc -w` | ||
| 6 | echo messages in queue: `expr $messfiles - $messdirs` | ||
| 7 | echo messages in queue but not yet preprocessed: `expr $todofiles - $tododirs` | ||
diff --git a/qmail-queue.8 b/qmail-queue.8 new file mode 100644 index 0000000..12eea0c --- /dev/null +++ b/qmail-queue.8 | |||
| @@ -0,0 +1,155 @@ | |||
| 1 | .TH qmail-queue 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-queue \- queue a mail message for delivery | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-queue | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B qmail-queue | ||
| 8 | reads a mail message from descriptor 0. | ||
| 9 | It then reads envelope information from descriptor 1. | ||
| 10 | It places the message into the outgoing queue | ||
| 11 | for future delivery by | ||
| 12 | .BR qmail-send . | ||
| 13 | |||
| 14 | The envelope information is | ||
| 15 | an envelope sender address | ||
| 16 | followed by a list of envelope recipient addresses. | ||
| 17 | The sender address is preceded by the letter F | ||
| 18 | and terminated by a 0 byte. | ||
| 19 | Each recipient address is preceded by the letter T | ||
| 20 | and terminated by a 0 byte. | ||
| 21 | The list of recipient addresses is terminated by an extra 0 byte. | ||
| 22 | If | ||
| 23 | .B qmail-queue | ||
| 24 | sees end-of-file before the extra 0 byte, | ||
| 25 | it aborts without placing the message into the queue. | ||
| 26 | |||
| 27 | Every envelope recipient address | ||
| 28 | should contain a username, | ||
| 29 | an @ sign, | ||
| 30 | and a fully qualified domain name. | ||
| 31 | |||
| 32 | .B qmail-queue | ||
| 33 | always adds a | ||
| 34 | .B Received | ||
| 35 | line to the top of the message. | ||
| 36 | Other than this, | ||
| 37 | .B qmail-queue | ||
| 38 | does not inspect the message | ||
| 39 | and does not enforce any restrictions on its contents. | ||
| 40 | However, the recipients probably expect to see a proper header, | ||
| 41 | as described in | ||
| 42 | .BR qmail-header(5) . | ||
| 43 | .SH "FILESYSTEM RESTRICTIONS" | ||
| 44 | .B qmail-queue | ||
| 45 | imposes two constraints on the queue structure: | ||
| 46 | each | ||
| 47 | .B mess | ||
| 48 | subdirectory must be in the same filesystem as the | ||
| 49 | .B pid | ||
| 50 | directory; and each | ||
| 51 | .B todo | ||
| 52 | subdirectory must be in the same filesystem as the | ||
| 53 | .B intd | ||
| 54 | directory. | ||
| 55 | .SH "EXIT CODES" | ||
| 56 | .B qmail-queue | ||
| 57 | does not print diagnostics. | ||
| 58 | It exits | ||
| 59 | 0 if | ||
| 60 | it has successfully queued the message. | ||
| 61 | It exits between 1 and 99 if | ||
| 62 | it has failed to queue the message. | ||
| 63 | |||
| 64 | All | ||
| 65 | .B qmail-queue | ||
| 66 | error codes between 11 and 40 | ||
| 67 | indicate permanent errors: | ||
| 68 | .TP 5 | ||
| 69 | .B 11 | ||
| 70 | Address too long. | ||
| 71 | .TP | ||
| 72 | .B 31 | ||
| 73 | Mail server permanently refuses to send the message to any recipients. | ||
| 74 | (Not used by | ||
| 75 | .BR qmail-queue , | ||
| 76 | but can be used by programs offering the same interface.) | ||
| 77 | .PP | ||
| 78 | All other | ||
| 79 | .B qmail-queue | ||
| 80 | error codes indicate temporary errors: | ||
| 81 | .TP 5 | ||
| 82 | .B 51 | ||
| 83 | Out of memory. | ||
| 84 | .TP | ||
| 85 | .B 52 | ||
| 86 | Timeout. | ||
| 87 | .TP | ||
| 88 | .B 53 | ||
| 89 | Write error; e.g., disk full. | ||
| 90 | .TP | ||
| 91 | .B 54 | ||
| 92 | Unable to read the message or envelope. | ||
| 93 | .TP | ||
| 94 | .B 55 | ||
| 95 | Unable to read a configuration file. | ||
| 96 | (Not used by | ||
| 97 | .BR qmail-queue .) | ||
| 98 | .TP | ||
| 99 | .B 56 | ||
| 100 | Problem making a network connection from this host. | ||
| 101 | (Not used by | ||
| 102 | .BR qmail-queue .) | ||
| 103 | .TP | ||
| 104 | .B 61 | ||
| 105 | Problem with the qmail home directory. | ||
| 106 | .TP | ||
| 107 | .B 62 | ||
| 108 | Problem with the queue directory. | ||
| 109 | .TP | ||
| 110 | .B 63 | ||
| 111 | Problem with queue/pid. | ||
| 112 | .TP | ||
| 113 | .B 64 | ||
| 114 | Problem with queue/mess. | ||
| 115 | .TP | ||
| 116 | .B 65 | ||
| 117 | Problem with queue/intd. | ||
| 118 | .TP | ||
| 119 | .B 66 | ||
| 120 | Problem with queue/todo. | ||
| 121 | .TP | ||
| 122 | .B 71 | ||
| 123 | Mail server temporarily refuses to send the message to any recipients. | ||
| 124 | (Not used by | ||
| 125 | .BR qmail-queue .) | ||
| 126 | .TP | ||
| 127 | .B 72 | ||
| 128 | Connection to mail server timed out. | ||
| 129 | (Not used by | ||
| 130 | .BR qmail-queue .) | ||
| 131 | .TP | ||
| 132 | .B 73 | ||
| 133 | Connection to mail server rejected. | ||
| 134 | (Not used by | ||
| 135 | .BR qmail-queue .) | ||
| 136 | .TP | ||
| 137 | .B 74 | ||
| 138 | Connection to mail server succeeded, | ||
| 139 | but communication failed. | ||
| 140 | (Not used by | ||
| 141 | .BR qmail-queue .) | ||
| 142 | .TP | ||
| 143 | .B 81 | ||
| 144 | Internal bug; e.g., segmentation fault. | ||
| 145 | .TP | ||
| 146 | .B 91 | ||
| 147 | Envelope format error. | ||
| 148 | .SH "SEE ALSO" | ||
| 149 | addresses(5), | ||
| 150 | envelopes(5), | ||
| 151 | qmail-header(5), | ||
| 152 | qmail-inject(8), | ||
| 153 | qmail-qmqpc(8), | ||
| 154 | qmail-send(8), | ||
| 155 | qmail-smtpd(8) | ||
diff --git a/qmail-queue.c b/qmail-queue.c new file mode 100644 index 0000000..4b39a8f --- /dev/null +++ b/qmail-queue.c | |||
| @@ -0,0 +1,254 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include "readwrite.h" | ||
| 4 | #include "sig.h" | ||
| 5 | #include "exit.h" | ||
| 6 | #include "open.h" | ||
| 7 | #include "seek.h" | ||
| 8 | #include "fmt.h" | ||
| 9 | #include "alloc.h" | ||
| 10 | #include "substdio.h" | ||
| 11 | #include "datetime.h" | ||
| 12 | #include "now.h" | ||
| 13 | #include "triggerpull.h" | ||
| 14 | #include "extra.h" | ||
| 15 | #include "auto_qmail.h" | ||
| 16 | #include "auto_uids.h" | ||
| 17 | #include "date822fmt.h" | ||
| 18 | #include "fmtqfn.h" | ||
| 19 | |||
| 20 | #define DEATH 86400 /* 24 hours; _must_ be below q-s's OSSIFIED (36 hours) */ | ||
| 21 | #define ADDR 1003 | ||
| 22 | |||
| 23 | char inbuf[2048]; | ||
| 24 | struct substdio ssin; | ||
| 25 | char outbuf[256]; | ||
| 26 | struct substdio ssout; | ||
| 27 | |||
| 28 | datetime_sec starttime; | ||
| 29 | struct datetime dt; | ||
| 30 | unsigned long mypid; | ||
| 31 | unsigned long uid; | ||
| 32 | char *pidfn; | ||
| 33 | struct stat pidst; | ||
| 34 | unsigned long messnum; | ||
| 35 | char *messfn; | ||
| 36 | char *todofn; | ||
| 37 | char *intdfn; | ||
| 38 | int messfd; | ||
| 39 | int intdfd; | ||
| 40 | int flagmademess = 0; | ||
| 41 | int flagmadeintd = 0; | ||
| 42 | |||
| 43 | void cleanup() | ||
| 44 | { | ||
| 45 | if (flagmadeintd) | ||
| 46 | { | ||
| 47 | seek_trunc(intdfd,0); | ||
| 48 | if (unlink(intdfn) == -1) return; | ||
| 49 | } | ||
| 50 | if (flagmademess) | ||
| 51 | { | ||
| 52 | seek_trunc(messfd,0); | ||
| 53 | if (unlink(messfn) == -1) return; | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | void die(e) int e; { _exit(e); } | ||
| 58 | void die_write() { cleanup(); die(53); } | ||
| 59 | void die_read() { cleanup(); die(54); } | ||
| 60 | void sigalrm() { /* thou shalt not clean up here */ die(52); } | ||
| 61 | void sigbug() { die(81); } | ||
| 62 | |||
| 63 | unsigned int receivedlen; | ||
| 64 | char *received; | ||
| 65 | /* "Received: (qmail-queue invoked by alias); 26 Sep 1995 04:46:54 -0000\n" */ | ||
| 66 | |||
| 67 | static unsigned int receivedfmt(s) | ||
| 68 | char *s; | ||
| 69 | { | ||
| 70 | unsigned int i; | ||
| 71 | unsigned int len; | ||
| 72 | len = 0; | ||
| 73 | i = fmt_str(s,"Received: (qmail "); len += i; if (s) s += i; | ||
| 74 | i = fmt_ulong(s,mypid); len += i; if (s) s += i; | ||
| 75 | i = fmt_str(s," invoked "); len += i; if (s) s += i; | ||
| 76 | if (uid == auto_uida) | ||
| 77 | { i = fmt_str(s,"by alias"); len += i; if (s) s += i; } | ||
| 78 | else if (uid == auto_uidd) | ||
| 79 | { i = fmt_str(s,"from network"); len += i; if (s) s += i; } | ||
| 80 | else if (uid == auto_uids) | ||
| 81 | { i = fmt_str(s,"for bounce"); len += i; if (s) s += i; } | ||
| 82 | else | ||
| 83 | { | ||
| 84 | i = fmt_str(s,"by uid "); len += i; if (s) s += i; | ||
| 85 | i = fmt_ulong(s,uid); len += i; if (s) s += i; | ||
| 86 | } | ||
| 87 | i = fmt_str(s,"); "); len += i; if (s) s += i; | ||
| 88 | i = date822fmt(s,&dt); len += i; if (s) s += i; | ||
| 89 | return len; | ||
| 90 | } | ||
| 91 | |||
| 92 | void received_setup() | ||
| 93 | { | ||
| 94 | receivedlen = receivedfmt((char *) 0); | ||
| 95 | received = alloc(receivedlen + 1); | ||
| 96 | if (!received) die(51); | ||
| 97 | receivedfmt(received); | ||
| 98 | } | ||
| 99 | |||
| 100 | unsigned int pidfmt(s,seq) | ||
| 101 | char *s; | ||
| 102 | unsigned long seq; | ||
| 103 | { | ||
| 104 | unsigned int i; | ||
| 105 | unsigned int len; | ||
| 106 | |||
| 107 | len = 0; | ||
| 108 | i = fmt_str(s,"pid/"); len += i; if (s) s += i; | ||
| 109 | i = fmt_ulong(s,mypid); len += i; if (s) s += i; | ||
| 110 | i = fmt_str(s,"."); len += i; if (s) s += i; | ||
| 111 | i = fmt_ulong(s,starttime); len += i; if (s) s += i; | ||
| 112 | i = fmt_str(s,"."); len += i; if (s) s += i; | ||
| 113 | i = fmt_ulong(s,seq); len += i; if (s) s += i; | ||
| 114 | ++len; if (s) *s++ = 0; | ||
| 115 | |||
| 116 | return len; | ||
| 117 | } | ||
| 118 | |||
| 119 | char *fnnum(dirslash,flagsplit) | ||
| 120 | char *dirslash; | ||
| 121 | int flagsplit; | ||
| 122 | { | ||
| 123 | char *s; | ||
| 124 | |||
| 125 | s = alloc(fmtqfn((char *) 0,dirslash,messnum,flagsplit)); | ||
| 126 | if (!s) die(51); | ||
| 127 | fmtqfn(s,dirslash,messnum,flagsplit); | ||
| 128 | return s; | ||
| 129 | } | ||
| 130 | |||
| 131 | void pidopen() | ||
| 132 | { | ||
| 133 | unsigned int len; | ||
| 134 | unsigned long seq; | ||
| 135 | |||
| 136 | seq = 1; | ||
| 137 | len = pidfmt((char *) 0,seq); | ||
| 138 | pidfn = alloc(len); | ||
| 139 | if (!pidfn) die(51); | ||
| 140 | |||
| 141 | for (seq = 1;seq < 10;++seq) | ||
| 142 | { | ||
| 143 | if (pidfmt((char *) 0,seq) > len) die(81); /* paranoia */ | ||
| 144 | pidfmt(pidfn,seq); | ||
| 145 | messfd = open_excl(pidfn); | ||
| 146 | if (messfd != -1) return; | ||
| 147 | } | ||
| 148 | |||
| 149 | die(63); | ||
| 150 | } | ||
| 151 | |||
| 152 | char tmp[FMT_ULONG]; | ||
| 153 | |||
| 154 | void main() | ||
| 155 | { | ||
| 156 | unsigned int len; | ||
| 157 | char ch; | ||
| 158 | |||
| 159 | sig_blocknone(); | ||
| 160 | umask(033); | ||
| 161 | if (chdir(auto_qmail) == -1) die(61); | ||
| 162 | if (chdir("queue") == -1) die(62); | ||
| 163 | |||
| 164 | mypid = getpid(); | ||
| 165 | uid = getuid(); | ||
| 166 | starttime = now(); | ||
| 167 | datetime_tai(&dt,starttime); | ||
| 168 | |||
| 169 | received_setup(); | ||
| 170 | |||
| 171 | sig_pipeignore(); | ||
| 172 | sig_miscignore(); | ||
| 173 | sig_alarmcatch(sigalrm); | ||
| 174 | sig_bugcatch(sigbug); | ||
| 175 | |||
| 176 | alarm(DEATH); | ||
| 177 | |||
| 178 | pidopen(); | ||
| 179 | if (fstat(messfd,&pidst) == -1) die(63); | ||
| 180 | |||
| 181 | messnum = pidst.st_ino; | ||
| 182 | messfn = fnnum("mess/",1); | ||
| 183 | todofn = fnnum("todo/",0); | ||
| 184 | intdfn = fnnum("intd/",0); | ||
| 185 | |||
| 186 | if (link(pidfn,messfn) == -1) die(64); | ||
| 187 | if (unlink(pidfn) == -1) die(63); | ||
| 188 | flagmademess = 1; | ||
| 189 | |||
| 190 | substdio_fdbuf(&ssout,write,messfd,outbuf,sizeof(outbuf)); | ||
| 191 | substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf)); | ||
| 192 | |||
| 193 | if (substdio_bput(&ssout,received,receivedlen) == -1) die_write(); | ||
| 194 | |||
| 195 | switch(substdio_copy(&ssout,&ssin)) | ||
| 196 | { | ||
| 197 | case -2: die_read(); | ||
| 198 | case -3: die_write(); | ||
| 199 | } | ||
| 200 | |||
| 201 | if (substdio_flush(&ssout) == -1) die_write(); | ||
| 202 | if (fsync(messfd) == -1) die_write(); | ||
| 203 | |||
| 204 | intdfd = open_excl(intdfn); | ||
| 205 | if (intdfd == -1) die(65); | ||
| 206 | flagmadeintd = 1; | ||
| 207 | |||
| 208 | substdio_fdbuf(&ssout,write,intdfd,outbuf,sizeof(outbuf)); | ||
| 209 | substdio_fdbuf(&ssin,read,1,inbuf,sizeof(inbuf)); | ||
| 210 | |||
| 211 | if (substdio_bput(&ssout,"u",1) == -1) die_write(); | ||
| 212 | if (substdio_bput(&ssout,tmp,fmt_ulong(tmp,uid)) == -1) die_write(); | ||
| 213 | if (substdio_bput(&ssout,"",1) == -1) die_write(); | ||
| 214 | |||
| 215 | if (substdio_bput(&ssout,"p",1) == -1) die_write(); | ||
| 216 | if (substdio_bput(&ssout,tmp,fmt_ulong(tmp,mypid)) == -1) die_write(); | ||
| 217 | if (substdio_bput(&ssout,"",1) == -1) die_write(); | ||
| 218 | |||
| 219 | if (substdio_get(&ssin,&ch,1) < 1) die_read(); | ||
| 220 | if (ch != 'F') die(91); | ||
| 221 | if (substdio_bput(&ssout,&ch,1) == -1) die_write(); | ||
| 222 | for (len = 0;len < ADDR;++len) | ||
| 223 | { | ||
| 224 | if (substdio_get(&ssin,&ch,1) < 1) die_read(); | ||
| 225 | if (substdio_put(&ssout,&ch,1) == -1) die_write(); | ||
| 226 | if (!ch) break; | ||
| 227 | } | ||
| 228 | if (len >= ADDR) die(11); | ||
| 229 | |||
| 230 | if (substdio_bput(&ssout,QUEUE_EXTRA,QUEUE_EXTRALEN) == -1) die_write(); | ||
| 231 | |||
| 232 | for (;;) | ||
| 233 | { | ||
| 234 | if (substdio_get(&ssin,&ch,1) < 1) die_read(); | ||
| 235 | if (!ch) break; | ||
| 236 | if (ch != 'T') die(91); | ||
| 237 | if (substdio_bput(&ssout,&ch,1) == -1) die_write(); | ||
| 238 | for (len = 0;len < ADDR;++len) | ||
| 239 | { | ||
| 240 | if (substdio_get(&ssin,&ch,1) < 1) die_read(); | ||
| 241 | if (substdio_bput(&ssout,&ch,1) == -1) die_write(); | ||
| 242 | if (!ch) break; | ||
| 243 | } | ||
| 244 | if (len >= ADDR) die(11); | ||
| 245 | } | ||
| 246 | |||
| 247 | if (substdio_flush(&ssout) == -1) die_write(); | ||
| 248 | if (fsync(intdfd) == -1) die_write(); | ||
| 249 | |||
| 250 | if (link(intdfn,todofn) == -1) die(66); | ||
| 251 | |||
| 252 | triggerpull(); | ||
| 253 | die(0); | ||
| 254 | } | ||
diff --git a/qmail-remote.8 b/qmail-remote.8 new file mode 100644 index 0000000..08bae85 --- /dev/null +++ b/qmail-remote.8 | |||
| @@ -0,0 +1,205 @@ | |||
| 1 | .TH qmail-remote 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-remote \- send mail via SMTP | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-remote | ||
| 6 | .I host | ||
| 7 | .I sender | ||
| 8 | .I recip | ||
| 9 | [ | ||
| 10 | .I recip ... | ||
| 11 | ] | ||
| 12 | .SH DESCRIPTION | ||
| 13 | .B qmail-remote | ||
| 14 | reads a mail message from its input | ||
| 15 | and sends the message | ||
| 16 | to one or more recipients | ||
| 17 | at a remote host. | ||
| 18 | |||
| 19 | The remote host is | ||
| 20 | .BR qmail-remote 's | ||
| 21 | first argument, | ||
| 22 | .IR host . | ||
| 23 | .B qmail-remote | ||
| 24 | sends the message to | ||
| 25 | .IR host , | ||
| 26 | or to a mail exchanger for | ||
| 27 | .I host | ||
| 28 | listed in the Domain Name System, | ||
| 29 | via the Simple Mail Transfer Protocol (SMTP). | ||
| 30 | .I host | ||
| 31 | can be either a fully-qualified domain name: | ||
| 32 | |||
| 33 | .EX | ||
| 34 | silverton.berkeley.edu | ||
| 35 | .EE | ||
| 36 | |||
| 37 | or an IP address enclosed in brackets: | ||
| 38 | |||
| 39 | .EX | ||
| 40 | [128.32.183.163] | ||
| 41 | .EE | ||
| 42 | |||
| 43 | The envelope recipient addresses are listed as | ||
| 44 | .I recip | ||
| 45 | arguments to | ||
| 46 | .BR qmail-remote . | ||
| 47 | The envelope sender address is listed as | ||
| 48 | .I sender\fP. | ||
| 49 | |||
| 50 | Note that | ||
| 51 | .B qmail-remote | ||
| 52 | does not take options | ||
| 53 | and does not follow the | ||
| 54 | .B getopt | ||
| 55 | standard. | ||
| 56 | .SH TRANSPARENCY | ||
| 57 | End-of-file in SMTP is encoded as dot CR LF. | ||
| 58 | A dot at the beginning of a line is encoded as dot dot. | ||
| 59 | It is impossible in SMTP to send a message that does not end with a newline. | ||
| 60 | .B qmail-remote | ||
| 61 | converts the UNIX newline convention into the SMTP newline convention | ||
| 62 | by inserting CR before each LF. | ||
| 63 | |||
| 64 | It is a violation of the SMTP protocol | ||
| 65 | to send a message that contains long lines or non-ASCII characters. | ||
| 66 | However, | ||
| 67 | .B qmail-remote | ||
| 68 | will happily send such messages. | ||
| 69 | It is the user's responsibility to avoid generating illegal messages. | ||
| 70 | .SH "RESULTS" | ||
| 71 | .B qmail-remote | ||
| 72 | prints some number of | ||
| 73 | .I recipient reports\fP, | ||
| 74 | followed by a | ||
| 75 | .I message report\fR. | ||
| 76 | Each report is terminated by a 0 byte. | ||
| 77 | Each report begins with a single letter: | ||
| 78 | .TP 5 | ||
| 79 | r | ||
| 80 | Recipient report: acceptance. | ||
| 81 | .TP 5 | ||
| 82 | h | ||
| 83 | Recipient report: permanent rejection. | ||
| 84 | .TP 5 | ||
| 85 | s | ||
| 86 | Recipient report: temporary rejection. | ||
| 87 | .TP 5 | ||
| 88 | K | ||
| 89 | Message report: success. | ||
| 90 | .I host | ||
| 91 | has taken responsibility for delivering the message to each | ||
| 92 | acceptable recipient. | ||
| 93 | .TP 5 | ||
| 94 | Z | ||
| 95 | Message report: temporary failure. | ||
| 96 | .TP 5 | ||
| 97 | D | ||
| 98 | Message report: permanent failure. | ||
| 99 | .PP | ||
| 100 | After this letter comes a human-readable description of | ||
| 101 | what happened. | ||
| 102 | |||
| 103 | The recipient reports will always be printed in the same order as | ||
| 104 | .BR qmail-remote 's | ||
| 105 | .I recip | ||
| 106 | arguments. | ||
| 107 | Note that in failure cases there may be fewer | ||
| 108 | recipient reports | ||
| 109 | than | ||
| 110 | .I recip | ||
| 111 | arguments. | ||
| 112 | |||
| 113 | .B qmail-remote | ||
| 114 | always exits zero. | ||
| 115 | .SH "CONTROL FILES" | ||
| 116 | .TP 5 | ||
| 117 | .I helohost | ||
| 118 | Current host name, | ||
| 119 | for use solely in saying hello to the remote SMTP server. | ||
| 120 | Default: | ||
| 121 | .IR me , | ||
| 122 | if that is supplied; | ||
| 123 | otherwise | ||
| 124 | .B qmail-remote | ||
| 125 | refuses to run. | ||
| 126 | .TP 5 | ||
| 127 | .I smtproutes | ||
| 128 | Artificial SMTP routes. | ||
| 129 | Each route has the form | ||
| 130 | .IR domain\fB:\fIrelay , | ||
| 131 | without any extra spaces. | ||
| 132 | If | ||
| 133 | .I domain | ||
| 134 | matches | ||
| 135 | .IR host , | ||
| 136 | .B qmail-remote | ||
| 137 | will connect to | ||
| 138 | .IR relay , | ||
| 139 | as if | ||
| 140 | .I host | ||
| 141 | had | ||
| 142 | .I relay | ||
| 143 | as its only MX. | ||
| 144 | (It will also avoid doing any CNAME lookups on | ||
| 145 | .IR recip .) | ||
| 146 | .I host | ||
| 147 | may include a colon and a port number to use instead of the | ||
| 148 | normal SMTP port, 25: | ||
| 149 | |||
| 150 | .EX | ||
| 151 | inside.af.mil:firewall.af.mil:26 | ||
| 152 | .EE | ||
| 153 | |||
| 154 | .I relay | ||
| 155 | may be empty; | ||
| 156 | this tells | ||
| 157 | .B qmail-remote | ||
| 158 | to look up MX records as usual. | ||
| 159 | .I smtproutes | ||
| 160 | may include wildcards: | ||
| 161 | |||
| 162 | .EX | ||
| 163 | .af.mil: | ||
| 164 | :heaven.af.mil | ||
| 165 | .EE | ||
| 166 | |||
| 167 | Here | ||
| 168 | any address ending with | ||
| 169 | .B .af.mil | ||
| 170 | (but not | ||
| 171 | .B af.mil | ||
| 172 | itself) | ||
| 173 | is routed by its MX records; | ||
| 174 | any other address is artificially routed to | ||
| 175 | .BR heaven.af.mil . | ||
| 176 | |||
| 177 | The | ||
| 178 | .B qmail | ||
| 179 | system does not protect you if you create an artificial | ||
| 180 | mail loop between machines. | ||
| 181 | However, | ||
| 182 | you are always safe using | ||
| 183 | .I smtproutes | ||
| 184 | if you do not accept mail from the network. | ||
| 185 | .TP 5 | ||
| 186 | .I timeoutconnect | ||
| 187 | Number of seconds | ||
| 188 | .B qmail-remote | ||
| 189 | will wait for the remote SMTP server to accept a connection. | ||
| 190 | Default: 60. | ||
| 191 | The kernel normally imposes a 75-second upper limit. | ||
| 192 | .TP 5 | ||
| 193 | .I timeoutremote | ||
| 194 | Number of seconds | ||
| 195 | .B qmail-remote | ||
| 196 | will wait for each response from the remote SMTP server. | ||
| 197 | Default: 1200. | ||
| 198 | .SH "SEE ALSO" | ||
| 199 | addresses(5), | ||
| 200 | envelopes(5), | ||
| 201 | qmail-control(5), | ||
| 202 | qmail-send(8), | ||
| 203 | qmail-smtpd(8), | ||
| 204 | qmail-tcpok(8), | ||
| 205 | qmail-tcpto(8) | ||
diff --git a/qmail-remote.c b/qmail-remote.c new file mode 100644 index 0000000..7d65473 --- /dev/null +++ b/qmail-remote.c | |||
| @@ -0,0 +1,427 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/socket.h> | ||
| 3 | #include <netinet/in.h> | ||
| 4 | #include <arpa/inet.h> | ||
| 5 | #include "sig.h" | ||
| 6 | #include "stralloc.h" | ||
| 7 | #include "substdio.h" | ||
| 8 | #include "subfd.h" | ||
| 9 | #include "scan.h" | ||
| 10 | #include "case.h" | ||
| 11 | #include "error.h" | ||
| 12 | #include "auto_qmail.h" | ||
| 13 | #include "control.h" | ||
| 14 | #include "dns.h" | ||
| 15 | #include "alloc.h" | ||
| 16 | #include "quote.h" | ||
| 17 | #include "ip.h" | ||
| 18 | #include "ipalloc.h" | ||
| 19 | #include "ipme.h" | ||
| 20 | #include "gen_alloc.h" | ||
| 21 | #include "gen_allocdefs.h" | ||
| 22 | #include "str.h" | ||
| 23 | #include "now.h" | ||
| 24 | #include "exit.h" | ||
| 25 | #include "constmap.h" | ||
| 26 | #include "tcpto.h" | ||
| 27 | #include "readwrite.h" | ||
| 28 | #include "timeoutconn.h" | ||
| 29 | #include "timeoutread.h" | ||
| 30 | #include "timeoutwrite.h" | ||
| 31 | |||
| 32 | #define HUGESMTPTEXT 5000 | ||
| 33 | |||
| 34 | #define PORT_SMTP 25 /* silly rabbit, /etc/services is for users */ | ||
| 35 | unsigned long port = PORT_SMTP; | ||
| 36 | |||
| 37 | GEN_ALLOC_typedef(saa,stralloc,sa,len,a) | ||
| 38 | GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus) | ||
| 39 | static stralloc sauninit = {0}; | ||
| 40 | |||
| 41 | stralloc helohost = {0}; | ||
| 42 | stralloc routes = {0}; | ||
| 43 | struct constmap maproutes; | ||
| 44 | stralloc host = {0}; | ||
| 45 | stralloc sender = {0}; | ||
| 46 | |||
| 47 | saa reciplist = {0}; | ||
| 48 | |||
| 49 | struct ip_address partner; | ||
| 50 | |||
| 51 | void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); } | ||
| 52 | void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); } | ||
| 53 | void zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); } | ||
| 54 | void outsafe(sa) stralloc *sa; { int i; char ch; | ||
| 55 | for (i = 0;i < sa->len;++i) { | ||
| 56 | ch = sa->s[i]; if (ch < 33) ch = '?'; if (ch > 126) ch = '?'; | ||
| 57 | if (substdio_put(subfdoutsmall,&ch,1) == -1) _exit(0); } } | ||
| 58 | |||
| 59 | void temp_nomem() { out("ZOut of memory. (#4.3.0)\n"); zerodie(); } | ||
| 60 | void temp_oserr() { out("Z\ | ||
| 61 | System resources temporarily unavailable. (#4.3.0)\n"); zerodie(); } | ||
| 62 | void temp_noconn() { out("Z\ | ||
| 63 | Sorry, I wasn't able to establish an SMTP connection. (#4.4.1)\n"); zerodie(); } | ||
| 64 | void temp_read() { out("ZUnable to read message. (#4.3.0)\n"); zerodie(); } | ||
| 65 | void temp_dnscanon() { out("Z\ | ||
| 66 | CNAME lookup failed temporarily. (#4.4.3)\n"); zerodie(); } | ||
| 67 | void temp_dns() { out("Z\ | ||
| 68 | Sorry, I couldn't find any host by that name. (#4.1.2)\n"); zerodie(); } | ||
| 69 | void temp_chdir() { out("Z\ | ||
| 70 | Unable to switch to home directory. (#4.3.0)\n"); zerodie(); } | ||
| 71 | void temp_control() { out("Z\ | ||
| 72 | Unable to read control files. (#4.3.0)\n"); zerodie(); } | ||
| 73 | void perm_partialline() { out("D\ | ||
| 74 | SMTP cannot transfer messages with partial final lines. (#5.6.2)\n"); zerodie(); } | ||
| 75 | void perm_usage() { out("D\ | ||
| 76 | I (qmail-remote) was invoked improperly. (#5.3.5)\n"); zerodie(); } | ||
| 77 | void perm_dns() { out("D\ | ||
| 78 | Sorry, I couldn't find any host named "); | ||
| 79 | outsafe(&host); | ||
| 80 | out(". (#5.1.2)\n"); zerodie(); } | ||
| 81 | void perm_nomx() { out("D\ | ||
| 82 | Sorry, I couldn't find a mail exchanger or IP address. (#5.4.4)\n"); | ||
| 83 | zerodie(); } | ||
| 84 | void perm_ambigmx() { out("D\ | ||
| 85 | Sorry. Although I'm listed as a best-preference MX or A for that host,\n\ | ||
| 86 | it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n"); | ||
| 87 | zerodie(); } | ||
| 88 | |||
| 89 | void outhost() | ||
| 90 | { | ||
| 91 | char x[IPFMT]; | ||
| 92 | if (substdio_put(subfdoutsmall,x,ip_fmt(x,&partner)) == -1) _exit(0); | ||
| 93 | } | ||
| 94 | |||
| 95 | int flagcritical = 0; | ||
| 96 | |||
| 97 | void dropped() { | ||
| 98 | out("ZConnected to "); | ||
| 99 | outhost(); | ||
| 100 | out(" but connection died. "); | ||
| 101 | if (flagcritical) out("Possible duplicate! "); | ||
| 102 | out("(#4.4.2)\n"); | ||
| 103 | zerodie(); | ||
| 104 | } | ||
| 105 | |||
| 106 | int timeoutconnect = 60; | ||
| 107 | int smtpfd; | ||
| 108 | int timeout = 1200; | ||
| 109 | |||
| 110 | int saferead(fd,buf,len) int fd; char *buf; int len; | ||
| 111 | { | ||
| 112 | int r; | ||
| 113 | r = timeoutread(timeout,smtpfd,buf,len); | ||
| 114 | if (r <= 0) dropped(); | ||
| 115 | return r; | ||
| 116 | } | ||
| 117 | int safewrite(fd,buf,len) int fd; char *buf; int len; | ||
| 118 | { | ||
| 119 | int r; | ||
| 120 | r = timeoutwrite(timeout,smtpfd,buf,len); | ||
| 121 | if (r <= 0) dropped(); | ||
| 122 | return r; | ||
| 123 | } | ||
| 124 | |||
| 125 | char inbuf[1024]; | ||
| 126 | substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf); | ||
| 127 | char smtptobuf[1024]; | ||
| 128 | substdio smtpto = SUBSTDIO_FDBUF(safewrite,-1,smtptobuf,sizeof smtptobuf); | ||
| 129 | char smtpfrombuf[128]; | ||
| 130 | substdio smtpfrom = SUBSTDIO_FDBUF(saferead,-1,smtpfrombuf,sizeof smtpfrombuf); | ||
| 131 | |||
| 132 | stralloc smtptext = {0}; | ||
| 133 | |||
| 134 | void get(ch) | ||
| 135 | char *ch; | ||
| 136 | { | ||
| 137 | substdio_get(&smtpfrom,ch,1); | ||
| 138 | if (*ch != '\r') | ||
| 139 | if (smtptext.len < HUGESMTPTEXT) | ||
| 140 | if (!stralloc_append(&smtptext,ch)) temp_nomem(); | ||
| 141 | } | ||
| 142 | |||
| 143 | unsigned long smtpcode() | ||
| 144 | { | ||
| 145 | unsigned char ch; | ||
| 146 | unsigned long code; | ||
| 147 | |||
| 148 | if (!stralloc_copys(&smtptext,"")) temp_nomem(); | ||
| 149 | |||
| 150 | get(&ch); code = ch - '0'; | ||
| 151 | get(&ch); code = code * 10 + (ch - '0'); | ||
| 152 | get(&ch); code = code * 10 + (ch - '0'); | ||
| 153 | for (;;) { | ||
| 154 | get(&ch); | ||
| 155 | if (ch != '-') break; | ||
| 156 | while (ch != '\n') get(&ch); | ||
| 157 | get(&ch); | ||
| 158 | get(&ch); | ||
| 159 | get(&ch); | ||
| 160 | } | ||
| 161 | while (ch != '\n') get(&ch); | ||
| 162 | |||
| 163 | return code; | ||
| 164 | } | ||
| 165 | |||
| 166 | void outsmtptext() | ||
| 167 | { | ||
| 168 | int i; | ||
| 169 | if (smtptext.s) if (smtptext.len) { | ||
| 170 | out("Remote host said: "); | ||
| 171 | for (i = 0;i < smtptext.len;++i) | ||
| 172 | if (!smtptext.s[i]) smtptext.s[i] = '?'; | ||
| 173 | if (substdio_put(subfdoutsmall,smtptext.s,smtptext.len) == -1) _exit(0); | ||
| 174 | smtptext.len = 0; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | void quit(prepend,append) | ||
| 179 | char *prepend; | ||
| 180 | char *append; | ||
| 181 | { | ||
| 182 | substdio_putsflush(&smtpto,"QUIT\r\n"); | ||
| 183 | /* waiting for remote side is just too ridiculous */ | ||
| 184 | out(prepend); | ||
| 185 | outhost(); | ||
| 186 | out(append); | ||
| 187 | out(".\n"); | ||
| 188 | outsmtptext(); | ||
| 189 | zerodie(); | ||
| 190 | } | ||
| 191 | |||
| 192 | void blast() | ||
| 193 | { | ||
| 194 | int r; | ||
| 195 | char ch; | ||
| 196 | |||
| 197 | for (;;) { | ||
| 198 | r = substdio_get(&ssin,&ch,1); | ||
| 199 | if (r == 0) break; | ||
| 200 | if (r == -1) temp_read(); | ||
| 201 | if (ch == '.') | ||
| 202 | substdio_put(&smtpto,".",1); | ||
| 203 | while (ch != '\n') { | ||
| 204 | substdio_put(&smtpto,&ch,1); | ||
| 205 | r = substdio_get(&ssin,&ch,1); | ||
| 206 | if (r == 0) perm_partialline(); | ||
| 207 | if (r == -1) temp_read(); | ||
| 208 | } | ||
| 209 | substdio_put(&smtpto,"\r\n",2); | ||
| 210 | } | ||
| 211 | |||
| 212 | flagcritical = 1; | ||
| 213 | substdio_put(&smtpto,".\r\n",3); | ||
| 214 | substdio_flush(&smtpto); | ||
| 215 | } | ||
| 216 | |||
| 217 | stralloc recip = {0}; | ||
| 218 | |||
| 219 | void smtp() | ||
| 220 | { | ||
| 221 | unsigned long code; | ||
| 222 | int flagbother; | ||
| 223 | int i; | ||
| 224 | |||
| 225 | if (smtpcode() != 220) quit("ZConnected to "," but greeting failed"); | ||
| 226 | |||
| 227 | substdio_puts(&smtpto,"HELO "); | ||
| 228 | substdio_put(&smtpto,helohost.s,helohost.len); | ||
| 229 | substdio_puts(&smtpto,"\r\n"); | ||
| 230 | substdio_flush(&smtpto); | ||
| 231 | if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected"); | ||
| 232 | |||
| 233 | substdio_puts(&smtpto,"MAIL FROM:<"); | ||
| 234 | substdio_put(&smtpto,sender.s,sender.len); | ||
| 235 | substdio_puts(&smtpto,">\r\n"); | ||
| 236 | substdio_flush(&smtpto); | ||
| 237 | code = smtpcode(); | ||
| 238 | if (code >= 500) quit("DConnected to "," but sender was rejected"); | ||
| 239 | if (code >= 400) quit("ZConnected to "," but sender was rejected"); | ||
| 240 | |||
| 241 | flagbother = 0; | ||
| 242 | for (i = 0;i < reciplist.len;++i) { | ||
| 243 | substdio_puts(&smtpto,"RCPT TO:<"); | ||
| 244 | substdio_put(&smtpto,reciplist.sa[i].s,reciplist.sa[i].len); | ||
| 245 | substdio_puts(&smtpto,">\r\n"); | ||
| 246 | substdio_flush(&smtpto); | ||
| 247 | code = smtpcode(); | ||
| 248 | if (code >= 500) { | ||
| 249 | out("h"); outhost(); out(" does not like recipient.\n"); | ||
| 250 | outsmtptext(); zero(); | ||
| 251 | } | ||
| 252 | else if (code >= 400) { | ||
| 253 | out("s"); outhost(); out(" does not like recipient.\n"); | ||
| 254 | outsmtptext(); zero(); | ||
| 255 | } | ||
| 256 | else { | ||
| 257 | out("r"); zero(); | ||
| 258 | flagbother = 1; | ||
| 259 | } | ||
| 260 | } | ||
| 261 | if (!flagbother) quit("DGiving up on ",""); | ||
| 262 | |||
| 263 | substdio_putsflush(&smtpto,"DATA\r\n"); | ||
| 264 | code = smtpcode(); | ||
| 265 | if (code >= 500) quit("D"," failed on DATA command"); | ||
| 266 | if (code >= 400) quit("Z"," failed on DATA command"); | ||
| 267 | |||
| 268 | blast(); | ||
| 269 | code = smtpcode(); | ||
| 270 | flagcritical = 0; | ||
| 271 | if (code >= 500) quit("D"," failed after I sent the message"); | ||
| 272 | if (code >= 400) quit("Z"," failed after I sent the message"); | ||
| 273 | quit("K"," accepted message"); | ||
| 274 | } | ||
| 275 | |||
| 276 | stralloc canonhost = {0}; | ||
| 277 | stralloc canonbox = {0}; | ||
| 278 | |||
| 279 | void addrmangle(saout,s,flagalias,flagcname) | ||
| 280 | stralloc *saout; /* host has to be canonical, box has to be quoted */ | ||
| 281 | char *s; | ||
| 282 | int *flagalias; | ||
| 283 | int flagcname; | ||
| 284 | { | ||
| 285 | int j; | ||
| 286 | |||
| 287 | *flagalias = flagcname; | ||
| 288 | |||
| 289 | j = str_rchr(s,'@'); | ||
| 290 | if (!s[j]) { | ||
| 291 | if (!stralloc_copys(saout,s)) temp_nomem(); | ||
| 292 | return; | ||
| 293 | } | ||
| 294 | if (!stralloc_copys(&canonbox,s)) temp_nomem(); | ||
| 295 | canonbox.len = j; | ||
| 296 | if (!quote(saout,&canonbox)) temp_nomem(); | ||
| 297 | if (!stralloc_cats(saout,"@")) temp_nomem(); | ||
| 298 | |||
| 299 | if (!stralloc_copys(&canonhost,s + j + 1)) temp_nomem(); | ||
| 300 | if (flagcname) | ||
| 301 | switch(dns_cname(&canonhost)) { | ||
| 302 | case 0: *flagalias = 0; break; | ||
| 303 | case DNS_MEM: temp_nomem(); | ||
| 304 | case DNS_SOFT: temp_dnscanon(); | ||
| 305 | case DNS_HARD: ; /* alias loop, not our problem */ | ||
| 306 | } | ||
| 307 | |||
| 308 | if (!stralloc_cat(saout,&canonhost)) temp_nomem(); | ||
| 309 | } | ||
| 310 | |||
| 311 | void getcontrols() | ||
| 312 | { | ||
| 313 | if (control_init() == -1) temp_control(); | ||
| 314 | if (control_readint(&timeout,"control/timeoutremote") == -1) temp_control(); | ||
| 315 | if (control_readint(&timeoutconnect,"control/timeoutconnect") == -1) | ||
| 316 | temp_control(); | ||
| 317 | if (control_rldef(&helohost,"control/helohost",1,(char *) 0) != 1) | ||
| 318 | temp_control(); | ||
| 319 | switch(control_readfile(&routes,"control/smtproutes",0)) { | ||
| 320 | case -1: | ||
| 321 | temp_control(); | ||
| 322 | case 0: | ||
| 323 | if (!constmap_init(&maproutes,"",0,1)) temp_nomem(); break; | ||
| 324 | case 1: | ||
| 325 | if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break; | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | void main(argc,argv) | ||
| 330 | int argc; | ||
| 331 | char **argv; | ||
| 332 | { | ||
| 333 | static ipalloc ip = {0}; | ||
| 334 | int i; | ||
| 335 | unsigned long random; | ||
| 336 | char **recips; | ||
| 337 | unsigned long prefme; | ||
| 338 | int flagallaliases; | ||
| 339 | int flagalias; | ||
| 340 | char *relayhost; | ||
| 341 | |||
| 342 | sig_pipeignore(); | ||
| 343 | if (argc < 4) perm_usage(); | ||
| 344 | if (chdir(auto_qmail) == -1) temp_chdir(); | ||
| 345 | getcontrols(); | ||
| 346 | |||
| 347 | |||
| 348 | if (!stralloc_copys(&host,argv[1])) temp_nomem(); | ||
| 349 | |||
| 350 | relayhost = 0; | ||
| 351 | for (i = 0;i <= host.len;++i) | ||
| 352 | if ((i == 0) || (i == host.len) || (host.s[i] == '.')) | ||
| 353 | if (relayhost = constmap(&maproutes,host.s + i,host.len - i)) | ||
| 354 | break; | ||
| 355 | if (relayhost && !*relayhost) relayhost = 0; | ||
| 356 | |||
| 357 | if (relayhost) { | ||
| 358 | i = str_chr(relayhost,':'); | ||
| 359 | if (relayhost[i]) { | ||
| 360 | scan_ulong(relayhost + i + 1,&port); | ||
| 361 | relayhost[i] = 0; | ||
| 362 | } | ||
| 363 | if (!stralloc_copys(&host,relayhost)) temp_nomem(); | ||
| 364 | } | ||
| 365 | |||
| 366 | |||
| 367 | addrmangle(&sender,argv[2],&flagalias,0); | ||
| 368 | |||
| 369 | if (!saa_readyplus(&reciplist,0)) temp_nomem(); | ||
| 370 | if (ipme_init() != 1) temp_oserr(); | ||
| 371 | |||
| 372 | flagallaliases = 1; | ||
| 373 | recips = argv + 3; | ||
| 374 | while (*recips) { | ||
| 375 | if (!saa_readyplus(&reciplist,1)) temp_nomem(); | ||
| 376 | reciplist.sa[reciplist.len] = sauninit; | ||
| 377 | addrmangle(reciplist.sa + reciplist.len,*recips,&flagalias,!relayhost); | ||
| 378 | if (!flagalias) flagallaliases = 0; | ||
| 379 | ++reciplist.len; | ||
| 380 | ++recips; | ||
| 381 | } | ||
| 382 | |||
| 383 | |||
| 384 | random = now() + (getpid() << 16); | ||
| 385 | switch (relayhost ? dns_ip(&ip,&host) : dns_mxip(&ip,&host,random)) { | ||
| 386 | case DNS_MEM: temp_nomem(); | ||
| 387 | case DNS_SOFT: temp_dns(); | ||
| 388 | case DNS_HARD: perm_dns(); | ||
| 389 | case 1: | ||
| 390 | if (ip.len <= 0) temp_dns(); | ||
| 391 | } | ||
| 392 | |||
| 393 | if (ip.len <= 0) perm_nomx(); | ||
| 394 | |||
| 395 | prefme = 100000; | ||
| 396 | for (i = 0;i < ip.len;++i) | ||
| 397 | if (ipme_is(&ip.ix[i].ip)) | ||
| 398 | if (ip.ix[i].pref < prefme) | ||
| 399 | prefme = ip.ix[i].pref; | ||
| 400 | |||
| 401 | if (relayhost) prefme = 300000; | ||
| 402 | if (flagallaliases) prefme = 500000; | ||
| 403 | |||
| 404 | for (i = 0;i < ip.len;++i) | ||
| 405 | if (ip.ix[i].pref < prefme) | ||
| 406 | break; | ||
| 407 | |||
| 408 | if (i >= ip.len) | ||
| 409 | perm_ambigmx(); | ||
| 410 | |||
| 411 | for (i = 0;i < ip.len;++i) if (ip.ix[i].pref < prefme) { | ||
| 412 | if (tcpto(&ip.ix[i].ip)) continue; | ||
| 413 | |||
| 414 | smtpfd = socket(AF_INET,SOCK_STREAM,0); | ||
| 415 | if (smtpfd == -1) temp_oserr(); | ||
| 416 | |||
| 417 | if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) { | ||
| 418 | tcpto_err(&ip.ix[i].ip,0); | ||
| 419 | partner = ip.ix[i].ip; | ||
| 420 | smtp(); /* does not return */ | ||
| 421 | } | ||
| 422 | tcpto_err(&ip.ix[i].ip,errno == error_timeout); | ||
| 423 | close(smtpfd); | ||
| 424 | } | ||
| 425 | |||
| 426 | temp_noconn(); | ||
| 427 | } | ||
diff --git a/qmail-rspawn.8 b/qmail-rspawn.8 new file mode 100644 index 0000000..33e8d0d --- /dev/null +++ b/qmail-rspawn.8 | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | .TH qmail-rspawn 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-rspawn \- schedule remote deliveries | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-rspawn | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B qmail-rspawn | ||
| 8 | reads a series of remote delivery commands from descriptor 0, | ||
| 9 | invokes | ||
| 10 | .B qmail-remote | ||
| 11 | to perform the deliveries, | ||
| 12 | and prints the results to descriptor 1. | ||
| 13 | |||
| 14 | .B qmail-rspawn | ||
| 15 | invokes | ||
| 16 | .B qmail-remote | ||
| 17 | asynchronously, | ||
| 18 | so the results may not be in the same order as the commands. | ||
| 19 | .SH "SEE ALSO" | ||
| 20 | qmail-send(8), | ||
| 21 | qmail-remote(8) | ||
diff --git a/qmail-rspawn.c b/qmail-rspawn.c new file mode 100644 index 0000000..9d838e6 --- /dev/null +++ b/qmail-rspawn.c | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | #include "fd.h" | ||
| 2 | #include "wait.h" | ||
| 3 | #include "substdio.h" | ||
| 4 | #include "exit.h" | ||
| 5 | #include "fork.h" | ||
| 6 | #include "error.h" | ||
| 7 | #include "tcpto.h" | ||
| 8 | |||
| 9 | void initialize(argc,argv) | ||
| 10 | int argc; | ||
| 11 | char **argv; | ||
| 12 | { | ||
| 13 | tcpto_clean(); | ||
| 14 | } | ||
| 15 | |||
| 16 | int truncreport = 0; | ||
| 17 | |||
| 18 | void report(ss,wstat,s,len) | ||
| 19 | substdio *ss; | ||
| 20 | int wstat; | ||
| 21 | char *s; | ||
| 22 | int len; | ||
| 23 | { | ||
| 24 | int j; | ||
| 25 | int k; | ||
| 26 | int result; | ||
| 27 | int orr; | ||
| 28 | |||
| 29 | if (wait_crashed(wstat)) | ||
| 30 | { substdio_puts(ss,"Zqmail-remote crashed.\n"); return; } | ||
| 31 | switch(wait_exitcode(wstat)) | ||
| 32 | { | ||
| 33 | case 0: break; | ||
| 34 | case 111: substdio_puts(ss,"ZUnable to run qmail-remote.\n"); return; | ||
| 35 | default: substdio_puts(ss,"DUnable to run qmail-remote.\n"); return; | ||
| 36 | } | ||
| 37 | if (!len) | ||
| 38 | { substdio_puts(ss,"Zqmail-remote produced no output.\n"); return; } | ||
| 39 | |||
| 40 | result = -1; | ||
| 41 | j = 0; | ||
| 42 | for (k = 0;k < len;++k) | ||
| 43 | if (!s[k]) | ||
| 44 | { | ||
| 45 | if (s[j] == 'K') { result = 1; break; } | ||
| 46 | if (s[j] == 'Z') { result = 0; break; } | ||
| 47 | if (s[j] == 'D') break; | ||
| 48 | j = k + 1; | ||
| 49 | } | ||
| 50 | |||
| 51 | orr = result; | ||
| 52 | switch(s[0]) | ||
| 53 | { | ||
| 54 | case 's': orr = 0; break; | ||
| 55 | case 'h': orr = -1; | ||
| 56 | } | ||
| 57 | |||
| 58 | switch(orr) | ||
| 59 | { | ||
| 60 | case 1: substdio_put(ss,"K",1); break; | ||
| 61 | case 0: substdio_put(ss,"Z",1); break; | ||
| 62 | case -1: substdio_put(ss,"D",1); break; | ||
| 63 | } | ||
| 64 | |||
| 65 | for (k = 1;k < len;) | ||
| 66 | if (!s[k++]) | ||
| 67 | { | ||
| 68 | substdio_puts(ss,s + 1); | ||
| 69 | if (result <= orr) | ||
| 70 | if (k < len) | ||
| 71 | switch(s[k]) | ||
| 72 | { | ||
| 73 | case 'Z': case 'D': case 'K': | ||
| 74 | substdio_puts(ss,s + k + 1); | ||
| 75 | } | ||
| 76 | break; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | int spawn(fdmess,fdout,s,r,at) | ||
| 81 | int fdmess; int fdout; | ||
| 82 | char *s; char *r; int at; | ||
| 83 | { | ||
| 84 | int f; | ||
| 85 | char *(args[5]); | ||
| 86 | |||
| 87 | args[0] = "qmail-remote"; | ||
| 88 | args[1] = r + at + 1; | ||
| 89 | args[2] = s; | ||
| 90 | args[3] = r; | ||
| 91 | args[4] = 0; | ||
| 92 | |||
| 93 | if (!(f = vfork())) | ||
| 94 | { | ||
| 95 | if (fd_move(0,fdmess) == -1) _exit(111); | ||
| 96 | if (fd_move(1,fdout) == -1) _exit(111); | ||
| 97 | if (fd_copy(2,1) == -1) _exit(111); | ||
| 98 | execvp(*args,args); | ||
| 99 | if (error_temp(errno)) _exit(111); | ||
| 100 | _exit(100); | ||
| 101 | } | ||
| 102 | return f; | ||
| 103 | } | ||
diff --git a/qmail-send.9 b/qmail-send.9 new file mode 100644 index 0000000..acb04d0 --- /dev/null +++ b/qmail-send.9 | |||
| @@ -0,0 +1,246 @@ | |||
| 1 | .TH qmail-send 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-send \- deliver mail messages from the queue | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-send | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B qmail-send | ||
| 8 | handles messages placed into the outgoing queue by | ||
| 9 | .BR qmail-queue . | ||
| 10 | It uses | ||
| 11 | .B qmail-lspawn | ||
| 12 | to deliver messages to local recipients and | ||
| 13 | .B qmail-rspawn | ||
| 14 | to deliver messages to remote recipients. | ||
| 15 | If a message is temporarily undeliverable to one or more addresses, | ||
| 16 | .B qmail-send | ||
| 17 | leaves it in the queue and tries the addresses again later. | ||
| 18 | |||
| 19 | .B qmail-send | ||
| 20 | prints a readable record of its activities to descriptor 0. | ||
| 21 | It writes commands to | ||
| 22 | .BR qmail-lspawn , | ||
| 23 | .BR qmail-rspawn , | ||
| 24 | and | ||
| 25 | .B qmail-clean | ||
| 26 | on descriptors 1, 3, and 5, | ||
| 27 | and reads responses from descriptors 2, 4, and 6. | ||
| 28 | .B qmail-send | ||
| 29 | is responsible for avoiding deadlock. | ||
| 30 | |||
| 31 | If | ||
| 32 | .B qmail-send | ||
| 33 | receives a TERM signal, | ||
| 34 | it will exit cleanly, after waiting | ||
| 35 | (possibly more than a minute) | ||
| 36 | for current delivery attempts to finish. | ||
| 37 | |||
| 38 | If | ||
| 39 | .B qmail-send | ||
| 40 | receives an ALRM signal, | ||
| 41 | it will reschedule every message in the queue for immediate delivery. | ||
| 42 | .SH "CONTROL FILES" | ||
| 43 | .B WARNING: | ||
| 44 | .B qmail-send | ||
| 45 | reads its control files only when it starts. | ||
| 46 | If you change the control files, | ||
| 47 | you must stop and restart | ||
| 48 | .BR qmail-send . | ||
| 49 | Exception: | ||
| 50 | If | ||
| 51 | .B qmail-send | ||
| 52 | receives a HUP signal, | ||
| 53 | it will reread | ||
| 54 | .I locals | ||
| 55 | and | ||
| 56 | .IR virtualdomains . | ||
| 57 | .TP 5 | ||
| 58 | .I bouncefrom | ||
| 59 | Bounce username. | ||
| 60 | Default: | ||
| 61 | .BR MAILER-DAEMON . | ||
| 62 | .TP 5 | ||
| 63 | .I bouncehost | ||
| 64 | Bounce host. | ||
| 65 | Default: | ||
| 66 | .IR me , | ||
| 67 | if that is supplied; | ||
| 68 | otherwise the literal name | ||
| 69 | .BR bouncehost , | ||
| 70 | which is probably not what you want. | ||
| 71 | If a message is permanently undeliverable, | ||
| 72 | .B qmail-send | ||
| 73 | sends a | ||
| 74 | .B single-bounce | ||
| 75 | notice back to the message's envelope sender. | ||
| 76 | The notice is | ||
| 77 | .B From: \fIbouncefrom\fB@\fIbouncehost\fR, | ||
| 78 | although its envelope sender is empty. | ||
| 79 | .TP 5 | ||
| 80 | .I concurrencylocal | ||
| 81 | Maximum number of simultaneous local delivery attempts. | ||
| 82 | Default: 10. | ||
| 83 | If 0, local deliveries will be put on hold. | ||
| 84 | .I concurrencylocal | ||
| 85 | is limited at compile time to | ||
| 86 | SPAWN. | ||
| 87 | .TP 5 | ||
| 88 | .I concurrencyremote | ||
| 89 | Maximum number of simultaneous remote delivery attempts. | ||
| 90 | Default: 20. | ||
| 91 | If 0, remote deliveries will be put on hold. | ||
| 92 | .I concurrencyremote | ||
| 93 | is limited at compile time to | ||
| 94 | SPAWN. | ||
| 95 | .TP 5 | ||
| 96 | .I doublebouncehost | ||
| 97 | Double-bounce host. | ||
| 98 | Default: | ||
| 99 | .IR me , | ||
| 100 | if that is supplied; | ||
| 101 | otherwise the literal name | ||
| 102 | .BR doublebouncehost , | ||
| 103 | which is probably not what you want. | ||
| 104 | .TP 5 | ||
| 105 | .I doublebounceto | ||
| 106 | User to receive double-bounces. | ||
| 107 | Default: | ||
| 108 | .BR postmaster . | ||
| 109 | If a single-bounce notice is permanently undeliverable, | ||
| 110 | .B qmail-send | ||
| 111 | sends a | ||
| 112 | .B double-bounce | ||
| 113 | notice to | ||
| 114 | .IR doublebounceto\fB@\fIdoublebouncehost . | ||
| 115 | (If that bounces, | ||
| 116 | .B qmail-send | ||
| 117 | gives up.) | ||
| 118 | .TP 5 | ||
| 119 | .I envnoathost | ||
| 120 | Presumed domain name for addresses without @ signs. | ||
| 121 | Default: | ||
| 122 | .IR me , | ||
| 123 | if that is supplied; | ||
| 124 | otherwise the literal name | ||
| 125 | .BR envnoathost , | ||
| 126 | which is probably not what you want. | ||
| 127 | If | ||
| 128 | .B qmail-send | ||
| 129 | sees an envelope recipient address without an @ sign, | ||
| 130 | it appends | ||
| 131 | .B @\fIenvnoathost\fR. | ||
| 132 | .TP 5 | ||
| 133 | .I locals | ||
| 134 | List of domain names that the current host | ||
| 135 | receives mail for, | ||
| 136 | one per line. | ||
| 137 | Default: | ||
| 138 | .IR me , | ||
| 139 | if that is supplied; | ||
| 140 | otherwise | ||
| 141 | .B qmail-send | ||
| 142 | refuses to run. | ||
| 143 | An address | ||
| 144 | .I user@domain | ||
| 145 | is considered local if | ||
| 146 | .I domain | ||
| 147 | is listed in | ||
| 148 | .IR locals . | ||
| 149 | .TP 5 | ||
| 150 | .I percenthack | ||
| 151 | List of domain names where the percent hack is applied. | ||
| 152 | If | ||
| 153 | .I domain | ||
| 154 | is listed in | ||
| 155 | .IR percenthack , | ||
| 156 | any address of the form | ||
| 157 | .I user%fqdn@domain | ||
| 158 | is rewritten as | ||
| 159 | .IR user@fqdn . | ||
| 160 | .I user | ||
| 161 | may contain %, | ||
| 162 | so the percent hack may be applied repeatedly. | ||
| 163 | .B qmail-send | ||
| 164 | handles | ||
| 165 | .I percenthack | ||
| 166 | before | ||
| 167 | .IR locals . | ||
| 168 | .TP 5 | ||
| 169 | .I queuelifetime | ||
| 170 | Number of seconds | ||
| 171 | a message can stay in the queue. | ||
| 172 | Default: 604800 (one week). | ||
| 173 | After this time expires, | ||
| 174 | .B qmail-send | ||
| 175 | will try the message once more, | ||
| 176 | but it will treat any temporary delivery failures as | ||
| 177 | permanent failures. | ||
| 178 | .TP 5 | ||
| 179 | .I virtualdomains | ||
| 180 | List of virtual users or domains, one per line. | ||
| 181 | A virtual user has the form | ||
| 182 | .IR user\fB@\fIdomain\fB:\fIprepend , | ||
| 183 | without any extra spaces. | ||
| 184 | When | ||
| 185 | .B qmail-send | ||
| 186 | sees the recipient address | ||
| 187 | .IR user\fB@\fIdomain , | ||
| 188 | it converts it to | ||
| 189 | .I prepend\fB-\fIuser\fB@\fIdomain | ||
| 190 | and treats it as local. | ||
| 191 | |||
| 192 | A virtual domain has the form | ||
| 193 | .IR domain\fB:\fIprepend . | ||
| 194 | It applies to any recipient address at | ||
| 195 | .IR domain . | ||
| 196 | For example, if | ||
| 197 | |||
| 198 | .EX | ||
| 199 | nowhere.mil:joeBREAKfoo | ||
| 200 | .EE | ||
| 201 | |||
| 202 | is in | ||
| 203 | .IR virtualdomains , | ||
| 204 | and a message arrives for | ||
| 205 | .BR info@nowhere.mil , | ||
| 206 | .B qmail-send | ||
| 207 | will rewrite the recipient address as | ||
| 208 | .B joeBREAKfoo-info@nowhere.mil | ||
| 209 | and deliver the message locally. | ||
| 210 | |||
| 211 | .I virtualdomains | ||
| 212 | may contain wildcards: | ||
| 213 | |||
| 214 | .EX | ||
| 215 | .fax:uucpBREAKfax | ||
| 216 | :aliasBREAKcatchall | ||
| 217 | .nowhere.mil:joeBREAKfoo-host | ||
| 218 | .EE | ||
| 219 | |||
| 220 | .I virtualdomains | ||
| 221 | may also contain exceptions: | ||
| 222 | an empty | ||
| 223 | .I prepend | ||
| 224 | means that | ||
| 225 | .I domain | ||
| 226 | is not a virtual domain. | ||
| 227 | |||
| 228 | .B qmail-send | ||
| 229 | handles | ||
| 230 | .I virtualdomains | ||
| 231 | after | ||
| 232 | .IR locals : | ||
| 233 | if a domain is listed in | ||
| 234 | .IR locals , | ||
| 235 | .I virtualdomains | ||
| 236 | does not apply. | ||
| 237 | .SH "SEE ALSO" | ||
| 238 | nice(1), | ||
| 239 | addresses(5), | ||
| 240 | envelopes(5), | ||
| 241 | qmail-control(5), | ||
| 242 | qmail-log(5), | ||
| 243 | qmail-queue(8), | ||
| 244 | qmail-clean(8), | ||
| 245 | qmail-lspawn(8), | ||
| 246 | qmail-rspawn(8) | ||
diff --git a/qmail-send.c b/qmail-send.c new file mode 100644 index 0000000..c31b522 --- /dev/null +++ b/qmail-send.c | |||
| @@ -0,0 +1,1612 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include "readwrite.h" | ||
| 4 | #include "sig.h" | ||
| 5 | #include "direntry.h" | ||
| 6 | #include "control.h" | ||
| 7 | #include "select.h" | ||
| 8 | #include "open.h" | ||
| 9 | #include "seek.h" | ||
| 10 | #include "exit.h" | ||
| 11 | #include "lock.h" | ||
| 12 | #include "ndelay.h" | ||
| 13 | #include "now.h" | ||
| 14 | #include "getln.h" | ||
| 15 | #include "substdio.h" | ||
| 16 | #include "alloc.h" | ||
| 17 | #include "error.h" | ||
| 18 | #include "stralloc.h" | ||
| 19 | #include "str.h" | ||
| 20 | #include "byte.h" | ||
| 21 | #include "fmt.h" | ||
| 22 | #include "scan.h" | ||
| 23 | #include "case.h" | ||
| 24 | #include "auto_qmail.h" | ||
| 25 | #include "trigger.h" | ||
| 26 | #include "newfield.h" | ||
| 27 | #include "quote.h" | ||
| 28 | #include "qmail.h" | ||
| 29 | #include "qsutil.h" | ||
| 30 | #include "prioq.h" | ||
| 31 | #include "constmap.h" | ||
| 32 | #include "fmtqfn.h" | ||
| 33 | #include "readsubdir.h" | ||
| 34 | |||
| 35 | /* critical timing feature #1: if not triggered, do not busy-loop */ | ||
| 36 | /* critical timing feature #2: if triggered, respond within fixed time */ | ||
| 37 | /* important timing feature: when triggered, respond instantly */ | ||
| 38 | #define SLEEP_TODO 1500 /* check todo/ every 25 minutes in any case */ | ||
| 39 | #define SLEEP_FUZZ 1 /* slop a bit on sleeps to avoid zeno effect */ | ||
| 40 | #define SLEEP_FOREVER 86400 /* absolute maximum time spent in select() */ | ||
| 41 | #define SLEEP_CLEANUP 76431 /* time between cleanups */ | ||
| 42 | #define SLEEP_SYSFAIL 123 | ||
| 43 | #define OSSIFIED 129600 /* 36 hours; _must_ exceed q-q's DEATH (24 hours) */ | ||
| 44 | |||
| 45 | int lifetime = 604800; | ||
| 46 | |||
| 47 | stralloc percenthack = {0}; | ||
| 48 | struct constmap mappercenthack; | ||
| 49 | stralloc locals = {0}; | ||
| 50 | struct constmap maplocals; | ||
| 51 | stralloc vdoms = {0}; | ||
| 52 | struct constmap mapvdoms; | ||
| 53 | stralloc envnoathost = {0}; | ||
| 54 | stralloc bouncefrom = {0}; | ||
| 55 | stralloc bouncehost = {0}; | ||
| 56 | stralloc doublebounceto = {0}; | ||
| 57 | stralloc doublebouncehost = {0}; | ||
| 58 | |||
| 59 | char strnum2[FMT_ULONG]; | ||
| 60 | char strnum3[FMT_ULONG]; | ||
| 61 | |||
| 62 | #define CHANNELS 2 | ||
| 63 | char *chanaddr[CHANNELS] = { "local/", "remote/" }; | ||
| 64 | char *chanstatusmsg[CHANNELS] = { " local ", " remote " }; | ||
| 65 | char *tochan[CHANNELS] = { " to local ", " to remote " }; | ||
| 66 | int chanfdout[CHANNELS] = { 1, 3 }; | ||
| 67 | int chanfdin[CHANNELS] = { 2, 4 }; | ||
| 68 | int chanskip[CHANNELS] = { 10, 20 }; | ||
| 69 | |||
| 70 | int flagexitasap = 0; void sigterm() { flagexitasap = 1; } | ||
| 71 | int flagrunasap = 0; void sigalrm() { flagrunasap = 1; } | ||
| 72 | int flagreadasap = 0; void sighup() { flagreadasap = 1; } | ||
| 73 | |||
| 74 | void cleandied() { log1("alert: oh no! lost qmail-clean connection! dying...\n"); | ||
| 75 | flagexitasap = 1; } | ||
| 76 | |||
| 77 | int flagspawnalive[CHANNELS]; | ||
| 78 | void spawndied(c) int c; { log1("alert: oh no! lost spawn connection! dying...\n"); | ||
| 79 | flagspawnalive[c] = 0; flagexitasap = 1; } | ||
| 80 | |||
| 81 | #define REPORTMAX 10000 | ||
| 82 | |||
| 83 | datetime_sec recent; | ||
| 84 | |||
| 85 | |||
| 86 | /* this file is too long ----------------------------------------- FILENAMES */ | ||
| 87 | |||
| 88 | stralloc fn = {0}; | ||
| 89 | stralloc fn2 = {0}; | ||
| 90 | char fnmake_strnum[FMT_ULONG]; | ||
| 91 | |||
| 92 | void fnmake_init() | ||
| 93 | { | ||
| 94 | while (!stralloc_ready(&fn,FMTQFN)) nomem(); | ||
| 95 | while (!stralloc_ready(&fn2,FMTQFN)) nomem(); | ||
| 96 | } | ||
| 97 | |||
| 98 | void fnmake_info(id) unsigned long id; { fn.len = fmtqfn(fn.s,"info/",id,1); } | ||
| 99 | void fnmake_todo(id) unsigned long id; { fn.len = fmtqfn(fn.s,"todo/",id,0); } | ||
| 100 | void fnmake_mess(id) unsigned long id; { fn.len = fmtqfn(fn.s,"mess/",id,1); } | ||
| 101 | void fnmake_foop(id) unsigned long id; { fn.len = fmtqfn(fn.s,"foop/",id,0); } | ||
| 102 | void fnmake_split(id) unsigned long id; { fn.len = fmtqfn(fn.s,"",id,1); } | ||
| 103 | void fnmake2_bounce(id) unsigned long id; | ||
| 104 | { fn2.len = fmtqfn(fn2.s,"bounce/",id,0); } | ||
| 105 | void fnmake_chanaddr(id,c) unsigned long id; int c; | ||
| 106 | { fn.len = fmtqfn(fn.s,chanaddr[c],id,1); } | ||
| 107 | |||
| 108 | |||
| 109 | /* this file is too long ----------------------------------------- REWRITING */ | ||
| 110 | |||
| 111 | stralloc rwline = {0}; | ||
| 112 | |||
| 113 | /* 1 if by land, 2 if by sea, 0 if out of memory. not allowed to barf. */ | ||
| 114 | /* may trash recip. must set up rwline, between a T and a \0. */ | ||
| 115 | int rewrite(recip) | ||
| 116 | char *recip; | ||
| 117 | { | ||
| 118 | int i; | ||
| 119 | int j; | ||
| 120 | char *x; | ||
| 121 | static stralloc addr = {0}; | ||
| 122 | int at; | ||
| 123 | |||
| 124 | if (!stralloc_copys(&rwline,"T")) return 0; | ||
| 125 | if (!stralloc_copys(&addr,recip)) return 0; | ||
| 126 | |||
| 127 | i = byte_rchr(addr.s,addr.len,'@'); | ||
| 128 | if (i == addr.len) { | ||
| 129 | if (!stralloc_cats(&addr,"@")) return 0; | ||
| 130 | if (!stralloc_cat(&addr,&envnoathost)) return 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | while (constmap(&mappercenthack,addr.s + i + 1,addr.len - i - 1)) { | ||
| 134 | j = byte_rchr(addr.s,i,'%'); | ||
| 135 | if (j == i) break; | ||
| 136 | addr.len = i; | ||
| 137 | i = j; | ||
| 138 | addr.s[i] = '@'; | ||
| 139 | } | ||
| 140 | |||
| 141 | at = byte_rchr(addr.s,addr.len,'@'); | ||
| 142 | |||
| 143 | if (constmap(&maplocals,addr.s + at + 1,addr.len - at - 1)) { | ||
| 144 | if (!stralloc_cat(&rwline,&addr)) return 0; | ||
| 145 | if (!stralloc_0(&rwline)) return 0; | ||
| 146 | return 1; | ||
| 147 | } | ||
| 148 | |||
| 149 | for (i = 0;i <= addr.len;++i) | ||
| 150 | if (!i || (i == at + 1) || (i == addr.len) || ((i > at) && (addr.s[i] == '.'))) | ||
| 151 | if (x = constmap(&mapvdoms,addr.s + i,addr.len - i)) { | ||
| 152 | if (!*x) break; | ||
| 153 | if (!stralloc_cats(&rwline,x)) return 0; | ||
| 154 | if (!stralloc_cats(&rwline,"-")) return 0; | ||
| 155 | if (!stralloc_cat(&rwline,&addr)) return 0; | ||
| 156 | if (!stralloc_0(&rwline)) return 0; | ||
| 157 | return 1; | ||
| 158 | } | ||
| 159 | |||
| 160 | if (!stralloc_cat(&rwline,&addr)) return 0; | ||
| 161 | if (!stralloc_0(&rwline)) return 0; | ||
| 162 | return 2; | ||
| 163 | } | ||
| 164 | |||
| 165 | void senderadd(sa,sender,recip) | ||
| 166 | stralloc *sa; | ||
| 167 | char *sender; | ||
| 168 | char *recip; | ||
| 169 | { | ||
| 170 | int i; | ||
| 171 | int j; | ||
| 172 | int k; | ||
| 173 | |||
| 174 | i = str_len(sender); | ||
| 175 | if (i >= 4) | ||
| 176 | if (str_equal(sender + i - 4,"-@[]")) | ||
| 177 | { | ||
| 178 | j = byte_rchr(sender,i - 4,'@'); | ||
| 179 | k = str_rchr(recip,'@'); | ||
| 180 | if (recip[k] && (j + 5 <= i)) | ||
| 181 | { | ||
| 182 | /* owner-@host-@[] -> owner-recipbox=reciphost@host */ | ||
| 183 | while (!stralloc_catb(sa,sender,j)) nomem(); | ||
| 184 | while (!stralloc_catb(sa,recip,k)) nomem(); | ||
| 185 | while (!stralloc_cats(sa,"=")) nomem(); | ||
| 186 | while (!stralloc_cats(sa,recip + k + 1)) nomem(); | ||
| 187 | while (!stralloc_cats(sa,"@")) nomem(); | ||
| 188 | while (!stralloc_catb(sa,sender + j + 1,i - 5 - j)) nomem(); | ||
| 189 | return; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | while (!stralloc_cats(sa,sender)) nomem(); | ||
| 193 | } | ||
| 194 | |||
| 195 | |||
| 196 | /* this file is too long ---------------------------------------------- INFO */ | ||
| 197 | |||
| 198 | int getinfo(sa,dt,id) | ||
| 199 | stralloc *sa; | ||
| 200 | datetime_sec *dt; | ||
| 201 | unsigned long id; | ||
| 202 | { | ||
| 203 | int fdinfo; | ||
| 204 | struct stat st; | ||
| 205 | static stralloc line = {0}; | ||
| 206 | int match; | ||
| 207 | substdio ss; | ||
| 208 | char buf[128]; | ||
| 209 | |||
| 210 | fnmake_info(id); | ||
| 211 | fdinfo = open_read(fn.s); | ||
| 212 | if (fdinfo == -1) return 0; | ||
| 213 | if (fstat(fdinfo,&st) == -1) { close(fdinfo); return 0; } | ||
| 214 | substdio_fdbuf(&ss,read,fdinfo,buf,sizeof(buf)); | ||
| 215 | if (getln(&ss,&line,&match,'\0') == -1) { close(fdinfo); return 0; } | ||
| 216 | close(fdinfo); | ||
| 217 | if (!match) return 0; | ||
| 218 | if (line.s[0] != 'F') return 0; | ||
| 219 | |||
| 220 | *dt = st.st_mtime; | ||
| 221 | while (!stralloc_copys(sa,line.s + 1)) nomem(); | ||
| 222 | while (!stralloc_0(sa)) nomem(); | ||
| 223 | return 1; | ||
| 224 | } | ||
| 225 | |||
| 226 | |||
| 227 | /* this file is too long ------------------------------------- COMMUNICATION */ | ||
| 228 | |||
| 229 | substdio sstoqc; char sstoqcbuf[1024]; | ||
| 230 | substdio ssfromqc; char ssfromqcbuf[1024]; | ||
| 231 | stralloc comm_buf[CHANNELS] = { {0}, {0} }; | ||
| 232 | int comm_pos[CHANNELS]; | ||
| 233 | |||
| 234 | void comm_init() | ||
| 235 | { | ||
| 236 | int c; | ||
| 237 | substdio_fdbuf(&sstoqc,write,5,sstoqcbuf,sizeof(sstoqcbuf)); | ||
| 238 | substdio_fdbuf(&ssfromqc,read,6,ssfromqcbuf,sizeof(ssfromqcbuf)); | ||
| 239 | for (c = 0;c < CHANNELS;++c) | ||
| 240 | if (ndelay_on(chanfdout[c]) == -1) | ||
| 241 | /* this is so stupid: NDELAY semantics should be default on write */ | ||
| 242 | spawndied(c); /* drastic, but better than risking deadlock */ | ||
| 243 | } | ||
| 244 | |||
| 245 | int comm_canwrite(c) | ||
| 246 | int c; | ||
| 247 | { | ||
| 248 | /* XXX: could allow a bigger buffer; say 10 recipients */ | ||
| 249 | if (comm_buf[c].s && comm_buf[c].len) return 0; | ||
| 250 | return 1; | ||
| 251 | } | ||
| 252 | |||
| 253 | void comm_write(c,delnum,id,sender,recip) | ||
| 254 | int c; | ||
| 255 | int delnum; | ||
| 256 | unsigned long id; | ||
| 257 | char *sender; | ||
| 258 | char *recip; | ||
| 259 | { | ||
| 260 | char ch; | ||
| 261 | if (comm_buf[c].s && comm_buf[c].len) return; | ||
| 262 | while (!stralloc_copys(&comm_buf[c],"")) nomem(); | ||
| 263 | ch = delnum; | ||
| 264 | while (!stralloc_append(&comm_buf[c],&ch)) nomem(); | ||
| 265 | fnmake_split(id); | ||
| 266 | while (!stralloc_cats(&comm_buf[c],fn.s)) nomem(); | ||
| 267 | while (!stralloc_0(&comm_buf[c])) nomem(); | ||
| 268 | senderadd(&comm_buf[c],sender,recip); | ||
| 269 | while (!stralloc_0(&comm_buf[c])) nomem(); | ||
| 270 | while (!stralloc_cats(&comm_buf[c],recip)) nomem(); | ||
| 271 | while (!stralloc_0(&comm_buf[c])) nomem(); | ||
| 272 | comm_pos[c] = 0; | ||
| 273 | } | ||
| 274 | |||
| 275 | void comm_selprep(nfds,wfds) | ||
| 276 | int *nfds; | ||
| 277 | fd_set *wfds; | ||
| 278 | { | ||
| 279 | int c; | ||
| 280 | for (c = 0;c < CHANNELS;++c) | ||
| 281 | if (flagspawnalive[c]) | ||
| 282 | if (comm_buf[c].s && comm_buf[c].len) | ||
| 283 | { | ||
| 284 | FD_SET(chanfdout[c],wfds); | ||
| 285 | if (*nfds <= chanfdout[c]) | ||
| 286 | *nfds = chanfdout[c] + 1; | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | void comm_do(wfds) | ||
| 291 | fd_set *wfds; | ||
| 292 | { | ||
| 293 | int c; | ||
| 294 | for (c = 0;c < CHANNELS;++c) | ||
| 295 | if (flagspawnalive[c]) | ||
| 296 | if (comm_buf[c].s && comm_buf[c].len) | ||
| 297 | if (FD_ISSET(chanfdout[c],wfds)) | ||
| 298 | { | ||
| 299 | int w; | ||
| 300 | int len; | ||
| 301 | len = comm_buf[c].len; | ||
| 302 | w = write(chanfdout[c],comm_buf[c].s + comm_pos[c],len - comm_pos[c]); | ||
| 303 | if (w <= 0) | ||
| 304 | { | ||
| 305 | if ((w == -1) && (errno == error_pipe)) | ||
| 306 | spawndied(c); | ||
| 307 | else | ||
| 308 | continue; /* kernel select() bug; can't avoid busy-looping */ | ||
| 309 | } | ||
| 310 | else | ||
| 311 | { | ||
| 312 | comm_pos[c] += w; | ||
| 313 | if (comm_pos[c] == len) | ||
| 314 | comm_buf[c].len = 0; | ||
| 315 | } | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | |||
| 320 | /* this file is too long ------------------------------------------ CLEANUPS */ | ||
| 321 | |||
| 322 | int flagcleanup; /* if 1, cleanupdir is initialized and ready */ | ||
| 323 | readsubdir cleanupdir; | ||
| 324 | datetime_sec cleanuptime; | ||
| 325 | |||
| 326 | void cleanup_init() | ||
| 327 | { | ||
| 328 | flagcleanup = 0; | ||
| 329 | cleanuptime = now(); | ||
| 330 | } | ||
| 331 | |||
| 332 | void cleanup_selprep(wakeup) | ||
| 333 | datetime_sec *wakeup; | ||
| 334 | { | ||
| 335 | if (flagcleanup) *wakeup = 0; | ||
| 336 | if (*wakeup > cleanuptime) *wakeup = cleanuptime; | ||
| 337 | } | ||
| 338 | |||
| 339 | void cleanup_do() | ||
| 340 | { | ||
| 341 | char ch; | ||
| 342 | struct stat st; | ||
| 343 | unsigned long id; | ||
| 344 | |||
| 345 | if (!flagcleanup) | ||
| 346 | { | ||
| 347 | if (recent < cleanuptime) return; | ||
| 348 | readsubdir_init(&cleanupdir,"mess",pausedir); | ||
| 349 | flagcleanup = 1; | ||
| 350 | } | ||
| 351 | |||
| 352 | switch(readsubdir_next(&cleanupdir,&id)) | ||
| 353 | { | ||
| 354 | case 1: | ||
| 355 | break; | ||
| 356 | case 0: | ||
| 357 | flagcleanup = 0; | ||
| 358 | cleanuptime = recent + SLEEP_CLEANUP; | ||
| 359 | default: | ||
| 360 | return; | ||
| 361 | } | ||
| 362 | |||
| 363 | fnmake_mess(id); | ||
| 364 | if (stat(fn.s,&st) == -1) return; /* probably qmail-queue deleted it */ | ||
| 365 | if (recent <= st.st_atime + OSSIFIED) return; | ||
| 366 | |||
| 367 | fnmake_info(id); | ||
| 368 | if (stat(fn.s,&st) == 0) return; | ||
| 369 | if (errno != error_noent) return; | ||
| 370 | fnmake_todo(id); | ||
| 371 | if (stat(fn.s,&st) == 0) return; | ||
| 372 | if (errno != error_noent) return; | ||
| 373 | |||
| 374 | fnmake_foop(id); | ||
| 375 | if (substdio_putflush(&sstoqc,fn.s,fn.len) == -1) { cleandied(); return; } | ||
| 376 | if (substdio_get(&ssfromqc,&ch,1) != 1) { cleandied(); return; } | ||
| 377 | if (ch != '+') | ||
| 378 | log3("warning: qmail-clean unable to clean up ",fn.s,"\n"); | ||
| 379 | } | ||
| 380 | |||
| 381 | |||
| 382 | /* this file is too long ----------------------------------- PRIORITY QUEUES */ | ||
| 383 | |||
| 384 | prioq pqdone = {0}; /* -todo +info; HOPEFULLY -local -remote */ | ||
| 385 | prioq pqchan[CHANNELS] = { {0}, {0} }; | ||
| 386 | /* pqchan 0: -todo +info +local ?remote */ | ||
| 387 | /* pqchan 1: -todo +info ?local +remote */ | ||
| 388 | prioq pqfail = {0}; /* stat() failure; has to be pqadded again */ | ||
| 389 | |||
| 390 | void pqadd(id) | ||
| 391 | unsigned long id; | ||
| 392 | { | ||
| 393 | struct prioq_elt pe; | ||
| 394 | struct prioq_elt pechan[CHANNELS]; | ||
| 395 | int flagchan[CHANNELS]; | ||
| 396 | struct stat st; | ||
| 397 | int c; | ||
| 398 | |||
| 399 | #define CHECKSTAT if (errno != error_noent) goto fail; | ||
| 400 | |||
| 401 | fnmake_info(id); | ||
| 402 | if (stat(fn.s,&st) == -1) | ||
| 403 | { | ||
| 404 | CHECKSTAT | ||
| 405 | return; /* someone yanking our chain */ | ||
| 406 | } | ||
| 407 | |||
| 408 | fnmake_todo(id); | ||
| 409 | if (stat(fn.s,&st) != -1) return; /* look, ma, dad crashed writing info! */ | ||
| 410 | CHECKSTAT | ||
| 411 | |||
| 412 | for (c = 0;c < CHANNELS;++c) | ||
| 413 | { | ||
| 414 | fnmake_chanaddr(id,c); | ||
| 415 | if (stat(fn.s,&st) == -1) { flagchan[c] = 0; CHECKSTAT } | ||
| 416 | else { flagchan[c] = 1; pechan[c].id = id; pechan[c].dt = st.st_mtime; } | ||
| 417 | } | ||
| 418 | |||
| 419 | for (c = 0;c < CHANNELS;++c) | ||
| 420 | if (flagchan[c]) | ||
| 421 | while (!prioq_insert(&pqchan[c],&pechan[c])) nomem(); | ||
| 422 | |||
| 423 | for (c = 0;c < CHANNELS;++c) if (flagchan[c]) break; | ||
| 424 | if (c == CHANNELS) | ||
| 425 | { | ||
| 426 | pe.id = id; pe.dt = now(); | ||
| 427 | while (!prioq_insert(&pqdone,&pe)) nomem(); | ||
| 428 | } | ||
| 429 | |||
| 430 | return; | ||
| 431 | |||
| 432 | fail: | ||
| 433 | log3("warning: unable to stat ",fn.s,"; will try again later\n"); | ||
| 434 | pe.id = id; pe.dt = now() + SLEEP_SYSFAIL; | ||
| 435 | while (!prioq_insert(&pqfail,&pe)) nomem(); | ||
| 436 | } | ||
| 437 | |||
| 438 | void pqstart() | ||
| 439 | { | ||
| 440 | readsubdir rs; | ||
| 441 | int x; | ||
| 442 | unsigned long id; | ||
| 443 | |||
| 444 | readsubdir_init(&rs,"info",pausedir); | ||
| 445 | |||
| 446 | while (x = readsubdir_next(&rs,&id)) | ||
| 447 | if (x > 0) | ||
| 448 | pqadd(id); | ||
| 449 | } | ||
| 450 | |||
| 451 | void pqfinish() | ||
| 452 | { | ||
| 453 | int c; | ||
| 454 | struct prioq_elt pe; | ||
| 455 | time_t ut[2]; /* XXX: more portable than utimbuf, but still worrisome */ | ||
| 456 | |||
| 457 | for (c = 0;c < CHANNELS;++c) | ||
| 458 | while (prioq_min(&pqchan[c],&pe)) | ||
| 459 | { | ||
| 460 | prioq_delmin(&pqchan[c]); | ||
| 461 | fnmake_chanaddr(pe.id,c); | ||
| 462 | ut[0] = ut[1] = pe.dt; | ||
| 463 | if (utime(fn.s,ut) == -1) | ||
| 464 | log3("warning: unable to utime ",fn.s,"; message will be retried too soon\n"); | ||
| 465 | } | ||
| 466 | } | ||
| 467 | |||
| 468 | void pqrun() | ||
| 469 | { | ||
| 470 | int c; | ||
| 471 | int i; | ||
| 472 | for (c = 0;c < CHANNELS;++c) | ||
| 473 | if (pqchan[c].p) | ||
| 474 | if (pqchan[c].len) | ||
| 475 | for (i = 0;i < pqchan[c].len;++i) | ||
| 476 | pqchan[c].p[i].dt = recent; | ||
| 477 | } | ||
| 478 | |||
| 479 | |||
| 480 | /* this file is too long ---------------------------------------------- JOBS */ | ||
| 481 | |||
| 482 | struct job | ||
| 483 | { | ||
| 484 | int refs; /* if 0, this struct is unused */ | ||
| 485 | unsigned long id; | ||
| 486 | int channel; | ||
| 487 | datetime_sec retry; | ||
| 488 | stralloc sender; | ||
| 489 | int numtodo; | ||
| 490 | int flaghiteof; | ||
| 491 | int flagdying; | ||
| 492 | } | ||
| 493 | ; | ||
| 494 | |||
| 495 | int numjobs; | ||
| 496 | struct job *jo; | ||
| 497 | |||
| 498 | void job_init() | ||
| 499 | { | ||
| 500 | int j; | ||
| 501 | while (!(jo = (struct job *) alloc(numjobs * sizeof(struct job)))) nomem(); | ||
| 502 | for (j = 0;j < numjobs;++j) | ||
| 503 | { | ||
| 504 | jo[j].refs = 0; | ||
| 505 | jo[j].sender.s = 0; | ||
| 506 | } | ||
| 507 | } | ||
| 508 | |||
| 509 | int job_avail() | ||
| 510 | { | ||
| 511 | int j; | ||
| 512 | for (j = 0;j < numjobs;++j) if (!jo[j].refs) return 1; | ||
| 513 | return 0; | ||
| 514 | } | ||
| 515 | |||
| 516 | int job_open(id,channel) | ||
| 517 | unsigned long id; | ||
| 518 | int channel; | ||
| 519 | { | ||
| 520 | int j; | ||
| 521 | for (j = 0;j < numjobs;++j) if (!jo[j].refs) break; | ||
| 522 | if (j == numjobs) return -1; | ||
| 523 | jo[j].refs = 1; | ||
| 524 | jo[j].id = id; | ||
| 525 | jo[j].channel = channel; | ||
| 526 | jo[j].numtodo = 0; | ||
| 527 | jo[j].flaghiteof = 0; | ||
| 528 | return j; | ||
| 529 | } | ||
| 530 | |||
| 531 | void job_close(j) | ||
| 532 | int j; | ||
| 533 | { | ||
| 534 | struct prioq_elt pe; | ||
| 535 | struct stat st; | ||
| 536 | |||
| 537 | if (0 < --jo[j].refs) return; | ||
| 538 | |||
| 539 | pe.id = jo[j].id; | ||
| 540 | pe.dt = jo[j].retry; | ||
| 541 | if (jo[j].flaghiteof && !jo[j].numtodo) | ||
| 542 | { | ||
| 543 | fnmake_chanaddr(jo[j].id,jo[j].channel); | ||
| 544 | if (unlink(fn.s) == -1) | ||
| 545 | { | ||
| 546 | log3("warning: unable to unlink ",fn.s,"; will try again later\n"); | ||
| 547 | pe.dt = now() + SLEEP_SYSFAIL; | ||
| 548 | } | ||
| 549 | else | ||
| 550 | { | ||
| 551 | int c; | ||
| 552 | for (c = 0;c < CHANNELS;++c) if (c != jo[j].channel) | ||
| 553 | { | ||
| 554 | fnmake_chanaddr(jo[j].id,c); | ||
| 555 | if (stat(fn.s,&st) == 0) return; /* more channels going */ | ||
| 556 | if (errno != error_noent) | ||
| 557 | { | ||
| 558 | log3("warning: unable to stat ",fn.s,"\n"); | ||
| 559 | break; /* this is the only reason for HOPEFULLY */ | ||
| 560 | } | ||
| 561 | } | ||
| 562 | pe.dt = now(); | ||
| 563 | while (!prioq_insert(&pqdone,&pe)) nomem(); | ||
| 564 | return; | ||
| 565 | } | ||
| 566 | } | ||
| 567 | |||
| 568 | while (!prioq_insert(&pqchan[jo[j].channel],&pe)) nomem(); | ||
| 569 | } | ||
| 570 | |||
| 571 | |||
| 572 | /* this file is too long ------------------------------------------- BOUNCES */ | ||
| 573 | |||
| 574 | char *stripvdomprepend(recip) | ||
| 575 | char *recip; | ||
| 576 | { | ||
| 577 | int i; | ||
| 578 | char *domain; | ||
| 579 | int domainlen; | ||
| 580 | char *prepend; | ||
| 581 | |||
| 582 | i = str_rchr(recip,'@'); | ||
| 583 | if (!recip[i]) return recip; | ||
| 584 | domain = recip + i + 1; | ||
| 585 | domainlen = str_len(domain); | ||
| 586 | |||
| 587 | for (i = 0;i <= domainlen;++i) | ||
| 588 | if ((i == 0) || (i == domainlen) || (domain[i] == '.')) | ||
| 589 | if (prepend = constmap(&mapvdoms,domain + i,domainlen - i)) | ||
| 590 | { | ||
| 591 | if (!*prepend) break; | ||
| 592 | i = str_len(prepend); | ||
| 593 | if (str_diffn(recip,prepend,i)) break; | ||
| 594 | if (recip[i] != '-') break; | ||
| 595 | return recip + i + 1; | ||
| 596 | } | ||
| 597 | return recip; | ||
| 598 | } | ||
| 599 | |||
| 600 | stralloc bouncetext = {0}; | ||
| 601 | |||
| 602 | void addbounce(id,recip,report) | ||
| 603 | unsigned long id; | ||
| 604 | char *recip; | ||
| 605 | char *report; | ||
| 606 | { | ||
| 607 | int fd; | ||
| 608 | int pos; | ||
| 609 | int w; | ||
| 610 | while (!stralloc_copys(&bouncetext,"<")) nomem(); | ||
| 611 | while (!stralloc_cats(&bouncetext,stripvdomprepend(recip))) nomem(); | ||
| 612 | for (pos = 0;pos < bouncetext.len;++pos) | ||
| 613 | if (bouncetext.s[pos] == '\n') | ||
| 614 | bouncetext.s[pos] = '_'; | ||
| 615 | while (!stralloc_cats(&bouncetext,">:\n")) nomem(); | ||
| 616 | while (!stralloc_cats(&bouncetext,report)) nomem(); | ||
| 617 | if (report[0]) | ||
| 618 | if (report[str_len(report) - 1] != '\n') | ||
| 619 | while (!stralloc_cats(&bouncetext,"\n")) nomem(); | ||
| 620 | for (pos = bouncetext.len - 2;pos > 0;--pos) | ||
| 621 | if (bouncetext.s[pos] == '\n') | ||
| 622 | if (bouncetext.s[pos - 1] == '\n') | ||
| 623 | bouncetext.s[pos] = '/'; | ||
| 624 | while (!stralloc_cats(&bouncetext,"\n")) nomem(); | ||
| 625 | fnmake2_bounce(id); | ||
| 626 | for (;;) | ||
| 627 | { | ||
| 628 | fd = open_append(fn2.s); | ||
| 629 | if (fd != -1) break; | ||
| 630 | log1("alert: unable to append to bounce message; HELP! sleeping...\n"); | ||
| 631 | sleep(10); | ||
| 632 | } | ||
| 633 | pos = 0; | ||
| 634 | while (pos < bouncetext.len) | ||
| 635 | { | ||
| 636 | w = write(fd,bouncetext.s + pos,bouncetext.len - pos); | ||
| 637 | if (w <= 0) | ||
| 638 | { | ||
| 639 | log1("alert: unable to append to bounce message; HELP! sleeping...\n"); | ||
| 640 | sleep(10); | ||
| 641 | } | ||
| 642 | else | ||
| 643 | pos += w; | ||
| 644 | } | ||
| 645 | close(fd); | ||
| 646 | } | ||
| 647 | |||
| 648 | int injectbounce(id) | ||
| 649 | unsigned long id; | ||
| 650 | { | ||
| 651 | struct qmail qqt; | ||
| 652 | struct stat st; | ||
| 653 | char *bouncesender; | ||
| 654 | char *bouncerecip; | ||
| 655 | int r; | ||
| 656 | int fd; | ||
| 657 | substdio ssread; | ||
| 658 | char buf[128]; | ||
| 659 | char inbuf[128]; | ||
| 660 | static stralloc sender = {0}; | ||
| 661 | static stralloc quoted = {0}; | ||
| 662 | datetime_sec birth; | ||
| 663 | unsigned long qp; | ||
| 664 | |||
| 665 | if (!getinfo(&sender,&birth,id)) return 0; /* XXX: print warning */ | ||
| 666 | |||
| 667 | /* owner-@host-@[] -> owner-@host */ | ||
| 668 | if (sender.len >= 5) | ||
| 669 | if (str_equal(sender.s + sender.len - 5,"-@[]")) | ||
| 670 | { | ||
| 671 | sender.len -= 4; | ||
| 672 | sender.s[sender.len - 1] = 0; | ||
| 673 | } | ||
| 674 | |||
| 675 | fnmake2_bounce(id); | ||
| 676 | fnmake_mess(id); | ||
| 677 | if (stat(fn2.s,&st) == -1) | ||
| 678 | { | ||
| 679 | if (errno == error_noent) | ||
| 680 | return 1; | ||
| 681 | log3("warning: unable to stat ",fn2.s,"\n"); | ||
| 682 | return 0; | ||
| 683 | } | ||
| 684 | if (str_equal(sender.s,"#@[]")) | ||
| 685 | log3("triple bounce: discarding ",fn2.s,"\n"); | ||
| 686 | else | ||
| 687 | { | ||
| 688 | if (qmail_open(&qqt) == -1) | ||
| 689 | { log1("warning: unable to start qmail-queue, will try later\n"); return 0; } | ||
| 690 | qp = qmail_qp(&qqt); | ||
| 691 | |||
| 692 | if (*sender.s) { bouncesender = ""; bouncerecip = sender.s; } | ||
| 693 | else { bouncesender = "#@[]"; bouncerecip = doublebounceto.s; } | ||
| 694 | |||
| 695 | while (!newfield_datemake(now())) nomem(); | ||
| 696 | qmail_put(&qqt,newfield_date.s,newfield_date.len); | ||
| 697 | qmail_puts(&qqt,"From: "); | ||
| 698 | while (!quote("ed,&bouncefrom)) nomem(); | ||
| 699 | qmail_put(&qqt,quoted.s,quoted.len); | ||
| 700 | qmail_puts(&qqt,"@"); | ||
| 701 | qmail_put(&qqt,bouncehost.s,bouncehost.len); | ||
| 702 | qmail_puts(&qqt,"\nTo: "); | ||
| 703 | while (!quote2("ed,bouncerecip)) nomem(); | ||
| 704 | qmail_put(&qqt,quoted.s,quoted.len); | ||
| 705 | qmail_puts(&qqt,"\n\ | ||
| 706 | Subject: failure notice\n\ | ||
| 707 | \n\ | ||
| 708 | Hi. This is the qmail-send program at "); | ||
| 709 | qmail_put(&qqt,bouncehost.s,bouncehost.len); | ||
| 710 | qmail_puts(&qqt,*sender.s ? ".\n\ | ||
| 711 | I'm afraid I wasn't able to deliver your message to the following addresses.\n\ | ||
| 712 | This is a permanent error; I've given up. Sorry it didn't work out.\n\ | ||
| 713 | \n\ | ||
| 714 | " : ".\n\ | ||
| 715 | I tried to deliver a bounce message to this address, but the bounce bounced!\n\ | ||
| 716 | \n\ | ||
| 717 | "); | ||
| 718 | |||
| 719 | fd = open_read(fn2.s); | ||
| 720 | if (fd == -1) | ||
| 721 | qmail_fail(&qqt); | ||
| 722 | else | ||
| 723 | { | ||
| 724 | substdio_fdbuf(&ssread,read,fd,inbuf,sizeof(inbuf)); | ||
| 725 | while ((r = substdio_get(&ssread,buf,sizeof(buf))) > 0) | ||
| 726 | qmail_put(&qqt,buf,r); | ||
| 727 | close(fd); | ||
| 728 | if (r == -1) | ||
| 729 | qmail_fail(&qqt); | ||
| 730 | } | ||
| 731 | |||
| 732 | qmail_puts(&qqt,*sender.s ? "--- Below this line is a copy of the message.\n\n" : "--- Below this line is the original bounce.\n\n"); | ||
| 733 | qmail_puts(&qqt,"Return-Path: <"); | ||
| 734 | while (!quote2("ed,sender.s)) nomem(); | ||
| 735 | qmail_put(&qqt,quoted.s,quoted.len); | ||
| 736 | qmail_puts(&qqt,">\n"); | ||
| 737 | |||
| 738 | fd = open_read(fn.s); | ||
| 739 | if (fd == -1) | ||
| 740 | qmail_fail(&qqt); | ||
| 741 | else | ||
| 742 | { | ||
| 743 | substdio_fdbuf(&ssread,read,fd,inbuf,sizeof(inbuf)); | ||
| 744 | while ((r = substdio_get(&ssread,buf,sizeof(buf))) > 0) | ||
| 745 | qmail_put(&qqt,buf,r); | ||
| 746 | close(fd); | ||
| 747 | if (r == -1) | ||
| 748 | qmail_fail(&qqt); | ||
| 749 | } | ||
| 750 | |||
| 751 | qmail_from(&qqt,bouncesender); | ||
| 752 | qmail_to(&qqt,bouncerecip); | ||
| 753 | if (*qmail_close(&qqt)) | ||
| 754 | { log1("warning: trouble injecting bounce message, will try later\n"); return 0; } | ||
| 755 | |||
| 756 | strnum2[fmt_ulong(strnum2,id)] = 0; | ||
| 757 | log2("bounce msg ",strnum2); | ||
| 758 | strnum2[fmt_ulong(strnum2,qp)] = 0; | ||
| 759 | log3(" qp ",strnum2,"\n"); | ||
| 760 | } | ||
| 761 | if (unlink(fn2.s) == -1) | ||
| 762 | { | ||
| 763 | log3("warning: unable to unlink ",fn2.s,"\n"); | ||
| 764 | return 0; | ||
| 765 | } | ||
| 766 | return 1; | ||
| 767 | } | ||
| 768 | |||
| 769 | |||
| 770 | /* this file is too long ---------------------------------------- DELIVERIES */ | ||
| 771 | |||
| 772 | struct del | ||
| 773 | { | ||
| 774 | int used; | ||
| 775 | int j; | ||
| 776 | unsigned long delid; | ||
| 777 | seek_pos mpos; | ||
| 778 | stralloc recip; | ||
| 779 | } | ||
| 780 | ; | ||
| 781 | |||
| 782 | unsigned long masterdelid = 1; | ||
| 783 | unsigned int concurrency[CHANNELS] = { 10, 20 }; | ||
| 784 | unsigned int concurrencyused[CHANNELS] = { 0, 0 }; | ||
| 785 | struct del *d[CHANNELS]; | ||
| 786 | stralloc dline[CHANNELS]; | ||
| 787 | char delbuf[2048]; | ||
| 788 | |||
| 789 | void del_status() | ||
| 790 | { | ||
| 791 | int c; | ||
| 792 | |||
| 793 | log1("status:"); | ||
| 794 | for (c = 0;c < CHANNELS;++c) { | ||
| 795 | strnum2[fmt_ulong(strnum2,(unsigned long) concurrencyused[c])] = 0; | ||
| 796 | strnum3[fmt_ulong(strnum3,(unsigned long) concurrency[c])] = 0; | ||
| 797 | log2(chanstatusmsg[c],strnum2); | ||
| 798 | log2("/",strnum3); | ||
| 799 | } | ||
| 800 | if (flagexitasap) log1(" exitasap"); | ||
| 801 | log1("\n"); | ||
| 802 | } | ||
| 803 | |||
| 804 | void del_init() | ||
| 805 | { | ||
| 806 | int c; | ||
| 807 | int i; | ||
| 808 | for (c = 0;c < CHANNELS;++c) | ||
| 809 | { | ||
| 810 | flagspawnalive[c] = 1; | ||
| 811 | while (!(d[c] = (struct del *) alloc(concurrency[c] * sizeof(struct del)))) | ||
| 812 | nomem(); | ||
| 813 | for (i = 0;i < concurrency[c];++i) | ||
| 814 | { d[c][i].used = 0; d[c][i].recip.s = 0; } | ||
| 815 | dline[c].s = 0; | ||
| 816 | while (!stralloc_copys(&dline[c],"")) nomem(); | ||
| 817 | } | ||
| 818 | del_status(); | ||
| 819 | } | ||
| 820 | |||
| 821 | int del_canexit() | ||
| 822 | { | ||
| 823 | int c; | ||
| 824 | for (c = 0;c < CHANNELS;++c) | ||
| 825 | if (flagspawnalive[c]) /* if dead, nothing we can do about its jobs */ | ||
| 826 | if (concurrencyused[c]) return 0; | ||
| 827 | return 1; | ||
| 828 | } | ||
| 829 | |||
| 830 | int del_avail(c) | ||
| 831 | int c; | ||
| 832 | { | ||
| 833 | return flagspawnalive[c] && comm_canwrite(c) && (concurrencyused[c] < concurrency[c]); | ||
| 834 | } | ||
| 835 | |||
| 836 | void del_start(j,mpos,recip) | ||
| 837 | int j; | ||
| 838 | seek_pos mpos; | ||
| 839 | char *recip; | ||
| 840 | { | ||
| 841 | int i; | ||
| 842 | int c; | ||
| 843 | |||
| 844 | c = jo[j].channel; | ||
| 845 | if (!flagspawnalive[c]) return; | ||
| 846 | if (!comm_canwrite(c)) return; | ||
| 847 | |||
| 848 | for (i = 0;i < concurrency[c];++i) if (!d[c][i].used) break; | ||
| 849 | if (i == concurrency[c]) return; | ||
| 850 | |||
| 851 | if (!stralloc_copys(&d[c][i].recip,recip)) { nomem(); return; } | ||
| 852 | if (!stralloc_0(&d[c][i].recip)) { nomem(); return; } | ||
| 853 | d[c][i].j = j; ++jo[j].refs; | ||
| 854 | d[c][i].delid = masterdelid++; | ||
| 855 | d[c][i].mpos = mpos; | ||
| 856 | d[c][i].used = 1; ++concurrencyused[c]; | ||
| 857 | |||
| 858 | comm_write(c,i,jo[j].id,jo[j].sender.s,recip); | ||
| 859 | |||
| 860 | strnum2[fmt_ulong(strnum2,d[c][i].delid)] = 0; | ||
| 861 | strnum3[fmt_ulong(strnum3,jo[j].id)] = 0; | ||
| 862 | log2("starting delivery ",strnum2); | ||
| 863 | log3(": msg ",strnum3,tochan[c]); | ||
| 864 | logsafe(recip); | ||
| 865 | log1("\n"); | ||
| 866 | del_status(); | ||
| 867 | } | ||
| 868 | |||
| 869 | void markdone(c,id,pos) | ||
| 870 | int c; | ||
| 871 | unsigned long id; | ||
| 872 | seek_pos pos; | ||
| 873 | { | ||
| 874 | struct stat st; | ||
| 875 | int fd; | ||
| 876 | fnmake_chanaddr(id,c); | ||
| 877 | for (;;) | ||
| 878 | { | ||
| 879 | fd = open_write(fn.s); | ||
| 880 | if (fd == -1) break; | ||
| 881 | if (fstat(fd,&st) == -1) { close(fd); break; } | ||
| 882 | if (seek_set(fd,pos) == -1) { close(fd); break; } | ||
| 883 | if (write(fd,"D",1) != 1) { close(fd); break; } | ||
| 884 | /* further errors -> double delivery without us knowing about it, oh well */ | ||
| 885 | close(fd); | ||
| 886 | return; | ||
| 887 | } | ||
| 888 | log3("warning: trouble marking ",fn.s,"; message will be delivered twice!\n"); | ||
| 889 | } | ||
| 890 | |||
| 891 | void del_dochan(c) | ||
| 892 | int c; | ||
| 893 | { | ||
| 894 | int r; | ||
| 895 | char ch; | ||
| 896 | int i; | ||
| 897 | int delnum; | ||
| 898 | r = read(chanfdin[c],delbuf,sizeof(delbuf)); | ||
| 899 | if (r == -1) return; | ||
| 900 | if (r == 0) { spawndied(c); return; } | ||
| 901 | for (i = 0;i < r;++i) | ||
| 902 | { | ||
| 903 | ch = delbuf[i]; | ||
| 904 | while (!stralloc_append(&dline[c],&ch)) nomem(); | ||
| 905 | if (dline[c].len > REPORTMAX) | ||
| 906 | dline[c].len = REPORTMAX; | ||
| 907 | /* qmail-lspawn and qmail-rspawn are responsible for keeping it short */ | ||
| 908 | /* but from a security point of view, we don't trust rspawn */ | ||
| 909 | if (!ch && (dline[c].len > 1)) | ||
| 910 | { | ||
| 911 | delnum = (unsigned int) (unsigned char) dline[c].s[0]; | ||
| 912 | if ((delnum < 0) || (delnum >= concurrency[c]) || !d[c][delnum].used) | ||
| 913 | log1("warning: internal error: delivery report out of range\n"); | ||
| 914 | else | ||
| 915 | { | ||
| 916 | strnum3[fmt_ulong(strnum3,d[c][delnum].delid)] = 0; | ||
| 917 | if (dline[c].s[1] == 'Z') | ||
| 918 | if (jo[d[c][delnum].j].flagdying) | ||
| 919 | { | ||
| 920 | dline[c].s[1] = 'D'; | ||
| 921 | --dline[c].len; | ||
| 922 | while (!stralloc_cats(&dline[c],"I'm not going to try again; this message has been in the queue too long.\n")) nomem(); | ||
| 923 | while (!stralloc_0(&dline[c])) nomem(); | ||
| 924 | } | ||
| 925 | switch(dline[c].s[1]) | ||
| 926 | { | ||
| 927 | case 'K': | ||
| 928 | log3("delivery ",strnum3,": success: "); | ||
| 929 | logsafe(dline[c].s + 2); | ||
| 930 | log1("\n"); | ||
| 931 | markdone(c,jo[d[c][delnum].j].id,d[c][delnum].mpos); | ||
| 932 | --jo[d[c][delnum].j].numtodo; | ||
| 933 | break; | ||
| 934 | case 'Z': | ||
| 935 | log3("delivery ",strnum3,": deferral: "); | ||
| 936 | logsafe(dline[c].s + 2); | ||
| 937 | log1("\n"); | ||
| 938 | break; | ||
| 939 | case 'D': | ||
| 940 | log3("delivery ",strnum3,": failure: "); | ||
| 941 | logsafe(dline[c].s + 2); | ||
| 942 | log1("\n"); | ||
| 943 | addbounce(jo[d[c][delnum].j].id,d[c][delnum].recip.s,dline[c].s + 2); | ||
| 944 | markdone(c,jo[d[c][delnum].j].id,d[c][delnum].mpos); | ||
| 945 | --jo[d[c][delnum].j].numtodo; | ||
| 946 | break; | ||
| 947 | default: | ||
| 948 | log3("delivery ",strnum3,": report mangled, will defer\n"); | ||
| 949 | } | ||
| 950 | job_close(d[c][delnum].j); | ||
| 951 | d[c][delnum].used = 0; --concurrencyused[c]; | ||
| 952 | del_status(); | ||
| 953 | } | ||
| 954 | dline[c].len = 0; | ||
| 955 | } | ||
| 956 | } | ||
| 957 | } | ||
| 958 | |||
| 959 | void del_selprep(nfds,rfds) | ||
| 960 | int *nfds; | ||
| 961 | fd_set *rfds; | ||
| 962 | { | ||
| 963 | int c; | ||
| 964 | for (c = 0;c < CHANNELS;++c) | ||
| 965 | if (flagspawnalive[c]) | ||
| 966 | { | ||
| 967 | FD_SET(chanfdin[c],rfds); | ||
| 968 | if (*nfds <= chanfdin[c]) | ||
| 969 | *nfds = chanfdin[c] + 1; | ||
| 970 | } | ||
| 971 | } | ||
| 972 | |||
| 973 | void del_do(rfds) | ||
| 974 | fd_set *rfds; | ||
| 975 | { | ||
| 976 | int c; | ||
| 977 | for (c = 0;c < CHANNELS;++c) | ||
| 978 | if (flagspawnalive[c]) | ||
| 979 | if (FD_ISSET(chanfdin[c],rfds)) | ||
| 980 | del_dochan(c); | ||
| 981 | } | ||
| 982 | |||
| 983 | |||
| 984 | /* this file is too long -------------------------------------------- PASSES */ | ||
| 985 | |||
| 986 | struct | ||
| 987 | { | ||
| 988 | unsigned long id; /* if 0, need a new pass */ | ||
| 989 | int j; /* defined if id; job number */ | ||
| 990 | int fd; /* defined if id; reading from {local,remote} */ | ||
| 991 | seek_pos mpos; /* defined if id; mark position */ | ||
| 992 | substdio ss; | ||
| 993 | char buf[128]; | ||
| 994 | } | ||
| 995 | pass[CHANNELS]; | ||
| 996 | |||
| 997 | void pass_init() | ||
| 998 | { | ||
| 999 | int c; | ||
| 1000 | for (c = 0;c < CHANNELS;++c) pass[c].id = 0; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | void pass_selprep(wakeup) | ||
| 1004 | datetime_sec *wakeup; | ||
| 1005 | { | ||
| 1006 | int c; | ||
| 1007 | struct prioq_elt pe; | ||
| 1008 | if (flagexitasap) return; | ||
| 1009 | for (c = 0;c < CHANNELS;++c) | ||
| 1010 | if (pass[c].id) | ||
| 1011 | if (del_avail(c)) | ||
| 1012 | { *wakeup = 0; return; } | ||
| 1013 | if (job_avail()) | ||
| 1014 | for (c = 0;c < CHANNELS;++c) | ||
| 1015 | if (!pass[c].id) | ||
| 1016 | if (prioq_min(&pqchan[c],&pe)) | ||
| 1017 | if (*wakeup > pe.dt) | ||
| 1018 | *wakeup = pe.dt; | ||
| 1019 | if (prioq_min(&pqfail,&pe)) | ||
| 1020 | if (*wakeup > pe.dt) | ||
| 1021 | *wakeup = pe.dt; | ||
| 1022 | if (prioq_min(&pqdone,&pe)) | ||
| 1023 | if (*wakeup > pe.dt) | ||
| 1024 | *wakeup = pe.dt; | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | static datetime_sec squareroot(x) /* result^2 <= x < (result + 1)^2 */ | ||
| 1028 | datetime_sec x; /* assuming: >= 0 */ | ||
| 1029 | { | ||
| 1030 | datetime_sec y; | ||
| 1031 | datetime_sec yy; | ||
| 1032 | datetime_sec y21; | ||
| 1033 | int j; | ||
| 1034 | |||
| 1035 | y = 0; yy = 0; | ||
| 1036 | for (j = 15;j >= 0;--j) | ||
| 1037 | { | ||
| 1038 | y21 = (y << (j + 1)) + (1 << (j + j)); | ||
| 1039 | if (y21 <= x - yy) { y += (1 << j); yy += y21; } | ||
| 1040 | } | ||
| 1041 | return y; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | datetime_sec nextretry(birth,c) | ||
| 1045 | datetime_sec birth; | ||
| 1046 | int c; | ||
| 1047 | { | ||
| 1048 | int n; | ||
| 1049 | |||
| 1050 | if (birth > recent) n = 0; | ||
| 1051 | else n = squareroot(recent - birth); /* no need to add fuzz to recent */ | ||
| 1052 | n += chanskip[c]; | ||
| 1053 | return birth + n * n; | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | void pass_dochan(c) | ||
| 1057 | int c; | ||
| 1058 | { | ||
| 1059 | datetime_sec birth; | ||
| 1060 | struct prioq_elt pe; | ||
| 1061 | static stralloc line = {0}; | ||
| 1062 | int match; | ||
| 1063 | |||
| 1064 | if (flagexitasap) return; | ||
| 1065 | |||
| 1066 | if (!pass[c].id) | ||
| 1067 | { | ||
| 1068 | if (!job_avail()) return; | ||
| 1069 | if (!prioq_min(&pqchan[c],&pe)) return; | ||
| 1070 | if (pe.dt > recent) return; | ||
| 1071 | fnmake_chanaddr(pe.id,c); | ||
| 1072 | |||
| 1073 | prioq_delmin(&pqchan[c]); | ||
| 1074 | pass[c].mpos = 0; | ||
| 1075 | pass[c].fd = open_read(fn.s); | ||
| 1076 | if (pass[c].fd == -1) goto trouble; | ||
| 1077 | if (!getinfo(&line,&birth,pe.id)) { close(pass[c].fd); goto trouble; } | ||
| 1078 | pass[c].id = pe.id; | ||
| 1079 | substdio_fdbuf(&pass[c].ss,read,pass[c].fd,pass[c].buf,sizeof(pass[c].buf)); | ||
| 1080 | pass[c].j = job_open(pe.id,c); | ||
| 1081 | jo[pass[c].j].retry = nextretry(birth,c); | ||
| 1082 | jo[pass[c].j].flagdying = (recent > birth + lifetime); | ||
| 1083 | while (!stralloc_copy(&jo[pass[c].j].sender,&line)) nomem(); | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | if (!del_avail(c)) return; | ||
| 1087 | |||
| 1088 | if (getln(&pass[c].ss,&line,&match,'\0') == -1) | ||
| 1089 | { | ||
| 1090 | fnmake_chanaddr(pass[c].id,c); | ||
| 1091 | log3("warning: trouble reading ",fn.s,"; will try again later\n"); | ||
| 1092 | close(pass[c].fd); | ||
| 1093 | job_close(pass[c].j); | ||
| 1094 | pass[c].id = 0; | ||
| 1095 | return; | ||
| 1096 | } | ||
| 1097 | if (!match) | ||
| 1098 | { | ||
| 1099 | close(pass[c].fd); | ||
| 1100 | jo[pass[c].j].flaghiteof = 1; | ||
| 1101 | job_close(pass[c].j); | ||
| 1102 | pass[c].id = 0; | ||
| 1103 | return; | ||
| 1104 | } | ||
| 1105 | switch(line.s[0]) | ||
| 1106 | { | ||
| 1107 | case 'T': | ||
| 1108 | ++jo[pass[c].j].numtodo; | ||
| 1109 | del_start(pass[c].j,pass[c].mpos,line.s + 1); | ||
| 1110 | break; | ||
| 1111 | case 'D': | ||
| 1112 | break; | ||
| 1113 | default: | ||
| 1114 | fnmake_chanaddr(pass[c].id,c); | ||
| 1115 | log3("warning: unknown record type in ",fn.s,"!\n"); | ||
| 1116 | close(pass[c].fd); | ||
| 1117 | job_close(pass[c].j); | ||
| 1118 | pass[c].id = 0; | ||
| 1119 | return; | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | pass[c].mpos += line.len; | ||
| 1123 | return; | ||
| 1124 | |||
| 1125 | trouble: | ||
| 1126 | log3("warning: trouble opening ",fn.s,"; will try again later\n"); | ||
| 1127 | pe.dt = recent + SLEEP_SYSFAIL; | ||
| 1128 | while (!prioq_insert(&pqchan[c],&pe)) nomem(); | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | void messdone(id) | ||
| 1132 | unsigned long id; | ||
| 1133 | { | ||
| 1134 | char ch; | ||
| 1135 | int c; | ||
| 1136 | struct prioq_elt pe; | ||
| 1137 | struct stat st; | ||
| 1138 | |||
| 1139 | for (c = 0;c < CHANNELS;++c) | ||
| 1140 | { | ||
| 1141 | fnmake_chanaddr(id,c); | ||
| 1142 | if (stat(fn.s,&st) == 0) return; /* false alarm; consequence of HOPEFULLY */ | ||
| 1143 | if (errno != error_noent) | ||
| 1144 | { | ||
| 1145 | log3("warning: unable to stat ",fn.s,"; will try again later\n"); | ||
| 1146 | goto fail; | ||
| 1147 | } | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | fnmake_todo(id); | ||
| 1151 | if (stat(fn.s,&st) == 0) return; | ||
| 1152 | if (errno != error_noent) | ||
| 1153 | { | ||
| 1154 | log3("warning: unable to stat ",fn.s,"; will try again later\n"); | ||
| 1155 | goto fail; | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | fnmake_info(id); | ||
| 1159 | if (stat(fn.s,&st) == -1) | ||
| 1160 | { | ||
| 1161 | if (errno == error_noent) return; | ||
| 1162 | log3("warning: unable to stat ",fn.s,"; will try again later\n"); | ||
| 1163 | goto fail; | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | /* -todo +info -local -remote ?bounce */ | ||
| 1167 | if (!injectbounce(id)) | ||
| 1168 | goto fail; /* injectbounce() produced error message */ | ||
| 1169 | |||
| 1170 | strnum3[fmt_ulong(strnum3,id)] = 0; | ||
| 1171 | log3("end msg ",strnum3,"\n"); | ||
| 1172 | |||
| 1173 | /* -todo +info -local -remote -bounce */ | ||
| 1174 | fnmake_info(id); | ||
| 1175 | if (unlink(fn.s) == -1) | ||
| 1176 | { | ||
| 1177 | log3("warning: unable to unlink ",fn.s,"; will try again later\n"); | ||
| 1178 | goto fail; | ||
| 1179 | } | ||
| 1180 | |||
| 1181 | /* -todo -info -local -remote -bounce; we can relax */ | ||
| 1182 | fnmake_foop(id); | ||
| 1183 | if (substdio_putflush(&sstoqc,fn.s,fn.len) == -1) { cleandied(); return; } | ||
| 1184 | if (substdio_get(&ssfromqc,&ch,1) != 1) { cleandied(); return; } | ||
| 1185 | if (ch != '+') | ||
| 1186 | log3("warning: qmail-clean unable to clean up ",fn.s,"\n"); | ||
| 1187 | |||
| 1188 | return; | ||
| 1189 | |||
| 1190 | fail: | ||
| 1191 | pe.id = id; pe.dt = now() + SLEEP_SYSFAIL; | ||
| 1192 | while (!prioq_insert(&pqdone,&pe)) nomem(); | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | void pass_do() | ||
| 1196 | { | ||
| 1197 | int c; | ||
| 1198 | struct prioq_elt pe; | ||
| 1199 | |||
| 1200 | for (c = 0;c < CHANNELS;++c) pass_dochan(c); | ||
| 1201 | if (prioq_min(&pqfail,&pe)) | ||
| 1202 | if (pe.dt <= recent) | ||
| 1203 | { | ||
| 1204 | prioq_delmin(&pqfail); | ||
| 1205 | pqadd(pe.id); | ||
| 1206 | } | ||
| 1207 | if (prioq_min(&pqdone,&pe)) | ||
| 1208 | if (pe.dt <= recent) | ||
| 1209 | { | ||
| 1210 | prioq_delmin(&pqdone); | ||
| 1211 | messdone(pe.id); | ||
| 1212 | } | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | |||
| 1216 | /* this file is too long ---------------------------------------------- TODO */ | ||
| 1217 | |||
| 1218 | datetime_sec nexttodorun; | ||
| 1219 | DIR *tododir; /* if 0, have to opendir again */ | ||
| 1220 | stralloc todoline = {0}; | ||
| 1221 | char todobuf[SUBSTDIO_INSIZE]; | ||
| 1222 | char todobufinfo[512]; | ||
| 1223 | char todobufchan[CHANNELS][1024]; | ||
| 1224 | |||
| 1225 | void todo_init() | ||
| 1226 | { | ||
| 1227 | tododir = 0; | ||
| 1228 | nexttodorun = now(); | ||
| 1229 | trigger_set(); | ||
| 1230 | } | ||
| 1231 | |||
| 1232 | void todo_selprep(nfds,rfds,wakeup) | ||
| 1233 | int *nfds; | ||
| 1234 | fd_set *rfds; | ||
| 1235 | datetime_sec *wakeup; | ||
| 1236 | { | ||
| 1237 | if (flagexitasap) return; | ||
| 1238 | trigger_selprep(nfds,rfds); | ||
| 1239 | if (tododir) *wakeup = 0; | ||
| 1240 | if (*wakeup > nexttodorun) *wakeup = nexttodorun; | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | void todo_do(rfds) | ||
| 1244 | fd_set *rfds; | ||
| 1245 | { | ||
| 1246 | struct stat st; | ||
| 1247 | substdio ss; int fd; | ||
| 1248 | substdio ssinfo; int fdinfo; | ||
| 1249 | substdio sschan[CHANNELS]; | ||
| 1250 | int fdchan[CHANNELS]; | ||
| 1251 | int flagchan[CHANNELS]; | ||
| 1252 | struct prioq_elt pe; | ||
| 1253 | char ch; | ||
| 1254 | int match; | ||
| 1255 | unsigned long id; | ||
| 1256 | unsigned int len; | ||
| 1257 | direntry *d; | ||
| 1258 | int c; | ||
| 1259 | unsigned long uid; | ||
| 1260 | unsigned long pid; | ||
| 1261 | |||
| 1262 | fd = -1; | ||
| 1263 | fdinfo = -1; | ||
| 1264 | for (c = 0;c < CHANNELS;++c) fdchan[c] = -1; | ||
| 1265 | |||
| 1266 | if (flagexitasap) return; | ||
| 1267 | |||
| 1268 | if (!tododir) | ||
| 1269 | { | ||
| 1270 | if (!trigger_pulled(rfds)) | ||
| 1271 | if (recent < nexttodorun) | ||
| 1272 | return; | ||
| 1273 | trigger_set(); | ||
| 1274 | tododir = opendir("todo"); | ||
| 1275 | if (!tododir) | ||
| 1276 | { | ||
| 1277 | pausedir("todo"); | ||
| 1278 | return; | ||
| 1279 | } | ||
| 1280 | nexttodorun = recent + SLEEP_TODO; | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | d = readdir(tododir); | ||
| 1284 | if (!d) | ||
| 1285 | { | ||
| 1286 | closedir(tododir); | ||
| 1287 | tododir = 0; | ||
| 1288 | return; | ||
| 1289 | } | ||
| 1290 | if (str_equal(d->d_name,".")) return; | ||
| 1291 | if (str_equal(d->d_name,"..")) return; | ||
| 1292 | len = scan_ulong(d->d_name,&id); | ||
| 1293 | if (!len || d->d_name[len]) return; | ||
| 1294 | |||
| 1295 | fnmake_todo(id); | ||
| 1296 | |||
| 1297 | fd = open_read(fn.s); | ||
| 1298 | if (fd == -1) { log3("warning: unable to open ",fn.s,"\n"); return; } | ||
| 1299 | |||
| 1300 | fnmake_mess(id); | ||
| 1301 | /* just for the statistics */ | ||
| 1302 | if (stat(fn.s,&st) == -1) | ||
| 1303 | { log3("warning: unable to stat ",fn.s,"\n"); goto fail; } | ||
| 1304 | |||
| 1305 | for (c = 0;c < CHANNELS;++c) | ||
| 1306 | { | ||
| 1307 | fnmake_chanaddr(id,c); | ||
| 1308 | if (unlink(fn.s) == -1) if (errno != error_noent) | ||
| 1309 | { log3("warning: unable to unlink ",fn.s,"\n"); goto fail; } | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | fnmake_info(id); | ||
| 1313 | if (unlink(fn.s) == -1) if (errno != error_noent) | ||
| 1314 | { log3("warning: unable to unlink ",fn.s,"\n"); goto fail; } | ||
| 1315 | |||
| 1316 | fdinfo = open_excl(fn.s); | ||
| 1317 | if (fdinfo == -1) | ||
| 1318 | { log3("warning: unable to create ",fn.s,"\n"); goto fail; } | ||
| 1319 | |||
| 1320 | strnum3[fmt_ulong(strnum3,id)] = 0; | ||
| 1321 | log3("new msg ",strnum3,"\n"); | ||
| 1322 | |||
| 1323 | for (c = 0;c < CHANNELS;++c) flagchan[c] = 0; | ||
| 1324 | |||
| 1325 | substdio_fdbuf(&ss,read,fd,todobuf,sizeof(todobuf)); | ||
| 1326 | substdio_fdbuf(&ssinfo,write,fdinfo,todobufinfo,sizeof(todobufinfo)); | ||
| 1327 | |||
| 1328 | uid = 0; | ||
| 1329 | pid = 0; | ||
| 1330 | |||
| 1331 | for (;;) | ||
| 1332 | { | ||
| 1333 | if (getln(&ss,&todoline,&match,'\0') == -1) | ||
| 1334 | { | ||
| 1335 | /* perhaps we're out of memory, perhaps an I/O error */ | ||
| 1336 | fnmake_todo(id); | ||
| 1337 | log3("warning: trouble reading ",fn.s,"\n"); goto fail; | ||
| 1338 | } | ||
| 1339 | if (!match) break; | ||
| 1340 | |||
| 1341 | switch(todoline.s[0]) | ||
| 1342 | { | ||
| 1343 | case 'u': | ||
| 1344 | scan_ulong(todoline.s + 1,&uid); | ||
| 1345 | break; | ||
| 1346 | case 'p': | ||
| 1347 | scan_ulong(todoline.s + 1,&pid); | ||
| 1348 | break; | ||
| 1349 | case 'F': | ||
| 1350 | if (substdio_putflush(&ssinfo,todoline.s,todoline.len) == -1) | ||
| 1351 | { | ||
| 1352 | fnmake_info(id); | ||
| 1353 | log3("warning: trouble writing to ",fn.s,"\n"); goto fail; | ||
| 1354 | } | ||
| 1355 | log2("info msg ",strnum3); | ||
| 1356 | strnum2[fmt_ulong(strnum2,(unsigned long) st.st_size)] = 0; | ||
| 1357 | log2(": bytes ",strnum2); | ||
| 1358 | log1(" from <"); logsafe(todoline.s + 1); | ||
| 1359 | strnum2[fmt_ulong(strnum2,pid)] = 0; | ||
| 1360 | log2("> qp ",strnum2); | ||
| 1361 | strnum2[fmt_ulong(strnum2,uid)] = 0; | ||
| 1362 | log2(" uid ",strnum2); | ||
| 1363 | log1("\n"); | ||
| 1364 | break; | ||
| 1365 | case 'T': | ||
| 1366 | switch(rewrite(todoline.s + 1)) | ||
| 1367 | { | ||
| 1368 | case 0: nomem(); goto fail; | ||
| 1369 | case 2: c = 1; break; | ||
| 1370 | default: c = 0; break; | ||
| 1371 | } | ||
| 1372 | if (fdchan[c] == -1) | ||
| 1373 | { | ||
| 1374 | fnmake_chanaddr(id,c); | ||
| 1375 | fdchan[c] = open_excl(fn.s); | ||
| 1376 | if (fdchan[c] == -1) | ||
| 1377 | { log3("warning: unable to create ",fn.s,"\n"); goto fail; } | ||
| 1378 | substdio_fdbuf(&sschan[c] | ||
| 1379 | ,write,fdchan[c],todobufchan[c],sizeof(todobufchan[c])); | ||
| 1380 | flagchan[c] = 1; | ||
| 1381 | } | ||
| 1382 | if (substdio_bput(&sschan[c],rwline.s,rwline.len) == -1) | ||
| 1383 | { | ||
| 1384 | fnmake_chanaddr(id,c); | ||
| 1385 | log3("warning: trouble writing to ",fn.s,"\n"); goto fail; | ||
| 1386 | } | ||
| 1387 | break; | ||
| 1388 | default: | ||
| 1389 | fnmake_todo(id); | ||
| 1390 | log3("warning: unknown record type in ",fn.s,"\n"); goto fail; | ||
| 1391 | } | ||
| 1392 | } | ||
| 1393 | |||
| 1394 | close(fd); fd = -1; | ||
| 1395 | |||
| 1396 | fnmake_info(id); | ||
| 1397 | if (substdio_flush(&ssinfo) == -1) | ||
| 1398 | { log3("warning: trouble writing to ",fn.s,"\n"); goto fail; } | ||
| 1399 | if (fsync(fdinfo) == -1) | ||
| 1400 | { log3("warning: trouble fsyncing ",fn.s,"\n"); goto fail; } | ||
| 1401 | close(fdinfo); fdinfo = -1; | ||
| 1402 | |||
| 1403 | for (c = 0;c < CHANNELS;++c) | ||
| 1404 | if (fdchan[c] != -1) | ||
| 1405 | { | ||
| 1406 | fnmake_chanaddr(id,c); | ||
| 1407 | if (substdio_flush(&sschan[c]) == -1) | ||
| 1408 | { log3("warning: trouble writing to ",fn.s,"\n"); goto fail; } | ||
| 1409 | if (fsync(fdchan[c]) == -1) | ||
| 1410 | { log3("warning: trouble fsyncing ",fn.s,"\n"); goto fail; } | ||
| 1411 | close(fdchan[c]); fdchan[c] = -1; | ||
| 1412 | } | ||
| 1413 | |||
| 1414 | fnmake_todo(id); | ||
| 1415 | if (substdio_putflush(&sstoqc,fn.s,fn.len) == -1) { cleandied(); return; } | ||
| 1416 | if (substdio_get(&ssfromqc,&ch,1) != 1) { cleandied(); return; } | ||
| 1417 | if (ch != '+') | ||
| 1418 | { | ||
| 1419 | log3("warning: qmail-clean unable to clean up ",fn.s,"\n"); | ||
| 1420 | return; | ||
| 1421 | } | ||
| 1422 | |||
| 1423 | pe.id = id; pe.dt = now(); | ||
| 1424 | for (c = 0;c < CHANNELS;++c) | ||
| 1425 | if (flagchan[c]) | ||
| 1426 | while (!prioq_insert(&pqchan[c],&pe)) nomem(); | ||
| 1427 | |||
| 1428 | for (c = 0;c < CHANNELS;++c) if (flagchan[c]) break; | ||
| 1429 | if (c == CHANNELS) | ||
| 1430 | while (!prioq_insert(&pqdone,&pe)) nomem(); | ||
| 1431 | |||
| 1432 | return; | ||
| 1433 | |||
| 1434 | fail: | ||
| 1435 | if (fd != -1) close(fd); | ||
| 1436 | if (fdinfo != -1) close(fdinfo); | ||
| 1437 | for (c = 0;c < CHANNELS;++c) | ||
| 1438 | if (fdchan[c] != -1) close(fdchan[c]); | ||
| 1439 | } | ||
| 1440 | |||
| 1441 | |||
| 1442 | /* this file is too long ---------------------------------------------- MAIN */ | ||
| 1443 | |||
| 1444 | int getcontrols() { if (control_init() == -1) return 0; | ||
| 1445 | if (control_readint(&lifetime,"control/queuelifetime") == -1) return 0; | ||
| 1446 | if (control_readint(&concurrency[0],"control/concurrencylocal") == -1) return 0; | ||
| 1447 | if (control_readint(&concurrency[1],"control/concurrencyremote") == -1) return 0; | ||
| 1448 | if (control_rldef(&envnoathost,"control/envnoathost",1,"envnoathost") != 1) return 0; | ||
| 1449 | if (control_rldef(&bouncefrom,"control/bouncefrom",0,"MAILER-DAEMON") != 1) return 0; | ||
| 1450 | if (control_rldef(&bouncehost,"control/bouncehost",1,"bouncehost") != 1) return 0; | ||
| 1451 | if (control_rldef(&doublebouncehost,"control/doublebouncehost",1,"doublebouncehost") != 1) return 0; | ||
| 1452 | if (control_rldef(&doublebounceto,"control/doublebounceto",0,"postmaster") != 1) return 0; | ||
| 1453 | if (!stralloc_cats(&doublebounceto,"@")) return 0; | ||
| 1454 | if (!stralloc_cat(&doublebounceto,&doublebouncehost)) return 0; | ||
| 1455 | if (!stralloc_0(&doublebounceto)) return 0; | ||
| 1456 | if (control_readfile(&locals,"control/locals",1) != 1) return 0; | ||
| 1457 | if (!constmap_init(&maplocals,locals.s,locals.len,0)) return 0; | ||
| 1458 | switch(control_readfile(&percenthack,"control/percenthack",0)) | ||
| 1459 | { | ||
| 1460 | case -1: return 0; | ||
| 1461 | case 0: if (!constmap_init(&mappercenthack,"",0,0)) return 0; break; | ||
| 1462 | case 1: if (!constmap_init(&mappercenthack,percenthack.s,percenthack.len,0)) return 0; break; | ||
| 1463 | } | ||
| 1464 | switch(control_readfile(&vdoms,"control/virtualdomains",0)) | ||
| 1465 | { | ||
| 1466 | case -1: return 0; | ||
| 1467 | case 0: if (!constmap_init(&mapvdoms,"",0,1)) return 0; break; | ||
| 1468 | case 1: if (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) return 0; break; | ||
| 1469 | } | ||
| 1470 | return 1; } | ||
| 1471 | |||
| 1472 | stralloc newlocals = {0}; | ||
| 1473 | stralloc newvdoms = {0}; | ||
| 1474 | |||
| 1475 | void regetcontrols() | ||
| 1476 | { | ||
| 1477 | int r; | ||
| 1478 | |||
| 1479 | if (control_readfile(&newlocals,"control/locals",1) != 1) | ||
| 1480 | { log1("alert: unable to reread control/locals\n"); return; } | ||
| 1481 | r = control_readfile(&newvdoms,"control/virtualdomains",0); | ||
| 1482 | if (r == -1) | ||
| 1483 | { log1("alert: unable to reread control/virtualdomains\n"); return; } | ||
| 1484 | |||
| 1485 | constmap_free(&maplocals); | ||
| 1486 | constmap_free(&mapvdoms); | ||
| 1487 | |||
| 1488 | while (!stralloc_copy(&locals,&newlocals)) nomem(); | ||
| 1489 | while (!constmap_init(&maplocals,locals.s,locals.len,0)) nomem(); | ||
| 1490 | |||
| 1491 | if (r) | ||
| 1492 | { | ||
| 1493 | while (!stralloc_copy(&vdoms,&newvdoms)) nomem(); | ||
| 1494 | while (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) nomem(); | ||
| 1495 | } | ||
| 1496 | else | ||
| 1497 | while (!constmap_init(&mapvdoms,"",0,1)) nomem(); | ||
| 1498 | } | ||
| 1499 | |||
| 1500 | void reread() | ||
| 1501 | { | ||
| 1502 | if (chdir(auto_qmail) == -1) | ||
| 1503 | { | ||
| 1504 | log1("alert: unable to reread controls: unable to switch to home directory\n"); | ||
| 1505 | return; | ||
| 1506 | } | ||
| 1507 | regetcontrols(); | ||
| 1508 | while (chdir("queue") == -1) | ||
| 1509 | { | ||
| 1510 | log1("alert: unable to switch back to queue directory; HELP! sleeping...\n"); | ||
| 1511 | sleep(10); | ||
| 1512 | } | ||
| 1513 | } | ||
| 1514 | |||
| 1515 | void main() | ||
| 1516 | { | ||
| 1517 | int fd; | ||
| 1518 | datetime_sec wakeup; | ||
| 1519 | fd_set rfds; | ||
| 1520 | fd_set wfds; | ||
| 1521 | int nfds; | ||
| 1522 | struct timeval tv; | ||
| 1523 | int c; | ||
| 1524 | |||
| 1525 | if (chdir(auto_qmail) == -1) | ||
| 1526 | { log1("alert: cannot start: unable to switch to home directory\n"); _exit(111); } | ||
| 1527 | if (!getcontrols()) | ||
| 1528 | { log1("alert: cannot start: unable to read controls\n"); _exit(111); } | ||
| 1529 | if (chdir("queue") == -1) | ||
| 1530 | { log1("alert: cannot start: unable to switch to queue directory\n"); _exit(111); } | ||
| 1531 | sig_pipeignore(); | ||
| 1532 | sig_termcatch(sigterm); | ||
| 1533 | sig_alarmcatch(sigalrm); | ||
| 1534 | sig_hangupcatch(sighup); | ||
| 1535 | sig_childdefault(); | ||
| 1536 | umask(077); | ||
| 1537 | |||
| 1538 | fd = open_write("lock/sendmutex"); | ||
| 1539 | if (fd == -1) | ||
| 1540 | { log1("alert: cannot start: unable to open mutex\n"); _exit(111); } | ||
| 1541 | if (lock_exnb(fd) == -1) | ||
| 1542 | { log1("alert: cannot start: qmail-send is already running\n"); _exit(111); } | ||
| 1543 | |||
| 1544 | numjobs = 0; | ||
| 1545 | for (c = 0;c < CHANNELS;++c) | ||
| 1546 | { | ||
| 1547 | char ch; | ||
| 1548 | int u; | ||
| 1549 | int r; | ||
| 1550 | do | ||
| 1551 | r = read(chanfdin[c],&ch,1); | ||
| 1552 | while ((r == -1) && (errno == error_intr)); | ||
| 1553 | if (r < 1) | ||
| 1554 | { log1("alert: cannot start: hath the daemon spawn no fire?\n"); _exit(111); } | ||
| 1555 | u = (unsigned int) (unsigned char) ch; | ||
| 1556 | if (concurrency[c] > u) concurrency[c] = u; | ||
| 1557 | numjobs += concurrency[c]; | ||
| 1558 | } | ||
| 1559 | |||
| 1560 | fnmake_init(); | ||
| 1561 | |||
| 1562 | comm_init(); | ||
| 1563 | |||
| 1564 | pqstart(); | ||
| 1565 | job_init(); | ||
| 1566 | del_init(); | ||
| 1567 | pass_init(); | ||
| 1568 | todo_init(); | ||
| 1569 | cleanup_init(); | ||
| 1570 | |||
| 1571 | while (!flagexitasap || !del_canexit()) | ||
| 1572 | { | ||
| 1573 | recent = now(); | ||
| 1574 | |||
| 1575 | if (flagrunasap) { flagrunasap = 0; pqrun(); } | ||
| 1576 | if (flagreadasap) { flagreadasap = 0; reread(); } | ||
| 1577 | |||
| 1578 | wakeup = recent + SLEEP_FOREVER; | ||
| 1579 | FD_ZERO(&rfds); | ||
| 1580 | FD_ZERO(&wfds); | ||
| 1581 | nfds = 1; | ||
| 1582 | |||
| 1583 | comm_selprep(&nfds,&wfds); | ||
| 1584 | del_selprep(&nfds,&rfds); | ||
| 1585 | pass_selprep(&wakeup); | ||
| 1586 | todo_selprep(&nfds,&rfds,&wakeup); | ||
| 1587 | cleanup_selprep(&wakeup); | ||
| 1588 | |||
| 1589 | if (wakeup <= recent) tv.tv_sec = 0; | ||
| 1590 | else tv.tv_sec = wakeup - recent + SLEEP_FUZZ; | ||
| 1591 | tv.tv_usec = 0; | ||
| 1592 | |||
| 1593 | if (select(nfds,&rfds,&wfds,(fd_set *) 0,&tv) == -1) | ||
| 1594 | if (errno == error_intr) | ||
| 1595 | ; | ||
| 1596 | else | ||
| 1597 | log1("warning: trouble in select\n"); | ||
| 1598 | else | ||
| 1599 | { | ||
| 1600 | recent = now(); | ||
| 1601 | |||
| 1602 | comm_do(&wfds); | ||
| 1603 | del_do(&rfds); | ||
| 1604 | todo_do(&rfds); | ||
| 1605 | pass_do(); | ||
| 1606 | cleanup_do(); | ||
| 1607 | } | ||
| 1608 | } | ||
| 1609 | pqfinish(); | ||
| 1610 | log1("status: exiting\n"); | ||
| 1611 | _exit(0); | ||
| 1612 | } | ||
diff --git a/qmail-showctl.8 b/qmail-showctl.8 new file mode 100644 index 0000000..e6a211d --- /dev/null +++ b/qmail-showctl.8 | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | .TH qmail-showctl 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-showctl \- analyze the qmail configuration files | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-showctl | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B qmail-showctl | ||
| 8 | explains the current | ||
| 9 | .B qmail | ||
| 10 | configuration. | ||
| 11 | .SH "SEE ALSO" | ||
| 12 | qmail-control(8) | ||
diff --git a/qmail-showctl.c b/qmail-showctl.c new file mode 100644 index 0000000..a24aa63 --- /dev/null +++ b/qmail-showctl.c | |||
| @@ -0,0 +1,306 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include "substdio.h" | ||
| 4 | #include "subfd.h" | ||
| 5 | #include "exit.h" | ||
| 6 | #include "fmt.h" | ||
| 7 | #include "str.h" | ||
| 8 | #include "control.h" | ||
| 9 | #include "constmap.h" | ||
| 10 | #include "stralloc.h" | ||
| 11 | #include "direntry.h" | ||
| 12 | #include "auto_uids.h" | ||
| 13 | #include "auto_qmail.h" | ||
| 14 | #include "auto_break.h" | ||
| 15 | #include "auto_patrn.h" | ||
| 16 | #include "auto_spawn.h" | ||
| 17 | #include "auto_split.h" | ||
| 18 | |||
| 19 | stralloc me = {0}; | ||
| 20 | int meok; | ||
| 21 | |||
| 22 | stralloc line = {0}; | ||
| 23 | char num[FMT_ULONG]; | ||
| 24 | |||
| 25 | void safeput(buf,len) | ||
| 26 | char *buf; | ||
| 27 | unsigned int len; | ||
| 28 | { | ||
| 29 | char ch; | ||
| 30 | |||
| 31 | while (len > 0) { | ||
| 32 | ch = *buf; | ||
| 33 | if ((ch < 32) || (ch > 126)) ch = '?'; | ||
| 34 | substdio_put(subfdout,&ch,1); | ||
| 35 | ++buf; | ||
| 36 | --len; | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | void do_int(fn,def,pre,post) | ||
| 41 | char *fn; | ||
| 42 | char *def; | ||
| 43 | char *pre; | ||
| 44 | char *post; | ||
| 45 | { | ||
| 46 | int i; | ||
| 47 | substdio_puts(subfdout,"\n"); | ||
| 48 | substdio_puts(subfdout,fn); | ||
| 49 | substdio_puts(subfdout,": "); | ||
| 50 | switch(control_readint(&i,fn)) { | ||
| 51 | case 0: | ||
| 52 | substdio_puts(subfdout,"(Default.) "); | ||
| 53 | substdio_puts(subfdout,pre); | ||
| 54 | substdio_puts(subfdout,def); | ||
| 55 | substdio_puts(subfdout,post); | ||
| 56 | substdio_puts(subfdout,".\n"); | ||
| 57 | break; | ||
| 58 | case 1: | ||
| 59 | if (i < 0) i = 0; | ||
| 60 | substdio_puts(subfdout,pre); | ||
| 61 | substdio_put(subfdout,num,fmt_uint(num,i)); | ||
| 62 | substdio_puts(subfdout,post); | ||
| 63 | substdio_puts(subfdout,".\n"); | ||
| 64 | break; | ||
| 65 | default: | ||
| 66 | substdio_puts(subfdout,"Oops! Trouble reading this file.\n"); | ||
| 67 | break; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | void do_str(fn,flagme,def,pre) | ||
| 72 | char *fn; | ||
| 73 | int flagme; | ||
| 74 | char *def; | ||
| 75 | char *pre; | ||
| 76 | { | ||
| 77 | substdio_puts(subfdout,"\n"); | ||
| 78 | substdio_puts(subfdout,fn); | ||
| 79 | substdio_puts(subfdout,": "); | ||
| 80 | switch(control_readline(&line,fn)) { | ||
| 81 | case 0: | ||
| 82 | substdio_puts(subfdout,"(Default.) "); | ||
| 83 | if (!stralloc_copys(&line,def)) { | ||
| 84 | substdio_puts(subfdout,"Oops! Out of memory.\n"); | ||
| 85 | break; | ||
| 86 | } | ||
| 87 | if (flagme && meok) | ||
| 88 | if (!stralloc_copy(&line,&me)) { | ||
| 89 | substdio_puts(subfdout,"Oops! Out of memory.\n"); | ||
| 90 | break; | ||
| 91 | } | ||
| 92 | case 1: | ||
| 93 | substdio_puts(subfdout,pre); | ||
| 94 | safeput(line.s,line.len); | ||
| 95 | substdio_puts(subfdout,".\n"); | ||
| 96 | break; | ||
| 97 | default: | ||
| 98 | substdio_puts(subfdout,"Oops! Trouble reading this file.\n"); | ||
| 99 | break; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | int do_lst(fn,def,pre,post) | ||
| 104 | char *fn; | ||
| 105 | char *def; | ||
| 106 | char *pre; | ||
| 107 | char *post; | ||
| 108 | { | ||
| 109 | int i; | ||
| 110 | int j; | ||
| 111 | |||
| 112 | substdio_puts(subfdout,"\n"); | ||
| 113 | substdio_puts(subfdout,fn); | ||
| 114 | substdio_puts(subfdout,": "); | ||
| 115 | switch(control_readfile(&line,fn)) { | ||
| 116 | case 0: | ||
| 117 | substdio_puts(subfdout,"(Default.) "); | ||
| 118 | substdio_puts(subfdout,def); | ||
| 119 | substdio_puts(subfdout,"\n"); | ||
| 120 | return 0; | ||
| 121 | case 1: | ||
| 122 | substdio_puts(subfdout,"\n"); | ||
| 123 | i = 0; | ||
| 124 | for (j = 0;j < line.len;++j) | ||
| 125 | if (!line.s[j]) { | ||
| 126 | substdio_puts(subfdout,pre); | ||
| 127 | safeput(line.s + i,j - i); | ||
| 128 | substdio_puts(subfdout,post); | ||
| 129 | substdio_puts(subfdout,"\n"); | ||
| 130 | i = j + 1; | ||
| 131 | } | ||
| 132 | return 1; | ||
| 133 | default: | ||
| 134 | substdio_puts(subfdout,"Oops! Trouble reading this file.\n"); | ||
| 135 | return -1; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | void main() | ||
| 140 | { | ||
| 141 | DIR *dir; | ||
| 142 | direntry *d; | ||
| 143 | struct stat stmrh; | ||
| 144 | struct stat stmrhcdb; | ||
| 145 | |||
| 146 | substdio_puts(subfdout,"qmail home directory: "); | ||
| 147 | substdio_puts(subfdout,auto_qmail); | ||
| 148 | substdio_puts(subfdout,".\n"); | ||
| 149 | |||
| 150 | substdio_puts(subfdout,"user-ext delimiter: "); | ||
| 151 | substdio_puts(subfdout,auto_break); | ||
| 152 | substdio_puts(subfdout,".\n"); | ||
| 153 | |||
| 154 | substdio_puts(subfdout,"paternalism (in decimal): "); | ||
| 155 | substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_patrn)); | ||
| 156 | substdio_puts(subfdout,".\n"); | ||
| 157 | |||
| 158 | substdio_puts(subfdout,"silent concurrency limit: "); | ||
| 159 | substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_spawn)); | ||
| 160 | substdio_puts(subfdout,".\n"); | ||
| 161 | |||
| 162 | substdio_puts(subfdout,"subdirectory split: "); | ||
| 163 | substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_split)); | ||
| 164 | substdio_puts(subfdout,".\n"); | ||
| 165 | |||
| 166 | substdio_puts(subfdout,"user ids: "); | ||
| 167 | substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uida)); | ||
| 168 | substdio_puts(subfdout,", "); | ||
| 169 | substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uidd)); | ||
| 170 | substdio_puts(subfdout,", "); | ||
| 171 | substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uidl)); | ||
| 172 | substdio_puts(subfdout,", "); | ||
| 173 | substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uido)); | ||
| 174 | substdio_puts(subfdout,", "); | ||
| 175 | substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uidp)); | ||
| 176 | substdio_puts(subfdout,", "); | ||
| 177 | substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uidq)); | ||
| 178 | substdio_puts(subfdout,", "); | ||
| 179 | substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uidr)); | ||
| 180 | substdio_puts(subfdout,", "); | ||
| 181 | substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uids)); | ||
| 182 | substdio_puts(subfdout,".\n"); | ||
| 183 | |||
| 184 | substdio_puts(subfdout,"group ids: "); | ||
| 185 | substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_gidn)); | ||
| 186 | substdio_puts(subfdout,", "); | ||
| 187 | substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_gidq)); | ||
| 188 | substdio_puts(subfdout,".\n"); | ||
| 189 | |||
| 190 | if (chdir(auto_qmail) == -1) { | ||
| 191 | substdio_puts(subfdout,"Oops! Unable to chdir to "); | ||
| 192 | substdio_puts(subfdout,auto_qmail); | ||
| 193 | substdio_puts(subfdout,".\n"); | ||
| 194 | substdio_flush(subfdout); | ||
| 195 | _exit(111); | ||
| 196 | } | ||
| 197 | if (chdir("control") == -1) { | ||
| 198 | substdio_puts(subfdout,"Oops! Unable to chdir to control.\n"); | ||
| 199 | substdio_flush(subfdout); | ||
| 200 | _exit(111); | ||
| 201 | } | ||
| 202 | |||
| 203 | dir = opendir("."); | ||
| 204 | if (!dir) { | ||
| 205 | substdio_puts(subfdout,"Oops! Unable to open current directory.\n"); | ||
| 206 | substdio_flush(subfdout); | ||
| 207 | _exit(111); | ||
| 208 | } | ||
| 209 | |||
| 210 | meok = control_readline(&me,"me"); | ||
| 211 | if (meok == -1) { | ||
| 212 | substdio_puts(subfdout,"Oops! Trouble reading control/me."); | ||
| 213 | substdio_flush(subfdout); | ||
| 214 | _exit(111); | ||
| 215 | } | ||
| 216 | |||
| 217 | do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM."); | ||
| 218 | do_str("bouncefrom",0,"MAILER-DAEMON","Bounce user name is "); | ||
| 219 | do_str("bouncehost",1,"bouncehost","Bounce host name is "); | ||
| 220 | do_int("concurrencylocal","10","Local concurrency is ",""); | ||
| 221 | do_int("concurrencyremote","20","Remote concurrency is ",""); | ||
| 222 | do_int("databytes","0","SMTP DATA limit is "," bytes"); | ||
| 223 | do_str("defaultdomain",1,"defaultdomain","Default domain name is "); | ||
| 224 | do_str("defaulthost",1,"defaulthost","Default host name is "); | ||
| 225 | do_str("doublebouncehost",1,"doublebouncehost","2B recipient host: "); | ||
| 226 | do_str("doublebounceto",0,"postmaster","2B recipient user: "); | ||
| 227 | do_str("envnoathost",1,"envnoathost","Presumed domain name is "); | ||
| 228 | do_str("helohost",1,"helohost","SMTP client HELO host name is "); | ||
| 229 | do_str("idhost",1,"idhost","Message-ID host name is "); | ||
| 230 | do_str("localiphost",1,"localiphost","Local IP address becomes "); | ||
| 231 | do_lst("locals","Messages for me are delivered locally.","Messages for "," are delivered locally."); | ||
| 232 | do_str("me",0,"undefined! Uh-oh","My name is "); | ||
| 233 | do_lst("percenthack","The percent hack is not allowed.","The percent hack is allowed for user%host@","."); | ||
| 234 | do_str("plusdomain",1,"plusdomain","Plus domain name is "); | ||
| 235 | do_lst("qmqpservers","No QMQP servers.","QMQP server: ","."); | ||
| 236 | do_int("queuelifetime","604800","Message lifetime in the queue is "," seconds"); | ||
| 237 | |||
| 238 | if (do_lst("rcpthosts","SMTP clients may send messages to any recipient.","SMTP clients may send messages to recipients at ",".")) | ||
| 239 | do_lst("morercpthosts","No effect.","SMTP clients may send messages to recipients at ","."); | ||
| 240 | else | ||
| 241 | do_lst("morercpthosts","No rcpthosts; morercpthosts is irrelevant.","No rcpthosts; doesn't matter that morercpthosts has ","."); | ||
| 242 | /* XXX: check morercpthosts.cdb contents */ | ||
| 243 | substdio_puts(subfdout,"\nmorercpthosts.cdb: "); | ||
| 244 | if (stat("morercpthosts",&stmrh) == -1) | ||
| 245 | if (stat("morercpthosts.cdb",&stmrhcdb) == -1) | ||
| 246 | substdio_puts(subfdout,"(Default.) No effect.\n"); | ||
| 247 | else | ||
| 248 | substdio_puts(subfdout,"Oops! morercpthosts.cdb exists but morercpthosts doesn't.\n"); | ||
| 249 | else | ||
| 250 | if (stat("morercpthosts.cdb",&stmrhcdb) == -1) | ||
| 251 | substdio_puts(subfdout,"Oops! morercpthosts exists but morercpthosts.cdb doesn't.\n"); | ||
| 252 | else | ||
| 253 | if (stmrh.st_mtime > stmrhcdb.st_mtime) | ||
| 254 | substdio_puts(subfdout,"Oops! morercpthosts.cdb is older than morercpthosts.\n"); | ||
| 255 | else | ||
| 256 | substdio_puts(subfdout,"Modified recently enough; hopefully up to date.\n"); | ||
| 257 | |||
| 258 | do_str("smtpgreeting",1,"smtpgreeting","SMTP greeting: 220 "); | ||
| 259 | do_lst("smtproutes","No artificial SMTP routes.","SMTP route: ",""); | ||
| 260 | do_int("timeoutconnect","60","SMTP client connection timeout is "," seconds"); | ||
| 261 | do_int("timeoutremote","1200","SMTP client data timeout is "," seconds"); | ||
| 262 | do_int("timeoutsmtpd","1200","SMTP server data timeout is "," seconds"); | ||
| 263 | do_lst("virtualdomains","No virtual domains.","Virtual domain: ",""); | ||
| 264 | |||
| 265 | while (d = readdir(dir)) { | ||
| 266 | if (str_equal(d->d_name,".")) continue; | ||
| 267 | if (str_equal(d->d_name,"..")) continue; | ||
| 268 | if (str_equal(d->d_name,"bouncefrom")) continue; | ||
| 269 | if (str_equal(d->d_name,"bouncehost")) continue; | ||
| 270 | if (str_equal(d->d_name,"badmailfrom")) continue; | ||
| 271 | if (str_equal(d->d_name,"bouncefrom")) continue; | ||
| 272 | if (str_equal(d->d_name,"bouncehost")) continue; | ||
| 273 | if (str_equal(d->d_name,"concurrencylocal")) continue; | ||
| 274 | if (str_equal(d->d_name,"concurrencyremote")) continue; | ||
| 275 | if (str_equal(d->d_name,"databytes")) continue; | ||
| 276 | if (str_equal(d->d_name,"defaultdomain")) continue; | ||
| 277 | if (str_equal(d->d_name,"defaulthost")) continue; | ||
| 278 | if (str_equal(d->d_name,"doublebouncehost")) continue; | ||
| 279 | if (str_equal(d->d_name,"doublebounceto")) continue; | ||
| 280 | if (str_equal(d->d_name,"envnoathost")) continue; | ||
| 281 | if (str_equal(d->d_name,"helohost")) continue; | ||
| 282 | if (str_equal(d->d_name,"idhost")) continue; | ||
| 283 | if (str_equal(d->d_name,"localiphost")) continue; | ||
| 284 | if (str_equal(d->d_name,"locals")) continue; | ||
| 285 | if (str_equal(d->d_name,"me")) continue; | ||
| 286 | if (str_equal(d->d_name,"morercpthosts")) continue; | ||
| 287 | if (str_equal(d->d_name,"morercpthosts.cdb")) continue; | ||
| 288 | if (str_equal(d->d_name,"percenthack")) continue; | ||
| 289 | if (str_equal(d->d_name,"plusdomain")) continue; | ||
| 290 | if (str_equal(d->d_name,"qmqpservers")) continue; | ||
| 291 | if (str_equal(d->d_name,"queuelifetime")) continue; | ||
| 292 | if (str_equal(d->d_name,"rcpthosts")) continue; | ||
| 293 | if (str_equal(d->d_name,"smtpgreeting")) continue; | ||
| 294 | if (str_equal(d->d_name,"smtproutes")) continue; | ||
| 295 | if (str_equal(d->d_name,"timeoutconnect")) continue; | ||
| 296 | if (str_equal(d->d_name,"timeoutremote")) continue; | ||
| 297 | if (str_equal(d->d_name,"timeoutsmtpd")) continue; | ||
| 298 | if (str_equal(d->d_name,"virtualdomains")) continue; | ||
| 299 | substdio_puts(subfdout,"\n"); | ||
| 300 | substdio_puts(subfdout,d->d_name); | ||
| 301 | substdio_puts(subfdout,": I have no idea what this file does.\n"); | ||
| 302 | } | ||
| 303 | |||
| 304 | substdio_flush(subfdout); | ||
| 305 | _exit(0); | ||
| 306 | } | ||
diff --git a/qmail-smtpd.8 b/qmail-smtpd.8 new file mode 100644 index 0000000..c4640b8 --- /dev/null +++ b/qmail-smtpd.8 | |||
| @@ -0,0 +1,179 @@ | |||
| 1 | .TH qmail-smtpd 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-smtpd \- receive mail via SMTP | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-smtpd | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B qmail-smtpd | ||
| 8 | receives mail messages via the Simple Mail Transfer Protocol (SMTP) | ||
| 9 | and invokes | ||
| 10 | .B qmail-queue | ||
| 11 | to deposit them into the outgoing queue. | ||
| 12 | .B qmail-smtpd | ||
| 13 | must be supplied several environment variables; | ||
| 14 | see | ||
| 15 | .BR tcp-environ(5) . | ||
| 16 | |||
| 17 | .B qmail-smtpd | ||
| 18 | is responsible for counting hops. | ||
| 19 | It rejects any message with 100 or more | ||
| 20 | .B Received | ||
| 21 | or | ||
| 22 | .B Delivered-To | ||
| 23 | header fields. | ||
| 24 | |||
| 25 | .B qmail-smtpd | ||
| 26 | supports ESMTP, including the 8BITMIME and PIPELINING options. | ||
| 27 | .SH TRANSPARENCY | ||
| 28 | .B qmail-smtpd | ||
| 29 | converts the SMTP newline convention into the UNIX newline convention | ||
| 30 | by converting CR LF into LF. | ||
| 31 | It returns a temporary error and drops the connection on bare LFs; | ||
| 32 | see | ||
| 33 | .BR http://pobox.com/~djb/docs/smtplf.html . | ||
| 34 | |||
| 35 | .B qmail-smtpd | ||
| 36 | accepts messages that contain long lines or non-ASCII characters, | ||
| 37 | even though such messages violate the SMTP protocol. | ||
| 38 | .SH "CONTROL FILES" | ||
| 39 | .TP 5 | ||
| 40 | .I badmailfrom | ||
| 41 | Unacceptable envelope sender addresses. | ||
| 42 | .B qmail-smtpd | ||
| 43 | will reject every recipient address for a message | ||
| 44 | if the envelope sender address is listed in | ||
| 45 | .IR badmailfrom . | ||
| 46 | A line in | ||
| 47 | .I badmailfrom | ||
| 48 | may be of the form | ||
| 49 | .BR @\fIhost , | ||
| 50 | meaning every address at | ||
| 51 | .IR host . | ||
| 52 | .TP 5 | ||
| 53 | .I databytes | ||
| 54 | Maximum number of bytes allowed in a message, | ||
| 55 | or 0 for no limit. | ||
| 56 | Default: 0. | ||
| 57 | If a message exceeds this limit, | ||
| 58 | .B qmail-smtpd | ||
| 59 | returns a permanent error code to the client; | ||
| 60 | in contrast, if | ||
| 61 | the disk is full or | ||
| 62 | .B qmail-smtpd | ||
| 63 | hits a resource limit, | ||
| 64 | .B qmail-smtpd | ||
| 65 | returns a temporary error code. | ||
| 66 | |||
| 67 | .I databytes | ||
| 68 | counts bytes as stored on disk, not as transmitted through the network. | ||
| 69 | It does not count the | ||
| 70 | .B qmail-smtpd | ||
| 71 | Received line, the | ||
| 72 | .B qmail-queue | ||
| 73 | Received line, or the envelope. | ||
| 74 | |||
| 75 | If the environment variable | ||
| 76 | .B DATABYTES | ||
| 77 | is set, it overrides | ||
| 78 | .IR databytes . | ||
| 79 | .TP 5 | ||
| 80 | .I localiphost | ||
| 81 | Replacement host name for local IP addresses. | ||
| 82 | Default: | ||
| 83 | .IR me , | ||
| 84 | if that is supplied. | ||
| 85 | .B qmail-smtpd | ||
| 86 | is responsible for recognizing dotted-decimal addresses for the | ||
| 87 | current host. | ||
| 88 | When it sees a recipient address of the form | ||
| 89 | .IR box@[d.d.d.d] , | ||
| 90 | where | ||
| 91 | .I d.d.d.d | ||
| 92 | is a local IP address, | ||
| 93 | it replaces | ||
| 94 | .IR [d.d.d.d] | ||
| 95 | with | ||
| 96 | .IR localiphost . | ||
| 97 | This is done before | ||
| 98 | .IR rcpthosts . | ||
| 99 | .TP 5 | ||
| 100 | .I morercpthosts | ||
| 101 | Extra allowed RCPT domains. | ||
| 102 | If | ||
| 103 | .I rcpthosts | ||
| 104 | and | ||
| 105 | .I morercpthosts | ||
| 106 | both exist, | ||
| 107 | .I morercpthosts | ||
| 108 | is effectively appended to | ||
| 109 | .IR rcpthosts . | ||
| 110 | |||
| 111 | You must run | ||
| 112 | .B qmail-newmrh | ||
| 113 | whenever | ||
| 114 | .I morercpthosts | ||
| 115 | changes. | ||
| 116 | |||
| 117 | Rule of thumb for large sites: | ||
| 118 | Put your 50 most commonly used domains into | ||
| 119 | .IR rcpthosts , | ||
| 120 | and the rest into | ||
| 121 | .IR morercpthosts . | ||
| 122 | .TP 5 | ||
| 123 | .I rcpthosts | ||
| 124 | Allowed RCPT domains. | ||
| 125 | If | ||
| 126 | .I rcpthosts | ||
| 127 | is supplied, | ||
| 128 | .B qmail-smtpd | ||
| 129 | will reject | ||
| 130 | any envelope recipient address with a domain not listed in | ||
| 131 | .IR rcpthosts . | ||
| 132 | |||
| 133 | Exception: | ||
| 134 | If the environment variable | ||
| 135 | .B RELAYCLIENT | ||
| 136 | is set, | ||
| 137 | .B qmail-smtpd | ||
| 138 | will ignore | ||
| 139 | .IR rcpthosts , | ||
| 140 | and will append the value of | ||
| 141 | .B RELAYCLIENT | ||
| 142 | to each incoming recipient address. | ||
| 143 | |||
| 144 | .I rcpthosts | ||
| 145 | may include wildcards: | ||
| 146 | |||
| 147 | .EX | ||
| 148 | heaven.af.mil | ||
| 149 | .heaven.af.mil | ||
| 150 | .EE | ||
| 151 | |||
| 152 | Envelope recipient addresses without @ signs are | ||
| 153 | always allowed through. | ||
| 154 | .TP 5 | ||
| 155 | .I smtpgreeting | ||
| 156 | SMTP greeting message. | ||
| 157 | Default: | ||
| 158 | .IR me , | ||
| 159 | if that is supplied; | ||
| 160 | otherwise | ||
| 161 | .B qmail-smtpd | ||
| 162 | will refuse to run. | ||
| 163 | The first word of | ||
| 164 | .I smtpgreeting | ||
| 165 | should be the current host's name. | ||
| 166 | .TP 5 | ||
| 167 | .I timeoutsmtpd | ||
| 168 | Number of seconds | ||
| 169 | .B qmail-smtpd | ||
| 170 | will wait for each new buffer of data from the remote SMTP client. | ||
| 171 | Default: 1200. | ||
| 172 | .SH "SEE ALSO" | ||
| 173 | tcp-env(1), | ||
| 174 | tcp-environ(5), | ||
| 175 | qmail-control(5), | ||
| 176 | qmail-inject(8), | ||
| 177 | qmail-newmrh(8), | ||
| 178 | qmail-queue(8), | ||
| 179 | qmail-remote(8) | ||
diff --git a/qmail-smtpd.c b/qmail-smtpd.c new file mode 100644 index 0000000..1e28c88 --- /dev/null +++ b/qmail-smtpd.c | |||
| @@ -0,0 +1,421 @@ | |||
| 1 | #include "sig.h" | ||
| 2 | #include "readwrite.h" | ||
| 3 | #include "stralloc.h" | ||
| 4 | #include "substdio.h" | ||
| 5 | #include "alloc.h" | ||
| 6 | #include "auto_qmail.h" | ||
| 7 | #include "control.h" | ||
| 8 | #include "received.h" | ||
| 9 | #include "constmap.h" | ||
| 10 | #include "error.h" | ||
| 11 | #include "ipme.h" | ||
| 12 | #include "ip.h" | ||
| 13 | #include "qmail.h" | ||
| 14 | #include "str.h" | ||
| 15 | #include "fmt.h" | ||
| 16 | #include "scan.h" | ||
| 17 | #include "byte.h" | ||
| 18 | #include "case.h" | ||
| 19 | #include "env.h" | ||
| 20 | #include "now.h" | ||
| 21 | #include "exit.h" | ||
| 22 | #include "rcpthosts.h" | ||
| 23 | #include "timeoutread.h" | ||
| 24 | #include "timeoutwrite.h" | ||
| 25 | #include "commands.h" | ||
| 26 | |||
| 27 | #define MAXHOPS 100 | ||
| 28 | unsigned int databytes = 0; | ||
| 29 | int timeout = 1200; | ||
| 30 | |||
| 31 | int safewrite(fd,buf,len) int fd; char *buf; int len; | ||
| 32 | { | ||
| 33 | int r; | ||
| 34 | r = timeoutwrite(timeout,fd,buf,len); | ||
| 35 | if (r <= 0) _exit(1); | ||
| 36 | return r; | ||
| 37 | } | ||
| 38 | |||
| 39 | char ssoutbuf[512]; | ||
| 40 | substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf); | ||
| 41 | |||
| 42 | void flush() { substdio_flush(&ssout); } | ||
| 43 | void out(s) char *s; { substdio_puts(&ssout,s); } | ||
| 44 | |||
| 45 | void die_read() { _exit(1); } | ||
| 46 | void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); } | ||
| 47 | void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); } | ||
| 48 | void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); } | ||
| 49 | void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); } | ||
| 50 | void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); } | ||
| 51 | |||
| 52 | void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); } | ||
| 53 | void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); } | ||
| 54 | void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); } | ||
| 55 | void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); } | ||
| 56 | void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); } | ||
| 57 | void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); } | ||
| 58 | void err_noop() { out("250 ok\r\n"); } | ||
| 59 | void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); } | ||
| 60 | void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); } | ||
| 61 | |||
| 62 | |||
| 63 | stralloc greeting = {0}; | ||
| 64 | |||
| 65 | void smtp_greet(code) char *code; | ||
| 66 | { | ||
| 67 | substdio_puts(&ssout,code); | ||
| 68 | substdio_put(&ssout,greeting.s,greeting.len); | ||
| 69 | } | ||
| 70 | void smtp_help() | ||
| 71 | { | ||
| 72 | out("214 qmail home page: http://pobox.com/~djb/qmail.html\r\n"); | ||
| 73 | } | ||
| 74 | void smtp_quit() | ||
| 75 | { | ||
| 76 | smtp_greet("221 "); out("\r\n"); flush(); _exit(0); | ||
| 77 | } | ||
| 78 | |||
| 79 | char *remoteip; | ||
| 80 | char *remotehost; | ||
| 81 | char *remoteinfo; | ||
| 82 | char *local; | ||
| 83 | char *relayclient; | ||
| 84 | |||
| 85 | stralloc helohost = {0}; | ||
| 86 | char *fakehelo; /* pointer into helohost, or 0 */ | ||
| 87 | |||
| 88 | void dohelo(arg) char *arg; { | ||
| 89 | if (!stralloc_copys(&helohost,arg)) die_nomem(); | ||
| 90 | if (!stralloc_0(&helohost)) die_nomem(); | ||
| 91 | fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0; | ||
| 92 | } | ||
| 93 | |||
| 94 | int liphostok = 0; | ||
| 95 | stralloc liphost = {0}; | ||
| 96 | int bmfok = 0; | ||
| 97 | stralloc bmf = {0}; | ||
| 98 | struct constmap mapbmf; | ||
| 99 | |||
| 100 | void setup() | ||
| 101 | { | ||
| 102 | char *x; | ||
| 103 | unsigned long u; | ||
| 104 | |||
| 105 | if (control_init() == -1) die_control(); | ||
| 106 | if (control_rldef(&greeting,"control/smtpgreeting",1,(char *) 0) != 1) | ||
| 107 | die_control(); | ||
| 108 | liphostok = control_rldef(&liphost,"control/localiphost",1,(char *) 0); | ||
| 109 | if (liphostok == -1) die_control(); | ||
| 110 | if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control(); | ||
| 111 | if (timeout <= 0) timeout = 1; | ||
| 112 | |||
| 113 | if (rcpthosts_init() == -1) die_control(); | ||
| 114 | |||
| 115 | bmfok = control_readfile(&bmf,"control/badmailfrom",0); | ||
| 116 | if (bmfok == -1) die_control(); | ||
| 117 | if (bmfok) | ||
| 118 | if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem(); | ||
| 119 | |||
| 120 | if (control_readint(&databytes,"control/databytes") == -1) die_control(); | ||
| 121 | x = env_get("DATABYTES"); | ||
| 122 | if (x) { scan_ulong(x,&u); databytes = u; } | ||
| 123 | if (!(databytes + 1)) --databytes; | ||
| 124 | |||
| 125 | remoteip = env_get("TCPREMOTEIP"); | ||
| 126 | if (!remoteip) remoteip = "unknown"; | ||
| 127 | local = env_get("TCPLOCALHOST"); | ||
| 128 | if (!local) local = env_get("TCPLOCALIP"); | ||
| 129 | if (!local) local = "unknown"; | ||
| 130 | remotehost = env_get("TCPREMOTEHOST"); | ||
| 131 | if (!remotehost) remotehost = "unknown"; | ||
| 132 | remoteinfo = env_get("TCPREMOTEINFO"); | ||
| 133 | relayclient = env_get("RELAYCLIENT"); | ||
| 134 | dohelo(remotehost); | ||
| 135 | } | ||
| 136 | |||
| 137 | |||
| 138 | stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */ | ||
| 139 | |||
| 140 | int addrparse(arg) | ||
| 141 | char *arg; | ||
| 142 | { | ||
| 143 | int i; | ||
| 144 | char ch; | ||
| 145 | char terminator; | ||
| 146 | struct ip_address ip; | ||
| 147 | int flagesc; | ||
| 148 | int flagquoted; | ||
| 149 | |||
| 150 | terminator = '>'; | ||
| 151 | i = str_chr(arg,'<'); | ||
| 152 | if (arg[i]) | ||
| 153 | arg += i + 1; | ||
| 154 | else { /* partner should go read rfc 821 */ | ||
| 155 | terminator = ' '; | ||
| 156 | arg += str_chr(arg,':'); | ||
| 157 | if (*arg == ':') ++arg; | ||
| 158 | while (*arg == ' ') ++arg; | ||
| 159 | } | ||
| 160 | |||
| 161 | /* strip source route */ | ||
| 162 | if (*arg == '@') while (*arg) if (*arg++ == ':') break; | ||
| 163 | |||
| 164 | if (!stralloc_copys(&addr,"")) die_nomem(); | ||
| 165 | flagesc = 0; | ||
| 166 | flagquoted = 0; | ||
| 167 | for (i = 0;ch = arg[i];++i) { /* copy arg to addr, stripping quotes */ | ||
| 168 | if (flagesc) { | ||
| 169 | if (!stralloc_append(&addr,&ch)) die_nomem(); | ||
| 170 | flagesc = 0; | ||
| 171 | } | ||
| 172 | else { | ||
| 173 | if (!flagquoted && (ch == terminator)) break; | ||
| 174 | switch(ch) { | ||
| 175 | case '\\': flagesc = 1; break; | ||
| 176 | case '"': flagquoted = !flagquoted; break; | ||
| 177 | default: if (!stralloc_append(&addr,&ch)) die_nomem(); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | } | ||
| 181 | /* could check for termination failure here, but why bother? */ | ||
| 182 | if (!stralloc_append(&addr,"")) die_nomem(); | ||
| 183 | |||
| 184 | if (liphostok) { | ||
| 185 | i = byte_rchr(addr.s,addr.len,'@'); | ||
| 186 | if (i < addr.len) /* if not, partner should go read rfc 821 */ | ||
| 187 | if (addr.s[i + 1] == '[') | ||
| 188 | if (!addr.s[i + 1 + ip_scanbracket(addr.s + i + 1,&ip)]) | ||
| 189 | if (ipme_is(&ip)) { | ||
| 190 | addr.len = i + 1; | ||
| 191 | if (!stralloc_cat(&addr,&liphost)) die_nomem(); | ||
| 192 | if (!stralloc_0(&addr)) die_nomem(); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | if (addr.len > 900) return 0; | ||
| 197 | return 1; | ||
| 198 | } | ||
| 199 | |||
| 200 | int bmfcheck() | ||
| 201 | { | ||
| 202 | int j; | ||
| 203 | if (!bmfok) return 0; | ||
| 204 | if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1; | ||
| 205 | j = byte_rchr(addr.s,addr.len,'@'); | ||
| 206 | if (j < addr.len) | ||
| 207 | if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1; | ||
| 208 | return 0; | ||
| 209 | } | ||
| 210 | |||
| 211 | int addrallowed() | ||
| 212 | { | ||
| 213 | int r; | ||
| 214 | r = rcpthosts(addr.s,str_len(addr.s)); | ||
| 215 | if (r == -1) die_control(); | ||
| 216 | return r; | ||
| 217 | } | ||
| 218 | |||
| 219 | |||
| 220 | int seenmail = 0; | ||
| 221 | int flagbarf; /* defined if seenmail */ | ||
| 222 | stralloc mailfrom = {0}; | ||
| 223 | stralloc rcptto = {0}; | ||
| 224 | |||
| 225 | void smtp_helo(arg) char *arg; | ||
| 226 | { | ||
| 227 | smtp_greet("250 "); out("\r\n"); | ||
| 228 | seenmail = 0; dohelo(arg); | ||
| 229 | } | ||
| 230 | void smtp_ehlo(arg) char *arg; | ||
| 231 | { | ||
| 232 | smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); | ||
| 233 | seenmail = 0; dohelo(arg); | ||
| 234 | } | ||
| 235 | void smtp_rset() | ||
| 236 | { | ||
| 237 | seenmail = 0; | ||
| 238 | out("250 flushed\r\n"); | ||
| 239 | } | ||
| 240 | void smtp_mail(arg) char *arg; | ||
| 241 | { | ||
| 242 | if (!addrparse(arg)) { err_syntax(); return; } | ||
| 243 | flagbarf = bmfcheck(); | ||
| 244 | seenmail = 1; | ||
| 245 | if (!stralloc_copys(&rcptto,"")) die_nomem(); | ||
| 246 | if (!stralloc_copys(&mailfrom,addr.s)) die_nomem(); | ||
| 247 | if (!stralloc_0(&mailfrom)) die_nomem(); | ||
| 248 | out("250 ok\r\n"); | ||
| 249 | } | ||
| 250 | void smtp_rcpt(arg) char *arg; { | ||
| 251 | if (!seenmail) { err_wantmail(); return; } | ||
| 252 | if (!addrparse(arg)) { err_syntax(); return; } | ||
| 253 | if (flagbarf) { err_bmf(); return; } | ||
| 254 | if (relayclient) { | ||
| 255 | --addr.len; | ||
| 256 | if (!stralloc_cats(&addr,relayclient)) die_nomem(); | ||
| 257 | if (!stralloc_0(&addr)) die_nomem(); | ||
| 258 | } | ||
| 259 | else | ||
| 260 | if (!addrallowed()) { err_nogateway(); return; } | ||
| 261 | if (!stralloc_cats(&rcptto,"T")) die_nomem(); | ||
| 262 | if (!stralloc_cats(&rcptto,addr.s)) die_nomem(); | ||
| 263 | if (!stralloc_0(&rcptto)) die_nomem(); | ||
| 264 | out("250 ok\r\n"); | ||
| 265 | } | ||
| 266 | |||
| 267 | |||
| 268 | int saferead(fd,buf,len) int fd; char *buf; int len; | ||
| 269 | { | ||
| 270 | int r; | ||
| 271 | flush(); | ||
| 272 | r = timeoutread(timeout,fd,buf,len); | ||
| 273 | if (r == -1) if (errno == error_timeout) die_alarm(); | ||
| 274 | if (r <= 0) die_read(); | ||
| 275 | return r; | ||
| 276 | } | ||
| 277 | |||
| 278 | char ssinbuf[1024]; | ||
| 279 | substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf); | ||
| 280 | |||
| 281 | struct qmail qqt; | ||
| 282 | unsigned int bytestooverflow = 0; | ||
| 283 | |||
| 284 | void put(ch) | ||
| 285 | char *ch; | ||
| 286 | { | ||
| 287 | if (bytestooverflow) | ||
| 288 | if (!--bytestooverflow) | ||
| 289 | qmail_fail(&qqt); | ||
| 290 | qmail_put(&qqt,ch,1); | ||
| 291 | } | ||
| 292 | |||
| 293 | void blast(hops) | ||
| 294 | int *hops; | ||
| 295 | { | ||
| 296 | char ch; | ||
| 297 | int state; | ||
| 298 | int flaginheader; | ||
| 299 | int pos; /* number of bytes since most recent \n, if fih */ | ||
| 300 | int flagmaybex; /* 1 if this line might match RECEIVED, if fih */ | ||
| 301 | int flagmaybey; /* 1 if this line might match \r\n, if fih */ | ||
| 302 | int flagmaybez; /* 1 if this line might match DELIVERED, if fih */ | ||
| 303 | |||
| 304 | state = 1; | ||
| 305 | *hops = 0; | ||
| 306 | flaginheader = 1; | ||
| 307 | pos = 0; flagmaybex = flagmaybey = flagmaybez = 1; | ||
| 308 | for (;;) { | ||
| 309 | substdio_get(&ssin,&ch,1); | ||
| 310 | if (flaginheader) { | ||
| 311 | if (pos < 9) { | ||
| 312 | if (ch != "delivered"[pos]) if (ch != "DELIVERED"[pos]) flagmaybez = 0; | ||
| 313 | if (flagmaybez) if (pos == 8) ++*hops; | ||
| 314 | if (pos < 8) | ||
| 315 | if (ch != "received"[pos]) if (ch != "RECEIVED"[pos]) flagmaybex = 0; | ||
| 316 | if (flagmaybex) if (pos == 7) ++*hops; | ||
| 317 | if (pos < 2) if (ch != "\r\n"[pos]) flagmaybey = 0; | ||
| 318 | if (flagmaybey) if (pos == 1) flaginheader = 0; | ||
| 319 | } | ||
| 320 | ++pos; | ||
| 321 | if (ch == '\n') { pos = 0; flagmaybex = flagmaybey = flagmaybez = 1; } | ||
| 322 | } | ||
| 323 | switch(state) { | ||
| 324 | case 0: | ||
| 325 | if (ch == '\n') straynewline(); | ||
| 326 | if (ch == '\r') { state = 4; continue; } | ||
| 327 | break; | ||
| 328 | case 1: /* \r\n */ | ||
| 329 | if (ch == '\n') straynewline(); | ||
| 330 | if (ch == '.') { state = 2; continue; } | ||
| 331 | if (ch == '\r') { state = 4; continue; } | ||
| 332 | state = 0; | ||
| 333 | break; | ||
| 334 | case 2: /* \r\n + . */ | ||
| 335 | if (ch == '\n') straynewline(); | ||
| 336 | if (ch == '\r') { state = 3; continue; } | ||
| 337 | state = 0; | ||
| 338 | break; | ||
| 339 | case 3: /* \r\n + .\r */ | ||
| 340 | if (ch == '\n') return; | ||
| 341 | put("."); | ||
| 342 | put("\r"); | ||
| 343 | if (ch == '\r') { state = 4; continue; } | ||
| 344 | state = 0; | ||
| 345 | break; | ||
| 346 | case 4: /* + \r */ | ||
| 347 | if (ch == '\n') { state = 1; break; } | ||
| 348 | if (ch != '\r') { put("\r"); state = 0; } | ||
| 349 | } | ||
| 350 | put(&ch); | ||
| 351 | } | ||
| 352 | } | ||
| 353 | |||
| 354 | char accept_buf[FMT_ULONG]; | ||
| 355 | void acceptmessage(qp) unsigned long qp; | ||
| 356 | { | ||
| 357 | datetime_sec when; | ||
| 358 | when = now(); | ||
| 359 | out("250 ok "); | ||
| 360 | accept_buf[fmt_ulong(accept_buf,(unsigned long) when)] = 0; | ||
| 361 | out(accept_buf); | ||
| 362 | out(" qp "); | ||
| 363 | accept_buf[fmt_ulong(accept_buf,qp)] = 0; | ||
| 364 | out(accept_buf); | ||
| 365 | out("\r\n"); | ||
| 366 | } | ||
| 367 | |||
| 368 | void smtp_data() { | ||
| 369 | int hops; | ||
| 370 | unsigned long qp; | ||
| 371 | char *qqx; | ||
| 372 | |||
| 373 | if (!seenmail) { err_wantmail(); return; } | ||
| 374 | if (!rcptto.len) { err_wantrcpt(); return; } | ||
| 375 | seenmail = 0; | ||
| 376 | if (databytes) bytestooverflow = databytes + 1; | ||
| 377 | if (qmail_open(&qqt) == -1) { err_qqt(); return; } | ||
| 378 | qp = qmail_qp(&qqt); | ||
| 379 | out("354 go ahead\r\n"); | ||
| 380 | |||
| 381 | received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo); | ||
| 382 | blast(&hops); | ||
| 383 | hops = (hops >= MAXHOPS); | ||
| 384 | if (hops) qmail_fail(&qqt); | ||
| 385 | qmail_from(&qqt,mailfrom.s); | ||
| 386 | qmail_put(&qqt,rcptto.s,rcptto.len); | ||
| 387 | |||
| 388 | qqx = qmail_close(&qqt); | ||
| 389 | if (!*qqx) { acceptmessage(qp); return; } | ||
| 390 | if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; } | ||
| 391 | if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; } | ||
| 392 | if (*qqx == 'D') out("554 "); else out("451 "); | ||
| 393 | out(qqx + 1); | ||
| 394 | out("\r\n"); | ||
| 395 | } | ||
| 396 | |||
| 397 | struct commands smtpcommands[] = { | ||
| 398 | { "rcpt", smtp_rcpt, 0 } | ||
| 399 | , { "mail", smtp_mail, 0 } | ||
| 400 | , { "data", smtp_data, flush } | ||
| 401 | , { "quit", smtp_quit, flush } | ||
| 402 | , { "helo", smtp_helo, flush } | ||
| 403 | , { "ehlo", smtp_ehlo, flush } | ||
| 404 | , { "rset", smtp_rset, 0 } | ||
| 405 | , { "help", smtp_help, flush } | ||
| 406 | , { "noop", err_noop, flush } | ||
| 407 | , { "vrfy", err_vrfy, flush } | ||
| 408 | , { 0, err_unimpl, flush } | ||
| 409 | } ; | ||
| 410 | |||
| 411 | void main() | ||
| 412 | { | ||
| 413 | sig_pipeignore(); | ||
| 414 | if (chdir(auto_qmail) == -1) die_control(); | ||
| 415 | setup(); | ||
| 416 | if (ipme_init() != 1) die_ipme(); | ||
| 417 | smtp_greet("220 "); | ||
| 418 | out(" ESMTP\r\n"); | ||
| 419 | if (commands(&ssin,&smtpcommands) == 0) die_read(); | ||
| 420 | die_nomem(); | ||
| 421 | } | ||
diff --git a/qmail-start.9 b/qmail-start.9 new file mode 100644 index 0000000..29876ec --- /dev/null +++ b/qmail-start.9 | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | .TH qmail-start 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-start \- turn on mail delivery | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-start | ||
| 6 | [ | ||
| 7 | .I defaultdelivery | ||
| 8 | [ | ||
| 9 | .I logger arg ... | ||
| 10 | ] | ||
| 11 | ] | ||
| 12 | .SH DESCRIPTION | ||
| 13 | .B qmail-start | ||
| 14 | invokes | ||
| 15 | .BR qmail-send , | ||
| 16 | .BR qmail-lspawn , | ||
| 17 | .BR qmail-rspawn , | ||
| 18 | and | ||
| 19 | .BR qmail-clean , | ||
| 20 | under the proper uids and gids. | ||
| 21 | These four daemons cooperate to deliver messages from the queue. | ||
| 22 | |||
| 23 | .B qmail-start | ||
| 24 | arranges for | ||
| 25 | .BR qmail-send 's | ||
| 26 | activity record to be sent to | ||
| 27 | .BR qmail-start 's | ||
| 28 | output. | ||
| 29 | See | ||
| 30 | .B qmail-log(5) | ||
| 31 | for the format of the activity record. | ||
| 32 | Other than this, | ||
| 33 | .B qmail-start | ||
| 34 | does not print anything, even on failure. | ||
| 35 | |||
| 36 | If | ||
| 37 | .I defaultdelivery | ||
| 38 | is supplied, | ||
| 39 | .B qmail-start | ||
| 40 | passes it to | ||
| 41 | .BR qmail-lspawn . | ||
| 42 | |||
| 43 | If | ||
| 44 | .I logger | ||
| 45 | is supplied, | ||
| 46 | .B qmail-start | ||
| 47 | invokes | ||
| 48 | .I logger | ||
| 49 | with the given arguments, | ||
| 50 | and feeds | ||
| 51 | .BR qmail-send 's | ||
| 52 | activity record through | ||
| 53 | .IR logger . | ||
| 54 | |||
| 55 | Environment variables given to | ||
| 56 | .B qmail-start | ||
| 57 | will eventually be passed on to | ||
| 58 | .BR qmail-local , | ||
| 59 | so make sure to clean up the environment if you run | ||
| 60 | .B qmail-start | ||
| 61 | manually: | ||
| 62 | |||
| 63 | .EX | ||
| 64 | # env - PATH="QMAILHOME/bin:$PATH" | ||
| 65 | .br | ||
| 66 | qmail-start ./Mailbox splogger qmail & | ||
| 67 | .br | ||
| 68 | (all on one line) | ||
| 69 | .EE | ||
| 70 | |||
| 71 | Resource limits, controlling ttys, et al. are also passed from | ||
| 72 | .B qmail-start | ||
| 73 | to | ||
| 74 | .BR qmail-local . | ||
| 75 | |||
| 76 | Note that | ||
| 77 | .B qmail-send | ||
| 78 | normally juggles several simultaneous deliveries. | ||
| 79 | To reduce | ||
| 80 | .BR qmail-send 's | ||
| 81 | impact on other programs, | ||
| 82 | you can run | ||
| 83 | .B qmail-start | ||
| 84 | with a low priority. | ||
| 85 | .SH "SEE ALSO" | ||
| 86 | logger(1), | ||
| 87 | splogger(1), | ||
| 88 | nice(1), | ||
| 89 | qmail-log(5), | ||
| 90 | qmail-local(8), | ||
| 91 | qmail-clean(8), | ||
| 92 | qmail-lspawn(8), | ||
| 93 | qmail-rspawn(8), | ||
| 94 | qmail-send(8) | ||
diff --git a/qmail-start.c b/qmail-start.c new file mode 100644 index 0000000..37423b0 --- /dev/null +++ b/qmail-start.c | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | #include "fd.h" | ||
| 2 | #include "prot.h" | ||
| 3 | #include "exit.h" | ||
| 4 | #include "fork.h" | ||
| 5 | #include "auto_uids.h" | ||
| 6 | |||
| 7 | char *(qsargs[]) = { "qmail-send", 0 }; | ||
| 8 | char *(qcargs[]) = { "qmail-clean", 0 }; | ||
| 9 | char *(qlargs[]) = { "qmail-lspawn", "./Mailbox", 0 }; | ||
| 10 | char *(qrargs[]) = { "qmail-rspawn", 0 }; | ||
| 11 | |||
| 12 | void die() { _exit(111); } | ||
| 13 | |||
| 14 | int pi0[2]; | ||
| 15 | int pi1[2]; | ||
| 16 | int pi2[2]; | ||
| 17 | int pi3[2]; | ||
| 18 | int pi4[2]; | ||
| 19 | int pi5[2]; | ||
| 20 | int pi6[2]; | ||
| 21 | |||
| 22 | void close23456() { close(2); close(3); close(4); close(5); close(6); } | ||
| 23 | |||
| 24 | void closepipes() { | ||
| 25 | close(pi1[0]); close(pi1[1]); close(pi2[0]); close(pi2[1]); | ||
| 26 | close(pi3[0]); close(pi3[1]); close(pi4[0]); close(pi4[1]); | ||
| 27 | close(pi5[0]); close(pi5[1]); close(pi6[0]); close(pi6[1]); | ||
| 28 | } | ||
| 29 | |||
| 30 | void main(argc,argv) | ||
| 31 | int argc; | ||
| 32 | char **argv; | ||
| 33 | { | ||
| 34 | if (chdir("/") == -1) die(); | ||
| 35 | umask(077); | ||
| 36 | if (prot_gid(auto_gidq) == -1) die(); | ||
| 37 | |||
| 38 | if (fd_copy(2,0) == -1) die(); | ||
| 39 | if (fd_copy(3,0) == -1) die(); | ||
| 40 | if (fd_copy(4,0) == -1) die(); | ||
| 41 | if (fd_copy(5,0) == -1) die(); | ||
| 42 | if (fd_copy(6,0) == -1) die(); | ||
| 43 | |||
| 44 | if (argv[1]) { | ||
| 45 | qlargs[1] = argv[1]; | ||
| 46 | ++argv; | ||
| 47 | } | ||
| 48 | |||
| 49 | if (argv[1]) { | ||
| 50 | if (pipe(pi0) == -1) die(); | ||
| 51 | switch(fork()) { | ||
| 52 | case -1: | ||
| 53 | die(); | ||
| 54 | case 0: | ||
| 55 | if (prot_gid(auto_gidn) == -1) die(); | ||
| 56 | if (prot_uid(auto_uidl) == -1) die(); | ||
| 57 | close(pi0[1]); | ||
| 58 | if (fd_move(0,pi0[0]) == -1) die(); | ||
| 59 | close23456(); | ||
| 60 | execvp(argv[1],argv + 1); | ||
| 61 | die(); | ||
| 62 | } | ||
| 63 | close(pi0[0]); | ||
| 64 | if (fd_move(1,pi0[1]) == -1) die(); | ||
| 65 | } | ||
| 66 | |||
| 67 | if (pipe(pi1) == -1) die(); | ||
| 68 | if (pipe(pi2) == -1) die(); | ||
| 69 | if (pipe(pi3) == -1) die(); | ||
| 70 | if (pipe(pi4) == -1) die(); | ||
| 71 | if (pipe(pi5) == -1) die(); | ||
| 72 | if (pipe(pi6) == -1) die(); | ||
| 73 | |||
| 74 | switch(fork()) { | ||
| 75 | case -1: die(); | ||
| 76 | case 0: | ||
| 77 | if (fd_copy(0,pi1[0]) == -1) die(); | ||
| 78 | if (fd_copy(1,pi2[1]) == -1) die(); | ||
| 79 | close23456(); | ||
| 80 | closepipes(); | ||
| 81 | execvp(*qlargs,qlargs); | ||
| 82 | die(); | ||
| 83 | } | ||
| 84 | |||
| 85 | switch(fork()) { | ||
| 86 | case -1: die(); | ||
| 87 | case 0: | ||
| 88 | if (prot_uid(auto_uidr) == -1) die(); | ||
| 89 | if (fd_copy(0,pi3[0]) == -1) die(); | ||
| 90 | if (fd_copy(1,pi4[1]) == -1) die(); | ||
| 91 | close23456(); | ||
| 92 | closepipes(); | ||
| 93 | execvp(*qrargs,qrargs); | ||
| 94 | die(); | ||
| 95 | } | ||
| 96 | |||
| 97 | switch(fork()) { | ||
| 98 | case -1: die(); | ||
| 99 | case 0: | ||
| 100 | if (prot_uid(auto_uidq) == -1) die(); | ||
| 101 | if (fd_copy(0,pi5[0]) == -1) die(); | ||
| 102 | if (fd_copy(1,pi6[1]) == -1) die(); | ||
| 103 | close23456(); | ||
| 104 | closepipes(); | ||
| 105 | execvp(*qcargs,qcargs); | ||
| 106 | die(); | ||
| 107 | } | ||
| 108 | |||
| 109 | if (prot_uid(auto_uids) == -1) die(); | ||
| 110 | if (fd_copy(0,1) == -1) die(); | ||
| 111 | if (fd_copy(1,pi1[1]) == -1) die(); | ||
| 112 | if (fd_copy(2,pi2[0]) == -1) die(); | ||
| 113 | if (fd_copy(3,pi3[1]) == -1) die(); | ||
| 114 | if (fd_copy(4,pi4[0]) == -1) die(); | ||
| 115 | if (fd_copy(5,pi5[1]) == -1) die(); | ||
| 116 | if (fd_copy(6,pi6[0]) == -1) die(); | ||
| 117 | closepipes(); | ||
| 118 | execvp(*qsargs,qsargs); | ||
| 119 | die(); | ||
| 120 | } | ||
diff --git a/qmail-tcpok.8 b/qmail-tcpok.8 new file mode 100644 index 0000000..ed2efcf --- /dev/null +++ b/qmail-tcpok.8 | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | .TH qmail-tcpok 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-tcpok \- clear TCP timeout table | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-tcpok | ||
| 6 | .SH DESCRIPTION | ||
| 7 | .B qmail-tcpok | ||
| 8 | erases | ||
| 9 | .BR qmail-remote 's | ||
| 10 | current list of timeouts, | ||
| 11 | so that | ||
| 12 | .B qmail-remote | ||
| 13 | does not make any assumptions about failing addresses. | ||
| 14 | |||
| 15 | .B qmail-tcpok | ||
| 16 | must be run either as | ||
| 17 | .B root | ||
| 18 | or with user id | ||
| 19 | .B qmailr | ||
| 20 | and group id | ||
| 21 | .BR qmail . | ||
| 22 | .SH "SEE ALSO" | ||
| 23 | qmail-remote(8), | ||
| 24 | qmail-tcpto(8) | ||
diff --git a/qmail-tcpok.c b/qmail-tcpok.c new file mode 100644 index 0000000..a9b9652 --- /dev/null +++ b/qmail-tcpok.c | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | #include "strerr.h" | ||
| 2 | #include "substdio.h" | ||
| 3 | #include "lock.h" | ||
| 4 | #include "open.h" | ||
| 5 | #include "readwrite.h" | ||
| 6 | #include "auto_qmail.h" | ||
| 7 | #include "exit.h" | ||
| 8 | |||
| 9 | #define FATAL "qmail-tcpok: fatal: " | ||
| 10 | |||
| 11 | char buf[1024]; /* XXX: must match size in tcpto_clean.c, tcpto.c */ | ||
| 12 | substdio ss; | ||
| 13 | |||
| 14 | void main() | ||
| 15 | { | ||
| 16 | int fd; | ||
| 17 | int i; | ||
| 18 | |||
| 19 | if (chdir(auto_qmail) == -1) | ||
| 20 | strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": "); | ||
| 21 | if (chdir("queue/lock") == -1) | ||
| 22 | strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,"/queue/lock: "); | ||
| 23 | |||
| 24 | fd = open_write("tcpto"); | ||
| 25 | if (fd == -1) | ||
| 26 | strerr_die4sys(111,FATAL,"unable to write ",auto_qmail,"/queue/lock/tcpto: "); | ||
| 27 | if (lock_ex(fd) == -1) | ||
| 28 | strerr_die4sys(111,FATAL,"unable to lock ",auto_qmail,"/queue/lock/tcpto: "); | ||
| 29 | |||
| 30 | substdio_fdbuf(&ss,write,fd,buf,sizeof buf); | ||
| 31 | for (i = 0;i < sizeof buf;++i) substdio_put(&ss,"",1); | ||
| 32 | if (substdio_flush(&ss) == -1) | ||
| 33 | strerr_die4sys(111,FATAL,"unable to clear ",auto_qmail,"/queue/lock/tcpto: "); | ||
| 34 | _exit(0); | ||
| 35 | } | ||
diff --git a/qmail-tcpto.8 b/qmail-tcpto.8 new file mode 100644 index 0000000..cb4ddd6 --- /dev/null +++ b/qmail-tcpto.8 | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | .TH qmail-tcpto 8 | ||
| 2 | .SH NAME | ||
| 3 | qmail-tcpto \- print TCP timeout table | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B qmail-tcpto | ||
| 6 | .SH DESCRIPTION | ||
| 7 | After an SMTP connection attempt times out, | ||
| 8 | .B qmail-remote | ||
| 9 | records the relevant IP address. | ||
| 10 | If the same address fails again (after at least two minutes with | ||
| 11 | no intervening successful connections), | ||
| 12 | .B qmail-remote | ||
| 13 | assumes that further attempts will fail for at least another hour. | ||
| 14 | |||
| 15 | .B qmail-tcpto | ||
| 16 | prints | ||
| 17 | .BR qmail-remote 's | ||
| 18 | current list of timeouts. | ||
| 19 | |||
| 20 | .B qmail-tcpto | ||
| 21 | must be run either as | ||
| 22 | .B root | ||
| 23 | or with user id | ||
| 24 | .B qmailr | ||
| 25 | and group id | ||
| 26 | .BR qmail . | ||
| 27 | .SH "SEE ALSO" | ||
| 28 | qmail-qread(8), | ||
| 29 | qmail-remote(8), | ||
| 30 | qmail-tcpok(8) | ||
diff --git a/qmail-tcpto.c b/qmail-tcpto.c new file mode 100644 index 0000000..d181ecf --- /dev/null +++ b/qmail-tcpto.c | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | /* XXX: this program knows quite a bit about tcpto's internals */ | ||
| 2 | |||
| 3 | #include "substdio.h" | ||
| 4 | #include "subfd.h" | ||
| 5 | #include "auto_qmail.h" | ||
| 6 | #include "fmt.h" | ||
| 7 | #include "ip.h" | ||
| 8 | #include "lock.h" | ||
| 9 | #include "error.h" | ||
| 10 | #include "exit.h" | ||
| 11 | #include "datetime.h" | ||
| 12 | #include "now.h" | ||
| 13 | |||
| 14 | void die(n) int n; { substdio_flush(subfdout); _exit(n); } | ||
| 15 | |||
| 16 | void warn(s) char *s; | ||
| 17 | { | ||
| 18 | char *x; | ||
| 19 | x = error_str(errno); | ||
| 20 | substdio_puts(subfdout,s); | ||
| 21 | substdio_puts(subfdout,": "); | ||
| 22 | substdio_puts(subfdout,x); | ||
| 23 | substdio_puts(subfdout,"\n"); | ||
| 24 | } | ||
| 25 | |||
| 26 | void die_chdir() { warn("fatal: unable to chdir"); die(111); } | ||
| 27 | void die_open() { warn("fatal: unable to open tcpto"); die(111); } | ||
| 28 | void die_lock() { warn("fatal: unable to lock tcpto"); die(111); } | ||
| 29 | void die_read() { warn("fatal: unable to read tcpto"); die(111); } | ||
| 30 | |||
| 31 | char tcpto_buf[1024]; | ||
| 32 | |||
| 33 | char tmp[FMT_ULONG + IPFMT]; | ||
| 34 | |||
| 35 | void main() | ||
| 36 | { | ||
| 37 | int fdlock; | ||
| 38 | int fd; | ||
| 39 | int r; | ||
| 40 | int i; | ||
| 41 | char *record; | ||
| 42 | struct ip_address ip; | ||
| 43 | datetime_sec when; | ||
| 44 | datetime_sec start; | ||
| 45 | |||
| 46 | if (chdir(auto_qmail) == -1) die_chdir(); | ||
| 47 | if (chdir("queue/lock") == -1) die_chdir(); | ||
| 48 | |||
| 49 | fdlock = open_write("tcpto"); | ||
| 50 | if (fdlock == -1) die_open(); | ||
| 51 | fd = open_read("tcpto"); | ||
| 52 | if (fd == -1) die_open(); | ||
| 53 | if (lock_ex(fdlock) == -1) die_lock(); | ||
| 54 | r = read(fd,tcpto_buf,sizeof(tcpto_buf)); | ||
| 55 | close(fd); | ||
| 56 | close(fdlock); | ||
| 57 | |||
| 58 | if (r == -1) die_read(); | ||
| 59 | r >>= 4; | ||
| 60 | |||
| 61 | start = now(); | ||
| 62 | |||
| 63 | record = tcpto_buf; | ||
| 64 | for (i = 0;i < r;++i) | ||
| 65 | { | ||
| 66 | if (record[4] >= 1) | ||
| 67 | { | ||
| 68 | byte_copy(&ip,4,record); | ||
| 69 | when = (unsigned long) (unsigned char) record[11]; | ||
| 70 | when = (when << 8) + (unsigned long) (unsigned char) record[10]; | ||
| 71 | when = (when << 8) + (unsigned long) (unsigned char) record[9]; | ||
| 72 | when = (when << 8) + (unsigned long) (unsigned char) record[8]; | ||
| 73 | |||
| 74 | substdio_put(subfdout,tmp,ip_fmt(tmp,&ip)); | ||
| 75 | substdio_puts(subfdout," timed out "); | ||
| 76 | substdio_put(subfdout,tmp,fmt_ulong(tmp,(unsigned long) (start - when))); | ||
| 77 | substdio_puts(subfdout," seconds ago; # recent timeouts: "); | ||
| 78 | substdio_put(subfdout,tmp,fmt_ulong(tmp,(unsigned long) (unsigned char) record[4])); | ||
| 79 | substdio_puts(subfdout,"\n"); | ||
| 80 | } | ||
| 81 | record += 16; | ||
| 82 | } | ||
| 83 | |||
| 84 | die(0); | ||
| 85 | } | ||
diff --git a/qmail-upq.sh b/qmail-upq.sh new file mode 100644 index 0000000..a068196 --- /dev/null +++ b/qmail-upq.sh | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | cd QMAIL | ||
| 2 | cd queue | ||
| 3 | for dir in mess info local remote | ||
| 4 | do | ||
| 5 | ( cd $dir; find . -type f -print ) | ( | ||
| 6 | cd $dir | ||
| 7 | while read path | ||
| 8 | do | ||
| 9 | id=`basename "$path"` | ||
| 10 | sub=`expr "$id" % SPLIT` | ||
| 11 | mv "$path" "$sub"/"$id" | ||
| 12 | done | ||
| 13 | ) | ||
| 14 | done | ||
diff --git a/qmail-users.9 b/qmail-users.9 new file mode 100644 index 0000000..c44a452 --- /dev/null +++ b/qmail-users.9 | |||
| @@ -0,0 +1,113 @@ | |||
| 1 | .TH qmail-users 5 | ||
| 2 | .SH NAME | ||
| 3 | qmail-users \- assign mail addresses to users | ||
| 4 | .SH OVERVIEW | ||
| 5 | The file | ||
| 6 | .B QMAILHOME/users/assign | ||
| 7 | assigns addresses to users. For example, | ||
| 8 | |||
| 9 | .EX | ||
| 10 | =joe.shmoe:joe:503:78:/home/joe::: | ||
| 11 | .EE | ||
| 12 | |||
| 13 | says that mail for | ||
| 14 | .B joe.shmoe | ||
| 15 | should be delivered to user | ||
| 16 | .BR joe , | ||
| 17 | with uid 503 and gid 78, | ||
| 18 | as specified by | ||
| 19 | .BR /home/joe/.qmail . | ||
| 20 | |||
| 21 | Assignments fed to | ||
| 22 | .B qmail-newu | ||
| 23 | will be used by | ||
| 24 | .B qmail-lspawn | ||
| 25 | to control | ||
| 26 | .BR qmail-local 's | ||
| 27 | deliveries. | ||
| 28 | See | ||
| 29 | .BR qmail-newu (8). | ||
| 30 | A change to | ||
| 31 | .B QMAILHOME/users/assign | ||
| 32 | will have no effect until | ||
| 33 | .B qmail-newu | ||
| 34 | is run. | ||
| 35 | .SH STRUCTURE | ||
| 36 | .B QMAILHOME/users/assign | ||
| 37 | is a series of assignments, one per line. | ||
| 38 | It ends with a line containing a single dot. | ||
| 39 | Lines must not contain NUL. | ||
| 40 | .SH "SIMPLE ASSIGNMENTS" | ||
| 41 | A simple assignment is a line of the form | ||
| 42 | |||
| 43 | .EX | ||
| 44 | =local:user:uid:gid:homedir:dash:ext: | ||
| 45 | .EE | ||
| 46 | |||
| 47 | Here | ||
| 48 | .I local | ||
| 49 | is an address; | ||
| 50 | .IR user , | ||
| 51 | .IR uid , | ||
| 52 | and | ||
| 53 | .I gid | ||
| 54 | are the account name, uid, and gid | ||
| 55 | of the user in charge of | ||
| 56 | .IR local ; | ||
| 57 | and messages to | ||
| 58 | .I local | ||
| 59 | will be controlled by | ||
| 60 | .IR homedir\fB/.qmail\fIdashext . | ||
| 61 | |||
| 62 | If there are several assignments for the same | ||
| 63 | .I local | ||
| 64 | address, | ||
| 65 | .B qmail-lspawn | ||
| 66 | will use the first one. | ||
| 67 | |||
| 68 | .I local | ||
| 69 | is interpreted without regard to case. | ||
| 70 | .SH "WILDCARD ASSIGNMENTS" | ||
| 71 | A wildcard assignment is a line of the form | ||
| 72 | |||
| 73 | .EX | ||
| 74 | +loc:user:uid:gid:homedir:dash:pre: | ||
| 75 | .EE | ||
| 76 | |||
| 77 | This assignment applies to any address beginning with | ||
| 78 | .IR loc , | ||
| 79 | including | ||
| 80 | .I loc | ||
| 81 | itself. | ||
| 82 | It means the same as | ||
| 83 | |||
| 84 | .EX | ||
| 85 | =locext:user:uid:gid:homedir:dash:preext: | ||
| 86 | .EE | ||
| 87 | |||
| 88 | for every string | ||
| 89 | .IR ext . | ||
| 90 | |||
| 91 | A more specific wildcard assignment overrides a less specific | ||
| 92 | assignment, and a simple assignment overrides any wildcard assignment. | ||
| 93 | For example: | ||
| 94 | |||
| 95 | .EX | ||
| 96 | +:alias:7790:2108:QMAILHOME/alias:-:: | ||
| 97 | +joe-:joe:507:100:/home/joe:-:: | ||
| 98 | =joe:joe:507:100:/home/joe::: | ||
| 99 | .EE | ||
| 100 | |||
| 101 | The address | ||
| 102 | .B joe | ||
| 103 | is handled by the third line; | ||
| 104 | the address | ||
| 105 | .B joe-direct | ||
| 106 | is handled by the second line; | ||
| 107 | the address | ||
| 108 | .B bill | ||
| 109 | is handled by the first line. | ||
| 110 | .SH "SEE ALSO" | ||
| 111 | qmail-pw2u(8), | ||
| 112 | qmail-newu(8), | ||
| 113 | qmail-lspawn(8) | ||
| @@ -0,0 +1,66 @@ | |||
| 1 | .TH qmail 7 | ||
| 2 | .SH "NAME" | ||
| 3 | qmail \- overview of qmail documentation | ||
| 4 | .SH "INTRODUCTION" | ||
| 5 | .B qmail | ||
| 6 | is a secure, reliable, efficient, simple message transfer agent. | ||
| 7 | |||
| 8 | Users who want to control incoming messages | ||
| 9 | should read | ||
| 10 | .BR dot-qmail (5). | ||
| 11 | Available commands for the | ||
| 12 | .B .qmail | ||
| 13 | file include | ||
| 14 | .BR qbiff (1), | ||
| 15 | .BR qreceipt (1), | ||
| 16 | .BR forward (1), | ||
| 17 | .BR bouncesaying (1), | ||
| 18 | and | ||
| 19 | .BR condredirect (1). | ||
| 20 | Other helpful commands include | ||
| 21 | .BR maildirmake (1), | ||
| 22 | .BR maildir2mbox (1), | ||
| 23 | and | ||
| 24 | .BR maildirwatch (1). | ||
| 25 | |||
| 26 | System administrators who want to control the entire | ||
| 27 | .B qmail | ||
| 28 | system should start with | ||
| 29 | .BR qmail-control (5) | ||
| 30 | and | ||
| 31 | .BR qmail-start (8). | ||
| 32 | There are three queue-monitoring tools: | ||
| 33 | .BR qmail-qread (8), | ||
| 34 | .BR qmail-qstat (8), | ||
| 35 | and | ||
| 36 | .BR qmail-tcpto (8). | ||
| 37 | Incoming SMTP connections are handled by | ||
| 38 | .BR qmail-smtpd (8). | ||
| 39 | |||
| 40 | .B qmail | ||
| 41 | offers two command-line message-sending interfaces: | ||
| 42 | .BR qmail-inject (8) | ||
| 43 | and | ||
| 44 | .BR mailsubj (1). | ||
| 45 | For background information on Internet mail messages, | ||
| 46 | see | ||
| 47 | .BR addresses (5), | ||
| 48 | .BR envelopes (5), | ||
| 49 | .BR qmail-header (5), | ||
| 50 | and | ||
| 51 | .BR forgeries (7). | ||
| 52 | |||
| 53 | Miscellaneous documentation includes | ||
| 54 | .BR qmail-limits (7) | ||
| 55 | and | ||
| 56 | .BR qmail-pop3d (8). | ||
| 57 | |||
| 58 | This documentation describes version | ||
| 59 | 1.03 | ||
| 60 | of | ||
| 61 | .BR qmail . | ||
| 62 | See | ||
| 63 | .B http://pobox.com/~djb/qmail.html | ||
| 64 | for other | ||
| 65 | .BR qmail -related | ||
| 66 | software. | ||
| @@ -0,0 +1,125 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "readwrite.h" | ||
| 3 | #include "wait.h" | ||
| 4 | #include "exit.h" | ||
| 5 | #include "fork.h" | ||
| 6 | #include "fd.h" | ||
| 7 | #include "qmail.h" | ||
| 8 | #include "auto_qmail.h" | ||
| 9 | |||
| 10 | static char *binqqargs[2] = { "bin/qmail-queue", 0 } ; | ||
| 11 | |||
| 12 | int qmail_open(qq) | ||
| 13 | struct qmail *qq; | ||
| 14 | { | ||
| 15 | int pim[2]; | ||
| 16 | int pie[2]; | ||
| 17 | |||
| 18 | if (pipe(pim) == -1) return -1; | ||
| 19 | if (pipe(pie) == -1) { close(pim[0]); close(pim[1]); return -1; } | ||
| 20 | |||
| 21 | switch(qq->pid = vfork()) { | ||
| 22 | case -1: | ||
| 23 | close(pim[0]); close(pim[1]); | ||
| 24 | close(pie[0]); close(pie[1]); | ||
| 25 | return -1; | ||
| 26 | case 0: | ||
| 27 | close(pim[1]); | ||
| 28 | close(pie[1]); | ||
| 29 | if (fd_move(0,pim[0]) == -1) _exit(120); | ||
| 30 | if (fd_move(1,pie[0]) == -1) _exit(120); | ||
| 31 | if (chdir(auto_qmail) == -1) _exit(61); | ||
| 32 | execv(*binqqargs,binqqargs); | ||
| 33 | _exit(120); | ||
| 34 | } | ||
| 35 | |||
| 36 | qq->fdm = pim[1]; close(pim[0]); | ||
| 37 | qq->fde = pie[1]; close(pie[0]); | ||
| 38 | substdio_fdbuf(&qq->ss,write,qq->fdm,qq->buf,sizeof(qq->buf)); | ||
| 39 | qq->flagerr = 0; | ||
| 40 | return 0; | ||
| 41 | } | ||
| 42 | |||
| 43 | unsigned long qmail_qp(qq) struct qmail *qq; | ||
| 44 | { | ||
| 45 | return qq->pid; | ||
| 46 | } | ||
| 47 | |||
| 48 | void qmail_fail(qq) struct qmail *qq; | ||
| 49 | { | ||
| 50 | qq->flagerr = 1; | ||
| 51 | } | ||
| 52 | |||
| 53 | void qmail_put(qq,s,len) struct qmail *qq; char *s; int len; | ||
| 54 | { | ||
| 55 | if (!qq->flagerr) if (substdio_put(&qq->ss,s,len) == -1) qq->flagerr = 1; | ||
| 56 | } | ||
| 57 | |||
| 58 | void qmail_puts(qq,s) struct qmail *qq; char *s; | ||
| 59 | { | ||
| 60 | if (!qq->flagerr) if (substdio_puts(&qq->ss,s) == -1) qq->flagerr = 1; | ||
| 61 | } | ||
| 62 | |||
| 63 | void qmail_from(qq,s) struct qmail *qq; char *s; | ||
| 64 | { | ||
| 65 | if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1; | ||
| 66 | close(qq->fdm); | ||
| 67 | substdio_fdbuf(&qq->ss,write,qq->fde,qq->buf,sizeof(qq->buf)); | ||
| 68 | qmail_put(qq,"F",1); | ||
| 69 | qmail_puts(qq,s); | ||
| 70 | qmail_put(qq,"",1); | ||
| 71 | } | ||
| 72 | |||
| 73 | void qmail_to(qq,s) struct qmail *qq; char *s; | ||
| 74 | { | ||
| 75 | qmail_put(qq,"T",1); | ||
| 76 | qmail_puts(qq,s); | ||
| 77 | qmail_put(qq,"",1); | ||
| 78 | } | ||
| 79 | |||
| 80 | char *qmail_close(qq) | ||
| 81 | struct qmail *qq; | ||
| 82 | { | ||
| 83 | int wstat; | ||
| 84 | int exitcode; | ||
| 85 | |||
| 86 | qmail_put(qq,"",1); | ||
| 87 | if (!qq->flagerr) if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1; | ||
| 88 | close(qq->fde); | ||
| 89 | |||
| 90 | if (wait_pid(&wstat,qq->pid) != qq->pid) | ||
| 91 | return "Zqq waitpid surprise (#4.3.0)"; | ||
| 92 | if (wait_crashed(wstat)) | ||
| 93 | return "Zqq crashed (#4.3.0)"; | ||
| 94 | exitcode = wait_exitcode(wstat); | ||
| 95 | |||
| 96 | switch(exitcode) { | ||
| 97 | case 115: /* compatibility */ | ||
| 98 | case 11: return "Denvelope address too long for qq (#5.1.3)"; | ||
| 99 | case 31: return "Dmail server permanently rejected message (#5.3.0)"; | ||
| 100 | case 51: return "Zqq out of memory (#4.3.0)"; | ||
| 101 | case 52: return "Zqq timeout (#4.3.0)"; | ||
| 102 | case 53: return "Zqq write error or disk full (#4.3.0)"; | ||
| 103 | case 0: if (!qq->flagerr) return ""; /* fall through */ | ||
| 104 | case 54: return "Zqq read error (#4.3.0)"; | ||
| 105 | case 55: return "Zqq unable to read configuration (#4.3.0)"; | ||
| 106 | case 56: return "Zqq trouble making network connection (#4.3.0)"; | ||
| 107 | case 61: return "Zqq trouble in home directory (#4.3.0)"; | ||
| 108 | case 63: | ||
| 109 | case 64: | ||
| 110 | case 65: | ||
| 111 | case 66: | ||
| 112 | case 62: return "Zqq trouble creating files in queue (#4.3.0)"; | ||
| 113 | case 71: return "Zmail server temporarily rejected message (#4.3.0)"; | ||
| 114 | case 72: return "Zconnection to mail server timed out (#4.4.1)"; | ||
| 115 | case 73: return "Zconnection to mail server rejected (#4.4.1)"; | ||
| 116 | case 74: return "Zcommunication with mail server failed (#4.4.2)"; | ||
| 117 | case 91: /* fall through */ | ||
| 118 | case 81: return "Zqq internal bug (#4.3.0)"; | ||
| 119 | case 120: return "Zunable to exec qq (#4.3.0)"; | ||
| 120 | default: | ||
| 121 | if ((exitcode >= 11) && (exitcode <= 40)) | ||
| 122 | return "Dqq permanent problem (#5.3.0)"; | ||
| 123 | return "Zqq temporary problem (#4.3.0)"; | ||
| 124 | } | ||
| 125 | } | ||
| @@ -0,0 +1,24 @@ | |||
| 1 | #ifndef QMAIL_H | ||
| 2 | #define QMAIL_H | ||
| 3 | |||
| 4 | #include "substdio.h" | ||
| 5 | |||
| 6 | struct qmail { | ||
| 7 | int flagerr; | ||
| 8 | unsigned long pid; | ||
| 9 | int fdm; | ||
| 10 | int fde; | ||
| 11 | substdio ss; | ||
| 12 | char buf[1024]; | ||
| 13 | } ; | ||
| 14 | |||
| 15 | extern int qmail_open(); | ||
| 16 | extern void qmail_put(); | ||
| 17 | extern void qmail_puts(); | ||
| 18 | extern void qmail_from(); | ||
| 19 | extern void qmail_to(); | ||
| 20 | extern void qmail_fail(); | ||
| 21 | extern char *qmail_close(); | ||
| 22 | extern unsigned long qmail_qp(); | ||
| 23 | |||
| 24 | #endif | ||
diff --git a/qreceipt.1 b/qreceipt.1 new file mode 100644 index 0000000..4d3cd08 --- /dev/null +++ b/qreceipt.1 | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | .TH qreceipt 1 | ||
| 2 | .SH NAME | ||
| 3 | qreceipt \- respond to delivery notice requests | ||
| 4 | .SH SYNOPSIS | ||
| 5 | in | ||
| 6 | .BR .qmail : | ||
| 7 | .B |qreceipt | ||
| 8 | .I youraddress | ||
| 9 | .SH DESCRIPTION | ||
| 10 | When a mail message arrives with | ||
| 11 | .I youraddress | ||
| 12 | listed in a | ||
| 13 | .B Notice-Requested-Upon-Delivery-To | ||
| 14 | header field, | ||
| 15 | .B qreceipt | ||
| 16 | sends a success notice back to the envelope sender. | ||
| 17 | |||
| 18 | .B WARNING: | ||
| 19 | If you create a | ||
| 20 | .B .qmail | ||
| 21 | file to enable | ||
| 22 | .BR qreceipt , | ||
| 23 | make sure to also add a line specifying delivery to your normal mailbox. | ||
| 24 | For example: | ||
| 25 | |||
| 26 | .EX | ||
| 27 | /home/joe/Mailbox | ||
| 28 | .br | ||
| 29 | |qreceipt joe@nowhere.mil | ||
| 30 | .EE | ||
| 31 | .SH "SEE ALSO" | ||
| 32 | dot-qmail(5), | ||
| 33 | envelopes(5) | ||
diff --git a/qreceipt.c b/qreceipt.c new file mode 100644 index 0000000..49b9807 --- /dev/null +++ b/qreceipt.c | |||
| @@ -0,0 +1,131 @@ | |||
| 1 | #include "sig.h" | ||
| 2 | #include "env.h" | ||
| 3 | #include "substdio.h" | ||
| 4 | #include "stralloc.h" | ||
| 5 | #include "subfd.h" | ||
| 6 | #include "getln.h" | ||
| 7 | #include "alloc.h" | ||
| 8 | #include "str.h" | ||
| 9 | #include "hfield.h" | ||
| 10 | #include "token822.h" | ||
| 11 | #include "error.h" | ||
| 12 | #include "gen_alloc.h" | ||
| 13 | #include "gen_allocdefs.h" | ||
| 14 | #include "headerbody.h" | ||
| 15 | #include "exit.h" | ||
| 16 | #include "open.h" | ||
| 17 | #include "quote.h" | ||
| 18 | #include "qmail.h" | ||
| 19 | |||
| 20 | void die_noreceipt() { _exit(0); } | ||
| 21 | void die() { _exit(100); } | ||
| 22 | void die_temp() { _exit(111); } | ||
| 23 | void die_nomem() { | ||
| 24 | substdio_putsflush(subfderr,"qreceipt: fatal: out of memory\n"); die_temp(); } | ||
| 25 | void die_fork() { | ||
| 26 | substdio_putsflush(subfderr,"qreceipt: fatal: unable to fork\n"); die_temp(); } | ||
| 27 | void die_qqperm() { | ||
| 28 | substdio_putsflush(subfderr,"qreceipt: fatal: permanent qmail-queue error\n"); die(); } | ||
| 29 | void die_qqtemp() { | ||
| 30 | substdio_putsflush(subfderr,"qreceipt: fatal: temporary qmail-queue error\n"); die_temp(); } | ||
| 31 | void die_usage() { | ||
| 32 | substdio_putsflush(subfderr, | ||
| 33 | "qreceipt: usage: qreceipt deliveryaddress\n"); die(); } | ||
| 34 | void die_read() { | ||
| 35 | if (errno == error_nomem) die_nomem(); | ||
| 36 | substdio_putsflush(subfderr,"qreceipt: fatal: read error\n"); die_temp(); } | ||
| 37 | void doordie(sa,r) stralloc *sa; int r; { | ||
| 38 | if (r == 1) return; if (r == -1) die_nomem(); | ||
| 39 | substdio_putsflush(subfderr,"qreceipt: fatal: unable to parse this: "); | ||
| 40 | substdio_putflush(subfderr,sa->s,sa->len); die(); } | ||
| 41 | |||
| 42 | char *target; | ||
| 43 | |||
| 44 | int flagreceipt = 0; | ||
| 45 | |||
| 46 | char *returnpath; | ||
| 47 | stralloc messageid = {0}; | ||
| 48 | stralloc sanotice = {0}; | ||
| 49 | |||
| 50 | int rwnotice(addr) token822_alloc *addr; { token822_reverse(addr); | ||
| 51 | if (token822_unquote(&sanotice,addr) != 1) die_nomem(); | ||
| 52 | if (sanotice.len == str_len(target)) | ||
| 53 | if (!str_diffn(sanotice.s,target,sanotice.len)) | ||
| 54 | flagreceipt = 1; | ||
| 55 | token822_reverse(addr); return 1; } | ||
| 56 | |||
| 57 | struct qmail qqt; | ||
| 58 | |||
| 59 | stralloc quoted = {0}; | ||
| 60 | |||
| 61 | void finishheader() | ||
| 62 | { | ||
| 63 | char *qqx; | ||
| 64 | |||
| 65 | if (!flagreceipt) die_noreceipt(); | ||
| 66 | if (str_equal(returnpath,"")) die_noreceipt(); | ||
| 67 | if (str_equal(returnpath,"#@[]")) die_noreceipt(); | ||
| 68 | |||
| 69 | if (!quote2("ed,returnpath)) die_nomem(); | ||
| 70 | |||
| 71 | if (qmail_open(&qqt) == -1) die_fork(); | ||
| 72 | |||
| 73 | qmail_puts(&qqt,"From: DELIVERY NOTICE SYSTEM <"); | ||
| 74 | qmail_put(&qqt,quoted.s,quoted.len); | ||
| 75 | qmail_puts(&qqt,">\n"); | ||
| 76 | qmail_puts(&qqt,"To: <"); | ||
| 77 | qmail_put(&qqt,quoted.s,quoted.len); | ||
| 78 | qmail_puts(&qqt,">\n"); | ||
| 79 | qmail_puts(&qqt,"Subject: success notice\n\ | ||
| 80 | \n\ | ||
| 81 | Hi! This is the qreceipt program. Your message was delivered to the\n\ | ||
| 82 | following address: "); | ||
| 83 | qmail_puts(&qqt,target); | ||
| 84 | qmail_puts(&qqt,". Thanks for asking.\n"); | ||
| 85 | if (messageid.s) | ||
| 86 | { | ||
| 87 | qmail_puts(&qqt,"Your "); | ||
| 88 | qmail_put(&qqt,messageid.s,messageid.len); | ||
| 89 | } | ||
| 90 | |||
| 91 | qmail_from(&qqt,""); | ||
| 92 | qmail_to(&qqt,returnpath); | ||
| 93 | qqx = qmail_close(&qqt); | ||
| 94 | |||
| 95 | if (*qqx) | ||
| 96 | if (*qqx == 'D') die_qqperm(); | ||
| 97 | else die_qqtemp(); | ||
| 98 | } | ||
| 99 | |||
| 100 | stralloc hfbuf = {0}; | ||
| 101 | token822_alloc hfin = {0}; | ||
| 102 | token822_alloc hfrewrite = {0}; | ||
| 103 | token822_alloc hfaddr = {0}; | ||
| 104 | |||
| 105 | void doheaderfield(h) | ||
| 106 | stralloc *h; | ||
| 107 | { | ||
| 108 | switch(hfield_known(h->s,h->len)) | ||
| 109 | { | ||
| 110 | case H_MESSAGEID: | ||
| 111 | if (!stralloc_copy(&messageid,h)) die_nomem(); | ||
| 112 | break; | ||
| 113 | case H_NOTICEREQUESTEDUPONDELIVERYTO: | ||
| 114 | doordie(h,token822_parse(&hfin,h,&hfbuf)); | ||
| 115 | doordie(h,token822_addrlist(&hfrewrite,&hfaddr,&hfin,rwnotice)); | ||
| 116 | break; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | void dobody(h) stralloc *h; { ; } | ||
| 121 | |||
| 122 | void main(argc,argv) | ||
| 123 | int argc; | ||
| 124 | char **argv; | ||
| 125 | { | ||
| 126 | sig_pipeignore(); | ||
| 127 | if (!(target = argv[1])) die_usage(); | ||
| 128 | if (!(returnpath = env_get("SENDER"))) die_usage(); | ||
| 129 | if (headerbody(subfdin,doheaderfield,finishheader,dobody) == -1) die_read(); | ||
| 130 | die_noreceipt(); | ||
| 131 | } | ||
diff --git a/qsmhook.c b/qsmhook.c new file mode 100644 index 0000000..d5b38aa --- /dev/null +++ b/qsmhook.c | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | #include "fd.h" | ||
| 2 | #include "stralloc.h" | ||
| 3 | #include "readwrite.h" | ||
| 4 | #include "sgetopt.h" | ||
| 5 | #include "wait.h" | ||
| 6 | #include "env.h" | ||
| 7 | #include "byte.h" | ||
| 8 | #include "str.h" | ||
| 9 | #include "alloc.h" | ||
| 10 | #include "exit.h" | ||
| 11 | #include "fork.h" | ||
| 12 | #include "case.h" | ||
| 13 | #include "subfd.h" | ||
| 14 | #include "error.h" | ||
| 15 | #include "substdio.h" | ||
| 16 | #include "sig.h" | ||
| 17 | |||
| 18 | void die(e,s) int e; char *s; { substdio_putsflush(subfderr,s); _exit(e); } | ||
| 19 | void die_usage() { die(100,"qsmhook: fatal: incorrect usage\n"); } | ||
| 20 | void die_temp() { die(111,"qsmhook: fatal: temporary problem\n"); } | ||
| 21 | void die_read() { die(111,"qsmhook: fatal: unable to read message\n"); } | ||
| 22 | void die_badcmd() { die(100,"qsmhook: fatal: command not found\n"); } | ||
| 23 | |||
| 24 | int flagrpline = 0; char *rpline; | ||
| 25 | int flagufline = 1; char *ufline; | ||
| 26 | int flagdtline = 0; char *dtline; | ||
| 27 | char *host; | ||
| 28 | char *sender; | ||
| 29 | char *recip; | ||
| 30 | |||
| 31 | stralloc newarg = {0}; | ||
| 32 | |||
| 33 | substdio ssout; | ||
| 34 | char outbuf[SUBSTDIO_OUTSIZE]; | ||
| 35 | substdio ssin; | ||
| 36 | char inbuf[SUBSTDIO_INSIZE]; | ||
| 37 | |||
| 38 | void main(argc,argv) | ||
| 39 | int argc; | ||
| 40 | char **argv; | ||
| 41 | { | ||
| 42 | int pid; | ||
| 43 | int wstat; | ||
| 44 | int pi[2]; | ||
| 45 | int opt; | ||
| 46 | char **arg; | ||
| 47 | char *x; | ||
| 48 | int i; | ||
| 49 | int flagesc; | ||
| 50 | |||
| 51 | sig_pipeignore(); | ||
| 52 | |||
| 53 | if (!(dtline = env_get("DTLINE"))) die_usage(); | ||
| 54 | if (!(rpline = env_get("RPLINE"))) die_usage(); | ||
| 55 | if (!(ufline = env_get("UFLINE"))) die_usage(); | ||
| 56 | if (!(recip = env_get("LOCAL"))) die_usage(); | ||
| 57 | if (!(host = env_get("HOST"))) die_usage(); | ||
| 58 | if (!(sender = env_get("SENDER"))) die_usage(); | ||
| 59 | |||
| 60 | while ((opt = getopt(argc,argv,"DFlMmnPsx:")) != opteof) | ||
| 61 | switch(opt) | ||
| 62 | { | ||
| 63 | case 'D': case 'F': case 'M': break; /* be serious */ | ||
| 64 | case 'l': flagdtline = 1; break; /* also return-receipt-to? blech */ | ||
| 65 | case 'm': break; /* we only handle one recipient anyway */ | ||
| 66 | case 'n': flagufline = 0; break; | ||
| 67 | case 's': break; /* could call quote() otherwise, i suppose... */ | ||
| 68 | case 'P': flagrpline = 1; break; | ||
| 69 | case 'x': | ||
| 70 | if (case_starts(recip,optarg)) | ||
| 71 | recip += str_len(optarg); | ||
| 72 | break; | ||
| 73 | default: | ||
| 74 | _exit(100); | ||
| 75 | } | ||
| 76 | argc -= optind; | ||
| 77 | argv += optind; | ||
| 78 | |||
| 79 | if (!*argv) die_usage(); | ||
| 80 | |||
| 81 | for (arg = argv;x = *arg;++arg) | ||
| 82 | { | ||
| 83 | if (!stralloc_copys(&newarg,"")) die_temp(); | ||
| 84 | flagesc = 0; | ||
| 85 | for (i = 0;x[i];++i) | ||
| 86 | if (flagesc) | ||
| 87 | { | ||
| 88 | switch(x[i]) | ||
| 89 | { | ||
| 90 | case '%': if (!stralloc_cats(&newarg,"%")) die_temp(); break; | ||
| 91 | case 'g': if (!stralloc_cats(&newarg,sender)) die_temp(); break; | ||
| 92 | case 'h': if (!stralloc_cats(&newarg,host)) die_temp(); break; | ||
| 93 | case 'u': if (!stralloc_cats(&newarg,recip)) die_temp(); break; | ||
| 94 | } | ||
| 95 | flagesc = 0; | ||
| 96 | } | ||
| 97 | else | ||
| 98 | if (x[i] == '%') | ||
| 99 | flagesc = 1; | ||
| 100 | else | ||
| 101 | if (!stralloc_append(&newarg,&x[i])) die_temp(); | ||
| 102 | if (!stralloc_0(&newarg)) die_temp(); | ||
| 103 | i = str_len(newarg.s) + 1; | ||
| 104 | if (!(x = alloc(i))) die_temp(); | ||
| 105 | byte_copy(x,i,newarg.s); | ||
| 106 | *arg = x; | ||
| 107 | } | ||
| 108 | |||
| 109 | if (pipe(pi) == -1) die_temp(); | ||
| 110 | |||
| 111 | switch(pid = fork()) | ||
| 112 | { | ||
| 113 | case -1: | ||
| 114 | die_temp(); | ||
| 115 | case 0: | ||
| 116 | close(pi[1]); | ||
| 117 | if (fd_move(0,pi[0]) == -1) die_temp(); | ||
| 118 | sig_pipedefault(); | ||
| 119 | execvp(*argv,argv); | ||
| 120 | if (error_temp(errno)) die_temp(); | ||
| 121 | die_badcmd(); | ||
| 122 | } | ||
| 123 | close(pi[0]); | ||
| 124 | |||
| 125 | substdio_fdbuf(&ssout,write,pi[1],outbuf,sizeof(outbuf)); | ||
| 126 | substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf)); | ||
| 127 | if (flagufline) substdio_bputs(&ssout,ufline); | ||
| 128 | if (flagrpline) substdio_bputs(&ssout,rpline); | ||
| 129 | if (flagdtline) substdio_bputs(&ssout,dtline); | ||
| 130 | if (substdio_copy(&ssout,&ssin) == -2) die_read(); | ||
| 131 | substdio_flush(&ssout); | ||
| 132 | close(pi[1]); | ||
| 133 | |||
| 134 | if (wait_pid(&wstat,pid) == -1) die_temp(); | ||
| 135 | if (wait_crashed(wstat)) die_temp(); | ||
| 136 | _exit(wait_exitcode(wstat)); | ||
| 137 | } | ||
diff --git a/qsutil.c b/qsutil.c new file mode 100644 index 0000000..80c619d --- /dev/null +++ b/qsutil.c | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | #include "stralloc.h" | ||
| 2 | #include "readwrite.h" | ||
| 3 | #include "substdio.h" | ||
| 4 | #include "qsutil.h" | ||
| 5 | |||
| 6 | static stralloc foo = {0}; | ||
| 7 | |||
| 8 | static char errbuf[1]; | ||
| 9 | static struct substdio sserr = SUBSTDIO_FDBUF(write,0,errbuf,1); | ||
| 10 | |||
| 11 | void logsa(sa) stralloc *sa; { | ||
| 12 | substdio_putflush(&sserr,sa->s,sa->len); } | ||
| 13 | void log1(s1) char *s1; { | ||
| 14 | substdio_putsflush(&sserr,s1); } | ||
| 15 | void log2(s1,s2) char *s1; char *s2; { | ||
| 16 | substdio_putsflush(&sserr,s1); | ||
| 17 | substdio_putsflush(&sserr,s2); } | ||
| 18 | void log3(s1,s2,s3) char *s1; char *s2; char *s3; { | ||
| 19 | substdio_putsflush(&sserr,s1); | ||
| 20 | substdio_putsflush(&sserr,s2); | ||
| 21 | substdio_putsflush(&sserr,s3); } | ||
| 22 | void nomem() { log1("alert: out of memory, sleeping...\n"); sleep(10); } | ||
| 23 | |||
| 24 | void pausedir(dir) char *dir; | ||
| 25 | { log3("alert: unable to opendir ",dir,", sleeping...\n"); sleep(10); } | ||
| 26 | |||
| 27 | static int issafe(ch) char ch; | ||
| 28 | { | ||
| 29 | if (ch == '%') return 0; /* general principle: allman's code is crap */ | ||
| 30 | if (ch < 33) return 0; | ||
| 31 | if (ch > 126) return 0; | ||
| 32 | return 1; | ||
| 33 | } | ||
| 34 | |||
| 35 | void logsafe(s) char *s; | ||
| 36 | { | ||
| 37 | int i; | ||
| 38 | while (!stralloc_copys(&foo,s)) nomem(); | ||
| 39 | for (i = 0;i < foo.len;++i) | ||
| 40 | if (foo.s[i] == '\n') | ||
| 41 | foo.s[i] = '/'; | ||
| 42 | else | ||
| 43 | if (!issafe(foo.s[i])) | ||
| 44 | foo.s[i] = '_'; | ||
| 45 | logsa(&foo); | ||
| 46 | } | ||
diff --git a/qsutil.h b/qsutil.h new file mode 100644 index 0000000..a746845 --- /dev/null +++ b/qsutil.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef QSUTIL_H | ||
| 2 | #define QSUTIL_H | ||
| 3 | |||
| 4 | extern void log1(); | ||
| 5 | extern void log2(); | ||
| 6 | extern void log3(); | ||
| 7 | extern void logsa(); | ||
| 8 | extern void nomem(); | ||
| 9 | extern void pausedir(); | ||
| 10 | extern void logsafe(); | ||
| 11 | |||
| 12 | #endif | ||
| @@ -0,0 +1,83 @@ | |||
| 1 | #include "stralloc.h" | ||
| 2 | #include "str.h" | ||
| 3 | #include "quote.h" | ||
| 4 | |||
| 5 | /* | ||
| 6 | quote() encodes a box as per rfc 821 and rfc 822, | ||
| 7 | while trying to do as little quoting as possible. | ||
| 8 | no, 821 and 822 don't have the same encoding. they're not even close. | ||
| 9 | no special encoding here for bytes above 127. | ||
| 10 | */ | ||
| 11 | |||
| 12 | static char ok[128] = { | ||
| 13 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 | ||
| 14 | ,0,7,0,7,7,7,7,7,0,0,7,7,0,7,7,7 ,7,7,7,7,7,7,7,7,7,7,0,0,0,7,0,7 | ||
| 15 | ,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 ,7,7,7,7,7,7,7,7,7,7,7,0,0,0,7,7 | ||
| 16 | ,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 ,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0 | ||
| 17 | } ; | ||
| 18 | |||
| 19 | static int doit(saout,sain) | ||
| 20 | stralloc *saout; | ||
| 21 | stralloc *sain; | ||
| 22 | { | ||
| 23 | char ch; | ||
| 24 | int i; | ||
| 25 | int j; | ||
| 26 | |||
| 27 | if (!stralloc_ready(saout,sain->len * 2 + 2)) return 0; | ||
| 28 | j = 0; | ||
| 29 | saout->s[j++] = '"'; | ||
| 30 | for (i = 0;i < sain->len;++i) | ||
| 31 | { | ||
| 32 | ch = sain->s[i]; | ||
| 33 | if ((ch == '\r') || (ch == '\n') || (ch == '"') || (ch == '\\')) | ||
| 34 | saout->s[j++] = '\\'; | ||
| 35 | saout->s[j++] = ch; | ||
| 36 | } | ||
| 37 | saout->s[j++] = '"'; | ||
| 38 | saout->len = j; | ||
| 39 | return 1; | ||
| 40 | } | ||
| 41 | |||
| 42 | int quote_need(s,n) | ||
| 43 | char *s; | ||
| 44 | unsigned int n; | ||
| 45 | { | ||
| 46 | unsigned char uch; | ||
| 47 | int i; | ||
| 48 | if (!n) return 1; | ||
| 49 | for (i = 0;i < n;++i) | ||
| 50 | { | ||
| 51 | uch = s[i]; | ||
| 52 | if (uch >= 128) return 1; | ||
| 53 | if (!ok[uch]) return 1; | ||
| 54 | } | ||
| 55 | if (s[0] == '.') return 1; | ||
| 56 | if (s[n - 1] == '.') return 1; | ||
| 57 | for (i = 0;i < n - 1;++i) if (s[i] == '.') if (s[i + 1] == '.') return 1; | ||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | int quote(saout,sain) | ||
| 62 | stralloc *saout; | ||
| 63 | stralloc *sain; | ||
| 64 | { | ||
| 65 | if (quote_need(sain->s,sain->len)) return doit(saout,sain); | ||
| 66 | return stralloc_copy(saout,sain); | ||
| 67 | } | ||
| 68 | |||
| 69 | static stralloc foo = {0}; | ||
| 70 | |||
| 71 | int quote2(sa,s) | ||
| 72 | stralloc *sa; | ||
| 73 | char *s; | ||
| 74 | { | ||
| 75 | int j; | ||
| 76 | if (!*s) return stralloc_copys(sa,s); | ||
| 77 | j = str_rchr(s,'@'); | ||
| 78 | if (!stralloc_copys(&foo,s)) return 0; | ||
| 79 | if (!s[j]) return quote(sa,&foo); | ||
| 80 | foo.len = j; | ||
| 81 | if (!quote(sa,&foo)) return 0; | ||
| 82 | return stralloc_cats(sa,s + j); | ||
| 83 | } | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef QUOTE_H | ||
| 2 | #define QUOTE_H | ||
| 3 | |||
| 4 | extern int quote_need(); | ||
| 5 | extern int quote(); | ||
| 6 | extern int quote2(); | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/rcpthosts.c b/rcpthosts.c new file mode 100644 index 0000000..1bc3018 --- /dev/null +++ b/rcpthosts.c | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | #include "cdb.h" | ||
| 2 | #include "byte.h" | ||
| 3 | #include "open.h" | ||
| 4 | #include "error.h" | ||
| 5 | #include "control.h" | ||
| 6 | #include "constmap.h" | ||
| 7 | #include "stralloc.h" | ||
| 8 | #include "rcpthosts.h" | ||
| 9 | |||
| 10 | static int flagrh = 0; | ||
| 11 | static stralloc rh = {0}; | ||
| 12 | static struct constmap maprh; | ||
| 13 | static int fdmrh; | ||
| 14 | |||
| 15 | int rcpthosts_init() | ||
| 16 | { | ||
| 17 | flagrh = control_readfile(&rh,"control/rcpthosts",0); | ||
| 18 | if (flagrh != 1) return flagrh; | ||
| 19 | if (!constmap_init(&maprh,rh.s,rh.len,0)) return flagrh = -1; | ||
| 20 | fdmrh = open_read("control/morercpthosts.cdb"); | ||
| 21 | if (fdmrh == -1) if (errno != error_noent) return flagrh = -1; | ||
| 22 | return 0; | ||
| 23 | } | ||
| 24 | |||
| 25 | static stralloc host = {0}; | ||
| 26 | |||
| 27 | int rcpthosts(buf,len) | ||
| 28 | char *buf; | ||
| 29 | int len; | ||
| 30 | { | ||
| 31 | int j; | ||
| 32 | |||
| 33 | if (flagrh != 1) return 1; | ||
| 34 | |||
| 35 | j = byte_rchr(buf,len,'@'); | ||
| 36 | if (j >= len) return 1; /* presumably envnoathost is acceptable */ | ||
| 37 | |||
| 38 | ++j; buf += j; len -= j; | ||
| 39 | |||
| 40 | if (!stralloc_copyb(&host,buf,len)) return -1; | ||
| 41 | buf = host.s; | ||
| 42 | case_lowerb(buf,len); | ||
| 43 | |||
| 44 | for (j = 0;j < len;++j) | ||
| 45 | if (!j || (buf[j] == '.')) | ||
| 46 | if (constmap(&maprh,buf + j,len - j)) return 1; | ||
| 47 | |||
| 48 | if (fdmrh != -1) { | ||
| 49 | uint32 dlen; | ||
| 50 | int r; | ||
| 51 | |||
| 52 | for (j = 0;j < len;++j) | ||
| 53 | if (!j || (buf[j] == '.')) { | ||
| 54 | r = cdb_seek(fdmrh,buf + j,len - j,&dlen); | ||
| 55 | if (r) return r; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | return 0; | ||
| 60 | } | ||
diff --git a/rcpthosts.h b/rcpthosts.h new file mode 100644 index 0000000..5e7e6cc --- /dev/null +++ b/rcpthosts.h | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef RCPTHOSTS_H | ||
| 2 | #define RCPTHOSTS_H | ||
| 3 | |||
| 4 | extern int rcpthosts_init(); | ||
| 5 | extern int rcpthosts(); | ||
| 6 | |||
| 7 | #endif | ||
diff --git a/readsubdir.c b/readsubdir.c new file mode 100644 index 0000000..81aa241 --- /dev/null +++ b/readsubdir.c | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | #include "readsubdir.h" | ||
| 2 | #include "fmt.h" | ||
| 3 | #include "scan.h" | ||
| 4 | #include "str.h" | ||
| 5 | #include "auto_split.h" | ||
| 6 | |||
| 7 | void readsubdir_init(rs,name,pause) | ||
| 8 | readsubdir *rs; | ||
| 9 | char *name; | ||
| 10 | void (*pause)(); | ||
| 11 | { | ||
| 12 | rs->name = name; | ||
| 13 | rs->pause = pause; | ||
| 14 | rs->dir = 0; | ||
| 15 | rs->pos = 0; | ||
| 16 | } | ||
| 17 | |||
| 18 | static char namepos[FMT_ULONG + 4 + READSUBDIR_NAMELEN]; | ||
| 19 | |||
| 20 | int readsubdir_next(rs,id) | ||
| 21 | readsubdir *rs; | ||
| 22 | unsigned long *id; | ||
| 23 | { | ||
| 24 | direntry *d; | ||
| 25 | unsigned int len; | ||
| 26 | |||
| 27 | if (!rs->dir) | ||
| 28 | { | ||
| 29 | if (rs->pos >= auto_split) return 0; | ||
| 30 | if (str_len(rs->name) > READSUBDIR_NAMELEN) { rs->pos++; return -1; } | ||
| 31 | len = 0; | ||
| 32 | len += fmt_str(namepos + len,rs->name); | ||
| 33 | namepos[len++] = '/'; | ||
| 34 | len += fmt_ulong(namepos + len,(unsigned long) rs->pos); | ||
| 35 | namepos[len] = 0; | ||
| 36 | while (!(rs->dir = opendir(namepos))) rs->pause(namepos); | ||
| 37 | rs->pos++; | ||
| 38 | return -1; | ||
| 39 | } | ||
| 40 | |||
| 41 | d = readdir(rs->dir); | ||
| 42 | if (!d) { closedir(rs->dir); rs->dir = 0; return -1; } | ||
| 43 | |||
| 44 | if (str_equal(d->d_name,".")) return -1; | ||
| 45 | if (str_equal(d->d_name,"..")) return -1; | ||
| 46 | len = scan_ulong(d->d_name,id); | ||
| 47 | if (!len || d->d_name[len]) return -2; | ||
| 48 | return 1; | ||
| 49 | } | ||
diff --git a/readsubdir.h b/readsubdir.h new file mode 100644 index 0000000..353942f --- /dev/null +++ b/readsubdir.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | #ifndef READSUBDIR_H | ||
| 2 | #define READSUBDIR_H | ||
| 3 | |||
| 4 | #include "direntry.h" | ||
| 5 | |||
| 6 | typedef struct readsubdir | ||
| 7 | { | ||
| 8 | DIR *dir; | ||
| 9 | int pos; | ||
| 10 | char *name; | ||
| 11 | void (*pause)(); | ||
| 12 | } | ||
| 13 | readsubdir; | ||
| 14 | |||
| 15 | extern void readsubdir_init(); | ||
| 16 | extern int readsubdir_next(); | ||
| 17 | |||
| 18 | #define READSUBDIR_NAMELEN 10 | ||
| 19 | |||
| 20 | #endif | ||
diff --git a/readwrite.h b/readwrite.h new file mode 100644 index 0000000..2a64968 --- /dev/null +++ b/readwrite.h | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef READWRITE_H | ||
| 2 | #define READWRITE_H | ||
| 3 | |||
| 4 | extern int read(); | ||
| 5 | extern int write(); | ||
| 6 | |||
| 7 | #endif | ||
diff --git a/received.c b/received.c new file mode 100644 index 0000000..07706d5 --- /dev/null +++ b/received.c | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | #include "fmt.h" | ||
| 2 | #include "qmail.h" | ||
| 3 | #include "now.h" | ||
| 4 | #include "datetime.h" | ||
| 5 | #include "date822fmt.h" | ||
| 6 | #include "received.h" | ||
| 7 | |||
| 8 | static int issafe(ch) char ch; | ||
| 9 | { | ||
| 10 | if (ch == '.') return 1; | ||
| 11 | if (ch == '@') return 1; | ||
| 12 | if (ch == '%') return 1; | ||
| 13 | if (ch == '+') return 1; | ||
| 14 | if (ch == '/') return 1; | ||
| 15 | if (ch == '=') return 1; | ||
| 16 | if (ch == ':') return 1; | ||
| 17 | if (ch == '-') return 1; | ||
| 18 | if ((ch >= 'a') && (ch <= 'z')) return 1; | ||
| 19 | if ((ch >= 'A') && (ch <= 'Z')) return 1; | ||
| 20 | if ((ch >= '0') && (ch <= '9')) return 1; | ||
| 21 | return 0; | ||
| 22 | } | ||
| 23 | |||
| 24 | void safeput(qqt,s) | ||
| 25 | struct qmail *qqt; | ||
| 26 | char *s; | ||
| 27 | { | ||
| 28 | char ch; | ||
| 29 | while (ch = *s++) { | ||
| 30 | if (!issafe(ch)) ch = '?'; | ||
| 31 | qmail_put(qqt,&ch,1); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | static char buf[DATE822FMT]; | ||
| 36 | |||
| 37 | /* "Received: from relay1.uu.net (HELO uunet.uu.net) (7@192.48.96.5)\n" */ | ||
| 38 | /* " by silverton.berkeley.edu with SMTP; 26 Sep 1995 04:46:54 -0000\n" */ | ||
| 39 | |||
| 40 | void received(qqt,protocol,local,remoteip,remotehost,remoteinfo,helo) | ||
| 41 | struct qmail *qqt; | ||
| 42 | char *protocol; | ||
| 43 | char *local; | ||
| 44 | char *remoteip; | ||
| 45 | char *remotehost; | ||
| 46 | char *remoteinfo; | ||
| 47 | char *helo; | ||
| 48 | { | ||
| 49 | struct datetime dt; | ||
| 50 | |||
| 51 | qmail_puts(qqt,"Received: from "); | ||
| 52 | safeput(qqt,remotehost); | ||
| 53 | if (helo) { | ||
| 54 | qmail_puts(qqt," (HELO "); | ||
| 55 | safeput(qqt,helo); | ||
| 56 | qmail_puts(qqt,")"); | ||
| 57 | } | ||
| 58 | qmail_puts(qqt," ("); | ||
| 59 | if (remoteinfo) { | ||
| 60 | safeput(qqt,remoteinfo); | ||
| 61 | qmail_puts(qqt,"@"); | ||
| 62 | } | ||
| 63 | safeput(qqt,remoteip); | ||
| 64 | qmail_puts(qqt,")\n by "); | ||
| 65 | safeput(qqt,local); | ||
| 66 | qmail_puts(qqt," with "); | ||
| 67 | qmail_puts(qqt,protocol); | ||
| 68 | qmail_puts(qqt,"; "); | ||
| 69 | datetime_tai(&dt,now()); | ||
| 70 | qmail_put(qqt,buf,date822fmt(buf,&dt)); | ||
| 71 | } | ||
diff --git a/received.h b/received.h new file mode 100644 index 0000000..4e39dda --- /dev/null +++ b/received.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef RECEIVED_H | ||
| 2 | #define RECEIVED_H | ||
| 3 | |||
| 4 | extern void received(); | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/remoteinfo.c b/remoteinfo.c new file mode 100644 index 0000000..c7abd70 --- /dev/null +++ b/remoteinfo.c | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/socket.h> | ||
| 3 | #include <netinet/in.h> | ||
| 4 | #include <fcntl.h> | ||
| 5 | #include "byte.h" | ||
| 6 | #include "substdio.h" | ||
| 7 | #include "ip.h" | ||
| 8 | #include "fmt.h" | ||
| 9 | #include "timeoutconn.h" | ||
| 10 | #include "timeoutread.h" | ||
| 11 | #include "timeoutwrite.h" | ||
| 12 | #include "remoteinfo.h" | ||
| 13 | |||
| 14 | static char line[999]; | ||
| 15 | static int t; | ||
| 16 | |||
| 17 | static int mywrite(fd,buf,len) int fd; char *buf; int len; | ||
| 18 | { | ||
| 19 | return timeoutwrite(t,fd,buf,len); | ||
| 20 | } | ||
| 21 | static int myread(fd,buf,len) int fd; char *buf; int len; | ||
| 22 | { | ||
| 23 | return timeoutread(t,fd,buf,len); | ||
| 24 | } | ||
| 25 | |||
| 26 | char *remoteinfo_get(ipr,rp,ipl,lp,timeout) | ||
| 27 | struct ip_address *ipr; | ||
| 28 | unsigned long rp; | ||
| 29 | struct ip_address *ipl; | ||
| 30 | unsigned long lp; | ||
| 31 | int timeout; | ||
| 32 | { | ||
| 33 | char *x; | ||
| 34 | int s; | ||
| 35 | struct sockaddr_in sin; | ||
| 36 | substdio ss; | ||
| 37 | char buf[32]; | ||
| 38 | unsigned int len; | ||
| 39 | int numcolons; | ||
| 40 | char ch; | ||
| 41 | |||
| 42 | t = timeout; | ||
| 43 | |||
| 44 | s = socket(AF_INET,SOCK_STREAM,0); | ||
| 45 | if (s == -1) return 0; | ||
| 46 | |||
| 47 | byte_zero(&sin,sizeof(sin)); | ||
| 48 | sin.sin_family = AF_INET; | ||
| 49 | byte_copy(&sin.sin_addr,4,ipl); | ||
| 50 | sin.sin_port = 0; | ||
| 51 | if (bind(s,(struct sockaddr *) &sin,sizeof(sin)) == -1) { close(s); return 0; } | ||
| 52 | if (timeoutconn(s,ipr,113,timeout) == -1) { close(s); return 0; } | ||
| 53 | fcntl(s,F_SETFL,fcntl(s,F_GETFL,0) & ~O_NDELAY); | ||
| 54 | |||
| 55 | len = 0; | ||
| 56 | len += fmt_ulong(line + len,rp); | ||
| 57 | len += fmt_str(line + len," , "); | ||
| 58 | len += fmt_ulong(line + len,lp); | ||
| 59 | len += fmt_str(line + len,"\r\n"); | ||
| 60 | |||
| 61 | substdio_fdbuf(&ss,mywrite,s,buf,sizeof buf); | ||
| 62 | if (substdio_putflush(&ss,line,len) == -1) { close(s); return 0; } | ||
| 63 | |||
| 64 | substdio_fdbuf(&ss,myread,s,buf,sizeof buf); | ||
| 65 | x = line; | ||
| 66 | numcolons = 0; | ||
| 67 | for (;;) { | ||
| 68 | if (substdio_get(&ss,&ch,1) != 1) { close(s); return 0; } | ||
| 69 | if ((ch == ' ') || (ch == '\t') || (ch == '\r')) continue; | ||
| 70 | if (ch == '\n') break; | ||
| 71 | if (numcolons < 3) { if (ch == ':') ++numcolons; } | ||
| 72 | else { *x++ = ch; if (x == line + sizeof(line) - 1) break; } | ||
| 73 | } | ||
| 74 | *x = 0; | ||
| 75 | close(s); | ||
| 76 | return line; | ||
| 77 | } | ||
diff --git a/remoteinfo.h b/remoteinfo.h new file mode 100644 index 0000000..d5d9097 --- /dev/null +++ b/remoteinfo.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef REMOTEINFO_H | ||
| 2 | #define REMOTEINFO_H | ||
| 3 | |||
| 4 | extern char *remoteinfo_get(); | ||
| 5 | |||
| 6 | #endif | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | #ifndef SCAN_H | ||
| 2 | #define SCAN_H | ||
| 3 | |||
| 4 | extern unsigned int scan_uint(); | ||
| 5 | extern unsigned int scan_xint(); | ||
| 6 | extern unsigned int scan_nbbint(); | ||
| 7 | extern unsigned int scan_ushort(); | ||
| 8 | extern unsigned int scan_xshort(); | ||
| 9 | extern unsigned int scan_nbbshort(); | ||
| 10 | extern unsigned int scan_ulong(); | ||
| 11 | extern unsigned int scan_xlong(); | ||
| 12 | extern unsigned int scan_nbblong(); | ||
| 13 | |||
| 14 | extern unsigned int scan_plusminus(); | ||
| 15 | extern unsigned int scan_0x(); | ||
| 16 | |||
| 17 | extern unsigned int scan_whitenskip(); | ||
| 18 | extern unsigned int scan_nonwhitenskip(); | ||
| 19 | extern unsigned int scan_charsetnskip(); | ||
| 20 | extern unsigned int scan_noncharsetnskip(); | ||
| 21 | |||
| 22 | extern unsigned int scan_strncmp(); | ||
| 23 | extern unsigned int scan_memcmp(); | ||
| 24 | |||
| 25 | extern unsigned int scan_long(); | ||
| 26 | |||
| 27 | #endif | ||
diff --git a/scan_8long.c b/scan_8long.c new file mode 100644 index 0000000..8b3a6df --- /dev/null +++ b/scan_8long.c | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #include "scan.h" | ||
| 2 | |||
| 3 | unsigned int scan_8long(s,u) register char *s; register unsigned long *u; | ||
| 4 | { | ||
| 5 | register unsigned int pos; register unsigned long result; | ||
| 6 | register unsigned long c; | ||
| 7 | pos = 0; result = 0; | ||
| 8 | while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 8) | ||
| 9 | { result = result * 8 + c; ++pos; } | ||
| 10 | *u = result; return pos; | ||
| 11 | } | ||
diff --git a/scan_ulong.c b/scan_ulong.c new file mode 100644 index 0000000..27c41ea --- /dev/null +++ b/scan_ulong.c | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #include "scan.h" | ||
| 2 | |||
| 3 | unsigned int scan_ulong(s,u) register char *s; register unsigned long *u; | ||
| 4 | { | ||
| 5 | register unsigned int pos; register unsigned long result; | ||
| 6 | register unsigned long c; | ||
| 7 | pos = 0; result = 0; | ||
| 8 | while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 10) | ||
| 9 | { result = result * 10 + c; ++pos; } | ||
| 10 | *u = result; return pos; | ||
| 11 | } | ||
| @@ -0,0 +1,15 @@ | |||
| 1 | #ifndef SEEK_H | ||
| 2 | #define SEEK_H | ||
| 3 | |||
| 4 | typedef unsigned long seek_pos; | ||
| 5 | |||
| 6 | extern seek_pos seek_cur(); | ||
| 7 | |||
| 8 | extern int seek_set(); | ||
| 9 | extern int seek_end(); | ||
| 10 | |||
| 11 | extern int seek_trunc(); | ||
| 12 | |||
| 13 | #define seek_begin(fd) (seek_set((fd),(seek_pos) 0)) | ||
| 14 | |||
| 15 | #endif | ||
diff --git a/seek_cur.c b/seek_cur.c new file mode 100644 index 0000000..c8a3ee8 --- /dev/null +++ b/seek_cur.c | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include "seek.h" | ||
| 3 | |||
| 4 | #define CUR 1 /* sigh */ | ||
| 5 | |||
| 6 | seek_pos seek_cur(fd) int fd; | ||
| 7 | { return lseek(fd,(off_t) 0,CUR); } | ||
diff --git a/seek_end.c b/seek_end.c new file mode 100644 index 0000000..8a7b3c5 --- /dev/null +++ b/seek_end.c | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include "seek.h" | ||
| 3 | |||
| 4 | #define END 2 /* sigh */ | ||
| 5 | |||
| 6 | int seek_end(fd) int fd; | ||
| 7 | { if (lseek(fd,(off_t) 0,END) == -1) return -1; return 0; } | ||
diff --git a/seek_set.c b/seek_set.c new file mode 100644 index 0000000..f540664 --- /dev/null +++ b/seek_set.c | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include "seek.h" | ||
| 3 | |||
| 4 | #define SET 0 /* sigh */ | ||
| 5 | |||
| 6 | int seek_set(fd,pos) int fd; seek_pos pos; | ||
| 7 | { if (lseek(fd,(off_t) pos,SET) == -1) return -1; return 0; } | ||
diff --git a/seek_trunc.c b/seek_trunc.c new file mode 100644 index 0000000..6a1a73e --- /dev/null +++ b/seek_trunc.c | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include "seek.h" | ||
| 3 | |||
| 4 | int seek_trunc(fd,pos) int fd; seek_pos pos; | ||
| 5 | { return ftruncate(fd,(off_t) pos); } | ||
diff --git a/select.h1 b/select.h1 new file mode 100644 index 0000000..32d0968 --- /dev/null +++ b/select.h1 | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef SELECT_H | ||
| 2 | #define SELECT_H | ||
| 3 | |||
| 4 | #include <sys/types.h> | ||
| 5 | #include <sys/time.h> | ||
| 6 | extern int select(); | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/select.h2 b/select.h2 new file mode 100644 index 0000000..eb4b8fe --- /dev/null +++ b/select.h2 | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #ifndef SELECT_H | ||
| 2 | #define SELECT_H | ||
| 3 | |||
| 4 | #include <sys/types.h> | ||
| 5 | #include <sys/time.h> | ||
| 6 | #include <sys/select.h> | ||
| 7 | extern int select(); | ||
| 8 | |||
| 9 | #endif | ||
diff --git a/sendmail.c b/sendmail.c new file mode 100644 index 0000000..46d0e4b --- /dev/null +++ b/sendmail.c | |||
| @@ -0,0 +1,129 @@ | |||
| 1 | #include "sgetopt.h" | ||
| 2 | #include "substdio.h" | ||
| 3 | #include "subfd.h" | ||
| 4 | #include "alloc.h" | ||
| 5 | #include "auto_qmail.h" | ||
| 6 | #include "exit.h" | ||
| 7 | #include "env.h" | ||
| 8 | #include "str.h" | ||
| 9 | |||
| 10 | void nomem() | ||
| 11 | { | ||
| 12 | substdio_putsflush(subfderr,"sendmail: fatal: out of memory\n"); | ||
| 13 | _exit(111); | ||
| 14 | } | ||
| 15 | |||
| 16 | void die_usage() | ||
| 17 | { | ||
| 18 | substdio_putsflush(subfderr,"sendmail: usage: sendmail [ -t ] [ -fsender ] [ -Fname ] [ -bp ] [ -bs ] [ arg ... ]\n"); | ||
| 19 | _exit(100); | ||
| 20 | } | ||
| 21 | |||
| 22 | char *smtpdarg[] = { "bin/qmail-smtpd", 0 }; | ||
| 23 | void smtpd() | ||
| 24 | { | ||
| 25 | if (!env_get("PROTO")) { | ||
| 26 | if (!env_put("RELAYCLIENT=")) nomem(); | ||
| 27 | if (!env_put("DATABYTES=0")) nomem(); | ||
| 28 | if (!env_put("PROTO=TCP")) nomem(); | ||
| 29 | if (!env_put("TCPLOCALIP=127.0.0.1")) nomem(); | ||
| 30 | if (!env_put("TCPLOCALHOST=localhost")) nomem(); | ||
| 31 | if (!env_put("TCPREMOTEIP=127.0.0.1")) nomem(); | ||
| 32 | if (!env_put("TCPREMOTEHOST=localhost")) nomem(); | ||
| 33 | if (!env_put("TCPREMOTEINFO=sendmail-bs")) nomem(); | ||
| 34 | } | ||
| 35 | execv(*smtpdarg,smtpdarg); | ||
| 36 | substdio_putsflush(subfderr,"sendmail: fatal: unable to run qmail-smtpd\n"); | ||
| 37 | _exit(111); | ||
| 38 | } | ||
| 39 | |||
| 40 | char *qreadarg[] = { "bin/qmail-qread", 0 }; | ||
| 41 | void mailq() | ||
| 42 | { | ||
| 43 | execv(*qreadarg,qreadarg); | ||
| 44 | substdio_putsflush(subfderr,"sendmail: fatal: unable to run qmail-qread\n"); | ||
| 45 | _exit(111); | ||
| 46 | } | ||
| 47 | |||
| 48 | int flagh; | ||
| 49 | char *sender; | ||
| 50 | |||
| 51 | void main(argc,argv) | ||
| 52 | int argc; | ||
| 53 | char **argv; | ||
| 54 | { | ||
| 55 | int opt; | ||
| 56 | char **qiargv; | ||
| 57 | char **arg; | ||
| 58 | int i; | ||
| 59 | |||
| 60 | if (chdir(auto_qmail) == -1) { | ||
| 61 | substdio_putsflush(subfderr,"sendmail: fatal: unable to switch to qmail home directory\n"); | ||
| 62 | _exit(111); | ||
| 63 | } | ||
| 64 | |||
| 65 | flagh = 0; | ||
| 66 | sender = 0; | ||
| 67 | while ((opt = getopt(argc,argv,"vimte:f:p:o:B:F:EJxb:")) != opteof) | ||
| 68 | switch(opt) { | ||
| 69 | case 'B': break; | ||
| 70 | case 't': flagh = 1; break; | ||
| 71 | case 'f': sender = optarg; break; | ||
| 72 | case 'F': if (!env_put2("MAILNAME",optarg)) nomem(); break; | ||
| 73 | case 'p': break; /* could generate a Received line from optarg */ | ||
| 74 | case 'v': break; | ||
| 75 | case 'i': break; /* what an absurd concept */ | ||
| 76 | case 'x': break; /* SVR4 stupidity */ | ||
| 77 | case 'm': break; /* twisted-paper-path blindness, incompetent design */ | ||
| 78 | case 'e': break; /* qmail has only one error mode */ | ||
| 79 | case 'o': | ||
| 80 | switch(optarg[0]) { | ||
| 81 | case 'd': break; /* qmail has only one delivery mode */ | ||
| 82 | case 'e': break; /* see 'e' above */ | ||
| 83 | case 'i': break; /* see 'i' above */ | ||
| 84 | case 'm': break; /* see 'm' above */ | ||
| 85 | } | ||
| 86 | break; | ||
| 87 | case 'E': case 'J': /* Sony NEWS-OS */ | ||
| 88 | while (argv[optind][optpos]) ++optpos; /* skip optional argument */ | ||
| 89 | break; | ||
| 90 | case 'b': | ||
| 91 | switch(optarg[0]) { | ||
| 92 | case 'm': break; | ||
| 93 | case 'p': mailq(); | ||
| 94 | case 's': smtpd(); | ||
| 95 | default: die_usage(); | ||
| 96 | } | ||
| 97 | break; | ||
| 98 | default: | ||
| 99 | die_usage(); | ||
| 100 | } | ||
| 101 | argc -= optind; | ||
| 102 | argv += optind; | ||
| 103 | |||
| 104 | if (str_equal(optprogname,"mailq")) | ||
| 105 | mailq(); | ||
| 106 | |||
| 107 | if (str_equal(optprogname,"newaliases")) { | ||
| 108 | substdio_putsflush(subfderr,"sendmail: fatal: please use fastforward/newaliases instead\n"); | ||
| 109 | _exit(100); | ||
| 110 | } | ||
| 111 | |||
| 112 | qiargv = (char **) alloc((argc + 10) * sizeof(char *)); | ||
| 113 | if (!qiargv) nomem(); | ||
| 114 | |||
| 115 | arg = qiargv; | ||
| 116 | *arg++ = "bin/qmail-inject"; | ||
| 117 | *arg++ = (flagh ? "-H" : "-a"); | ||
| 118 | if (sender) { | ||
| 119 | *arg++ = "-f"; | ||
| 120 | *arg++ = sender; | ||
| 121 | } | ||
| 122 | *arg++ = "--"; | ||
| 123 | for (i = 0;i < argc;++i) *arg++ = argv[i]; | ||
| 124 | *arg = 0; | ||
| 125 | |||
| 126 | execv(*qiargv,qiargv); | ||
| 127 | substdio_putsflush(subfderr,"sendmail: fatal: unable to run qmail-inject\n"); | ||
| 128 | _exit(111); | ||
| 129 | } | ||
diff --git a/sgetopt.3 b/sgetopt.3 new file mode 100644 index 0000000..bde0c2b --- /dev/null +++ b/sgetopt.3 | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | .TH sgetopt 3 | ||
| 2 | .SH NAME | ||
| 3 | sgetopt \- get option character from command line | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <sgetopt.h> | ||
| 6 | .SH DESCRIPTION | ||
| 7 | The | ||
| 8 | .B sgetopt | ||
| 9 | library is just like the | ||
| 10 | .B getopt | ||
| 11 | library, | ||
| 12 | except that it prints errors using | ||
| 13 | .B substdio | ||
| 14 | rather than | ||
| 15 | .BR stdio . | ||
| 16 | |||
| 17 | See | ||
| 18 | .B getopt(3) | ||
| 19 | for interface details. | ||
| 20 | .SH VERSION | ||
| 21 | sgetopt version 1.9, 931201. | ||
| 22 | .SH AUTHOR | ||
| 23 | Placed into the public domain by Daniel J. Bernstein. | ||
| 24 | .SH "SEE ALSO" | ||
| 25 | getopt(3), | ||
| 26 | subgetopt(3), | ||
| 27 | subfd(3), | ||
| 28 | substdio(3) | ||
diff --git a/sgetopt.c b/sgetopt.c new file mode 100644 index 0000000..a8bffc0 --- /dev/null +++ b/sgetopt.c | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | /* sgetopt.c, sgetopt.h: (yet another) improved getopt clone, outer layer | ||
| 2 | D. J. Bernstein, djb@pobox.com. | ||
| 3 | Depends on subgetopt.h, substdio.h, subfd.h. | ||
| 4 | No system requirements. | ||
| 5 | 19970208: Cleanups. | ||
| 6 | 931201: Baseline. | ||
| 7 | No known patent problems. | ||
| 8 | |||
| 9 | Documentation in sgetopt.3. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include "substdio.h" | ||
| 13 | #include "subfd.h" | ||
| 14 | #define SGETOPTNOSHORT | ||
| 15 | #include "sgetopt.h" | ||
| 16 | #define SUBGETOPTNOSHORT | ||
| 17 | #include "subgetopt.h" | ||
| 18 | |||
| 19 | #define getopt sgetoptmine | ||
| 20 | #define optind subgetoptind | ||
| 21 | #define opterr sgetopterr | ||
| 22 | #define optproblem subgetoptproblem | ||
| 23 | #define optprogname sgetoptprogname | ||
| 24 | |||
| 25 | int opterr = 1; | ||
| 26 | char *optprogname = 0; | ||
| 27 | |||
| 28 | int getopt(argc,argv,opts) | ||
| 29 | int argc; | ||
| 30 | char **argv; | ||
| 31 | char *opts; | ||
| 32 | { | ||
| 33 | int c; | ||
| 34 | char *s; | ||
| 35 | |||
| 36 | if (!optprogname) { | ||
| 37 | optprogname = *argv; | ||
| 38 | if (!optprogname) optprogname = ""; | ||
| 39 | for (s = optprogname;*s;++s) if (*s == '/') optprogname = s + 1; | ||
| 40 | } | ||
| 41 | c = subgetopt(argc,argv,opts); | ||
| 42 | if (opterr) | ||
| 43 | if (c == '?') { | ||
| 44 | char chp[2]; chp[0] = optproblem; chp[1] = '\n'; | ||
| 45 | substdio_puts(subfderr,optprogname); | ||
| 46 | if (argv[optind] && (optind < argc)) | ||
| 47 | substdio_puts(subfderr,": illegal option -- "); | ||
| 48 | else | ||
| 49 | substdio_puts(subfderr,": option requires an argument -- "); | ||
| 50 | substdio_put(subfderr,chp,2); | ||
| 51 | substdio_flush(subfderr); | ||
| 52 | } | ||
| 53 | return c; | ||
| 54 | } | ||
diff --git a/sgetopt.h b/sgetopt.h new file mode 100644 index 0000000..5f89127 --- /dev/null +++ b/sgetopt.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | #ifndef SGETOPT_H | ||
| 2 | #define SGETOPT_H | ||
| 3 | |||
| 4 | #ifndef SGETOPTNOSHORT | ||
| 5 | #define getopt sgetoptmine | ||
| 6 | #define optarg subgetoptarg | ||
| 7 | #define optind subgetoptind | ||
| 8 | #define optpos subgetoptpos | ||
| 9 | #define opterr sgetopterr | ||
| 10 | #define optproblem subgetoptproblem | ||
| 11 | #define optprogname sgetoptprogname | ||
| 12 | #define opteof subgetoptdone | ||
| 13 | #endif | ||
| 14 | |||
| 15 | #include "subgetopt.h" | ||
| 16 | |||
| 17 | extern int sgetoptmine(); | ||
| 18 | extern int sgetopterr; | ||
| 19 | extern char *sgetoptprogname; | ||
| 20 | |||
| 21 | #endif | ||
| @@ -0,0 +1,43 @@ | |||
| 1 | #ifndef SIG_H | ||
| 2 | #define SIG_H | ||
| 3 | |||
| 4 | extern void sig_catch(); | ||
| 5 | extern void sig_block(); | ||
| 6 | extern void sig_unblock(); | ||
| 7 | extern void sig_blocknone(); | ||
| 8 | extern void sig_pause(); | ||
| 9 | |||
| 10 | extern void sig_dfl(); | ||
| 11 | |||
| 12 | extern void sig_miscignore(); | ||
| 13 | extern void sig_bugcatch(); | ||
| 14 | |||
| 15 | extern void sig_pipeignore(); | ||
| 16 | extern void sig_pipedefault(); | ||
| 17 | |||
| 18 | extern void sig_contblock(); | ||
| 19 | extern void sig_contunblock(); | ||
| 20 | extern void sig_contcatch(); | ||
| 21 | extern void sig_contdefault(); | ||
| 22 | |||
| 23 | extern void sig_termblock(); | ||
| 24 | extern void sig_termunblock(); | ||
| 25 | extern void sig_termcatch(); | ||
| 26 | extern void sig_termdefault(); | ||
| 27 | |||
| 28 | extern void sig_alarmblock(); | ||
| 29 | extern void sig_alarmunblock(); | ||
| 30 | extern void sig_alarmcatch(); | ||
| 31 | extern void sig_alarmdefault(); | ||
| 32 | |||
| 33 | extern void sig_childblock(); | ||
| 34 | extern void sig_childunblock(); | ||
| 35 | extern void sig_childcatch(); | ||
| 36 | extern void sig_childdefault(); | ||
| 37 | |||
| 38 | extern void sig_hangupblock(); | ||
| 39 | extern void sig_hangupunblock(); | ||
| 40 | extern void sig_hangupcatch(); | ||
| 41 | extern void sig_hangupdefault(); | ||
| 42 | |||
| 43 | #endif | ||
diff --git a/sig_alarm.c b/sig_alarm.c new file mode 100644 index 0000000..7092fdc --- /dev/null +++ b/sig_alarm.c | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #include <signal.h> | ||
| 2 | #include "sig.h" | ||
| 3 | |||
| 4 | void sig_alarmblock() { sig_block(SIGALRM); } | ||
| 5 | void sig_alarmunblock() { sig_unblock(SIGALRM); } | ||
| 6 | void sig_alarmcatch(f) void (*f)(); { sig_catch(SIGALRM,f); } | ||
| 7 | void sig_alarmdefault() { sig_catch(SIGALRM,SIG_DFL); } | ||
diff --git a/sig_block.c b/sig_block.c new file mode 100644 index 0000000..c6b096a --- /dev/null +++ b/sig_block.c | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | #include <signal.h> | ||
| 2 | #include "sig.h" | ||
| 3 | #include "hassgprm.h" | ||
| 4 | |||
| 5 | void sig_block(sig) | ||
| 6 | int sig; | ||
| 7 | { | ||
| 8 | #ifdef HASSIGPROCMASK | ||
| 9 | sigset_t ss; | ||
| 10 | sigemptyset(&ss); | ||
| 11 | sigaddset(&ss,sig); | ||
| 12 | sigprocmask(SIG_BLOCK,&ss,(sigset_t *) 0); | ||
| 13 | #else | ||
| 14 | sigblock(1 << (sig - 1)); | ||
| 15 | #endif | ||
| 16 | } | ||
| 17 | |||
| 18 | void sig_unblock(sig) | ||
| 19 | int sig; | ||
| 20 | { | ||
| 21 | #ifdef HASSIGPROCMASK | ||
| 22 | sigset_t ss; | ||
| 23 | sigemptyset(&ss); | ||
| 24 | sigaddset(&ss,sig); | ||
| 25 | sigprocmask(SIG_UNBLOCK,&ss,(sigset_t *) 0); | ||
| 26 | #else | ||
| 27 | sigsetmask(sigsetmask(~0) & ~(1 << (sig - 1))); | ||
| 28 | #endif | ||
| 29 | } | ||
| 30 | |||
| 31 | void sig_blocknone() | ||
| 32 | { | ||
| 33 | #ifdef HASSIGPROCMASK | ||
| 34 | sigset_t ss; | ||
| 35 | sigemptyset(&ss); | ||
| 36 | sigprocmask(SIG_SETMASK,&ss,(sigset_t *) 0); | ||
| 37 | #else | ||
| 38 | sigsetmask(0); | ||
| 39 | #endif | ||
| 40 | } | ||
diff --git a/sig_bug.c b/sig_bug.c new file mode 100644 index 0000000..ae09c07 --- /dev/null +++ b/sig_bug.c | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #include <signal.h> | ||
| 2 | #include "sig.h" | ||
| 3 | |||
| 4 | void sig_bugcatch(f) void (*f)(); | ||
| 5 | { | ||
| 6 | sig_catch(SIGILL,f); | ||
| 7 | sig_catch(SIGABRT,f); | ||
| 8 | sig_catch(SIGFPE,f); | ||
| 9 | sig_catch(SIGBUS,f); | ||
| 10 | sig_catch(SIGSEGV,f); | ||
| 11 | #ifdef SIGSYS | ||
| 12 | sig_catch(SIGSYS,f); | ||
| 13 | #endif | ||
| 14 | #ifdef SIGEMT | ||
| 15 | sig_catch(SIGEMT,f); | ||
| 16 | #endif | ||
| 17 | } | ||
diff --git a/sig_catch.c b/sig_catch.c new file mode 100644 index 0000000..1888765 --- /dev/null +++ b/sig_catch.c | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | #include <signal.h> | ||
| 2 | #include "sig.h" | ||
| 3 | #include "hassgact.h" | ||
| 4 | |||
| 5 | void sig_catch(sig,f) | ||
| 6 | int sig; | ||
| 7 | void (*f)(); | ||
| 8 | { | ||
| 9 | #ifdef HASSIGACTION | ||
| 10 | struct sigaction sa; | ||
| 11 | sa.sa_handler = f; | ||
| 12 | sa.sa_flags = 0; | ||
| 13 | sigemptyset(&sa.sa_mask); | ||
| 14 | sigaction(sig,&sa,(struct sigaction *) 0); | ||
| 15 | #else | ||
| 16 | signal(sig,f); /* won't work under System V, even nowadays---dorks */ | ||
| 17 | #endif | ||
| 18 | } | ||
diff --git a/sig_child.c b/sig_child.c new file mode 100644 index 0000000..fd5b39b --- /dev/null +++ b/sig_child.c | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #include <signal.h> | ||
| 2 | #include "sig.h" | ||
| 3 | |||
| 4 | void sig_childblock() { sig_block(SIGCHLD); } | ||
| 5 | void sig_childunblock() { sig_unblock(SIGCHLD); } | ||
| 6 | void sig_childcatch(f) void (*f)(); { sig_catch(SIGCHLD,f); } | ||
| 7 | void sig_childdefault() { sig_catch(SIGCHLD,SIG_DFL); } | ||
diff --git a/sig_hup.c b/sig_hup.c new file mode 100644 index 0000000..4beb87f --- /dev/null +++ b/sig_hup.c | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #include <signal.h> | ||
| 2 | #include "sig.h" | ||
| 3 | |||
| 4 | void sig_hangupblock() { sig_block(SIGHUP); } | ||
| 5 | void sig_hangupunblock() { sig_unblock(SIGHUP); } | ||
| 6 | void sig_hangupcatch(f) void (*f)(); { sig_catch(SIGHUP,f); } | ||
| 7 | void sig_hangupdefault() { sig_catch(SIGHUP,SIG_DFL); } | ||
diff --git a/sig_misc.c b/sig_misc.c new file mode 100644 index 0000000..287f6cb --- /dev/null +++ b/sig_misc.c | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #include <signal.h> | ||
| 2 | #include "sig.h" | ||
| 3 | |||
| 4 | void sig_miscignore() | ||
| 5 | { | ||
| 6 | sig_catch(SIGVTALRM,SIG_IGN); | ||
| 7 | sig_catch(SIGPROF,SIG_IGN); | ||
| 8 | sig_catch(SIGQUIT,SIG_IGN); | ||
| 9 | sig_catch(SIGINT,SIG_IGN); | ||
| 10 | sig_catch(SIGHUP,SIG_IGN); | ||
| 11 | #ifdef SIGXCPU | ||
| 12 | sig_catch(SIGXCPU,SIG_IGN); | ||
| 13 | #endif | ||
| 14 | #ifdef SIGXFSZ | ||
| 15 | sig_catch(SIGXFSZ,SIG_IGN); | ||
| 16 | #endif | ||
| 17 | } | ||
diff --git a/sig_pause.c b/sig_pause.c new file mode 100644 index 0000000..3416734 --- /dev/null +++ b/sig_pause.c | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | #include <signal.h> | ||
| 2 | #include "sig.h" | ||
| 3 | #include "hassgprm.h" | ||
| 4 | |||
| 5 | void sig_pause() | ||
| 6 | { | ||
| 7 | #ifdef HASSIGPROCMASK | ||
| 8 | sigset_t ss; | ||
| 9 | sigemptyset(&ss); | ||
| 10 | sigsuspend(&ss); | ||
| 11 | #else | ||
| 12 | sigpause(0); | ||
| 13 | #endif | ||
| 14 | } | ||
diff --git a/sig_pipe.c b/sig_pipe.c new file mode 100644 index 0000000..594ae7d --- /dev/null +++ b/sig_pipe.c | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | #include <signal.h> | ||
| 2 | #include "sig.h" | ||
| 3 | |||
| 4 | void sig_pipeignore() { sig_catch(SIGPIPE,SIG_IGN); } | ||
| 5 | void sig_pipedefault() { sig_catch(SIGPIPE,SIG_DFL); } | ||
diff --git a/sig_term.c b/sig_term.c new file mode 100644 index 0000000..ca72cc3 --- /dev/null +++ b/sig_term.c | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #include <signal.h> | ||
| 2 | #include "sig.h" | ||
| 3 | |||
| 4 | void sig_termblock() { sig_block(SIGTERM); } | ||
| 5 | void sig_termunblock() { sig_unblock(SIGTERM); } | ||
| 6 | void sig_termcatch(f) void (*f)(); { sig_catch(SIGTERM,f); } | ||
| 7 | void sig_termdefault() { sig_catch(SIGTERM,SIG_DFL); } | ||
diff --git a/slurpclose.c b/slurpclose.c new file mode 100644 index 0000000..2fcef15 --- /dev/null +++ b/slurpclose.c | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | #include "stralloc.h" | ||
| 2 | #include "readwrite.h" | ||
| 3 | #include "slurpclose.h" | ||
| 4 | #include "error.h" | ||
| 5 | |||
| 6 | int slurpclose(fd,sa,bufsize) | ||
| 7 | int fd; | ||
| 8 | stralloc *sa; | ||
| 9 | int bufsize; | ||
| 10 | { | ||
| 11 | int r; | ||
| 12 | for (;;) { | ||
| 13 | if (!stralloc_readyplus(sa,bufsize)) { close(fd); return -1; } | ||
| 14 | r = read(fd,sa->s + sa->len,bufsize); | ||
| 15 | if (r == -1) if (errno == error_intr) continue; | ||
| 16 | if (r <= 0) { close(fd); return r; } | ||
| 17 | sa->len += r; | ||
| 18 | } | ||
| 19 | } | ||
diff --git a/slurpclose.h b/slurpclose.h new file mode 100644 index 0000000..57e9eec --- /dev/null +++ b/slurpclose.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef SLURPCLOSE_H | ||
| 2 | #define SLURPCLOSE_H | ||
| 3 | |||
| 4 | extern int slurpclose(); | ||
| 5 | |||
| 6 | #endif | ||
| @@ -0,0 +1,259 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include "sig.h" | ||
| 4 | #include "wait.h" | ||
| 5 | #include "substdio.h" | ||
| 6 | #include "byte.h" | ||
| 7 | #include "str.h" | ||
| 8 | #include "stralloc.h" | ||
| 9 | #include "select.h" | ||
| 10 | #include "exit.h" | ||
| 11 | #include "coe.h" | ||
| 12 | #include "open.h" | ||
| 13 | #include "error.h" | ||
| 14 | #include "auto_qmail.h" | ||
| 15 | #include "auto_uids.h" | ||
| 16 | #include "auto_spawn.h" | ||
| 17 | |||
| 18 | extern int truncreport; | ||
| 19 | extern int spawn(); | ||
| 20 | extern void report(); | ||
| 21 | extern void initialize(); | ||
| 22 | |||
| 23 | struct delivery | ||
| 24 | { | ||
| 25 | int used; | ||
| 26 | int fdin; /* pipe input */ | ||
| 27 | int pid; /* zero if child is dead */ | ||
| 28 | int wstat; /* if !pid: status of child */ | ||
| 29 | int fdout; /* pipe output, -1 if !pid; delays eof until after death */ | ||
| 30 | stralloc output; | ||
| 31 | } | ||
| 32 | ; | ||
| 33 | |||
| 34 | struct delivery *d; | ||
| 35 | |||
| 36 | void sigchld() | ||
| 37 | { | ||
| 38 | int wstat; | ||
| 39 | int pid; | ||
| 40 | int i; | ||
| 41 | while ((pid = wait_nohang(&wstat)) > 0) | ||
| 42 | for (i = 0;i < auto_spawn;++i) if (d[i].used) | ||
| 43 | if (d[i].pid == pid) | ||
| 44 | { | ||
| 45 | close(d[i].fdout); d[i].fdout = -1; | ||
| 46 | d[i].wstat = wstat; d[i].pid = 0; | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | int flagwriting = 1; | ||
| 51 | |||
| 52 | int okwrite(fd,buf,n) int fd; char *buf; int n; | ||
| 53 | { | ||
| 54 | int w; | ||
| 55 | if (!flagwriting) return n; | ||
| 56 | w = write(fd,buf,n); | ||
| 57 | if (w != -1) return w; | ||
| 58 | if (errno == error_intr) return -1; | ||
| 59 | flagwriting = 0; close(fd); | ||
| 60 | return n; | ||
| 61 | } | ||
| 62 | |||
| 63 | int flagreading = 1; | ||
| 64 | char outbuf[1024]; substdio ssout; | ||
| 65 | |||
| 66 | int stage = 0; /* reading 0:delnum 1:messid 2:sender 3:recip */ | ||
| 67 | int flagabort = 0; /* if 1, everything except delnum is garbage */ | ||
| 68 | int delnum; | ||
| 69 | stralloc messid = {0}; | ||
| 70 | stralloc sender = {0}; | ||
| 71 | stralloc recip = {0}; | ||
| 72 | |||
| 73 | void err(s) char *s; | ||
| 74 | { | ||
| 75 | char ch; ch = delnum; substdio_put(&ssout,&ch,1); | ||
| 76 | substdio_puts(&ssout,s); substdio_putflush(&ssout,"",1); | ||
| 77 | } | ||
| 78 | |||
| 79 | void docmd() | ||
| 80 | { | ||
| 81 | int f; | ||
| 82 | int i; | ||
| 83 | int j; | ||
| 84 | int fdmess; | ||
| 85 | int pi[2]; | ||
| 86 | struct stat st; | ||
| 87 | |||
| 88 | if (flagabort) { err("Zqmail-spawn out of memory. (#4.3.0)\n"); return; } | ||
| 89 | if (delnum < 0) { err("ZInternal error: delnum negative. (#4.3.5)\n"); return; } | ||
| 90 | if (delnum >= auto_spawn) { err("ZInternal error: delnum too big. (#4.3.5)\n"); return; } | ||
| 91 | if (d[delnum].used) { err("ZInternal error: delnum in use. (#4.3.5)\n"); return; } | ||
| 92 | for (i = 0;i < messid.len;++i) | ||
| 93 | if (messid.s[i]) | ||
| 94 | if (!i || (messid.s[i] != '/')) | ||
| 95 | if ((unsigned char) (messid.s[i] - '0') > 9) | ||
| 96 | { err("DInternal error: messid has nonnumerics. (#5.3.5)\n"); return; } | ||
| 97 | if (messid.len > 100) { err("DInternal error: messid too long. (#5.3.5)\n"); return; } | ||
| 98 | if (!messid.s[0]) { err("DInternal error: messid too short. (#5.3.5)\n"); return; } | ||
| 99 | |||
| 100 | if (!stralloc_copys(&d[delnum].output,"")) | ||
| 101 | { err("Zqmail-spawn out of memory. (#4.3.0)\n"); return; } | ||
| 102 | |||
| 103 | j = byte_rchr(recip.s,recip.len,'@'); | ||
| 104 | if (j >= recip.len) { err("DSorry, address must include host name. (#5.1.3)\n"); return; } | ||
| 105 | |||
| 106 | fdmess = open_read(messid.s); | ||
| 107 | if (fdmess == -1) { err("Zqmail-spawn unable to open message. (#4.3.0)\n"); return; } | ||
| 108 | |||
| 109 | if (fstat(fdmess,&st) == -1) | ||
| 110 | { close(fdmess); err("Zqmail-spawn unable to fstat message. (#4.3.0)\n"); return; } | ||
| 111 | if ((st.st_mode & S_IFMT) != S_IFREG) | ||
| 112 | { close(fdmess); err("ZSorry, message has wrong type. (#4.3.5)\n"); return; } | ||
| 113 | if (st.st_uid != auto_uidq) /* aaack! qmailq has to be trusted! */ | ||
| 114 | /* your security is already toast at this point. damage control... */ | ||
| 115 | { close(fdmess); err("ZSorry, message has wrong owner. (#4.3.5)\n"); return; } | ||
| 116 | |||
| 117 | if (pipe(pi) == -1) | ||
| 118 | { close(fdmess); err("Zqmail-spawn unable to create pipe. (#4.3.0)\n"); return; } | ||
| 119 | |||
| 120 | coe(pi[0]); | ||
| 121 | |||
| 122 | f = spawn(fdmess,pi[1],sender.s,recip.s,j); | ||
| 123 | close(fdmess); | ||
| 124 | if (f == -1) | ||
| 125 | { close(pi[0]); close(pi[1]); err("Zqmail-spawn unable to fork. (#4.3.0)\n"); return; } | ||
| 126 | |||
| 127 | d[delnum].fdin = pi[0]; | ||
| 128 | d[delnum].fdout = pi[1]; coe(pi[1]); | ||
| 129 | d[delnum].pid = f; | ||
| 130 | d[delnum].used = 1; | ||
| 131 | } | ||
| 132 | |||
| 133 | char cmdbuf[1024]; | ||
| 134 | |||
| 135 | void getcmd() | ||
| 136 | { | ||
| 137 | int i; | ||
| 138 | int r; | ||
| 139 | char ch; | ||
| 140 | |||
| 141 | r = read(0,cmdbuf,sizeof(cmdbuf)); | ||
| 142 | if (r == 0) | ||
| 143 | { flagreading = 0; return; } | ||
| 144 | if (r == -1) | ||
| 145 | { | ||
| 146 | if (errno != error_intr) | ||
| 147 | flagreading = 0; | ||
| 148 | return; | ||
| 149 | } | ||
| 150 | |||
| 151 | for (i = 0;i < r;++i) | ||
| 152 | { | ||
| 153 | ch = cmdbuf[i]; | ||
| 154 | switch(stage) | ||
| 155 | { | ||
| 156 | case 0: | ||
| 157 | delnum = (unsigned int) (unsigned char) ch; | ||
| 158 | messid.len = 0; stage = 1; break; | ||
| 159 | case 1: | ||
| 160 | if (!stralloc_append(&messid,&ch)) flagabort = 1; | ||
| 161 | if (ch) break; | ||
| 162 | sender.len = 0; stage = 2; break; | ||
| 163 | case 2: | ||
| 164 | if (!stralloc_append(&sender,&ch)) flagabort = 1; | ||
| 165 | if (ch) break; | ||
| 166 | recip.len = 0; stage = 3; break; | ||
| 167 | case 3: | ||
| 168 | if (!stralloc_append(&recip,&ch)) flagabort = 1; | ||
| 169 | if (ch) break; | ||
| 170 | docmd(); | ||
| 171 | flagabort = 0; stage = 0; break; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | char inbuf[128]; | ||
| 177 | |||
| 178 | void main(argc,argv) | ||
| 179 | int argc; | ||
| 180 | char **argv; | ||
| 181 | { | ||
| 182 | char ch; | ||
| 183 | int i; | ||
| 184 | int r; | ||
| 185 | fd_set rfds; | ||
| 186 | int nfds; | ||
| 187 | |||
| 188 | if (chdir(auto_qmail) == -1) _exit(111); | ||
| 189 | if (chdir("queue/mess") == -1) _exit(111); | ||
| 190 | if (!stralloc_copys(&messid,"")) _exit(111); | ||
| 191 | if (!stralloc_copys(&sender,"")) _exit(111); | ||
| 192 | if (!stralloc_copys(&recip,"")) _exit(111); | ||
| 193 | |||
| 194 | d = (struct delivery *) alloc((auto_spawn + 10) * sizeof(struct delivery)); | ||
| 195 | if (!d) _exit(111); | ||
| 196 | |||
| 197 | substdio_fdbuf(&ssout,okwrite,1,outbuf,sizeof(outbuf)); | ||
| 198 | |||
| 199 | sig_pipeignore(); | ||
| 200 | sig_childcatch(sigchld); | ||
| 201 | |||
| 202 | initialize(argc,argv); | ||
| 203 | |||
| 204 | ch = auto_spawn; substdio_putflush(&ssout,&ch,1); | ||
| 205 | |||
| 206 | for (i = 0;i < auto_spawn;++i) { d[i].used = 0; d[i].output.s = 0; } | ||
| 207 | |||
| 208 | for (;;) | ||
| 209 | { | ||
| 210 | if (!flagreading) | ||
| 211 | { | ||
| 212 | for (i = 0;i < auto_spawn;++i) if (d[i].used) break; | ||
| 213 | if (i >= auto_spawn) _exit(0); | ||
| 214 | } | ||
| 215 | sig_childunblock(); | ||
| 216 | |||
| 217 | FD_ZERO(&rfds); | ||
| 218 | if (flagreading) FD_SET(0,&rfds); | ||
| 219 | nfds = 1; | ||
| 220 | for (i = 0;i < auto_spawn;++i) if (d[i].used) | ||
| 221 | { FD_SET(d[i].fdin,&rfds); if (d[i].fdin >= nfds) nfds = d[i].fdin + 1; } | ||
| 222 | |||
| 223 | r = select(nfds,&rfds,(fd_set *) 0,(fd_set *) 0,(struct timeval *) 0); | ||
| 224 | sig_childblock(); | ||
| 225 | |||
| 226 | if (r != -1) | ||
| 227 | { | ||
| 228 | if (flagreading) | ||
| 229 | if (FD_ISSET(0,&rfds)) | ||
| 230 | getcmd(); | ||
| 231 | for (i = 0;i < auto_spawn;++i) if (d[i].used) | ||
| 232 | if (FD_ISSET(d[i].fdin,&rfds)) | ||
| 233 | { | ||
| 234 | r = read(d[i].fdin,inbuf,128); | ||
| 235 | if (r == -1) | ||
| 236 | continue; /* read error on a readable pipe? be serious */ | ||
| 237 | if (r == 0) | ||
| 238 | { | ||
| 239 | ch = i; substdio_put(&ssout,&ch,1); | ||
| 240 | report(&ssout,d[i].wstat,d[i].output.s,d[i].output.len); | ||
| 241 | substdio_put(&ssout,"",1); | ||
| 242 | substdio_flush(&ssout); | ||
| 243 | close(d[i].fdin); d[i].used = 0; | ||
| 244 | continue; | ||
| 245 | } | ||
| 246 | while (!stralloc_readyplus(&d[i].output,r)) sleep(10); /*XXX*/ | ||
| 247 | byte_copy(d[i].output.s + d[i].output.len,r,inbuf); | ||
| 248 | d[i].output.len += r; | ||
| 249 | if (truncreport > 100) | ||
| 250 | if (d[i].output.len > truncreport) | ||
| 251 | { | ||
| 252 | char *truncmess = "\nError report too long, sorry.\n"; | ||
| 253 | d[i].output.len = truncreport - str_len(truncmess) - 3; | ||
| 254 | stralloc_cats(&d[i].output,truncmess); | ||
| 255 | } | ||
| 256 | } | ||
| 257 | } | ||
| 258 | } | ||
| 259 | } | ||
diff --git a/splogger.8 b/splogger.8 new file mode 100644 index 0000000..15096b4 --- /dev/null +++ b/splogger.8 | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | .TH splogger 8 | ||
| 2 | .SH NAME | ||
| 3 | splogger \- make entries in syslog | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B splogger | ||
| 6 | [ | ||
| 7 | .I tag | ||
| 8 | [ | ||
| 9 | .I fac | ||
| 10 | ] | ||
| 11 | ] | ||
| 12 | .SH DESCRIPTION | ||
| 13 | .B splogger | ||
| 14 | reads a series of messages and feeds them to | ||
| 15 | .BR syslog . | ||
| 16 | At the front of each message it puts | ||
| 17 | .I tag | ||
| 18 | (default: | ||
| 19 | .BR splogger ) | ||
| 20 | and a numerical timestamp. | ||
| 21 | |||
| 22 | .B splogger | ||
| 23 | checks for | ||
| 24 | .B alert: | ||
| 25 | or | ||
| 26 | .B warning: | ||
| 27 | at the beginning of each message. | ||
| 28 | It selects a priority of | ||
| 29 | LOG_ALERT, LOG_WARNING, or LOG_INFO accordingly. | ||
| 30 | |||
| 31 | .B splogger | ||
| 32 | logs messages with facility | ||
| 33 | .IR fac . | ||
| 34 | .I fac | ||
| 35 | (default: 2) | ||
| 36 | must be numeric. | ||
| 37 | |||
| 38 | .B splogger | ||
| 39 | converts unprintable characters to question marks. | ||
| 40 | |||
| 41 | .B splogger | ||
| 42 | does not log blank lines. | ||
| 43 | |||
| 44 | .B splogger | ||
| 45 | folds messages after 800 characters, | ||
| 46 | since | ||
| 47 | .B syslog | ||
| 48 | can't handle long messages. | ||
| 49 | .B splogger | ||
| 50 | uses a + after the timestamp | ||
| 51 | to mark folded lines. | ||
| 52 | |||
| 53 | Note that the | ||
| 54 | .B syslog | ||
| 55 | mechanism is inherently unreliable: | ||
| 56 | it does not guarantee that messages will be logged. | ||
| 57 | It is also very slow. | ||
| 58 | .SH "SEE ALSO" | ||
| 59 | syslog(3), | ||
| 60 | logger(8) | ||
diff --git a/splogger.c b/splogger.c new file mode 100644 index 0000000..fc49a33 --- /dev/null +++ b/splogger.c | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/time.h> | ||
| 3 | #include <syslog.h> | ||
| 4 | #include "error.h" | ||
| 5 | #include "substdio.h" | ||
| 6 | #include "subfd.h" | ||
| 7 | #include "exit.h" | ||
| 8 | #include "str.h" | ||
| 9 | #include "scan.h" | ||
| 10 | #include "fmt.h" | ||
| 11 | |||
| 12 | char buf[800]; /* syslog truncates long lines (or crashes); GPACIC */ | ||
| 13 | int bufpos = 0; /* 0 <= bufpos < sizeof(buf) */ | ||
| 14 | int flagcont = 0; | ||
| 15 | int priority; /* defined if flagcont */ | ||
| 16 | char stamp[FMT_ULONG + FMT_ULONG + 3]; /* defined if flagcont */ | ||
| 17 | |||
| 18 | void stamp_make() | ||
| 19 | { | ||
| 20 | struct timeval tv; | ||
| 21 | char *s; | ||
| 22 | gettimeofday(&tv,(struct timezone *) 0); | ||
| 23 | s = stamp; | ||
| 24 | s += fmt_ulong(s,(unsigned long) tv.tv_sec); | ||
| 25 | *s++ = '.'; | ||
| 26 | s += fmt_uint0(s,(unsigned int) tv.tv_usec,6); | ||
| 27 | *s = 0; | ||
| 28 | } | ||
| 29 | |||
| 30 | void flush() | ||
| 31 | { | ||
| 32 | if (bufpos) { | ||
| 33 | buf[bufpos] = 0; | ||
| 34 | if (flagcont) | ||
| 35 | syslog(priority,"%s+%s",stamp,buf); /* logger folds invisibly; GPACIC */ | ||
| 36 | else { | ||
| 37 | stamp_make(); | ||
| 38 | priority = LOG_INFO; | ||
| 39 | if (str_start(buf,"warning:")) priority = LOG_WARNING; | ||
| 40 | if (str_start(buf,"alert:")) priority = LOG_ALERT; | ||
| 41 | syslog(priority,"%s %s",stamp,buf); | ||
| 42 | flagcont = 1; | ||
| 43 | } | ||
| 44 | } | ||
| 45 | bufpos = 0; | ||
| 46 | } | ||
| 47 | |||
| 48 | void main(argc,argv) | ||
| 49 | int argc; | ||
| 50 | char **argv; | ||
| 51 | { | ||
| 52 | char ch; | ||
| 53 | |||
| 54 | if (argv[1]) | ||
| 55 | if (argv[2]) { | ||
| 56 | unsigned long facility; | ||
| 57 | scan_ulong(argv[2],&facility); | ||
| 58 | openlog(argv[1],0,facility << 3); | ||
| 59 | } | ||
| 60 | else | ||
| 61 | openlog(argv[1],0,LOG_MAIL); | ||
| 62 | else | ||
| 63 | openlog("splogger",0,LOG_MAIL); | ||
| 64 | |||
| 65 | for (;;) { | ||
| 66 | if (substdio_get(subfdin,&ch,1) < 1) _exit(0); | ||
| 67 | if (ch == '\n') { flush(); flagcont = 0; continue; } | ||
| 68 | if (bufpos == sizeof(buf) - 1) flush(); | ||
| 69 | if ((ch < 32) || (ch > 126)) ch = '?'; /* logger truncates at 0; GPACIC */ | ||
| 70 | buf[bufpos++] = ch; | ||
| 71 | } | ||
| 72 | } | ||
| @@ -0,0 +1,14 @@ | |||
| 1 | #ifndef STR_H | ||
| 2 | #define STR_H | ||
| 3 | |||
| 4 | extern unsigned int str_copy(); | ||
| 5 | extern int str_diff(); | ||
| 6 | extern int str_diffn(); | ||
| 7 | extern unsigned int str_len(); | ||
| 8 | extern unsigned int str_chr(); | ||
| 9 | extern unsigned int str_rchr(); | ||
| 10 | extern int str_start(); | ||
| 11 | |||
| 12 | #define str_equal(s,t) (!str_diff((s),(t))) | ||
| 13 | |||
| 14 | #endif | ||
diff --git a/str_chr.c b/str_chr.c new file mode 100644 index 0000000..3691826 --- /dev/null +++ b/str_chr.c | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | #include "str.h" | ||
| 2 | |||
| 3 | unsigned int str_chr(s,c) | ||
| 4 | register char *s; | ||
| 5 | int c; | ||
| 6 | { | ||
| 7 | register char ch; | ||
| 8 | register char *t; | ||
| 9 | |||
| 10 | ch = c; | ||
| 11 | t = s; | ||
| 12 | for (;;) { | ||
| 13 | if (!*t) break; if (*t == ch) break; ++t; | ||
| 14 | if (!*t) break; if (*t == ch) break; ++t; | ||
| 15 | if (!*t) break; if (*t == ch) break; ++t; | ||
| 16 | if (!*t) break; if (*t == ch) break; ++t; | ||
| 17 | } | ||
| 18 | return t - s; | ||
| 19 | } | ||
diff --git a/str_cpy.c b/str_cpy.c new file mode 100644 index 0000000..453d790 --- /dev/null +++ b/str_cpy.c | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #include "str.h" | ||
| 2 | |||
| 3 | unsigned int str_copy(s,t) | ||
| 4 | register char *s; | ||
| 5 | register char *t; | ||
| 6 | { | ||
| 7 | register int len; | ||
| 8 | |||
| 9 | len = 0; | ||
| 10 | for (;;) { | ||
| 11 | if (!(*s = *t)) return len; ++s; ++t; ++len; | ||
| 12 | if (!(*s = *t)) return len; ++s; ++t; ++len; | ||
| 13 | if (!(*s = *t)) return len; ++s; ++t; ++len; | ||
| 14 | if (!(*s = *t)) return len; ++s; ++t; ++len; | ||
| 15 | } | ||
| 16 | } | ||
diff --git a/str_diff.c b/str_diff.c new file mode 100644 index 0000000..18f8927 --- /dev/null +++ b/str_diff.c | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #include "str.h" | ||
| 2 | |||
| 3 | int str_diff(s,t) | ||
| 4 | register char *s; | ||
| 5 | register char *t; | ||
| 6 | { | ||
| 7 | register char x; | ||
| 8 | |||
| 9 | for (;;) { | ||
| 10 | x = *s; if (x != *t) break; if (!x) break; ++s; ++t; | ||
| 11 | x = *s; if (x != *t) break; if (!x) break; ++s; ++t; | ||
| 12 | x = *s; if (x != *t) break; if (!x) break; ++s; ++t; | ||
| 13 | x = *s; if (x != *t) break; if (!x) break; ++s; ++t; | ||
| 14 | } | ||
| 15 | return ((int)(unsigned int)(unsigned char) x) | ||
| 16 | - ((int)(unsigned int)(unsigned char) *t); | ||
| 17 | } | ||
diff --git a/str_diffn.c b/str_diffn.c new file mode 100644 index 0000000..89142f1 --- /dev/null +++ b/str_diffn.c | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | #include "str.h" | ||
| 2 | |||
| 3 | int str_diffn(s,t,len) | ||
| 4 | register char *s; | ||
| 5 | register char *t; | ||
| 6 | unsigned int len; | ||
| 7 | { | ||
| 8 | register char x; | ||
| 9 | |||
| 10 | for (;;) { | ||
| 11 | if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t; | ||
| 12 | if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t; | ||
| 13 | if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t; | ||
| 14 | if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t; | ||
| 15 | } | ||
| 16 | return ((int)(unsigned int)(unsigned char) x) | ||
| 17 | - ((int)(unsigned int)(unsigned char) *t); | ||
| 18 | } | ||
diff --git a/str_len.c b/str_len.c new file mode 100644 index 0000000..2d2f88b --- /dev/null +++ b/str_len.c | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #include "str.h" | ||
| 2 | |||
| 3 | unsigned int str_len(s) | ||
| 4 | register char *s; | ||
| 5 | { | ||
| 6 | register char *t; | ||
| 7 | |||
| 8 | t = s; | ||
| 9 | for (;;) { | ||
| 10 | if (!*t) return t - s; ++t; | ||
| 11 | if (!*t) return t - s; ++t; | ||
| 12 | if (!*t) return t - s; ++t; | ||
| 13 | if (!*t) return t - s; ++t; | ||
| 14 | } | ||
| 15 | } | ||
diff --git a/str_rchr.c b/str_rchr.c new file mode 100644 index 0000000..1bf19d3 --- /dev/null +++ b/str_rchr.c | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | #include "str.h" | ||
| 2 | |||
| 3 | unsigned int str_rchr(s,c) | ||
| 4 | register char *s; | ||
| 5 | int c; | ||
| 6 | { | ||
| 7 | register char ch; | ||
| 8 | register char *t; | ||
| 9 | register char *u; | ||
| 10 | |||
| 11 | ch = c; | ||
| 12 | t = s; | ||
| 13 | u = 0; | ||
| 14 | for (;;) { | ||
| 15 | if (!*t) break; if (*t == ch) u = t; ++t; | ||
| 16 | if (!*t) break; if (*t == ch) u = t; ++t; | ||
| 17 | if (!*t) break; if (*t == ch) u = t; ++t; | ||
| 18 | if (!*t) break; if (*t == ch) u = t; ++t; | ||
| 19 | } | ||
| 20 | if (!u) u = t; | ||
| 21 | return u - s; | ||
| 22 | } | ||
diff --git a/str_start.c b/str_start.c new file mode 100644 index 0000000..2750af8 --- /dev/null +++ b/str_start.c | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #include "str.h" | ||
| 2 | |||
| 3 | int str_start(s,t) | ||
| 4 | register char *s; | ||
| 5 | register char *t; | ||
| 6 | { | ||
| 7 | register char x; | ||
| 8 | |||
| 9 | for (;;) { | ||
| 10 | x = *t++; if (!x) return 1; if (x != *s++) return 0; | ||
| 11 | x = *t++; if (!x) return 1; if (x != *s++) return 0; | ||
| 12 | x = *t++; if (!x) return 1; if (x != *s++) return 0; | ||
| 13 | x = *t++; if (!x) return 1; if (x != *s++) return 0; | ||
| 14 | } | ||
| 15 | } | ||
diff --git a/stralloc.3 b/stralloc.3 new file mode 100644 index 0000000..3123521 --- /dev/null +++ b/stralloc.3 | |||
| @@ -0,0 +1,160 @@ | |||
| 1 | .TH stralloc 3 | ||
| 2 | .SH NAME | ||
| 3 | stralloc \- dynamically allocated strings | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <stralloc.h> | ||
| 6 | |||
| 7 | int \fBstralloc_ready\fP(&\fIsa\fR,\fIlen\fR); | ||
| 8 | .br | ||
| 9 | int \fBstralloc_readyplus\fP(&\fIsa\fR,\fIlen\fR); | ||
| 10 | |||
| 11 | int \fBstralloc_copy\fP(&\fIsa\fR,&\fIsa2\fR); | ||
| 12 | .br | ||
| 13 | int \fBstralloc_copys\fP(&\fIsa\fR,\fIbuf\fR); | ||
| 14 | .br | ||
| 15 | int \fBstralloc_copyb\fP(&\fIsa\fR,\fIbuf\fR,\fIlen\fR); | ||
| 16 | |||
| 17 | int \fBstralloc_cat\fP(&\fIsa\fR,&\fIsa2\fR); | ||
| 18 | .br | ||
| 19 | int \fBstralloc_cats\fP(&\fIsa\fR,\fIbuf\fR); | ||
| 20 | .br | ||
| 21 | int \fBstralloc_catb\fP(&\fIsa\fR,\fIbuf\fR,\fIlen\fR); | ||
| 22 | |||
| 23 | int \fBstralloc_append\fP(&\fIsa\fR,\fIbuf\fR); | ||
| 24 | .br | ||
| 25 | int \fBstralloc_0\fP(&\fIsa\fR); | ||
| 26 | |||
| 27 | int \fBstralloc_starts\fP(&\fIsa\fR,\fIbuf\fR); | ||
| 28 | |||
| 29 | stralloc \fIsa\fR = {0}; | ||
| 30 | .br | ||
| 31 | stralloc \fIsa2\fR = {0}; | ||
| 32 | .br | ||
| 33 | unsigned int \fIlen\fR; | ||
| 34 | .br | ||
| 35 | char *\fIbuf\fR; | ||
| 36 | .SH DESCRIPTION | ||
| 37 | A | ||
| 38 | .B stralloc | ||
| 39 | variable holds a string in dynamically allocated space. | ||
| 40 | String length is limited only by memory. | ||
| 41 | String contents are unrestricted. | ||
| 42 | |||
| 43 | The | ||
| 44 | .B stralloc | ||
| 45 | structure has three components: | ||
| 46 | .I sa\fB.s | ||
| 47 | is a pointer to the string, or 0 if it is not allocated; | ||
| 48 | .I sa\fB.len | ||
| 49 | is the number of bytes in the string, if it is allocated; | ||
| 50 | .I sa\fB.a | ||
| 51 | is the number of bytes allocated for the string, if it is allocated. | ||
| 52 | A | ||
| 53 | .B stralloc | ||
| 54 | variable should be initialized to {0}, | ||
| 55 | meaning unallocated. | ||
| 56 | |||
| 57 | .B stralloc_ready | ||
| 58 | makes sure that | ||
| 59 | .I sa | ||
| 60 | has enough space allocated for | ||
| 61 | .I len | ||
| 62 | characters. | ||
| 63 | It allocates extra space if necessary. | ||
| 64 | |||
| 65 | .B stralloc_readyplus | ||
| 66 | makes sure that | ||
| 67 | .I sa | ||
| 68 | has enough space allocated for | ||
| 69 | .I len | ||
| 70 | characters more than its current length. | ||
| 71 | If | ||
| 72 | .I sa | ||
| 73 | is unallocated, | ||
| 74 | .B stralloc_readyplus | ||
| 75 | is the same as | ||
| 76 | .BR stralloc_ready . | ||
| 77 | |||
| 78 | .B stralloc_copy | ||
| 79 | copies | ||
| 80 | .I sa2 | ||
| 81 | to | ||
| 82 | .IR sa , | ||
| 83 | allocating space if necessary. | ||
| 84 | Here | ||
| 85 | .I sa2 | ||
| 86 | is an allocated | ||
| 87 | .B stralloc | ||
| 88 | variable. | ||
| 89 | |||
| 90 | .B stralloc_copys | ||
| 91 | copies a 0-terminated string, | ||
| 92 | .IR buf , | ||
| 93 | to | ||
| 94 | .IR sa , | ||
| 95 | without the 0. | ||
| 96 | |||
| 97 | .B stralloc_copyb | ||
| 98 | copies | ||
| 99 | .I len | ||
| 100 | characters from | ||
| 101 | .I buf | ||
| 102 | to | ||
| 103 | .IR sa . | ||
| 104 | |||
| 105 | .B stralloc_cat | ||
| 106 | appends | ||
| 107 | .I sa2 | ||
| 108 | to | ||
| 109 | .IR sa , | ||
| 110 | allocating space if necessary. | ||
| 111 | If | ||
| 112 | .I sa | ||
| 113 | is unallocated, | ||
| 114 | .B stralloc_cat | ||
| 115 | is the same as | ||
| 116 | .BR stralloc_copy . | ||
| 117 | |||
| 118 | .B stralloc_cats | ||
| 119 | and | ||
| 120 | .B stralloc_catb | ||
| 121 | are analogous to | ||
| 122 | .B stralloc_copys | ||
| 123 | and | ||
| 124 | .BR stralloc_copyb . | ||
| 125 | |||
| 126 | .B stralloc_append | ||
| 127 | adds a single character, | ||
| 128 | .IR *buf , | ||
| 129 | to | ||
| 130 | .IR sa , | ||
| 131 | allocating space if necessary. | ||
| 132 | |||
| 133 | .B stralloc_0 | ||
| 134 | adds a single 0 character | ||
| 135 | to | ||
| 136 | .IR sa . | ||
| 137 | |||
| 138 | .B stralloc_starts | ||
| 139 | returns 1 if the 0-terminated string | ||
| 140 | .IR buf , | ||
| 141 | without the 0, | ||
| 142 | is a prefix of | ||
| 143 | .IR sa . | ||
| 144 | .SH "ERROR HANDLING" | ||
| 145 | If a | ||
| 146 | .B stralloc | ||
| 147 | routine runs out of memory, | ||
| 148 | it leaves | ||
| 149 | .I sa | ||
| 150 | alone and returns 0, | ||
| 151 | setting | ||
| 152 | .B errno | ||
| 153 | appropriately. | ||
| 154 | On success it returns 1; | ||
| 155 | this guarantees that | ||
| 156 | .I sa | ||
| 157 | is allocated. | ||
| 158 | .SH "SEE ALSO" | ||
| 159 | alloc(3), | ||
| 160 | error(3) | ||
diff --git a/stralloc.h b/stralloc.h new file mode 100644 index 0000000..fca496c --- /dev/null +++ b/stralloc.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | #ifndef STRALLOC_H | ||
| 2 | #define STRALLOC_H | ||
| 3 | |||
| 4 | #include "gen_alloc.h" | ||
| 5 | |||
| 6 | GEN_ALLOC_typedef(stralloc,char,s,len,a) | ||
| 7 | |||
| 8 | extern int stralloc_ready(); | ||
| 9 | extern int stralloc_readyplus(); | ||
| 10 | extern int stralloc_copy(); | ||
| 11 | extern int stralloc_cat(); | ||
| 12 | extern int stralloc_copys(); | ||
| 13 | extern int stralloc_cats(); | ||
| 14 | extern int stralloc_copyb(); | ||
| 15 | extern int stralloc_catb(); | ||
| 16 | extern int stralloc_append(); /* beware: this takes a pointer to 1 char */ | ||
| 17 | extern int stralloc_starts(); | ||
| 18 | |||
| 19 | #define stralloc_0(sa) stralloc_append(sa,"") | ||
| 20 | |||
| 21 | #endif | ||
diff --git a/stralloc_arts.c b/stralloc_arts.c new file mode 100644 index 0000000..1ccb5a4 --- /dev/null +++ b/stralloc_arts.c | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #include "byte.h" | ||
| 2 | #include "str.h" | ||
| 3 | #include "stralloc.h" | ||
| 4 | |||
| 5 | int stralloc_starts(sa,s) | ||
| 6 | stralloc *sa; | ||
| 7 | char *s; | ||
| 8 | { | ||
| 9 | int len; | ||
| 10 | len = str_len(s); | ||
| 11 | return (sa->len >= len) && byte_equal(s,len,sa->s); | ||
| 12 | } | ||
diff --git a/stralloc_cat.c b/stralloc_cat.c new file mode 100644 index 0000000..efbb112 --- /dev/null +++ b/stralloc_cat.c | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #include "byte.h" | ||
| 2 | #include "stralloc.h" | ||
| 3 | |||
| 4 | int stralloc_cat(sato,safrom) | ||
| 5 | stralloc *sato; | ||
| 6 | stralloc *safrom; | ||
| 7 | { | ||
| 8 | return stralloc_catb(sato,safrom->s,safrom->len); | ||
| 9 | } | ||
diff --git a/stralloc_catb.c b/stralloc_catb.c new file mode 100644 index 0000000..67dbcc0 --- /dev/null +++ b/stralloc_catb.c | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #include "stralloc.h" | ||
| 2 | #include "byte.h" | ||
| 3 | |||
| 4 | int stralloc_catb(sa,s,n) | ||
| 5 | stralloc *sa; | ||
| 6 | char *s; | ||
| 7 | unsigned int n; | ||
| 8 | { | ||
| 9 | if (!sa->s) return stralloc_copyb(sa,s,n); | ||
| 10 | if (!stralloc_readyplus(sa,n + 1)) return 0; | ||
| 11 | byte_copy(sa->s + sa->len,n,s); | ||
| 12 | sa->len += n; | ||
| 13 | sa->s[sa->len] = 'Z'; /* ``offensive programming'' */ | ||
| 14 | return 1; | ||
| 15 | } | ||
diff --git a/stralloc_cats.c b/stralloc_cats.c new file mode 100644 index 0000000..d300286 --- /dev/null +++ b/stralloc_cats.c | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #include "byte.h" | ||
| 2 | #include "str.h" | ||
| 3 | #include "stralloc.h" | ||
| 4 | |||
| 5 | int stralloc_cats(sa,s) | ||
| 6 | stralloc *sa; | ||
| 7 | char *s; | ||
| 8 | { | ||
| 9 | return stralloc_catb(sa,s,str_len(s)); | ||
| 10 | } | ||
diff --git a/stralloc_copy.c b/stralloc_copy.c new file mode 100644 index 0000000..652aed6 --- /dev/null +++ b/stralloc_copy.c | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #include "byte.h" | ||
| 2 | #include "stralloc.h" | ||
| 3 | |||
| 4 | int stralloc_copy(sato,safrom) | ||
| 5 | stralloc *sato; | ||
| 6 | stralloc *safrom; | ||
| 7 | { | ||
| 8 | return stralloc_copyb(sato,safrom->s,safrom->len); | ||
| 9 | } | ||
diff --git a/stralloc_eady.c b/stralloc_eady.c new file mode 100644 index 0000000..3a31f4b --- /dev/null +++ b/stralloc_eady.c | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #include "alloc.h" | ||
| 2 | #include "stralloc.h" | ||
| 3 | #include "gen_allocdefs.h" | ||
| 4 | |||
| 5 | GEN_ALLOC_ready(stralloc,char,s,len,a,i,n,x,30,stralloc_ready) | ||
| 6 | GEN_ALLOC_readyplus(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus) | ||
diff --git a/stralloc_opyb.c b/stralloc_opyb.c new file mode 100644 index 0000000..ac258b3 --- /dev/null +++ b/stralloc_opyb.c | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | #include "stralloc.h" | ||
| 2 | #include "byte.h" | ||
| 3 | |||
| 4 | int stralloc_copyb(sa,s,n) | ||
| 5 | stralloc *sa; | ||
| 6 | char *s; | ||
| 7 | unsigned int n; | ||
| 8 | { | ||
| 9 | if (!stralloc_ready(sa,n + 1)) return 0; | ||
| 10 | byte_copy(sa->s,n,s); | ||
| 11 | sa->len = n; | ||
| 12 | sa->s[n] = 'Z'; /* ``offensive programming'' */ | ||
| 13 | return 1; | ||
| 14 | } | ||
diff --git a/stralloc_opys.c b/stralloc_opys.c new file mode 100644 index 0000000..fdd7807 --- /dev/null +++ b/stralloc_opys.c | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #include "byte.h" | ||
| 2 | #include "str.h" | ||
| 3 | #include "stralloc.h" | ||
| 4 | |||
| 5 | int stralloc_copys(sa,s) | ||
| 6 | stralloc *sa; | ||
| 7 | char *s; | ||
| 8 | { | ||
| 9 | return stralloc_copyb(sa,s,str_len(s)); | ||
| 10 | } | ||
diff --git a/stralloc_pend.c b/stralloc_pend.c new file mode 100644 index 0000000..a3443b8 --- /dev/null +++ b/stralloc_pend.c | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | #include "alloc.h" | ||
| 2 | #include "stralloc.h" | ||
| 3 | #include "gen_allocdefs.h" | ||
| 4 | |||
| 5 | GEN_ALLOC_append(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus,stralloc_append) | ||
diff --git a/strerr.h b/strerr.h new file mode 100644 index 0000000..d18e833 --- /dev/null +++ b/strerr.h | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | #ifndef STRERR_H | ||
| 2 | #define STRERR_H | ||
| 3 | |||
| 4 | struct strerr | ||
| 5 | { | ||
| 6 | struct strerr *who; | ||
| 7 | char *x; | ||
| 8 | char *y; | ||
| 9 | char *z; | ||
| 10 | } | ||
| 11 | ; | ||
| 12 | |||
| 13 | extern struct strerr strerr_sys; | ||
| 14 | extern void strerr_sysinit(); | ||
| 15 | |||
| 16 | extern char *strerr(); | ||
| 17 | extern void strerr_warn(); | ||
| 18 | extern void strerr_die(); | ||
| 19 | |||
| 20 | #define STRERR(r,se,a) \ | ||
| 21 | { se.who = 0; se.x = a; se.y = 0; se.z = 0; return r; } | ||
| 22 | |||
| 23 | #define STRERR_SYS(r,se,a) \ | ||
| 24 | { se.who = &strerr_sys; se.x = a; se.y = 0; se.z = 0; return r; } | ||
| 25 | #define STRERR_SYS3(r,se,a,b,c) \ | ||
| 26 | { se.who = &strerr_sys; se.x = a; se.y = b; se.z = c; return r; } | ||
| 27 | |||
| 28 | #define strerr_warn6(x1,x2,x3,x4,x5,x6,se) \ | ||
| 29 | strerr_warn((x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) (se)) | ||
| 30 | #define strerr_warn5(x1,x2,x3,x4,x5,se) \ | ||
| 31 | strerr_warn((x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) (se)) | ||
| 32 | #define strerr_warn4(x1,x2,x3,x4,se) \ | ||
| 33 | strerr_warn((x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) (se)) | ||
| 34 | #define strerr_warn3(x1,x2,x3,se) \ | ||
| 35 | strerr_warn((x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) | ||
| 36 | #define strerr_warn2(x1,x2,se) \ | ||
| 37 | strerr_warn((x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) | ||
| 38 | #define strerr_warn1(x1,se) \ | ||
| 39 | strerr_warn((x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) | ||
| 40 | |||
| 41 | #define strerr_die6(e,x1,x2,x3,x4,x5,x6,se) \ | ||
| 42 | strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) (se)) | ||
| 43 | #define strerr_die5(e,x1,x2,x3,x4,x5,se) \ | ||
| 44 | strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) (se)) | ||
| 45 | #define strerr_die4(e,x1,x2,x3,x4,se) \ | ||
| 46 | strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) (se)) | ||
| 47 | #define strerr_die3(e,x1,x2,x3,se) \ | ||
| 48 | strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) | ||
| 49 | #define strerr_die2(e,x1,x2,se) \ | ||
| 50 | strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) | ||
| 51 | #define strerr_die1(e,x1,se) \ | ||
| 52 | strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) | ||
| 53 | |||
| 54 | #define strerr_die6sys(e,x1,x2,x3,x4,x5,x6) \ | ||
| 55 | strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),&strerr_sys) | ||
| 56 | #define strerr_die5sys(e,x1,x2,x3,x4,x5) \ | ||
| 57 | strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,&strerr_sys) | ||
| 58 | #define strerr_die4sys(e,x1,x2,x3,x4) \ | ||
| 59 | strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,&strerr_sys) | ||
| 60 | #define strerr_die3sys(e,x1,x2,x3) \ | ||
| 61 | strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,&strerr_sys) | ||
| 62 | #define strerr_die2sys(e,x1,x2) \ | ||
| 63 | strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,&strerr_sys) | ||
| 64 | #define strerr_die1sys(e,x1) \ | ||
| 65 | strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,&strerr_sys) | ||
| 66 | |||
| 67 | #define strerr_die6x(e,x1,x2,x3,x4,x5,x6) \ | ||
| 68 | strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) 0) | ||
| 69 | #define strerr_die5x(e,x1,x2,x3,x4,x5) \ | ||
| 70 | strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) 0) | ||
| 71 | #define strerr_die4x(e,x1,x2,x3,x4) \ | ||
| 72 | strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) 0) | ||
| 73 | #define strerr_die3x(e,x1,x2,x3) \ | ||
| 74 | strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0) | ||
| 75 | #define strerr_die2x(e,x1,x2) \ | ||
| 76 | strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0) | ||
| 77 | #define strerr_die1x(e,x1) \ | ||
| 78 | strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0) | ||
| 79 | |||
| 80 | #endif | ||
diff --git a/strerr_die.c b/strerr_die.c new file mode 100644 index 0000000..6092020 --- /dev/null +++ b/strerr_die.c | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "subfd.h" | ||
| 3 | #include "exit.h" | ||
| 4 | #include "strerr.h" | ||
| 5 | |||
| 6 | void strerr_warn(x1,x2,x3,x4,x5,x6,se) | ||
| 7 | char *x1; char *x2; char *x3; char *x4; char *x5; char *x6; | ||
| 8 | struct strerr *se; | ||
| 9 | { | ||
| 10 | strerr_sysinit(); | ||
| 11 | |||
| 12 | if (x1) substdio_puts(subfderr,x1); | ||
| 13 | if (x2) substdio_puts(subfderr,x2); | ||
| 14 | if (x3) substdio_puts(subfderr,x3); | ||
| 15 | if (x4) substdio_puts(subfderr,x4); | ||
| 16 | if (x5) substdio_puts(subfderr,x5); | ||
| 17 | if (x6) substdio_puts(subfderr,x6); | ||
| 18 | |||
| 19 | while(se) { | ||
| 20 | if (se->x) substdio_puts(subfderr,se->x); | ||
| 21 | if (se->y) substdio_puts(subfderr,se->y); | ||
| 22 | if (se->z) substdio_puts(subfderr,se->z); | ||
| 23 | se = se->who; | ||
| 24 | } | ||
| 25 | |||
| 26 | substdio_puts(subfderr,"\n"); | ||
| 27 | substdio_flush(subfderr); | ||
| 28 | } | ||
| 29 | |||
| 30 | void strerr_die(e,x1,x2,x3,x4,x5,x6,se) | ||
| 31 | int e; | ||
| 32 | char *x1; char *x2; char *x3; char *x4; char *x5; char *x6; | ||
| 33 | struct strerr *se; | ||
| 34 | { | ||
| 35 | strerr_warn(x1,x2,x3,x4,x5,x6,se); | ||
| 36 | _exit(e); | ||
| 37 | } | ||
diff --git a/strerr_sys.c b/strerr_sys.c new file mode 100644 index 0000000..198198b --- /dev/null +++ b/strerr_sys.c | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #include "error.h" | ||
| 2 | #include "strerr.h" | ||
| 3 | |||
| 4 | struct strerr strerr_sys; | ||
| 5 | |||
| 6 | void strerr_sysinit() | ||
| 7 | { | ||
| 8 | strerr_sys.who = 0; | ||
| 9 | strerr_sys.x = error_str(errno); | ||
| 10 | strerr_sys.y = ""; | ||
| 11 | strerr_sys.z = ""; | ||
| 12 | } | ||
| @@ -0,0 +1,15 @@ | |||
| 1 | #ifndef SUBFD_H | ||
| 2 | #define SUBFD_H | ||
| 3 | |||
| 4 | #include "substdio.h" | ||
| 5 | |||
| 6 | extern substdio *subfdin; | ||
| 7 | extern substdio *subfdinsmall; | ||
| 8 | extern substdio *subfdout; | ||
| 9 | extern substdio *subfdoutsmall; | ||
| 10 | extern substdio *subfderr; | ||
| 11 | |||
| 12 | extern int subfd_read(); | ||
| 13 | extern int subfd_readsmall(); | ||
| 14 | |||
| 15 | #endif | ||
diff --git a/subfderr.c b/subfderr.c new file mode 100644 index 0000000..011ab0f --- /dev/null +++ b/subfderr.c | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #include "readwrite.h" | ||
| 2 | #include "substdio.h" | ||
| 3 | #include "subfd.h" | ||
| 4 | |||
| 5 | char subfd_errbuf[256]; | ||
| 6 | static substdio it = SUBSTDIO_FDBUF(write,2,subfd_errbuf,256); | ||
| 7 | substdio *subfderr = ⁢ | ||
diff --git a/subfdin.c b/subfdin.c new file mode 100644 index 0000000..a11d323 --- /dev/null +++ b/subfdin.c | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | #include "readwrite.h" | ||
| 2 | #include "substdio.h" | ||
| 3 | #include "subfd.h" | ||
| 4 | |||
| 5 | int subfd_read(fd,buf,len) int fd; char *buf; int len; | ||
| 6 | { | ||
| 7 | if (substdio_flush(subfdout) == -1) return -1; | ||
| 8 | return read(fd,buf,len); | ||
| 9 | } | ||
| 10 | |||
| 11 | char subfd_inbuf[SUBSTDIO_INSIZE]; | ||
| 12 | static substdio it = SUBSTDIO_FDBUF(subfd_read,0,subfd_inbuf,SUBSTDIO_INSIZE); | ||
| 13 | substdio *subfdin = ⁢ | ||
diff --git a/subfdins.c b/subfdins.c new file mode 100644 index 0000000..36983ac --- /dev/null +++ b/subfdins.c | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | #include "readwrite.h" | ||
| 2 | #include "substdio.h" | ||
| 3 | #include "subfd.h" | ||
| 4 | |||
| 5 | int subfd_readsmall(fd,buf,len) int fd; char *buf; int len; | ||
| 6 | { | ||
| 7 | if (substdio_flush(subfdoutsmall) == -1) return -1; | ||
| 8 | return read(fd,buf,len); | ||
| 9 | } | ||
| 10 | |||
| 11 | char subfd_inbufsmall[256]; | ||
| 12 | static substdio it = SUBSTDIO_FDBUF(subfd_readsmall,0,subfd_inbufsmall,256); | ||
| 13 | substdio *subfdinsmall = ⁢ | ||
diff --git a/subfdout.c b/subfdout.c new file mode 100644 index 0000000..0aee102 --- /dev/null +++ b/subfdout.c | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #include "readwrite.h" | ||
| 2 | #include "substdio.h" | ||
| 3 | #include "subfd.h" | ||
| 4 | |||
| 5 | char subfd_outbuf[SUBSTDIO_OUTSIZE]; | ||
| 6 | static substdio it = SUBSTDIO_FDBUF(write,1,subfd_outbuf,SUBSTDIO_OUTSIZE); | ||
| 7 | substdio *subfdout = ⁢ | ||
diff --git a/subfdouts.c b/subfdouts.c new file mode 100644 index 0000000..5be356d --- /dev/null +++ b/subfdouts.c | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #include "readwrite.h" | ||
| 2 | #include "substdio.h" | ||
| 3 | #include "subfd.h" | ||
| 4 | |||
| 5 | char subfd_outbufsmall[256]; | ||
| 6 | static substdio it = SUBSTDIO_FDBUF(write,1,subfd_outbufsmall,256); | ||
| 7 | substdio *subfdoutsmall = ⁢ | ||
diff --git a/subgetopt.3 b/subgetopt.3 new file mode 100644 index 0000000..aae03aa --- /dev/null +++ b/subgetopt.3 | |||
| @@ -0,0 +1,357 @@ | |||
| 1 | .TH subgetopt 3 | ||
| 2 | .SH NAME | ||
| 3 | subgetopt \- get option character from command line | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <subgetopt.h> | ||
| 6 | |||
| 7 | char *\fBsgoptarg\fP; | ||
| 8 | .br | ||
| 9 | int \fBsgoptind\fP; | ||
| 10 | .br | ||
| 11 | int \fBsgoptpos\fP; | ||
| 12 | .br | ||
| 13 | int \fBsgoptdone\fP; | ||
| 14 | .br | ||
| 15 | int \fBsgoptproblem\fP; | ||
| 16 | |||
| 17 | int \fBsgopt(\fP\fIargc,argv,opts\fR\fB)\fP; | ||
| 18 | |||
| 19 | int \fIargc\fR; | ||
| 20 | .br | ||
| 21 | char **\fIargv\fR; | ||
| 22 | .br | ||
| 23 | char *\fIopts\fR; | ||
| 24 | .SH DESCRIPTION | ||
| 25 | .B sgopt | ||
| 26 | returns the next valid command-line option character | ||
| 27 | from | ||
| 28 | .IR argv . | ||
| 29 | |||
| 30 | Valid option characters are listed in the | ||
| 31 | .I opts | ||
| 32 | string. | ||
| 33 | .I opts | ||
| 34 | may be empty. | ||
| 35 | A character in | ||
| 36 | .I opts | ||
| 37 | may be followed by a colon, | ||
| 38 | in which case it | ||
| 39 | takes an | ||
| 40 | .I option argument\fR. | ||
| 41 | Avoid using the characters ?, :, and \- as option characters. | ||
| 42 | |||
| 43 | Below | ||
| 44 | .I option argument | ||
| 45 | is abbreviated | ||
| 46 | as | ||
| 47 | .I optarg | ||
| 48 | and | ||
| 49 | .I command-line argument | ||
| 50 | is abbreviated as | ||
| 51 | .IR cmdarg . | ||
| 52 | |||
| 53 | Options are listed in cmdargs which begin with | ||
| 54 | a minus sign. | ||
| 55 | Several options which do not take optargs may be combined | ||
| 56 | into one cmdarg. | ||
| 57 | |||
| 58 | An option which takes an optarg may be handled in two ways. | ||
| 59 | If it appears at the very end of a cmdarg, | ||
| 60 | then the entire next cmdarg is the optarg. | ||
| 61 | But if there are any characters in the cmdarg | ||
| 62 | after the option character, | ||
| 63 | then those characters form the optarg. | ||
| 64 | The optarg is returned in | ||
| 65 | .BR sgoptarg . | ||
| 66 | Next time | ||
| 67 | .B sgopt | ||
| 68 | looks at the cmdarg which follows the optarg. | ||
| 69 | |||
| 70 | If a cmdarg does not begin with a hyphen, | ||
| 71 | or if it is a lone hyphen not followed by any characters, | ||
| 72 | or if it begins with two hyphens, | ||
| 73 | then it terminates option processing, | ||
| 74 | and | ||
| 75 | .B sgopt | ||
| 76 | returns an appropriate code. | ||
| 77 | If there are two hyphens, | ||
| 78 | .B sgopt | ||
| 79 | will advance attention to the next cmdarg, | ||
| 80 | so it can be called again to read further options. | ||
| 81 | .SH "PROPER USAGE" | ||
| 82 | .B sgoptproblem | ||
| 83 | should be used only when | ||
| 84 | .B sgopt | ||
| 85 | returns ?. | ||
| 86 | .B sgoptind | ||
| 87 | and | ||
| 88 | .B sgoptpos | ||
| 89 | are defined all the time. | ||
| 90 | .B sgoptarg | ||
| 91 | is defined all the time; | ||
| 92 | it is null unless | ||
| 93 | .B sgopt | ||
| 94 | has just returned an option with optarg. | ||
| 95 | |||
| 96 | .B sgopt | ||
| 97 | is typically used as follows. | ||
| 98 | |||
| 99 | .EX | ||
| 100 | #include <subgetopt.h> | ||
| 101 | |||
| 102 | main(argc,argv) int argc; char **argv; { int opt; | ||
| 103 | |||
| 104 | while ((opt = sgopt(argc,argv,"a:s")) != sgoptdone) | ||
| 105 | .br | ||
| 106 | switch(opt) { | ||
| 107 | .br | ||
| 108 | case 'a': | ||
| 109 | .br | ||
| 110 | printf("opt a with optarg %s\\n",sgoptarg); break; | ||
| 111 | .br | ||
| 112 | case 's': | ||
| 113 | .br | ||
| 114 | printf("opt s with no optarg\\n"); break; | ||
| 115 | .br | ||
| 116 | case '?': | ||
| 117 | .br | ||
| 118 | if (argv[sgoptind] && (sgoptind < argc)) | ||
| 119 | .br | ||
| 120 | printf("illegal opt %c\\n",sgoptproblem); | ||
| 121 | .br | ||
| 122 | else | ||
| 123 | .br | ||
| 124 | printf("missing arg, opt %c\\n",sgoptproblem); | ||
| 125 | .br | ||
| 126 | exit(1); | ||
| 127 | .br | ||
| 128 | } | ||
| 129 | |||
| 130 | argv += sgoptind; | ||
| 131 | .br | ||
| 132 | while (*argv) printf("argument %s\\n",*argv++); | ||
| 133 | .br | ||
| 134 | exit(0); | ||
| 135 | .br | ||
| 136 | } | ||
| 137 | .EE | ||
| 138 | |||
| 139 | The end of the command line is | ||
| 140 | marked by either | ||
| 141 | .IR argc , | ||
| 142 | or a null pointer in | ||
| 143 | .IR argv , | ||
| 144 | whichever comes first. | ||
| 145 | Normally | ||
| 146 | these two markers coincide, | ||
| 147 | so it is redundant | ||
| 148 | to test for | ||
| 149 | both | ||
| 150 | .I argv\fB[sgoptind] | ||
| 151 | and | ||
| 152 | .B sgoptind < \fIargc\fR. | ||
| 153 | The above code shows both tests as an illustration. | ||
| 154 | |||
| 155 | .B Multiple option sets: | ||
| 156 | One useful technique is to call | ||
| 157 | .B sgopt | ||
| 158 | with a primary | ||
| 159 | .I opts | ||
| 160 | until it returns EOF, | ||
| 161 | then call | ||
| 162 | .B sgopt | ||
| 163 | with a secondary | ||
| 164 | .I opts | ||
| 165 | until it returns EOF. | ||
| 166 | The user can provide primary options, then a double hyphen, | ||
| 167 | and then secondary options. | ||
| 168 | No special handling is needed if some or all of the options are | ||
| 169 | omitted. | ||
| 170 | The same technique can be used for any number of option sets | ||
| 171 | in series. | ||
| 172 | |||
| 173 | .B Multiple command lines: | ||
| 174 | Before parsing a new | ||
| 175 | .BR argv , | ||
| 176 | make sure to | ||
| 177 | set | ||
| 178 | .B sgoptind | ||
| 179 | and | ||
| 180 | .B sgoptpos | ||
| 181 | back to | ||
| 182 | 1 and 0. | ||
| 183 | .SH "PARSING STAGES" | ||
| 184 | .B sgopt | ||
| 185 | keeps track of its position in | ||
| 186 | .I argv | ||
| 187 | with | ||
| 188 | .B sgoptind | ||
| 189 | and | ||
| 190 | .BR sgoptpos , | ||
| 191 | which are initialized to 1 and 0. | ||
| 192 | It looks at | ||
| 193 | .I argv\fB[sgoptind][sgoptpos] | ||
| 194 | and following characters. | ||
| 195 | |||
| 196 | .B sgopt | ||
| 197 | indicates | ||
| 198 | that no more options are available by | ||
| 199 | returning | ||
| 200 | .BR sgoptdone , | ||
| 201 | which is initialized to | ||
| 202 | .BR SUBGETOPTDONE , | ||
| 203 | which is defined as \-1. | ||
| 204 | |||
| 205 | .B sgopt | ||
| 206 | begins by setting | ||
| 207 | .B optarg | ||
| 208 | to null. | ||
| 209 | |||
| 210 | .B Ending conditions: | ||
| 211 | If | ||
| 212 | .I argv | ||
| 213 | is null, or | ||
| 214 | .B sgoptind | ||
| 215 | is larger than | ||
| 216 | .IR argc , | ||
| 217 | or the current cmdarg | ||
| 218 | .I argv\fB[sgoptind] | ||
| 219 | is null, | ||
| 220 | then | ||
| 221 | .B sgopt | ||
| 222 | returns | ||
| 223 | .BR optdone . | ||
| 224 | |||
| 225 | .B Stage one: | ||
| 226 | If the current character | ||
| 227 | is zero, | ||
| 228 | .B sgopt | ||
| 229 | moves to the beginning of the next cmdarg. | ||
| 230 | It then checks the ending conditions again. | ||
| 231 | |||
| 232 | .B Stage two: | ||
| 233 | If | ||
| 234 | the current position is the begining of the cmdarg, | ||
| 235 | .B sgopt | ||
| 236 | checks whether | ||
| 237 | the current character | ||
| 238 | is a minus sign. | ||
| 239 | If not it returns | ||
| 240 | .BR optdone . | ||
| 241 | It then | ||
| 242 | moves | ||
| 243 | to the next character. | ||
| 244 | If that character is zero, | ||
| 245 | .B sgopt | ||
| 246 | moves | ||
| 247 | back to the beginning of the cmdarg, | ||
| 248 | and returns | ||
| 249 | .BR sgoptdone . | ||
| 250 | If the character is a minus sign, | ||
| 251 | .B sgopt | ||
| 252 | moves to the beginning of the next cmdarg, | ||
| 253 | and returns | ||
| 254 | .BR sgoptdone . | ||
| 255 | |||
| 256 | .B Stage three: | ||
| 257 | .B sgopt | ||
| 258 | records the current character, | ||
| 259 | .IR c , | ||
| 260 | and moves to the next character. | ||
| 261 | There are three possibilities: | ||
| 262 | (1) | ||
| 263 | .I c | ||
| 264 | is an option character without optarg in | ||
| 265 | .IR opts , | ||
| 266 | or | ||
| 267 | (2) | ||
| 268 | .I c | ||
| 269 | is an option character with optarg in | ||
| 270 | .IR opts , | ||
| 271 | or | ||
| 272 | (3) | ||
| 273 | .I c | ||
| 274 | does not appear in | ||
| 275 | .IR opts . | ||
| 276 | |||
| 277 | (1) | ||
| 278 | If | ||
| 279 | .I c | ||
| 280 | appears as an option character without optarg in | ||
| 281 | .IR opts , | ||
| 282 | .B sgopt | ||
| 283 | returns | ||
| 284 | .IR c . | ||
| 285 | |||
| 286 | (2) | ||
| 287 | If | ||
| 288 | .I c | ||
| 289 | appears as an option character with optarg in | ||
| 290 | .IR opts , | ||
| 291 | .B sgopt | ||
| 292 | sets | ||
| 293 | .B sgoptarg | ||
| 294 | to the current position, | ||
| 295 | and moves to the next cmdarg. | ||
| 296 | If | ||
| 297 | .B sgoptarg | ||
| 298 | is nonempty, | ||
| 299 | .B sgopt | ||
| 300 | returns | ||
| 301 | .IR c . | ||
| 302 | |||
| 303 | Then | ||
| 304 | .B sgopt | ||
| 305 | sets | ||
| 306 | .B sgoptarg | ||
| 307 | to | ||
| 308 | the current cmdarg. | ||
| 309 | If | ||
| 310 | the current cmdarg is null, | ||
| 311 | or past | ||
| 312 | .IR argc , | ||
| 313 | .B sgopt | ||
| 314 | sets | ||
| 315 | .B sgoptproblem | ||
| 316 | to | ||
| 317 | .I c | ||
| 318 | and returns ?. | ||
| 319 | Otherwise | ||
| 320 | .B sgopt | ||
| 321 | moves to the next | ||
| 322 | argument | ||
| 323 | and returns | ||
| 324 | .IR c . | ||
| 325 | |||
| 326 | (2) | ||
| 327 | If | ||
| 328 | .I c | ||
| 329 | does not appear in | ||
| 330 | .IR opts , | ||
| 331 | .B sgopt | ||
| 332 | sets | ||
| 333 | .B sgoptproblem | ||
| 334 | to | ||
| 335 | .I c | ||
| 336 | and returns ?. | ||
| 337 | .SH "SYNTAX NOTE" | ||
| 338 | .B sgopt | ||
| 339 | is actually a macro abbreviation for | ||
| 340 | .BR subgetopt . | ||
| 341 | The external | ||
| 342 | .B sg | ||
| 343 | variables are also macros | ||
| 344 | for | ||
| 345 | .BR subget . | ||
| 346 | These macros are defined in | ||
| 347 | .BR <subgetopt.h> , | ||
| 348 | unless | ||
| 349 | .B SUBGETOPTNOSHORT | ||
| 350 | is defined | ||
| 351 | when | ||
| 352 | .B <subgetopt.h> | ||
| 353 | is included. | ||
| 354 | .SH VERSION | ||
| 355 | subgetopt version 0.9, 931129. | ||
| 356 | .SH AUTHOR | ||
| 357 | Placed into the public domain by Daniel J. Bernstein. | ||
diff --git a/subgetopt.c b/subgetopt.c new file mode 100644 index 0000000..dacf376 --- /dev/null +++ b/subgetopt.c | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | /* subgetopt.c, subgetopt.h: (yet another) improved getopt clone, inner layer | ||
| 2 | D. J. Bernstein, djb@pobox.com. | ||
| 3 | No dependencies. | ||
| 4 | No system requirements. | ||
| 5 | 19970228: Cleanups. | ||
| 6 | 931129: Adapted from getopt.c. | ||
| 7 | No known patent problems. | ||
| 8 | |||
| 9 | Documentation in subgetopt.3. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #define SUBGETOPTNOSHORT | ||
| 13 | #include "subgetopt.h" | ||
| 14 | |||
| 15 | #define sgopt subgetopt | ||
| 16 | #define optind subgetoptind | ||
| 17 | #define optpos subgetoptpos | ||
| 18 | #define optarg subgetoptarg | ||
| 19 | #define optproblem subgetoptproblem | ||
| 20 | #define optdone subgetoptdone | ||
| 21 | |||
| 22 | int optind = 1; | ||
| 23 | int optpos = 0; | ||
| 24 | char *optarg = 0; | ||
| 25 | int optproblem = 0; | ||
| 26 | int optdone = SUBGETOPTDONE; | ||
| 27 | |||
| 28 | int sgopt(argc,argv,opts) | ||
| 29 | int argc; | ||
| 30 | char **argv; | ||
| 31 | char *opts; | ||
| 32 | { | ||
| 33 | int c; | ||
| 34 | char *s; | ||
| 35 | |||
| 36 | optarg = 0; | ||
| 37 | if (!argv || (optind >= argc) || !argv[optind]) return optdone; | ||
| 38 | if (optpos && !argv[optind][optpos]) { | ||
| 39 | ++optind; | ||
| 40 | optpos = 0; | ||
| 41 | if ((optind >= argc) || !argv[optind]) return optdone; | ||
| 42 | } | ||
| 43 | if (!optpos) { | ||
| 44 | if (argv[optind][0] != '-') return optdone; | ||
| 45 | ++optpos; | ||
| 46 | c = argv[optind][1]; | ||
| 47 | if ((c == '-') || (c == 0)) { | ||
| 48 | if (c) ++optind; | ||
| 49 | optpos = 0; | ||
| 50 | return optdone; | ||
| 51 | } | ||
| 52 | /* otherwise c is reassigned below */ | ||
| 53 | } | ||
| 54 | c = argv[optind][optpos]; | ||
| 55 | ++optpos; | ||
| 56 | s = opts; | ||
| 57 | while (*s) { | ||
| 58 | if (c == *s) { | ||
| 59 | if (s[1] == ':') { | ||
| 60 | optarg = argv[optind] + optpos; | ||
| 61 | ++optind; | ||
| 62 | optpos = 0; | ||
| 63 | if (!*optarg) { | ||
| 64 | optarg = argv[optind]; | ||
| 65 | if ((optind >= argc) || !optarg) { /* argument past end */ | ||
| 66 | optproblem = c; | ||
| 67 | return '?'; | ||
| 68 | } | ||
| 69 | ++optind; | ||
| 70 | } | ||
| 71 | } | ||
| 72 | return c; | ||
| 73 | } | ||
| 74 | ++s; | ||
| 75 | if (*s == ':') ++s; | ||
| 76 | } | ||
| 77 | optproblem = c; | ||
| 78 | return '?'; | ||
| 79 | } | ||
diff --git a/subgetopt.h b/subgetopt.h new file mode 100644 index 0000000..d26c62a --- /dev/null +++ b/subgetopt.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | #ifndef SUBGETOPT_H | ||
| 2 | #define SUBGETOPT_H | ||
| 3 | |||
| 4 | #ifndef SUBGETOPTNOSHORT | ||
| 5 | #define sgopt subgetopt | ||
| 6 | #define sgoptarg subgetoptarg | ||
| 7 | #define sgoptind subgetoptind | ||
| 8 | #define sgoptpos subgetoptpos | ||
| 9 | #define sgoptproblem subgetoptproblem | ||
| 10 | #define sgoptprogname subgetoptprogname | ||
| 11 | #define sgoptdone subgetoptdone | ||
| 12 | #endif | ||
| 13 | |||
| 14 | #define SUBGETOPTDONE -1 | ||
| 15 | |||
| 16 | extern int subgetopt(); | ||
| 17 | extern char *subgetoptarg; | ||
| 18 | extern int subgetoptind; | ||
| 19 | extern int subgetoptpos; | ||
| 20 | extern int subgetoptproblem; | ||
| 21 | extern char *subgetoptprogname; | ||
| 22 | extern int subgetoptdone; | ||
| 23 | |||
| 24 | #endif | ||
diff --git a/substdi.c b/substdi.c new file mode 100644 index 0000000..42407a1 --- /dev/null +++ b/substdi.c | |||
| @@ -0,0 +1,91 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "byte.h" | ||
| 3 | #include "error.h" | ||
| 4 | |||
| 5 | static int oneread(op,fd,buf,len) | ||
| 6 | register int (*op)(); | ||
| 7 | register int fd; | ||
| 8 | register char *buf; | ||
| 9 | register int len; | ||
| 10 | { | ||
| 11 | register int r; | ||
| 12 | |||
| 13 | for (;;) { | ||
| 14 | r = op(fd,buf,len); | ||
| 15 | if (r == -1) if (errno == error_intr) continue; | ||
| 16 | return r; | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | static int getthis(s,buf,len) | ||
| 21 | register substdio *s; | ||
| 22 | register char *buf; | ||
| 23 | register int len; | ||
| 24 | { | ||
| 25 | register int r; | ||
| 26 | register int q; | ||
| 27 | |||
| 28 | r = s->p; | ||
| 29 | q = r - len; | ||
| 30 | if (q > 0) { r = len; s->p = q; } else s->p = 0; | ||
| 31 | byte_copy(buf,r,s->x + s->n); | ||
| 32 | s->n += r; | ||
| 33 | return r; | ||
| 34 | } | ||
| 35 | |||
| 36 | int substdio_feed(s) | ||
| 37 | register substdio *s; | ||
| 38 | { | ||
| 39 | register int r; | ||
| 40 | register int q; | ||
| 41 | |||
| 42 | if (s->p) return s->p; | ||
| 43 | q = s->n; | ||
| 44 | r = oneread(s->op,s->fd,s->x,q); | ||
| 45 | if (r <= 0) return r; | ||
| 46 | s->p = r; | ||
| 47 | q -= r; | ||
| 48 | s->n = q; | ||
| 49 | if (q > 0) /* damn, gotta shift */ byte_copyr(s->x + q,r,s->x); | ||
| 50 | return r; | ||
| 51 | } | ||
| 52 | |||
| 53 | int substdio_bget(s,buf,len) | ||
| 54 | register substdio *s; | ||
| 55 | register char *buf; | ||
| 56 | register int len; | ||
| 57 | { | ||
| 58 | register int r; | ||
| 59 | |||
| 60 | if (s->p > 0) return getthis(s,buf,len); | ||
| 61 | r = s->n; if (r <= len) return oneread(s->op,s->fd,buf,r); | ||
| 62 | r = substdio_feed(s); if (r <= 0) return r; | ||
| 63 | return getthis(s,buf,len); | ||
| 64 | } | ||
| 65 | |||
| 66 | int substdio_get(s,buf,len) | ||
| 67 | register substdio *s; | ||
| 68 | register char *buf; | ||
| 69 | register int len; | ||
| 70 | { | ||
| 71 | register int r; | ||
| 72 | |||
| 73 | if (s->p > 0) return getthis(s,buf,len); | ||
| 74 | if (s->n <= len) return oneread(s->op,s->fd,buf,len); | ||
| 75 | r = substdio_feed(s); if (r <= 0) return r; | ||
| 76 | return getthis(s,buf,len); | ||
| 77 | } | ||
| 78 | |||
| 79 | char *substdio_peek(s) | ||
| 80 | register substdio *s; | ||
| 81 | { | ||
| 82 | return s->x + s->n; | ||
| 83 | } | ||
| 84 | |||
| 85 | void substdio_seek(s,len) | ||
| 86 | register substdio *s; | ||
| 87 | register int len; | ||
| 88 | { | ||
| 89 | s->n += len; | ||
| 90 | s->p -= len; | ||
| 91 | } | ||
diff --git a/substdio.c b/substdio.c new file mode 100644 index 0000000..d03dff2 --- /dev/null +++ b/substdio.c | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | |||
| 3 | void substdio_fdbuf(s,op,fd,buf,len) | ||
| 4 | register substdio *s; | ||
| 5 | register int (*op)(); | ||
| 6 | register int fd; | ||
| 7 | register char *buf; | ||
| 8 | register int len; | ||
| 9 | { | ||
| 10 | s->x = buf; | ||
| 11 | s->fd = fd; | ||
| 12 | s->op = op; | ||
| 13 | s->p = 0; | ||
| 14 | s->n = len; | ||
| 15 | } | ||
diff --git a/substdio.h b/substdio.h new file mode 100644 index 0000000..c3f7f7d --- /dev/null +++ b/substdio.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | #ifndef SUBSTDIO_H | ||
| 2 | #define SUBSTDIO_H | ||
| 3 | |||
| 4 | typedef struct substdio { | ||
| 5 | char *x; | ||
| 6 | int p; | ||
| 7 | int n; | ||
| 8 | int fd; | ||
| 9 | int (*op)(); | ||
| 10 | } substdio; | ||
| 11 | |||
| 12 | #define SUBSTDIO_FDBUF(op,fd,buf,len) { (buf), 0, (len), (fd), (op) } | ||
| 13 | |||
| 14 | extern void substdio_fdbuf(); | ||
| 15 | |||
| 16 | extern int substdio_flush(); | ||
| 17 | extern int substdio_put(); | ||
| 18 | extern int substdio_bput(); | ||
| 19 | extern int substdio_putflush(); | ||
| 20 | extern int substdio_puts(); | ||
| 21 | extern int substdio_bputs(); | ||
| 22 | extern int substdio_putsflush(); | ||
| 23 | |||
| 24 | extern int substdio_get(); | ||
| 25 | extern int substdio_bget(); | ||
| 26 | extern int substdio_feed(); | ||
| 27 | |||
| 28 | extern char *substdio_peek(); | ||
| 29 | extern void substdio_seek(); | ||
| 30 | |||
| 31 | #define substdio_fileno(s) ((s)->fd) | ||
| 32 | |||
| 33 | #define SUBSTDIO_INSIZE 8192 | ||
| 34 | #define SUBSTDIO_OUTSIZE 8192 | ||
| 35 | |||
| 36 | #define substdio_PEEK(s) ( (s)->x + (s)->n ) | ||
| 37 | #define substdio_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) ) | ||
| 38 | |||
| 39 | #define substdio_BPUTC(s,c) \ | ||
| 40 | ( ((s)->n != (s)->p) \ | ||
| 41 | ? ( (s)->x[(s)->p++] = (c), 0 ) \ | ||
| 42 | : substdio_bput((s),&(c),1) \ | ||
| 43 | ) | ||
| 44 | |||
| 45 | extern int substdio_copy(); | ||
| 46 | |||
| 47 | #endif | ||
diff --git a/substdio_copy.c b/substdio_copy.c new file mode 100644 index 0000000..71cf200 --- /dev/null +++ b/substdio_copy.c | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | |||
| 3 | int substdio_copy(ssout,ssin) | ||
| 4 | register substdio *ssout; | ||
| 5 | register substdio *ssin; | ||
| 6 | { | ||
| 7 | register int n; | ||
| 8 | register char *x; | ||
| 9 | |||
| 10 | for (;;) { | ||
| 11 | n = substdio_feed(ssin); | ||
| 12 | if (n < 0) return -2; | ||
| 13 | if (!n) return 0; | ||
| 14 | x = substdio_PEEK(ssin); | ||
| 15 | if (substdio_put(ssout,x,n) == -1) return -3; | ||
| 16 | substdio_SEEK(ssin,n); | ||
| 17 | } | ||
| 18 | } | ||
diff --git a/substdo.c b/substdo.c new file mode 100644 index 0000000..fb616f7 --- /dev/null +++ b/substdo.c | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | #include "substdio.h" | ||
| 2 | #include "str.h" | ||
| 3 | #include "byte.h" | ||
| 4 | #include "error.h" | ||
| 5 | |||
| 6 | static int allwrite(op,fd,buf,len) | ||
| 7 | register int (*op)(); | ||
| 8 | register int fd; | ||
| 9 | register char *buf; | ||
| 10 | register int len; | ||
| 11 | { | ||
| 12 | register int w; | ||
| 13 | |||
| 14 | while (len) { | ||
| 15 | w = op(fd,buf,len); | ||
| 16 | if (w == -1) { | ||
| 17 | if (errno == error_intr) continue; | ||
| 18 | return -1; /* note that some data may have been written */ | ||
| 19 | } | ||
| 20 | if (w == 0) ; /* luser's fault */ | ||
| 21 | buf += w; | ||
| 22 | len -= w; | ||
| 23 | } | ||
| 24 | return 0; | ||
| 25 | } | ||
| 26 | |||
| 27 | int substdio_flush(s) | ||
| 28 | register substdio *s; | ||
| 29 | { | ||
| 30 | register int p; | ||
| 31 | |||
| 32 | p = s->p; | ||
| 33 | if (!p) return 0; | ||
| 34 | s->p = 0; | ||
| 35 | return allwrite(s->op,s->fd,s->x,p); | ||
| 36 | } | ||
| 37 | |||
| 38 | int substdio_bput(s,buf,len) | ||
| 39 | register substdio *s; | ||
| 40 | register char *buf; | ||
| 41 | register int len; | ||
| 42 | { | ||
| 43 | register int n; | ||
| 44 | |||
| 45 | while (len > (n = s->n - s->p)) { | ||
| 46 | byte_copy(s->x + s->p,n,buf); s->p += n; buf += n; len -= n; | ||
| 47 | if (substdio_flush(s) == -1) return -1; | ||
| 48 | } | ||
| 49 | /* now len <= s->n - s->p */ | ||
| 50 | byte_copy(s->x + s->p,len,buf); | ||
| 51 | s->p += len; | ||
| 52 | return 0; | ||
| 53 | } | ||
| 54 | |||
| 55 | int substdio_put(s,buf,len) | ||
| 56 | register substdio *s; | ||
| 57 | register char *buf; | ||
| 58 | register int len; | ||
| 59 | { | ||
| 60 | register int n; | ||
| 61 | |||
| 62 | n = s->n; | ||
| 63 | if (len > n - s->p) { | ||
| 64 | if (substdio_flush(s) == -1) return -1; | ||
| 65 | /* now s->p == 0 */ | ||
| 66 | if (n < SUBSTDIO_OUTSIZE) n = SUBSTDIO_OUTSIZE; | ||
| 67 | while (len > s->n) { | ||
| 68 | if (n > len) n = len; | ||
| 69 | if (allwrite(s->op,s->fd,buf,n) == -1) return -1; | ||
| 70 | buf += n; | ||
| 71 | len -= n; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | /* now len <= s->n - s->p */ | ||
| 75 | byte_copy(s->x + s->p,len,buf); | ||
| 76 | s->p += len; | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | int substdio_putflush(s,buf,len) | ||
| 81 | register substdio *s; | ||
| 82 | register char *buf; | ||
| 83 | register int len; | ||
| 84 | { | ||
| 85 | if (substdio_flush(s) == -1) return -1; | ||
| 86 | return allwrite(s->op,s->fd,buf,len); | ||
| 87 | } | ||
| 88 | |||
| 89 | int substdio_bputs(s,buf) | ||
| 90 | register substdio *s; | ||
| 91 | register char *buf; | ||
| 92 | { | ||
| 93 | return substdio_bput(s,buf,str_len(buf)); | ||
| 94 | } | ||
| 95 | |||
| 96 | int substdio_puts(s,buf) | ||
| 97 | register substdio *s; | ||
| 98 | register char *buf; | ||
| 99 | { | ||
| 100 | return substdio_put(s,buf,str_len(buf)); | ||
| 101 | } | ||
| 102 | |||
| 103 | int substdio_putsflush(s,buf) | ||
| 104 | register substdio *s; | ||
| 105 | register char *buf; | ||
| 106 | { | ||
| 107 | return substdio_putflush(s,buf,str_len(buf)); | ||
| 108 | } | ||
diff --git a/tcp-env.1 b/tcp-env.1 new file mode 100644 index 0000000..edd46f2 --- /dev/null +++ b/tcp-env.1 | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | .TH tcp-env 1 | ||
| 2 | .SH NAME | ||
| 3 | tcp-env \- set up TCP-related environment variables | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B tcp-env | ||
| 6 | [ | ||
| 7 | .B \-rR | ||
| 8 | ] | ||
| 9 | [ | ||
| 10 | .B \-t\fItimeout | ||
| 11 | ] | ||
| 12 | .I program | ||
| 13 | [ | ||
| 14 | .I arg ... | ||
| 15 | ] | ||
| 16 | .SH DESCRIPTION | ||
| 17 | The input for | ||
| 18 | .B tcp-env | ||
| 19 | must be a TCP connection. | ||
| 20 | .B tcp-env | ||
| 21 | finds out information about that connection, | ||
| 22 | puts the information into several environment variables | ||
| 23 | as described in | ||
| 24 | .B tcp-environ(5), | ||
| 25 | and runs | ||
| 26 | .I program | ||
| 27 | with the given arguments. | ||
| 28 | |||
| 29 | Usually | ||
| 30 | .B tcp-env | ||
| 31 | is run from | ||
| 32 | .BR inetd . | ||
| 33 | It might instead be run from another server | ||
| 34 | that already sets up the right environment variables; | ||
| 35 | if | ||
| 36 | .B PROTO | ||
| 37 | is set to | ||
| 38 | .B TCP | ||
| 39 | when | ||
| 40 | .B tcp-env | ||
| 41 | is invoked, | ||
| 42 | .B tcp-env | ||
| 43 | assumes that all the other variables are set up properly, | ||
| 44 | and it does not check whether the input is a TCP connection. | ||
| 45 | .SH OPTIONS | ||
| 46 | .TP | ||
| 47 | .B \-r | ||
| 48 | (Default.) | ||
| 49 | Attempt to obtain | ||
| 50 | .B TCPREMOTEINFO | ||
| 51 | from the remote host. | ||
| 52 | .TP | ||
| 53 | .B \-R | ||
| 54 | Do not attempt to obtain | ||
| 55 | .B TCPREMOTEINFO | ||
| 56 | from the remote host. | ||
| 57 | .TP | ||
| 58 | .B \-t\fItimeout | ||
| 59 | Give up on the | ||
| 60 | .B TCPREMOTEINFO | ||
| 61 | connection attempt after | ||
| 62 | .I timeout | ||
| 63 | seconds. | ||
| 64 | Default: 30. | ||
| 65 | .SH "SEE ALSO" | ||
| 66 | tcp-environ(5), | ||
| 67 | inetd(8) | ||
diff --git a/tcp-env.c b/tcp-env.c new file mode 100644 index 0000000..feb85cc --- /dev/null +++ b/tcp-env.c | |||
| @@ -0,0 +1,129 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/socket.h> | ||
| 3 | #include <sys/param.h> | ||
| 4 | #include <netinet/in.h> | ||
| 5 | #include "sig.h" | ||
| 6 | #include "stralloc.h" | ||
| 7 | #include "str.h" | ||
| 8 | #include "env.h" | ||
| 9 | #include "fmt.h" | ||
| 10 | #include "scan.h" | ||
| 11 | #include "subgetopt.h" | ||
| 12 | #include "ip.h" | ||
| 13 | #include "dns.h" | ||
| 14 | #include "byte.h" | ||
| 15 | #include "remoteinfo.h" | ||
| 16 | #include "exit.h" | ||
| 17 | #include "case.h" | ||
| 18 | |||
| 19 | void die() { _exit(111); } | ||
| 20 | |||
| 21 | struct sockaddr_in salocal; | ||
| 22 | unsigned long localport; | ||
| 23 | struct ip_address iplocal; | ||
| 24 | stralloc localname = {0}; | ||
| 25 | |||
| 26 | struct sockaddr_in saremote; | ||
| 27 | unsigned long remoteport; | ||
| 28 | struct ip_address ipremote; | ||
| 29 | stralloc remotename = {0}; | ||
| 30 | |||
| 31 | char temp[IPFMT + FMT_ULONG]; | ||
| 32 | |||
| 33 | void main(argc,argv) | ||
| 34 | int argc; | ||
| 35 | char *argv[]; | ||
| 36 | { | ||
| 37 | int dummy; | ||
| 38 | char *proto; | ||
| 39 | int opt; | ||
| 40 | int flagremoteinfo; | ||
| 41 | unsigned long timeout; | ||
| 42 | |||
| 43 | sig_pipeignore(); | ||
| 44 | |||
| 45 | flagremoteinfo = 1; | ||
| 46 | timeout = 30; | ||
| 47 | while ((opt = sgopt(argc,argv,"rRt:")) != sgoptdone) | ||
| 48 | switch(opt) | ||
| 49 | { | ||
| 50 | case 'r': flagremoteinfo = 1; break; | ||
| 51 | case 'R': flagremoteinfo = 0; break; | ||
| 52 | case 't': scan_ulong(sgoptarg,&timeout); break; | ||
| 53 | } | ||
| 54 | |||
| 55 | argv += sgoptind; | ||
| 56 | argc -= sgoptind; | ||
| 57 | |||
| 58 | if (argc < 1) die(); | ||
| 59 | if (!env_init()) die(); | ||
| 60 | |||
| 61 | proto = env_get("PROTO"); | ||
| 62 | if (!proto || str_diff(proto,"TCP")) | ||
| 63 | { | ||
| 64 | if (!env_put("PROTO=TCP")) die(); | ||
| 65 | |||
| 66 | dummy = sizeof(salocal); | ||
| 67 | if (getsockname(0,(struct sockaddr *) &salocal,&dummy) == -1) die(); | ||
| 68 | |||
| 69 | localport = ntohs(salocal.sin_port); | ||
| 70 | temp[fmt_ulong(temp,localport)] = 0; | ||
| 71 | if (!env_put2("TCPLOCALPORT",temp)) die(); | ||
| 72 | |||
| 73 | byte_copy(&iplocal,4,&salocal.sin_addr); | ||
| 74 | temp[ip_fmt(temp,&iplocal)] = 0; | ||
| 75 | if (!env_put2("TCPLOCALIP",temp)) die(); | ||
| 76 | |||
| 77 | switch(dns_ptr(&localname,&iplocal)) | ||
| 78 | { | ||
| 79 | case DNS_MEM: die(); | ||
| 80 | case DNS_SOFT: | ||
| 81 | if (!stralloc_copys(&localname,"softdnserror")) die(); | ||
| 82 | case 0: | ||
| 83 | if (!stralloc_0(&localname)) die(); | ||
| 84 | case_lowers(localname.s); | ||
| 85 | if (!env_put2("TCPLOCALHOST",localname.s)) die(); | ||
| 86 | break; | ||
| 87 | default: | ||
| 88 | if (!env_unset("TCPLOCALHOST")) die(); | ||
| 89 | } | ||
| 90 | |||
| 91 | dummy = sizeof(saremote); | ||
| 92 | if (getpeername(0,(struct sockaddr *) &saremote,&dummy) == -1) die(); | ||
| 93 | |||
| 94 | remoteport = ntohs(saremote.sin_port); | ||
| 95 | temp[fmt_ulong(temp,remoteport)] = 0; | ||
| 96 | if (!env_put2("TCPREMOTEPORT",temp)) die(); | ||
| 97 | |||
| 98 | byte_copy(&ipremote,4,&saremote.sin_addr); | ||
| 99 | temp[ip_fmt(temp,&ipremote)] = 0; | ||
| 100 | if (!env_put2("TCPREMOTEIP",temp)) die(); | ||
| 101 | |||
| 102 | switch(dns_ptr(&remotename,&ipremote)) | ||
| 103 | { | ||
| 104 | case DNS_MEM: die(); | ||
| 105 | case DNS_SOFT: | ||
| 106 | if (!stralloc_copys(&remotename,"softdnserror")) die(); | ||
| 107 | case 0: | ||
| 108 | if (!stralloc_0(&remotename)) die(); | ||
| 109 | case_lowers(remotename.s); | ||
| 110 | if (!env_put2("TCPREMOTEHOST",remotename.s)) die(); | ||
| 111 | break; | ||
| 112 | default: | ||
| 113 | if (!env_unset("TCPREMOTEHOST")) die(); | ||
| 114 | } | ||
| 115 | |||
| 116 | if (!env_unset("TCPREMOTEINFO")) die(); | ||
| 117 | if (flagremoteinfo) | ||
| 118 | { | ||
| 119 | char *rinfo; | ||
| 120 | rinfo = remoteinfo_get(&ipremote,remoteport,&iplocal,localport,(int) timeout); | ||
| 121 | if (rinfo) | ||
| 122 | if (!env_put2("TCPREMOTEINFO",rinfo)) die(); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | sig_pipedefault(); | ||
| 127 | execvp(*argv,argv); | ||
| 128 | die(); | ||
| 129 | } | ||
diff --git a/tcp-environ.5 b/tcp-environ.5 new file mode 100644 index 0000000..b5cb83b --- /dev/null +++ b/tcp-environ.5 | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | .TH tcp-environ 5 | ||
| 2 | .SH NAME | ||
| 3 | tcp-environ \- TCP-related environment variables | ||
| 4 | .SH DESCRIPTION | ||
| 5 | The following environment variables | ||
| 6 | describe a TCP connection. | ||
| 7 | They are set up by | ||
| 8 | .BR tcp-env , | ||
| 9 | .BR tcpclient , | ||
| 10 | and | ||
| 11 | .BR tcpserver . | ||
| 12 | Note that | ||
| 13 | .BR TCPLOCALHOST , | ||
| 14 | .BR TCPREMOTEHOST , | ||
| 15 | and | ||
| 16 | .B TCPREMOTEINFO | ||
| 17 | can contain arbitrary characters. | ||
| 18 | .TP 5 | ||
| 19 | PROTO | ||
| 20 | The string | ||
| 21 | .BR TCP . | ||
| 22 | .TP 5 | ||
| 23 | TCPLOCALHOST | ||
| 24 | The domain name of the local host, | ||
| 25 | with uppercase letters converted to lowercase. | ||
| 26 | If there is no currently available domain name | ||
| 27 | for the local IP address, | ||
| 28 | .B TCPLOCALHOST | ||
| 29 | is not set. | ||
| 30 | .TP 5 | ||
| 31 | TCPLOCALIP | ||
| 32 | The IP address of the local host, in dotted-decimal form. | ||
| 33 | .TP 5 | ||
| 34 | TCPLOCALPORT | ||
| 35 | The local TCP port number, in decimal. | ||
| 36 | .TP 5 | ||
| 37 | TCPREMOTEHOST | ||
| 38 | The domain name of the remote host, | ||
| 39 | with uppercase letters converted to lowercase. | ||
| 40 | If there is no currently available domain name | ||
| 41 | for the remote IP address, | ||
| 42 | .B TCPREMOTEHOST | ||
| 43 | is not set. | ||
| 44 | .TP 5 | ||
| 45 | TCPREMOTEINFO | ||
| 46 | A connection-specific string, perhaps a username, | ||
| 47 | supplied by the remote host | ||
| 48 | via 931/1413/IDENT/TAP. | ||
| 49 | If the remote host did not supply connection information, | ||
| 50 | .B TCPREMOTEINFO | ||
| 51 | is not set. | ||
| 52 | .TP 5 | ||
| 53 | TCPREMOTEIP | ||
| 54 | The IP address of the remote host. | ||
| 55 | .TP 5 | ||
| 56 | TCPREMOTEPORT | ||
| 57 | The remote TCP port number. | ||
| 58 | .SH "SEE ALSO" | ||
| 59 | tcpclient(1), | ||
| 60 | tcpserver(1), | ||
| 61 | tcp-env(1), | ||
| 62 | tcp(4) | ||
| @@ -0,0 +1,165 @@ | |||
| 1 | #include "tcpto.h" | ||
| 2 | #include "open.h" | ||
| 3 | #include "lock.h" | ||
| 4 | #include "seek.h" | ||
| 5 | #include "now.h" | ||
| 6 | #include "ip.h" | ||
| 7 | #include "byte.h" | ||
| 8 | #include "datetime.h" | ||
| 9 | #include "readwrite.h" | ||
| 10 | |||
| 11 | char tcpto_buf[1024]; | ||
| 12 | |||
| 13 | static int flagwasthere; | ||
| 14 | static int fdlock; | ||
| 15 | |||
| 16 | static int getbuf() | ||
| 17 | { | ||
| 18 | int r; | ||
| 19 | int fd; | ||
| 20 | |||
| 21 | fdlock = open_write("queue/lock/tcpto"); | ||
| 22 | if (fdlock == -1) return 0; | ||
| 23 | fd = open_read("queue/lock/tcpto"); | ||
| 24 | if (fd == -1) { close(fdlock); return 0; } | ||
| 25 | if (lock_ex(fdlock) == -1) { close(fdlock); close(fd); return 0; } | ||
| 26 | r = read(fd,tcpto_buf,sizeof(tcpto_buf)); | ||
| 27 | close(fd); | ||
| 28 | if (r < 0) { close(fdlock); return 0; } | ||
| 29 | r >>= 4; | ||
| 30 | if (!r) close(fdlock); | ||
| 31 | return r; | ||
| 32 | } | ||
| 33 | |||
| 34 | int tcpto(ip) struct ip_address *ip; | ||
| 35 | { | ||
| 36 | int n; | ||
| 37 | int i; | ||
| 38 | char *record; | ||
| 39 | datetime_sec when; | ||
| 40 | |||
| 41 | flagwasthere = 0; | ||
| 42 | |||
| 43 | n = getbuf(); | ||
| 44 | if (!n) return 0; | ||
| 45 | close(fdlock); | ||
| 46 | |||
| 47 | record = tcpto_buf; | ||
| 48 | for (i = 0;i < n;++i) | ||
| 49 | { | ||
| 50 | if (byte_equal(ip->d,4,record)) | ||
| 51 | { | ||
| 52 | flagwasthere = 1; | ||
| 53 | if (record[4] >= 2) | ||
| 54 | { | ||
| 55 | when = (unsigned long) (unsigned char) record[11]; | ||
| 56 | when = (when << 8) + (unsigned long) (unsigned char) record[10]; | ||
| 57 | when = (when << 8) + (unsigned long) (unsigned char) record[9]; | ||
| 58 | when = (when << 8) + (unsigned long) (unsigned char) record[8]; | ||
| 59 | |||
| 60 | if (now() - when < ((60 + (getpid() & 31)) << 6)) | ||
| 61 | return 1; | ||
| 62 | } | ||
| 63 | return 0; | ||
| 64 | } | ||
| 65 | record += 16; | ||
| 66 | } | ||
| 67 | return 0; | ||
| 68 | } | ||
| 69 | |||
| 70 | void tcpto_err(ip,flagerr) struct ip_address *ip; int flagerr; | ||
| 71 | { | ||
| 72 | int n; | ||
| 73 | int i; | ||
| 74 | char *record; | ||
| 75 | datetime_sec when; | ||
| 76 | datetime_sec firstwhen; | ||
| 77 | int firstpos; | ||
| 78 | datetime_sec lastwhen; | ||
| 79 | |||
| 80 | if (!flagerr) | ||
| 81 | if (!flagwasthere) | ||
| 82 | return; /* could have been added, but not worth the effort to check */ | ||
| 83 | |||
| 84 | n = getbuf(); | ||
| 85 | if (!n) return; | ||
| 86 | |||
| 87 | record = tcpto_buf; | ||
| 88 | for (i = 0;i < n;++i) | ||
| 89 | { | ||
| 90 | if (byte_equal(ip->d,4,record)) | ||
| 91 | { | ||
| 92 | if (!flagerr) | ||
| 93 | record[4] = 0; | ||
| 94 | else | ||
| 95 | { | ||
| 96 | lastwhen = (unsigned long) (unsigned char) record[11]; | ||
| 97 | lastwhen = (lastwhen << 8) + (unsigned long) (unsigned char) record[10]; | ||
| 98 | lastwhen = (lastwhen << 8) + (unsigned long) (unsigned char) record[9]; | ||
| 99 | lastwhen = (lastwhen << 8) + (unsigned long) (unsigned char) record[8]; | ||
| 100 | when = now(); | ||
| 101 | |||
| 102 | if (record[4] && (when < 120 + lastwhen)) { close(fdlock); return; } | ||
| 103 | |||
| 104 | if (++record[4] > 10) record[4] = 10; | ||
| 105 | record[8] = when; when >>= 8; | ||
| 106 | record[9] = when; when >>= 8; | ||
| 107 | record[10] = when; when >>= 8; | ||
| 108 | record[11] = when; | ||
| 109 | } | ||
| 110 | if (seek_set(fdlock,i << 4) == 0) | ||
| 111 | if (write(fdlock,record,16) < 16) | ||
| 112 | ; /*XXX*/ | ||
| 113 | close(fdlock); | ||
| 114 | return; | ||
| 115 | } | ||
| 116 | record += 16; | ||
| 117 | } | ||
| 118 | |||
| 119 | if (!flagerr) { close(fdlock); return; } | ||
| 120 | |||
| 121 | record = tcpto_buf; | ||
| 122 | for (i = 0;i < n;++i) | ||
| 123 | { | ||
| 124 | if (!record[4]) break; | ||
| 125 | record += 16; | ||
| 126 | } | ||
| 127 | |||
| 128 | if (i >= n) | ||
| 129 | { | ||
| 130 | firstpos = -1; | ||
| 131 | record = tcpto_buf; | ||
| 132 | for (i = 0;i < n;++i) | ||
| 133 | { | ||
| 134 | when = (unsigned long) (unsigned char) record[11]; | ||
| 135 | when = (when << 8) + (unsigned long) (unsigned char) record[10]; | ||
| 136 | when = (when << 8) + (unsigned long) (unsigned char) record[9]; | ||
| 137 | when = (when << 8) + (unsigned long) (unsigned char) record[8]; | ||
| 138 | when += (record[4] << 10); | ||
| 139 | if ((firstpos < 0) || (when < firstwhen)) | ||
| 140 | { | ||
| 141 | firstpos = i; | ||
| 142 | firstwhen = when; | ||
| 143 | } | ||
| 144 | record += 16; | ||
| 145 | } | ||
| 146 | i = firstpos; | ||
| 147 | } | ||
| 148 | |||
| 149 | if (i >= 0) | ||
| 150 | { | ||
| 151 | record = tcpto_buf + (i << 4); | ||
| 152 | byte_copy(record,4,ip->d); | ||
| 153 | when = now(); | ||
| 154 | record[8] = when; when >>= 8; | ||
| 155 | record[9] = when; when >>= 8; | ||
| 156 | record[10] = when; when >>= 8; | ||
| 157 | record[11] = when; | ||
| 158 | record[4] = 1; | ||
| 159 | if (seek_set(fdlock,i << 4) == 0) | ||
| 160 | if (write(fdlock,record,16) < 16) | ||
| 161 | ; /*XXX*/ | ||
| 162 | } | ||
| 163 | |||
| 164 | close(fdlock); | ||
| 165 | } | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef TCPTO_H | ||
| 2 | #define TCPTO_H | ||
| 3 | |||
| 4 | extern int tcpto(); | ||
| 5 | extern void tcpto_err(); | ||
| 6 | extern void tcpto_clean(); | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/tcpto_clean.c b/tcpto_clean.c new file mode 100644 index 0000000..ed48506 --- /dev/null +++ b/tcpto_clean.c | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | #include "tcpto.h" | ||
| 2 | #include "open.h" | ||
| 3 | #include "substdio.h" | ||
| 4 | #include "readwrite.h" | ||
| 5 | |||
| 6 | char tcpto_cleanbuf[1024]; | ||
| 7 | |||
| 8 | void tcpto_clean() /* running from queue/mess */ | ||
| 9 | { | ||
| 10 | int fd; | ||
| 11 | int i; | ||
| 12 | substdio ss; | ||
| 13 | |||
| 14 | fd = open_write("../lock/tcpto"); | ||
| 15 | if (fd == -1) return; | ||
| 16 | substdio_fdbuf(&ss,write,fd,tcpto_cleanbuf,sizeof(tcpto_cleanbuf)); | ||
| 17 | for (i = 0;i < sizeof(tcpto_cleanbuf);++i) substdio_put(&ss,"",1); | ||
| 18 | substdio_flush(&ss); /* if it fails, bummer */ | ||
| 19 | close(fd); | ||
| 20 | } | ||
diff --git a/timeoutconn.c b/timeoutconn.c new file mode 100644 index 0000000..33a16d9 --- /dev/null +++ b/timeoutconn.c | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/socket.h> | ||
| 3 | #include <netinet/in.h> | ||
| 4 | #include <arpa/inet.h> | ||
| 5 | #include "ndelay.h" | ||
| 6 | #include "select.h" | ||
| 7 | #include "error.h" | ||
| 8 | #include "readwrite.h" | ||
| 9 | #include "ip.h" | ||
| 10 | #include "byte.h" | ||
| 11 | #include "timeoutconn.h" | ||
| 12 | |||
| 13 | int timeoutconn(s,ip,port,timeout) | ||
| 14 | int s; | ||
| 15 | struct ip_address *ip; | ||
| 16 | unsigned int port; | ||
| 17 | int timeout; | ||
| 18 | { | ||
| 19 | char ch; | ||
| 20 | struct sockaddr_in sin; | ||
| 21 | char *x; | ||
| 22 | fd_set wfds; | ||
| 23 | struct timeval tv; | ||
| 24 | |||
| 25 | byte_zero(&sin,sizeof(sin)); | ||
| 26 | byte_copy(&sin.sin_addr,4,ip); | ||
| 27 | x = (char *) &sin.sin_port; | ||
| 28 | x[1] = port; port >>= 8; x[0] = port; | ||
| 29 | sin.sin_family = AF_INET; | ||
| 30 | |||
| 31 | if (ndelay_on(s) == -1) return -1; | ||
| 32 | |||
| 33 | /* XXX: could bind s */ | ||
| 34 | |||
| 35 | if (connect(s,(struct sockaddr *) &sin,sizeof(sin)) == 0) { | ||
| 36 | ndelay_off(s); | ||
| 37 | return 0; | ||
| 38 | } | ||
| 39 | if ((errno != error_inprogress) && (errno != error_wouldblock)) return -1; | ||
| 40 | |||
| 41 | FD_ZERO(&wfds); | ||
| 42 | FD_SET(s,&wfds); | ||
| 43 | tv.tv_sec = timeout; tv.tv_usec = 0; | ||
| 44 | |||
| 45 | if (select(s + 1,(fd_set *) 0,&wfds,(fd_set *) 0,&tv) == -1) return -1; | ||
| 46 | if (FD_ISSET(s,&wfds)) { | ||
| 47 | int dummy; | ||
| 48 | dummy = sizeof(sin); | ||
| 49 | if (getpeername(s,(struct sockaddr *) &sin,&dummy) == -1) { | ||
| 50 | read(s,&ch,1); | ||
| 51 | return -1; | ||
| 52 | } | ||
| 53 | ndelay_off(s); | ||
| 54 | return 0; | ||
| 55 | } | ||
| 56 | |||
| 57 | errno = error_timeout; /* note that connect attempt is continuing */ | ||
| 58 | return -1; | ||
| 59 | } | ||
diff --git a/timeoutconn.h b/timeoutconn.h new file mode 100644 index 0000000..88aab06 --- /dev/null +++ b/timeoutconn.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef TIMEOUTCONN_H | ||
| 2 | #define TIMEOUTCONN_H | ||
| 3 | |||
| 4 | extern int timeoutconn(); | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/timeoutread.c b/timeoutread.c new file mode 100644 index 0000000..c75e29c --- /dev/null +++ b/timeoutread.c | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | #include "timeoutread.h" | ||
| 2 | #include "select.h" | ||
| 3 | #include "error.h" | ||
| 4 | #include "readwrite.h" | ||
| 5 | |||
| 6 | int timeoutread(t,fd,buf,len) int t; int fd; char *buf; int len; | ||
| 7 | { | ||
| 8 | fd_set rfds; | ||
| 9 | struct timeval tv; | ||
| 10 | |||
| 11 | tv.tv_sec = t; | ||
| 12 | tv.tv_usec = 0; | ||
| 13 | |||
| 14 | FD_ZERO(&rfds); | ||
| 15 | FD_SET(fd,&rfds); | ||
| 16 | |||
| 17 | if (select(fd + 1,&rfds,(fd_set *) 0,(fd_set *) 0,&tv) == -1) return -1; | ||
| 18 | if (FD_ISSET(fd,&rfds)) return read(fd,buf,len); | ||
| 19 | |||
| 20 | errno = error_timeout; | ||
| 21 | return -1; | ||
| 22 | } | ||
diff --git a/timeoutread.h b/timeoutread.h new file mode 100644 index 0000000..20d3bfc --- /dev/null +++ b/timeoutread.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef TIMEOUTREAD_H | ||
| 2 | #define TIMEOUTREAD_H | ||
| 3 | |||
| 4 | extern int timeoutread(); | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/timeoutwrite.c b/timeoutwrite.c new file mode 100644 index 0000000..516d283 --- /dev/null +++ b/timeoutwrite.c | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | #include "timeoutwrite.h" | ||
| 2 | #include "select.h" | ||
| 3 | #include "error.h" | ||
| 4 | #include "readwrite.h" | ||
| 5 | |||
| 6 | int timeoutwrite(t,fd,buf,len) int t; int fd; char *buf; int len; | ||
| 7 | { | ||
| 8 | fd_set wfds; | ||
| 9 | struct timeval tv; | ||
| 10 | |||
| 11 | tv.tv_sec = t; | ||
| 12 | tv.tv_usec = 0; | ||
| 13 | |||
| 14 | FD_ZERO(&wfds); | ||
| 15 | FD_SET(fd,&wfds); | ||
| 16 | |||
| 17 | if (select(fd + 1,(fd_set *) 0,&wfds,(fd_set *) 0,&tv) == -1) return -1; | ||
| 18 | if (FD_ISSET(fd,&wfds)) return write(fd,buf,len); | ||
| 19 | |||
| 20 | errno = error_timeout; | ||
| 21 | return -1; | ||
| 22 | } | ||
diff --git a/timeoutwrite.h b/timeoutwrite.h new file mode 100644 index 0000000..4725861 --- /dev/null +++ b/timeoutwrite.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef TIMEOUTWRITE_H | ||
| 2 | #define TIMEOUTWRITE_H | ||
| 3 | |||
| 4 | extern int timeoutwrite(); | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/token822.c b/token822.c new file mode 100644 index 0000000..48a4388 --- /dev/null +++ b/token822.c | |||
| @@ -0,0 +1,513 @@ | |||
| 1 | #include "stralloc.h" | ||
| 2 | #include "alloc.h" | ||
| 3 | #include "str.h" | ||
| 4 | #include "token822.h" | ||
| 5 | #include "gen_allocdefs.h" | ||
| 6 | |||
| 7 | static struct token822 comma = { TOKEN822_COMMA }; | ||
| 8 | |||
| 9 | void token822_reverse(ta) | ||
| 10 | token822_alloc *ta; | ||
| 11 | { | ||
| 12 | int i; | ||
| 13 | int n; | ||
| 14 | struct token822 temp; | ||
| 15 | |||
| 16 | n = ta->len - 1; | ||
| 17 | for (i = 0;i + i < n;++i) | ||
| 18 | { | ||
| 19 | temp = ta->t[i]; | ||
| 20 | ta->t[i] = ta->t[n - i]; | ||
| 21 | ta->t[n - i] = temp; | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | GEN_ALLOC_ready(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_ready) | ||
| 26 | GEN_ALLOC_readyplus(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_readyplus) | ||
| 27 | GEN_ALLOC_append(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_readyplus,token822_append) | ||
| 28 | |||
| 29 | static int needspace(t1,t2) | ||
| 30 | int t1; | ||
| 31 | int t2; | ||
| 32 | { | ||
| 33 | if (!t1) return 0; | ||
| 34 | if (t1 == TOKEN822_COLON) return 1; | ||
| 35 | if (t1 == TOKEN822_COMMA) return 1; | ||
| 36 | if (t2 == TOKEN822_LEFT) return 1; | ||
| 37 | switch(t1) | ||
| 38 | { | ||
| 39 | case TOKEN822_ATOM: case TOKEN822_LITERAL: | ||
| 40 | case TOKEN822_QUOTE: case TOKEN822_COMMENT: | ||
| 41 | switch(t2) | ||
| 42 | { | ||
| 43 | case TOKEN822_ATOM: case TOKEN822_LITERAL: | ||
| 44 | case TOKEN822_QUOTE: case TOKEN822_COMMENT: | ||
| 45 | return 1; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | return 0; | ||
| 49 | } | ||
| 50 | |||
| 51 | static int atomok(ch) | ||
| 52 | char ch; | ||
| 53 | { | ||
| 54 | switch(ch) | ||
| 55 | { | ||
| 56 | case ' ': case '\t': case '\r': case '\n': | ||
| 57 | case '(': case '[': case '"': | ||
| 58 | case '<': case '>': case ';': case ':': | ||
| 59 | case '@': case ',': case '.': | ||
| 60 | return 0; | ||
| 61 | } | ||
| 62 | return 1; | ||
| 63 | } | ||
| 64 | |||
| 65 | static void atomcheck(t) | ||
| 66 | struct token822 *t; | ||
| 67 | { | ||
| 68 | int i; | ||
| 69 | char ch; | ||
| 70 | for (i = 0;i < t->slen;++i) | ||
| 71 | { | ||
| 72 | ch = t->s[i]; | ||
| 73 | if ((ch < 32) || (ch > 126) || (ch == ')') || (ch == ']') || (ch == '\\')) | ||
| 74 | { | ||
| 75 | t->type = TOKEN822_QUOTE; | ||
| 76 | return; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | int token822_unparse(sa,ta,linelen) | ||
| 82 | stralloc *sa; | ||
| 83 | token822_alloc *ta; | ||
| 84 | unsigned int linelen; | ||
| 85 | { | ||
| 86 | struct token822 *t; | ||
| 87 | int len; | ||
| 88 | int ch; | ||
| 89 | int i; | ||
| 90 | int j; | ||
| 91 | int lasttype; | ||
| 92 | int newtype; | ||
| 93 | char *s; | ||
| 94 | char *lineb; | ||
| 95 | char *linee; | ||
| 96 | |||
| 97 | len = 0; | ||
| 98 | lasttype = 0; | ||
| 99 | for (i = 0;i < ta->len;++i) | ||
| 100 | { | ||
| 101 | t = ta->t + i; | ||
| 102 | newtype = t->type; | ||
| 103 | if (needspace(lasttype,newtype)) | ||
| 104 | ++len; | ||
| 105 | lasttype = newtype; | ||
| 106 | switch(newtype) | ||
| 107 | { | ||
| 108 | case TOKEN822_COMMA: | ||
| 109 | len += 3; break; | ||
| 110 | case TOKEN822_AT: case TOKEN822_DOT: case TOKEN822_LEFT: case TOKEN822_RIGHT: | ||
| 111 | case TOKEN822_SEMI: case TOKEN822_COLON: | ||
| 112 | ++len; break; | ||
| 113 | case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: case TOKEN822_COMMENT: | ||
| 114 | if (t->type != TOKEN822_ATOM) len += 2; | ||
| 115 | for (j = 0;j < t->slen;++j) | ||
| 116 | switch(ch = t->s[j]) | ||
| 117 | { | ||
| 118 | case '"': case '[': case ']': case '(': case ')': | ||
| 119 | case '\\': case '\r': case '\n': ++len; | ||
| 120 | default: ++len; | ||
| 121 | } | ||
| 122 | break; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | len += 2; | ||
| 126 | |||
| 127 | if (!stralloc_ready(sa,len)) | ||
| 128 | return -1; | ||
| 129 | |||
| 130 | s = sa->s; | ||
| 131 | lineb = s; | ||
| 132 | linee = 0; | ||
| 133 | |||
| 134 | lasttype = 0; | ||
| 135 | for (i = 0;i < ta->len;++i) | ||
| 136 | { | ||
| 137 | t = ta->t + i; | ||
| 138 | newtype = t->type; | ||
| 139 | if (needspace(lasttype,newtype)) | ||
| 140 | *s++ = ' '; | ||
| 141 | lasttype = newtype; | ||
| 142 | switch(newtype) | ||
| 143 | { | ||
| 144 | case TOKEN822_COMMA: | ||
| 145 | *s++ = ','; | ||
| 146 | #define NSUW \ | ||
| 147 | s[0] = '\n'; s[1] = ' '; \ | ||
| 148 | if (linee && (!linelen || (s - lineb <= linelen))) \ | ||
| 149 | { while (linee < s) { linee[0] = linee[2]; ++linee; } linee -= 2; } \ | ||
| 150 | else { if (linee) lineb = linee + 1; linee = s; s += 2; } | ||
| 151 | NSUW | ||
| 152 | break; | ||
| 153 | case TOKEN822_AT: *s++ = '@'; break; | ||
| 154 | case TOKEN822_DOT: *s++ = '.'; break; | ||
| 155 | case TOKEN822_LEFT: *s++ = '<'; break; | ||
| 156 | case TOKEN822_RIGHT: *s++ = '>'; break; | ||
| 157 | case TOKEN822_SEMI: *s++ = ';'; break; | ||
| 158 | case TOKEN822_COLON: *s++ = ':'; break; | ||
| 159 | case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: case TOKEN822_COMMENT: | ||
| 160 | if (t->type == TOKEN822_QUOTE) *s++ = '"'; | ||
| 161 | if (t->type == TOKEN822_LITERAL) *s++ = '['; | ||
| 162 | if (t->type == TOKEN822_COMMENT) *s++ = '('; | ||
| 163 | for (j = 0;j < t->slen;++j) | ||
| 164 | switch(ch = t->s[j]) | ||
| 165 | { | ||
| 166 | case '"': case '[': case ']': case '(': case ')': | ||
| 167 | case '\\': case '\r': case '\n': *s++ = '\\'; | ||
| 168 | default: *s++ = ch; | ||
| 169 | } | ||
| 170 | if (t->type == TOKEN822_QUOTE) *s++ = '"'; | ||
| 171 | if (t->type == TOKEN822_LITERAL) *s++ = ']'; | ||
| 172 | if (t->type == TOKEN822_COMMENT) *s++ = ')'; | ||
| 173 | break; | ||
| 174 | } | ||
| 175 | } | ||
| 176 | NSUW | ||
| 177 | --s; | ||
| 178 | sa->len = s - sa->s; | ||
| 179 | return 1; | ||
| 180 | } | ||
| 181 | |||
| 182 | int token822_unquote(sa,ta) | ||
| 183 | stralloc *sa; | ||
| 184 | token822_alloc *ta; | ||
| 185 | { | ||
| 186 | struct token822 *t; | ||
| 187 | int len; | ||
| 188 | int i; | ||
| 189 | int j; | ||
| 190 | char *s; | ||
| 191 | |||
| 192 | len = 0; | ||
| 193 | for (i = 0;i < ta->len;++i) | ||
| 194 | { | ||
| 195 | t = ta->t + i; | ||
| 196 | switch(t->type) | ||
| 197 | { | ||
| 198 | case TOKEN822_COMMA: case TOKEN822_AT: case TOKEN822_DOT: case TOKEN822_LEFT: | ||
| 199 | case TOKEN822_RIGHT: case TOKEN822_SEMI: case TOKEN822_COLON: | ||
| 200 | ++len; break; | ||
| 201 | case TOKEN822_LITERAL: | ||
| 202 | len += 2; | ||
| 203 | case TOKEN822_ATOM: case TOKEN822_QUOTE: | ||
| 204 | len += t->slen; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | if (!stralloc_ready(sa,len)) | ||
| 209 | return -1; | ||
| 210 | |||
| 211 | s = sa->s; | ||
| 212 | |||
| 213 | for (i = 0;i < ta->len;++i) | ||
| 214 | { | ||
| 215 | t = ta->t + i; | ||
| 216 | switch(t->type) | ||
| 217 | { | ||
| 218 | case TOKEN822_COMMA: *s++ = ','; break; | ||
| 219 | case TOKEN822_AT: *s++ = '@'; break; | ||
| 220 | case TOKEN822_DOT: *s++ = '.'; break; | ||
| 221 | case TOKEN822_LEFT: *s++ = '<'; break; | ||
| 222 | case TOKEN822_RIGHT: *s++ = '>'; break; | ||
| 223 | case TOKEN822_SEMI: *s++ = ';'; break; | ||
| 224 | case TOKEN822_COLON: *s++ = ':'; break; | ||
| 225 | case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: | ||
| 226 | if (t->type == TOKEN822_LITERAL) *s++ = '['; | ||
| 227 | for (j = 0;j < t->slen;++j) | ||
| 228 | *s++ = t->s[j]; | ||
| 229 | if (t->type == TOKEN822_LITERAL) *s++ = ']'; | ||
| 230 | break; | ||
| 231 | case TOKEN822_COMMENT: break; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | sa->len = s - sa->s; | ||
| 235 | return 1; | ||
| 236 | } | ||
| 237 | |||
| 238 | int token822_parse(ta,sa,buf) | ||
| 239 | token822_alloc *ta; | ||
| 240 | stralloc *sa; | ||
| 241 | stralloc *buf; | ||
| 242 | { | ||
| 243 | int i; | ||
| 244 | int salen; | ||
| 245 | int level; | ||
| 246 | struct token822 *t; | ||
| 247 | int numtoks; | ||
| 248 | int numchars; | ||
| 249 | char *cbuf; | ||
| 250 | |||
| 251 | salen = sa->len; | ||
| 252 | |||
| 253 | numchars = 0; | ||
| 254 | numtoks = 0; | ||
| 255 | for (i = 0;i < salen;++i) | ||
| 256 | switch(sa->s[i]) | ||
| 257 | { | ||
| 258 | case '.': case ',': case '@': case '<': case '>': case ':': case ';': | ||
| 259 | ++numtoks; break; | ||
| 260 | case ' ': case '\t': case '\r': case '\n': break; | ||
| 261 | case ')': case ']': return 0; | ||
| 262 | /* other control chars and non-ASCII chars are also bad, in theory */ | ||
| 263 | case '(': | ||
| 264 | level = 1; | ||
| 265 | while (level) | ||
| 266 | { | ||
| 267 | if (++i >= salen) return 0; | ||
| 268 | switch(sa->s[i]) | ||
| 269 | { | ||
| 270 | case '(': ++level; break; | ||
| 271 | case ')': --level; break; | ||
| 272 | case '\\': if (++i >= salen) return 0; | ||
| 273 | default: ++numchars; | ||
| 274 | } | ||
| 275 | } | ||
| 276 | ++numtoks; | ||
| 277 | break; | ||
| 278 | case '"': | ||
| 279 | level = 1; | ||
| 280 | while (level) | ||
| 281 | { | ||
| 282 | if (++i >= salen) return 0; | ||
| 283 | switch(sa->s[i]) | ||
| 284 | { | ||
| 285 | case '"': --level; break; | ||
| 286 | case '\\': if (++i >= salen) return 0; | ||
| 287 | default: ++numchars; | ||
| 288 | } | ||
| 289 | } | ||
| 290 | ++numtoks; | ||
| 291 | break; | ||
| 292 | case '[': | ||
| 293 | level = 1; | ||
| 294 | while (level) | ||
| 295 | { | ||
| 296 | if (++i >= salen) return 0; | ||
| 297 | switch(sa->s[i]) | ||
| 298 | { | ||
| 299 | case ']': --level; break; | ||
| 300 | case '\\': if (++i >= salen) return 0; | ||
| 301 | default: ++numchars; | ||
| 302 | } | ||
| 303 | } | ||
| 304 | ++numtoks; | ||
| 305 | break; | ||
| 306 | default: | ||
| 307 | do | ||
| 308 | { | ||
| 309 | if (sa->s[i] == '\\') if (++i >= salen) break; | ||
| 310 | ++numchars; | ||
| 311 | if (++i >= salen) | ||
| 312 | break; | ||
| 313 | } | ||
| 314 | while (atomok(sa->s[i])); | ||
| 315 | --i; | ||
| 316 | ++numtoks; | ||
| 317 | } | ||
| 318 | |||
| 319 | if (!token822_ready(ta,numtoks)) | ||
| 320 | return -1; | ||
| 321 | if (!stralloc_ready(buf,numchars)) | ||
| 322 | return -1; | ||
| 323 | cbuf = buf->s; | ||
| 324 | ta->len = numtoks; | ||
| 325 | |||
| 326 | t = ta->t; | ||
| 327 | for (i = 0;i < salen;++i) | ||
| 328 | switch(sa->s[i]) | ||
| 329 | { | ||
| 330 | case '.': t->type = TOKEN822_DOT; ++t; break; | ||
| 331 | case ',': t->type = TOKEN822_COMMA; ++t; break; | ||
| 332 | case '@': t->type = TOKEN822_AT; ++t; break; | ||
| 333 | case '<': t->type = TOKEN822_LEFT; ++t; break; | ||
| 334 | case '>': t->type = TOKEN822_RIGHT; ++t; break; | ||
| 335 | case ':': t->type = TOKEN822_COLON; ++t; break; | ||
| 336 | case ';': t->type = TOKEN822_SEMI; ++t; break; | ||
| 337 | case ' ': case '\t': case '\r': case '\n': break; | ||
| 338 | case '(': | ||
| 339 | t->type = TOKEN822_COMMENT; t->s = cbuf; t->slen = 0; | ||
| 340 | level = 1; | ||
| 341 | while (level) | ||
| 342 | { | ||
| 343 | ++i; /* assert: < salen */ | ||
| 344 | switch(sa->s[i]) | ||
| 345 | { | ||
| 346 | case '(': ++level; break; | ||
| 347 | case ')': --level; break; | ||
| 348 | case '\\': ++i; /* assert: < salen */ | ||
| 349 | default: *cbuf++ = sa->s[i]; ++t->slen; | ||
| 350 | } | ||
| 351 | } | ||
| 352 | ++t; | ||
| 353 | break; | ||
| 354 | case '"': | ||
| 355 | t->type = TOKEN822_QUOTE; t->s = cbuf; t->slen = 0; | ||
| 356 | level = 1; | ||
| 357 | while (level) | ||
| 358 | { | ||
| 359 | ++i; /* assert: < salen */ | ||
| 360 | switch(sa->s[i]) | ||
| 361 | { | ||
| 362 | case '"': --level; break; | ||
| 363 | case '\\': ++i; /* assert: < salen */ | ||
| 364 | default: *cbuf++ = sa->s[i]; ++t->slen; | ||
| 365 | } | ||
| 366 | } | ||
| 367 | ++t; | ||
| 368 | break; | ||
| 369 | case '[': | ||
| 370 | t->type = TOKEN822_LITERAL; t->s = cbuf; t->slen = 0; | ||
| 371 | level = 1; | ||
| 372 | while (level) | ||
| 373 | { | ||
| 374 | ++i; /* assert: < salen */ | ||
| 375 | switch(sa->s[i]) | ||
| 376 | { | ||
| 377 | case ']': --level; break; | ||
| 378 | case '\\': ++i; /* assert: < salen */ | ||
| 379 | default: *cbuf++ = sa->s[i]; ++t->slen; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | ++t; | ||
| 383 | break; | ||
| 384 | default: | ||
| 385 | t->type = TOKEN822_ATOM; t->s = cbuf; t->slen = 0; | ||
| 386 | do | ||
| 387 | { | ||
| 388 | if (sa->s[i] == '\\') if (++i >= salen) break; | ||
| 389 | *cbuf++ = sa->s[i]; ++t->slen; | ||
| 390 | if (++i >= salen) | ||
| 391 | break; | ||
| 392 | } | ||
| 393 | while (atomok(sa->s[i])); | ||
| 394 | atomcheck(t); | ||
| 395 | --i; | ||
| 396 | ++t; | ||
| 397 | } | ||
| 398 | return 1; | ||
| 399 | } | ||
| 400 | |||
| 401 | static int gotaddr(taout,taaddr,callback) | ||
| 402 | token822_alloc *taout; | ||
| 403 | token822_alloc *taaddr; | ||
| 404 | int (*callback)(); | ||
| 405 | { | ||
| 406 | int i; | ||
| 407 | |||
| 408 | if (callback(taaddr) != 1) | ||
| 409 | return 0; | ||
| 410 | |||
| 411 | if (!token822_readyplus(taout,taaddr->len)) | ||
| 412 | return 0; | ||
| 413 | |||
| 414 | for (i = 0;i < taaddr->len;++i) | ||
| 415 | taout->t[taout->len++] = taaddr->t[i]; | ||
| 416 | |||
| 417 | taaddr->len = 0; | ||
| 418 | return 1; | ||
| 419 | } | ||
| 420 | |||
| 421 | int token822_addrlist(taout,taaddr,ta,callback) | ||
| 422 | token822_alloc *taout; | ||
| 423 | token822_alloc *taaddr; | ||
| 424 | token822_alloc *ta; | ||
| 425 | int (*callback)(); | ||
| 426 | { | ||
| 427 | struct token822 *t; | ||
| 428 | struct token822 *beginning; | ||
| 429 | int ingroup; | ||
| 430 | int wordok; | ||
| 431 | |||
| 432 | taout->len = 0; | ||
| 433 | taaddr->len = 0; | ||
| 434 | |||
| 435 | if (!token822_readyplus(taout,1)) return -1; | ||
| 436 | if (!token822_readyplus(taaddr,1)) return -1; | ||
| 437 | |||
| 438 | ingroup = 0; | ||
| 439 | wordok = 1; | ||
| 440 | |||
| 441 | beginning = ta->t + 2; | ||
| 442 | t = ta->t + ta->len - 1; | ||
| 443 | |||
| 444 | /* rfc 822 address lists are easy to parse from right to left */ | ||
| 445 | |||
| 446 | #define FLUSH if (taaddr->len) if (!gotaddr(taout,taaddr,callback)) return -1; | ||
| 447 | #define FLUSHCOMMA if (taaddr->len) { \ | ||
| 448 | if (!gotaddr(taout,taaddr,callback)) return -1; \ | ||
| 449 | if (!token822_append(taout,&comma)) return -1; } | ||
| 450 | #define ADDRLEFT if (!token822_append(taaddr,t--)) return -1; | ||
| 451 | #define OUTLEFT if (!token822_append(taout,t--)) return -1; | ||
| 452 | |||
| 453 | while (t >= beginning) | ||
| 454 | { | ||
| 455 | switch(t->type) | ||
| 456 | { | ||
| 457 | case TOKEN822_SEMI: | ||
| 458 | FLUSHCOMMA | ||
| 459 | if (ingroup) return 0; | ||
| 460 | ingroup = 1; | ||
| 461 | wordok = 1; | ||
| 462 | break; | ||
| 463 | case TOKEN822_COLON: | ||
| 464 | FLUSH | ||
| 465 | if (!ingroup) return 0; | ||
| 466 | ingroup = 0; | ||
| 467 | while ((t >= beginning) && (t->type != TOKEN822_COMMA)) | ||
| 468 | OUTLEFT | ||
| 469 | if (t >= beginning) | ||
| 470 | OUTLEFT | ||
| 471 | wordok = 1; | ||
| 472 | continue; | ||
| 473 | case TOKEN822_RIGHT: | ||
| 474 | FLUSHCOMMA | ||
| 475 | OUTLEFT | ||
| 476 | while ((t >= beginning) && (t->type != TOKEN822_LEFT)) | ||
| 477 | ADDRLEFT | ||
| 478 | /* important to use address here even if it's empty: <> */ | ||
| 479 | if (!gotaddr(taout,taaddr,callback)) return -1; | ||
| 480 | if (t < beginning) return 0; | ||
| 481 | OUTLEFT | ||
| 482 | while ((t >= beginning) && ((t->type == TOKEN822_COMMENT) || (t->type == TOKEN822_ATOM) || (t->type == TOKEN822_QUOTE) || (t->type == TOKEN822_AT) || (t->type == TOKEN822_DOT))) | ||
| 483 | OUTLEFT | ||
| 484 | wordok = 0; | ||
| 485 | continue; | ||
| 486 | case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: | ||
| 487 | if (!wordok) | ||
| 488 | FLUSHCOMMA | ||
| 489 | wordok = 0; | ||
| 490 | ADDRLEFT | ||
| 491 | continue; | ||
| 492 | case TOKEN822_COMMENT: | ||
| 493 | /* comment is lexically a space; shouldn't affect wordok */ | ||
| 494 | break; | ||
| 495 | case TOKEN822_COMMA: | ||
| 496 | FLUSH | ||
| 497 | wordok = 1; | ||
| 498 | break; | ||
| 499 | default: | ||
| 500 | wordok = 1; | ||
| 501 | ADDRLEFT | ||
| 502 | continue; | ||
| 503 | } | ||
| 504 | OUTLEFT | ||
| 505 | } | ||
| 506 | FLUSH | ||
| 507 | ++t; | ||
| 508 | while (t > ta->t) | ||
| 509 | if (!token822_append(taout,--t)) return -1; | ||
| 510 | |||
| 511 | token822_reverse(taout); | ||
| 512 | return 1; | ||
| 513 | } | ||
diff --git a/token822.h b/token822.h new file mode 100644 index 0000000..9ca35cf --- /dev/null +++ b/token822.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | #ifndef TOKEN822_H | ||
| 2 | #define TOKEN822_H | ||
| 3 | |||
| 4 | struct token822 | ||
| 5 | { | ||
| 6 | int type; | ||
| 7 | char *s; | ||
| 8 | int slen; | ||
| 9 | } | ||
| 10 | ; | ||
| 11 | |||
| 12 | #include "gen_alloc.h" | ||
| 13 | GEN_ALLOC_typedef(token822_alloc,struct token822,t,len,a) | ||
| 14 | |||
| 15 | extern int token822_parse(); | ||
| 16 | extern int token822_addrlist(); | ||
| 17 | extern int token822_unquote(); | ||
| 18 | extern int token822_unparse(); | ||
| 19 | extern void token822_free(); | ||
| 20 | extern void token822_reverse(); | ||
| 21 | extern int token822_ready(); | ||
| 22 | extern int token822_readyplus(); | ||
| 23 | extern int token822_append(); | ||
| 24 | |||
| 25 | #define TOKEN822_ATOM 1 | ||
| 26 | #define TOKEN822_QUOTE 2 | ||
| 27 | #define TOKEN822_LITERAL 3 | ||
| 28 | #define TOKEN822_COMMENT 4 | ||
| 29 | #define TOKEN822_LEFT 5 | ||
| 30 | #define TOKEN822_RIGHT 6 | ||
| 31 | #define TOKEN822_AT 7 | ||
| 32 | #define TOKEN822_COMMA 8 | ||
| 33 | #define TOKEN822_SEMI 9 | ||
| 34 | #define TOKEN822_COLON 10 | ||
| 35 | #define TOKEN822_DOT 11 | ||
| 36 | |||
| 37 | #endif | ||
diff --git a/trigger.c b/trigger.c new file mode 100644 index 0000000..39f81b8 --- /dev/null +++ b/trigger.c | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | #include "select.h" | ||
| 2 | #include "open.h" | ||
| 3 | #include "trigger.h" | ||
| 4 | #include "hasnpbg1.h" | ||
| 5 | |||
| 6 | static int fd = -1; | ||
| 7 | #ifdef HASNAMEDPIPEBUG1 | ||
| 8 | static int fdw = -1; | ||
| 9 | #endif | ||
| 10 | |||
| 11 | void trigger_set() | ||
| 12 | { | ||
| 13 | if (fd != -1) | ||
| 14 | close(fd); | ||
| 15 | #ifdef HASNAMEDPIPEBUG1 | ||
| 16 | if (fdw != -1) | ||
| 17 | close(fdw); | ||
| 18 | #endif | ||
| 19 | fd = open_read("lock/trigger"); | ||
| 20 | #ifdef HASNAMEDPIPEBUG1 | ||
| 21 | fdw = open_write("lock/trigger"); | ||
| 22 | #endif | ||
| 23 | } | ||
| 24 | |||
| 25 | void trigger_selprep(nfds,rfds) | ||
| 26 | int *nfds; | ||
| 27 | fd_set *rfds; | ||
| 28 | { | ||
| 29 | if (fd != -1) | ||
| 30 | { | ||
| 31 | FD_SET(fd,rfds); | ||
| 32 | if (*nfds < fd + 1) *nfds = fd + 1; | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | int trigger_pulled(rfds) | ||
| 37 | fd_set *rfds; | ||
| 38 | { | ||
| 39 | if (fd != -1) if (FD_ISSET(fd,rfds)) return 1; | ||
| 40 | return 0; | ||
| 41 | } | ||
diff --git a/trigger.h b/trigger.h new file mode 100644 index 0000000..dec24ef --- /dev/null +++ b/trigger.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef TRIGGER_H | ||
| 2 | #define TRIGGER_H | ||
| 3 | |||
| 4 | extern void trigger_set(); | ||
| 5 | extern void trigger_selprep(); | ||
| 6 | extern int trigger_pulled(); | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/triggerpull.c b/triggerpull.c new file mode 100644 index 0000000..30b9a97 --- /dev/null +++ b/triggerpull.c | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #include "ndelay.h" | ||
| 2 | #include "open.h" | ||
| 3 | #include "triggerpull.h" | ||
| 4 | |||
| 5 | void triggerpull() | ||
| 6 | { | ||
| 7 | int fd; | ||
| 8 | |||
| 9 | fd = open_write("lock/trigger"); | ||
| 10 | if (fd >= 0) | ||
| 11 | { | ||
| 12 | ndelay_on(fd); | ||
| 13 | write(fd,"",1); /* if it fails, bummer */ | ||
| 14 | close(fd); | ||
| 15 | } | ||
| 16 | } | ||
diff --git a/triggerpull.h b/triggerpull.h new file mode 100644 index 0000000..6d097bb --- /dev/null +++ b/triggerpull.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef TRIGGERPULL_H | ||
| 2 | #define TRIGGERPULL_H | ||
| 3 | |||
| 4 | extern void triggerpull(); | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/trycpp.c b/trycpp.c new file mode 100644 index 0000000..d7d83ad --- /dev/null +++ b/trycpp.c | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | void main() | ||
| 2 | { | ||
| 3 | #ifdef NeXT | ||
| 4 | printf("nextstep\n"); exit(0); | ||
| 5 | #endif | ||
| 6 | printf("unknown\n"); exit(0); | ||
| 7 | } | ||
diff --git a/trydrent.c b/trydrent.c new file mode 100644 index 0000000..c778176 --- /dev/null +++ b/trydrent.c | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <dirent.h> | ||
| 3 | |||
| 4 | void foo() | ||
| 5 | { | ||
| 6 | DIR *dir; | ||
| 7 | struct dirent *d; | ||
| 8 | } | ||
diff --git a/tryflock.c b/tryflock.c new file mode 100644 index 0000000..8c8aa76 --- /dev/null +++ b/tryflock.c | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/file.h> | ||
| 3 | #include <fcntl.h> | ||
| 4 | |||
| 5 | void main() | ||
| 6 | { | ||
| 7 | flock(0,LOCK_EX | LOCK_UN | LOCK_NB); | ||
| 8 | } | ||
diff --git a/trylsock.c b/trylsock.c new file mode 100644 index 0000000..fbce408 --- /dev/null +++ b/trylsock.c | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | main() | ||
| 2 | { | ||
| 3 | ; | ||
| 4 | } | ||
diff --git a/trymkffo.c b/trymkffo.c new file mode 100644 index 0000000..0b119c6 --- /dev/null +++ b/trymkffo.c | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | |||
| 4 | void main() | ||
| 5 | { | ||
| 6 | mkfifo("temp-trymkffo",0); | ||
| 7 | } | ||
diff --git a/trynpbg1.c b/trynpbg1.c new file mode 100644 index 0000000..9d5f80b --- /dev/null +++ b/trynpbg1.c | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | #include "select.h" | ||
| 2 | #include "open.h" | ||
| 3 | #include "fifo.h" | ||
| 4 | |||
| 5 | #define FN "temp-trynpbg1.fifo" | ||
| 6 | |||
| 7 | void main() | ||
| 8 | { | ||
| 9 | int flagbug; | ||
| 10 | struct timeval instant; | ||
| 11 | fd_set rfds; | ||
| 12 | |||
| 13 | flagbug = 0; | ||
| 14 | if (fifo_make(FN,0600) != -1) { | ||
| 15 | close(0); | ||
| 16 | if (open_read(FN) == 0) { | ||
| 17 | FD_ZERO(&rfds); | ||
| 18 | FD_SET(0,&rfds); | ||
| 19 | instant.tv_sec = instant.tv_usec = 0; | ||
| 20 | if (select(1,&rfds,(fd_set *) 0,(fd_set *) 0,&instant) > 0) | ||
| 21 | flagbug = 1; | ||
| 22 | } | ||
| 23 | unlink(FN); | ||
| 24 | } | ||
| 25 | _exit(!flagbug); | ||
| 26 | } | ||
diff --git a/tryrsolv.c b/tryrsolv.c new file mode 100644 index 0000000..fbce408 --- /dev/null +++ b/tryrsolv.c | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | main() | ||
| 2 | { | ||
| 3 | ; | ||
| 4 | } | ||
diff --git a/trysalen.c b/trysalen.c new file mode 100644 index 0000000..731a109 --- /dev/null +++ b/trysalen.c | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/param.h> | ||
| 3 | #include <sys/time.h> | ||
| 4 | #include <sys/ioctl.h> | ||
| 5 | #include <sys/socket.h> | ||
| 6 | |||
| 7 | void foo() | ||
| 8 | { | ||
| 9 | struct sockaddr sa; | ||
| 10 | sa.sa_len = 0; | ||
| 11 | } | ||
diff --git a/trysgact.c b/trysgact.c new file mode 100644 index 0000000..263cb21 --- /dev/null +++ b/trysgact.c | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #include <signal.h> | ||
| 2 | |||
| 3 | void main() | ||
| 4 | { | ||
| 5 | struct sigaction sa; | ||
| 6 | sa.sa_handler = 0; | ||
| 7 | sa.sa_flags = 0; | ||
| 8 | sigemptyset(&sa.sa_mask); | ||
| 9 | sigaction(0,&sa,(struct sigaction *) 0); | ||
| 10 | } | ||
diff --git a/trysgprm.c b/trysgprm.c new file mode 100644 index 0000000..ed28857 --- /dev/null +++ b/trysgprm.c | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #include <signal.h> | ||
| 2 | |||
| 3 | void main() | ||
| 4 | { | ||
| 5 | sigset_t ss; | ||
| 6 | |||
| 7 | sigemptyset(&ss); | ||
| 8 | sigaddset(&ss,SIGCHLD); | ||
| 9 | sigprocmask(SIG_SETMASK,&ss,(sigset_t *) 0); | ||
| 10 | } | ||
diff --git a/tryshsgr.c b/tryshsgr.c new file mode 100644 index 0000000..807e15d --- /dev/null +++ b/tryshsgr.c | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | void main() | ||
| 2 | { | ||
| 3 | short x[4]; | ||
| 4 | |||
| 5 | x[0] = x[1] = 1; | ||
| 6 | if (getgroups(1,x) == 0) if (setgroups(1,x) == -1) _exit(1); | ||
| 7 | |||
| 8 | if (getgroups(1,x) == -1) _exit(1); | ||
| 9 | if (x[1] != 1) _exit(1); | ||
| 10 | x[1] = 2; | ||
| 11 | if (getgroups(1,x) == -1) _exit(1); | ||
| 12 | if (x[1] != 2) _exit(1); | ||
| 13 | _exit(0); | ||
| 14 | } | ||
diff --git a/trysysel.c b/trysysel.c new file mode 100644 index 0000000..f6ed055 --- /dev/null +++ b/trysysel.c | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/time.h> | ||
| 3 | #include <sys/select.h> /* SVR4 silliness */ | ||
| 4 | |||
| 5 | void foo() | ||
| 6 | { | ||
| 7 | ; | ||
| 8 | } | ||
diff --git a/trysyslog.c b/trysyslog.c new file mode 100644 index 0000000..4b99afc --- /dev/null +++ b/trysyslog.c | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/time.h> | ||
| 3 | #include <syslog.h> | ||
| 4 | |||
| 5 | main() | ||
| 6 | { | ||
| 7 | openlog("foo",0,LOG_MAIL); | ||
| 8 | syslog(0,"foo"); | ||
| 9 | } | ||
diff --git a/tryulong32.c b/tryulong32.c new file mode 100644 index 0000000..a108076 --- /dev/null +++ b/tryulong32.c | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | void main() | ||
| 2 | { | ||
| 3 | unsigned long u; | ||
| 4 | u = 1; | ||
| 5 | u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; | ||
| 6 | u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; | ||
| 7 | u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; | ||
| 8 | u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; | ||
| 9 | if (!u) _exit(0); | ||
| 10 | _exit(1); | ||
| 11 | } | ||
diff --git a/tryvfork.c b/tryvfork.c new file mode 100644 index 0000000..21387e4 --- /dev/null +++ b/tryvfork.c | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | void main() | ||
| 2 | { | ||
| 3 | vfork(); | ||
| 4 | } | ||
diff --git a/trywaitp.c b/trywaitp.c new file mode 100644 index 0000000..7e73bfa --- /dev/null +++ b/trywaitp.c | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/wait.h> | ||
| 3 | |||
| 4 | void main() | ||
| 5 | { | ||
| 6 | waitpid(0,0,0); | ||
| 7 | } | ||
diff --git a/uint32.h1 b/uint32.h1 new file mode 100644 index 0000000..6599aa0 --- /dev/null +++ b/uint32.h1 | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef UINT32_H | ||
| 2 | #define UINT32_H | ||
| 3 | |||
| 4 | typedef unsigned int uint32; | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/uint32.h2 b/uint32.h2 new file mode 100644 index 0000000..716430d --- /dev/null +++ b/uint32.h2 | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef UINT32_H | ||
| 2 | #define UINT32_H | ||
| 3 | |||
| 4 | typedef unsigned long uint32; | ||
| 5 | |||
| 6 | #endif | ||
| @@ -0,0 +1,93 @@ | |||
| 1 | .TH wait 3 | ||
| 2 | .SH NAME | ||
| 3 | wait \- check child process status | ||
| 4 | .SH SYNTAX | ||
| 5 | .B #include <wait.h> | ||
| 6 | |||
| 7 | int \fBwait_nohang\fP(&\fIwstat\fR); | ||
| 8 | .br | ||
| 9 | int \fBwait_stop\fP(&\fIwstat\fR); | ||
| 10 | .br | ||
| 11 | int \fBwait_stopnohang\fP(&\fIwstat\fR); | ||
| 12 | .br | ||
| 13 | int \fBwait_pid\fP(&\fIwstat\fR,\fIpid\fR); | ||
| 14 | |||
| 15 | int \fBwait_exitcode\fP(\fIwstat\fR); | ||
| 16 | .br | ||
| 17 | int \fBwait_crashed\fP(\fIwstat\fR); | ||
| 18 | .br | ||
| 19 | int \fBwait_stopped\fP(\fIwstat\fR); | ||
| 20 | .br | ||
| 21 | int \fBwait_stopsig\fP(\fIwstat\fR); | ||
| 22 | |||
| 23 | int \fIpid\fR; | ||
| 24 | .br | ||
| 25 | int \fIwstat\fR; | ||
| 26 | .SH DESCRIPTION | ||
| 27 | .B wait_nohang | ||
| 28 | looks for zombies (child processes that have exited). | ||
| 29 | If it sees a zombie, | ||
| 30 | it eliminates the zombie, | ||
| 31 | puts the zombie's exit status into | ||
| 32 | .IR wstat , | ||
| 33 | and returns the zombie's process ID. | ||
| 34 | If there are several zombies, | ||
| 35 | .B wait_nohang | ||
| 36 | picks one. | ||
| 37 | If there are children but no zombies, | ||
| 38 | .B wait_nohang | ||
| 39 | returns 0. | ||
| 40 | If there are no children, | ||
| 41 | .B wait_nohang | ||
| 42 | returns -1, | ||
| 43 | setting | ||
| 44 | .B errno | ||
| 45 | appropriately. | ||
| 46 | |||
| 47 | .B wait_stopnohang | ||
| 48 | is similar to | ||
| 49 | .BR wait_nohang , | ||
| 50 | but it also looks for children that have stopped. | ||
| 51 | |||
| 52 | .B wait_stop | ||
| 53 | is similar to | ||
| 54 | .BR wait_stopnohang , | ||
| 55 | but if there are children it will pause waiting for one of them | ||
| 56 | to stop or exit. | ||
| 57 | |||
| 58 | .B wait_pid | ||
| 59 | waits for child process | ||
| 60 | .I pid | ||
| 61 | to exit. | ||
| 62 | It eliminates any zombie that shows up in the meantime, | ||
| 63 | discarding the exit status. | ||
| 64 | |||
| 65 | .B wait_stop | ||
| 66 | and | ||
| 67 | .B wait_pid | ||
| 68 | retry upon | ||
| 69 | .BR error_intr . | ||
| 70 | .SH "STATUS PARSING" | ||
| 71 | If the child stopped, | ||
| 72 | .B wait_stopped | ||
| 73 | is nonzero; | ||
| 74 | .B wait_stopsig | ||
| 75 | is the signal that caused the child to stop. | ||
| 76 | |||
| 77 | If the child exited by crashing, | ||
| 78 | .B wait_stopped | ||
| 79 | is zero; | ||
| 80 | .B wait_crashed | ||
| 81 | is nonzero. | ||
| 82 | |||
| 83 | If the child exited normally, | ||
| 84 | .B wait_stopped | ||
| 85 | is zero; | ||
| 86 | .B wait_crashed | ||
| 87 | is zero; | ||
| 88 | and | ||
| 89 | .B wait_exitcode | ||
| 90 | is the child's exit code. | ||
| 91 | .SH "SEE ALSO" | ||
| 92 | wait(2), | ||
| 93 | error(3) | ||
| @@ -0,0 +1,14 @@ | |||
| 1 | #ifndef WAIT_H | ||
| 2 | #define WAIT_H | ||
| 3 | |||
| 4 | extern int wait_pid(); | ||
| 5 | extern int wait_nohang(); | ||
| 6 | extern int wait_stop(); | ||
| 7 | extern int wait_stopnohang(); | ||
| 8 | |||
| 9 | #define wait_crashed(w) ((w) & 127) | ||
| 10 | #define wait_exitcode(w) ((w) >> 8) | ||
| 11 | #define wait_stopsig(w) ((w) >> 8) | ||
| 12 | #define wait_stopped(w) (((w) & 127) == 127) | ||
| 13 | |||
| 14 | #endif | ||
diff --git a/wait_nohang.c b/wait_nohang.c new file mode 100644 index 0000000..bea2774 --- /dev/null +++ b/wait_nohang.c | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/wait.h> | ||
| 3 | #include "haswaitp.h" | ||
| 4 | |||
| 5 | int wait_nohang(wstat) int *wstat; | ||
| 6 | { | ||
| 7 | #ifdef HASWAITPID | ||
| 8 | return waitpid(-1,wstat,WNOHANG); | ||
| 9 | #else | ||
| 10 | return wait3(wstat,WNOHANG,(struct rusage *) 0); | ||
| 11 | #endif | ||
| 12 | } | ||
diff --git a/wait_pid.c b/wait_pid.c new file mode 100644 index 0000000..d7a7e84 --- /dev/null +++ b/wait_pid.c | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/wait.h> | ||
| 3 | #include "error.h" | ||
| 4 | #include "haswaitp.h" | ||
| 5 | |||
| 6 | #ifdef HASWAITPID | ||
| 7 | |||
| 8 | int wait_pid(wstat,pid) int *wstat; int pid; | ||
| 9 | { | ||
| 10 | int r; | ||
| 11 | |||
| 12 | do | ||
| 13 | r = waitpid(pid,wstat,0); | ||
| 14 | while ((r == -1) && (errno == error_intr)); | ||
| 15 | return r; | ||
| 16 | } | ||
| 17 | |||
| 18 | #else | ||
| 19 | |||
| 20 | /* XXX untested */ | ||
| 21 | /* XXX breaks down with more than two children */ | ||
| 22 | static int oldpid = 0; | ||
| 23 | static int oldwstat; /* defined if(oldpid) */ | ||
| 24 | |||
| 25 | int wait_pid(wstat,pid) int *wstat; int pid; | ||
| 26 | { | ||
| 27 | int r; | ||
| 28 | |||
| 29 | if (pid == oldpid) { *wstat = oldwstat; oldpid = 0; return pid; } | ||
| 30 | |||
| 31 | do { | ||
| 32 | r = wait(wstat); | ||
| 33 | if ((r != pid) && (r != -1)) { oldwstat = *wstat; oldpid = r; continue; } | ||
| 34 | } | ||
| 35 | while ((r == -1) && (errno == error_intr)); | ||
| 36 | return r; | ||
| 37 | } | ||
| 38 | |||
| 39 | #endif | ||
diff --git a/warn-auto.sh b/warn-auto.sh new file mode 100644 index 0000000..36d2313 --- /dev/null +++ b/warn-auto.sh | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | # WARNING: This file was auto-generated. Do not edit! | ||
diff --git a/warn-shsgr b/warn-shsgr new file mode 100644 index 0000000..37c351e --- /dev/null +++ b/warn-shsgr | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | Oops. Your getgroups() returned 0, and setgroups() failed; this means | ||
| 2 | that I can't reliably do my shsgr test. Please either ``make'' as root | ||
| 3 | or ``make'' while you're in one or more supplementary groups. | ||
