]>
diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/support/pop/popser.c
1 /* popser.c - the POP service */
3 static char ident
[]="@(#)$Id: popser.c,v 1.34 1995/12/07 18:54:35 jromine Exp $";
7 #include "../h/dropsbr.h"
10 #include "../h/formatsbr.h"
11 #include "../h/scansbr.h"
14 #include "../zotnet/bboards.h"
16 #include "../zotnet/mts.h"
22 #include <sys/types.h>
44 #define POPSERVICE "pop"
57 auth1
, auth2
, trans
, update
, halt
, error
61 auth1
, auth2
, trans
, mbox
, item
, ack
, update
, halt
, error
66 static int user (), pass ();
68 static isguest(), getbbmax();
70 static int xtnd1(), xtnd2();
72 static int xtnd1(), xtnd2(), xtnd3 ();
81 static int status (), list (), retrieve (), delete (), reset ();
82 static int top (), last ();
88 static int helo (), rdp2 (), acks (), ack2 (), fold (), nack ();
91 static struct vector
{
96 enum state v_win
, v_lose
;
98 "user", 1, 1, user
, auth1
, auth2
, auth1
,
99 "pass", 1, 1, pass
, auth2
, trans
, auth1
,
101 "rpop", 1, 1, rpop
, auth2
, trans
, auth1
,
104 "apop", 2, 2, apop
, auth1
, trans
, auth1
,
106 "quit", 0, 0, NULL
, auth1
, halt
, halt
,
107 "quit", 0, 0, NULL
, auth2
, halt
, halt
,
109 "stat", 0, 0, status
, trans
, trans
, trans
,
110 "list", 0, 1, list
, trans
, trans
, trans
,
111 "retr", 1, 1, retrieve
, trans
, trans
, trans
,
112 "dele", 1, 1, delete, trans
, trans
, trans
,
113 "noop", 0, 0, NULL
, trans
, trans
, trans
,
114 "rset", 0, 0, reset
, trans
, trans
, trans
,
116 "top", 2, 2, top
, trans
, trans
, trans
,
117 "last", 0, 0, last
, trans
, trans
, trans
,
120 "xtnd", 1, 2, xtnd
, trans
, trans
, trans
,
122 "xtnd", 1, 3, xtnd
, trans
, trans
, trans
,
125 "quit", 0, 0, quit
, trans
, halt
, halt
,
128 "helo", 2, 2, helo
, auth1
, mbox
, auth1
,
130 "fold", 1, 1, fold
, mbox
, mbox
, mbox
,
131 "quit", 0, 0, quit
, mbox
, halt
, halt
,
132 "read", 0, 1, rdp2
, mbox
, item
, error
,
134 "fold", 1, 1, fold
, item
, mbox
, mbox
,
135 "read", 0, 1, rdp2
, item
, item
, error
,
136 "quit", 0, 0, quit
, item
, halt
, halt
,
137 "retr", 0, 0, retrieve
, item
, ack
, error
,
139 "acks", 0, 0, ack2
, ack
, item
, error
,
140 "ackd", 0, 0, ack2
, ack
, item
, error
,
141 "nack", 0, 0, rdp2
, ack
, item
, error
,
142 "quit", 0, 0, NULL
, ack
, halt
, halt
,
148 static struct vector
*getvector ();
153 static int pop2
= NOTOK
; /* current pop2 msg, or NOTOK if pop3 */
161 static char *hostname
;
162 static char server
[BUFSIZ
];
163 static char timestamp
[BUFSIZ
];
165 static char username
[BUFSIZ
];
167 static char maildrop
[BUFSIZ
];
172 static long lastseen
;
178 static int guest_uid
;
179 static int guest_gid
;
181 static struct bboard
*BBhead
= NULL
;
182 static struct bboard
*BBtail
= NULL
;
184 static long BBtime
= 0L;
186 static struct bboard
*getbbaux ();
190 struct Msg
{ /* Msgs[0] contains info for entire maildrop */
192 #define m_id m_drop.d_id
193 #define m_size m_drop.d_size
194 #define m_last m_drop.d_start /* Msgs[i = 0] */
195 #define m_start m_drop.d_start /* Msgs[i > 0] */
196 #define m_stop m_drop.d_stop
204 static int nMsgs
= 0;
205 static struct Msg
*Msgs
= NULL
;
211 static int _sc_width
= 0;
212 static char *nfs
= NULL
;
218 #define TRMLEN (sizeof TRM - 1)
221 static TYPESIG
pipeser ();
228 struct passwd
*getpwnam();
232 void padvise (), padios ();
236 #define MBX_READ pmbx_read
237 static int pmbx_read ();
238 static char *p_copy(), *p_copyin(), *p_nextword();
239 static p_cmatch(), p_isdate(), p_ishead(), p_parse(), any();
241 #define MBX_READ mbx_read
243 extern int mbx_read ();
245 static int setup(), setupaux(), read_map(), read_file(), pmbx_size();
246 static int quitaux(), quitfile(), respond(), getline();
247 static m_gMsgs(), multiline(), multiend(), putline();
252 padvise (NULLCP
, LOG_INFO
, "initialize list of BBoards");
254 BBhead
= BBtail
= NULL
;
255 while (getbbaux (NULLCP
))
263 register struct bboard
*bb
,
266 if (BBtime
== getbbtime ())
269 padvise (NULLCP
, LOG_INFO
, "list of BBoards has changed");
271 for (bb
= BBhead
; bb
; bb
= bp
) {
275 free (bb
-> bb_name
);
277 free (bb
-> bb_file
);
278 if (bb
-> bb_archive
)
279 free (bb
-> bb_archive
);
281 free (bb
-> bb_info
);
285 free (bb
-> bb_passwd
);
287 free (bb
-> bb_date
);
289 free (bb
-> bb_addr
);
290 if (bb
-> bb_request
)
291 free (bb
-> bb_request
);
293 free (bb
-> bb_relay
);
295 for (p
= bb
-> bb_aka
; *p
; p
++)
297 free ((char *) bb
-> bb_aka
);
299 for (p
= bb
-> bb_leader
; *p
; p
++)
301 free ((char *) bb
-> bb_leader
);
303 for (p
= bb
-> bb_dist
; *p
; p
++)
305 free ((char *) bb
-> bb_dist
);
310 BBhead
= BBtail
= NULL
;
311 while (getbbaux (NULLCP
))
319 static char *kusername
;
321 kpop (in
, out
, principal
, rhost
, auth
)
324 char *principal
, *rhost
;
327 pop (in
, out
, priv
, rhost
)
336 #if defined (DPOP) || defined (BPOP)
337 register struct passwd
*pw
;
338 #endif /* defined (DPOP) || defined (BPOP) */
339 register struct vector
*v
;
347 (void) sprintf (server
, "%s KPOP server", myhost
);
350 (void) sprintf (server
, "%s server", priv
? "RPOP" : "POP");
353 if ((input
= fdopen (in
, "r")) == NULL
354 || (output
= fdopen (out
, "w")) == NULL
) {/* you lose big */
355 (void) respond (NOTOK
, "%s loses on initialization", server
);
358 (void) signal (SIGPIPE
, pipeser
);
360 if (principal
== NULLCP
) {
362 strcpy(buf
, "Authentication failed: ");
363 strcat(buf
, krb_err_txt
[auth
]);
364 (void) respond (NOTOK
, buf
);
367 kusername
= principal
;
371 if ((pw
= getpwnam (POPUID
)) == NULL
|| !setpwinfo (pw
, POPDB
, 1)) {
372 (void) respond (NOTOK
, "%s loses on DB initialization -- %s",
373 server
, pw
? getbberr () : "POP user-id unknown");
376 pop_uid
= pw
-> pw_uid
;
377 pop_gid
= pw
-> pw_gid
;
380 if ((pw
= getpwnam (popbbuser
)) && pw
-> pw_uid
) {
381 guest_uid
= pw
-> pw_uid
;
382 guest_gid
= pw
-> pw_gid
;
385 guest_uid
= guest_gid
= 0;
391 (void) time (&clock
);
392 (void) sprintf (timestamp
, "<%d.%ld@%s>", getpid (), clock
, myhost
);
394 (void) respond (OK
, "%s ready %s", server
, timestamp
);
396 for (mystate
= auth1
; mystate
!= halt
&& mystate
!= error
;)
397 switch (getline (buffer
, sizeof buffer
, input
)) {
399 if ((v
= getvector (buffer
, vec
)) == NULL
)
401 mystate
= (v
-> v_vec
? (v
-> v_vec
) (vec
)
402 : respond (OK
, NULLCP
)) == OK
410 (void) respond (NOTOK
, "%s signing off", server
);
417 static int helo (vec
) /* sort of "user" and "pass" */
420 pop2
= 0; /* now we're talkin' pop2! */
421 make_lower (username
, vec
[1]); /* helo user pass */
422 return pass (++vec
); /* user pass */
426 static int user (vec
)
429 make_lower (username
, vec
[1]);
431 if (!strcmp(username
, kusername
))
432 return respond (OK
, "Kerberos authentication succeeded. Send username as password (%s)", username
);
434 respond (NOTOK
, "Wrong username supplied (%s vs. %s)",
435 kusername
, username
);
439 return respond (OK
, "password required for %s", username
);
445 static int pass (vec
)
450 register struct passwd
*pw
;
452 register struct spwd
*shpw
;
455 register struct bboard
*pw
;
460 if ((pw
= getpwnam (username
)) != NULL
)
461 return setup(pw
, FALSE
);
463 return respond (NOTOK
, "no local password entry");
466 static struct bboard entry
;
467 static char entry_file
[BUFSIZ
] = "/usr/spool/pop";
470 pw
->bb_name
= username
;
471 strcat(entry_file
, username
);
472 pw
->bb_file
= entry_file
;
473 return setup(pw
, FALSE
);
484 gw
.pw_name
= popbbuser
;
485 gw
.pw_uid
= guest_uid
;
492 if ((pw
= getpwnam (username
)) == NULL
494 || *pw
-> pw_passwd
== NULL
495 || strcmp (crypt (vec
[1], pw
-> pw_passwd
), pw
-> pw_passwd
)) {
497 || (shpw
= getspnam (username
)) == NULL
498 || *shpw
-> sp_pwdp
== NULL
499 || strcmp (crypt (vec
[1], shpw
-> sp_pwdp
), shpw
-> sp_pwdp
)) {
502 trusted (0, hostname
, NULLCP
, 0, pw
? pw
-> pw_name
: username
,
503 pw
&& pw
-> pw_uid
== 0, POPSERVICE
, "tcp", NULL
);
505 return respond (NOTOK
, "login incorrect");
510 static struct bboard gw
;
512 gw
.bb_name
= popbbuser
;
518 if (((pw
= getbbnam (username
)) == NULL
519 && (pw
= getbbaka (username
)) == NULL
)
520 || *pw
-> bb_passwd
== NULL
521 || strcmp (crypt (vec
[1], pw
-> bb_passwd
), pw
-> bb_passwd
)) {
523 trusted (0, hostname
, NULLCP
, 0, pw
? pw
-> bb_name
: username
,
524 0, POPSERVICE
, "tcp", NULL
);
526 return respond (NOTOK
, "login incorrect");
534 if (trusted (1, hostname
, NULLCP
, 0, myhost
,
536 pw
-> pw_name
, pw
-> pw_uid
== 0,
540 POPSERVICE
, "tcp", NULL
)
542 return respond (NOTOK
, "permission denied");
544 return setup (pw
, guest
);
557 if (strcmp (username
, popbbuser
) || !guest_uid
)
559 if (popbblist
== NULL
|| (fp
= fopen (popbblist
, "r")) == NULL
)
564 while (fgets (buffer
, sizeof buffer
, fp
)) {
565 if (cp
= index (buffer
, '\n'))
567 if (strcmp (buffer
, hostname
) == 0) {
582 static int rpop (vec
)
586 register struct passwd
*pw
;
588 register int hostok
= 0;
592 register struct bboard
*pw
;
596 if (!rproto
|| (pw
= getpwnam (username
)) == NULL
) {
598 trusted (0, hostname
, vec
[1], 0, username
, 0, "rpop", "tcp",
601 return respond (NOTOK
, "login incorrect");
603 if (chdir (pw
-> pw_dir
) == NOTOK
&& chdir ("/") == NOTOK
)
604 return respond (NOTOK
, "no remote directory");
605 if (ruserok (hostname
, pw
-> pw_uid
== 0, vec
[1], username
) == NOTOK
) {
607 trusted (0, hostname
, vec
[1], 0, pw
-> pw_name
,
608 pw
-> pw_uid
== 0, "rpop", "tcp", NULL
);
610 return respond (NOTOK
, "permission denied");
614 || ((pw
= getbbnam (username
)) == NULL
615 && (pw
= getbbaka (username
)) == NULL
)) {
617 trusted (0, hostname
, vec
[1], 0, username
, 0, "rpop", "tcp",
620 return respond (NOTOK
, "login incorrect");
623 * hacked by Dave Cohrs Tue Feb 4 14:12:15 CST 1986
624 * to allow the hostname to be a list: user@host1,user@host2
625 * NOTE: the separator must be a comma -- no spaces are allowed
627 (void) sprintf (buffer
, "%s@%s", vec
[1], hostname
);
628 for (bp
= pw
-> bb_addr
; bp
; bp
= cp
) {
629 if ((cp
= index (bp
, ',')))
631 hostok
= uleq (bp
, buffer
);
639 trusted (0, hostname
, vec
[1], 0, pw
-> bb_name
, 0, "rpop",
642 return respond (NOTOK
, "permission denied");
647 if (trusted (1, hostname
, vec
[1], 0, username
,
655 return respond (NOTOK
, "permission denied");
657 return setup (pw
, FALSE
);
665 #include "../../uip/md5.c"
667 #include <sys/file.h>
673 static int apop (vec
)
678 register unsigned char *dp
;
682 register struct passwd
*pw
;
684 register struct bboard
*pw
;
691 struct authinfo auth
;
693 (void) strcpy (username
, vec
[1]);
696 if ((pw
= getpwnam (username
)) == NULL
697 || *pw
-> pw_passwd
== NULL
) {
698 return respond (NOTOK
, "user invalid");
701 if (((pw
= getbbnam (username
)) == NULL
702 && (pw
= getbbaka (username
)) == NULL
)
703 || *pw
-> bb_passwd
== NULL
) {
704 return respond (NOTOK
, "subscriber invalid");
708 if ((db
= dbm_open (APOP
, O_RDONLY
, 0)) == NULL
)
709 return respond (NOTOK
, "POP authorization DB not available (%d)",
711 if (fstat (dbm_pagfno (db
), &st
) != NOTOK
712 && (st
.st_mode
& 0777) != 0600) {
714 return respond (NOTOK
, "POP authorization DB has wrong mode (0%o)",
717 if (flock (dbm_pagfno (db
), LOCK_SH
) == NOTOK
) {
719 return respond (NOTOK
, "unable to lock POP authorization DB (%d)",
722 key
.dsize
= strlen (key
.dptr
= vec
[1]) + 1;
723 value
= dbm_fetch (db
, key
);
724 if (value
.dptr
== NULL
) {
726 return respond (NOTOK
, "not authorized");
728 bcopy (value
.dptr
, (char *) &auth
, sizeof auth
);
729 (void) sprintf (cp
= buffer
, "%s%*.*s", timestamp
, auth
.auth_secretlen
,
730 auth
.auth_secretlen
, auth
.auth_secret
);
734 MD5Init (&mdContext
);
735 MD5Update (&mdContext
, (unsigned char *) buffer
,
736 (unsigned int) (strlen (timestamp
) + auth
.auth_secretlen
));
737 MD5Final (digest
, &mdContext
);
740 for (ep
= (dp
= digest
) + sizeof digest
/ sizeof digest
[0];
743 (void) sprintf (cp
, "%02x", *dp
++ & 0xff);
746 if (strcmp (vec
[2], buffer
))
747 return respond (NOTOK
, "authentication failure");
749 return setup (pw
, 0);
755 static int setup (pw
, guest
)
757 register struct passwd
*pw
;
759 register struct bboard
*pw
;
765 (void) setgid (guest_gid
);
767 (void) initgroups (popbbuser
, guest_gid
);
769 (void) setuid (guest_uid
);
774 (void) setgid (pw
-> pw_gid
);
776 (void) initgroups (pw
-> pw_name
, pw
-> pw_gid
);
778 (void) setuid (pw
-> pw_uid
);
780 (void) setgid (pop_gid
);
782 (void) initgroups (POPUID
, pop_gid
);
784 (void) setuid (pop_uid
);
791 (void) sprintf (maildrop
, "%s/%s",
792 mmdfldir
&& *mmdfldir
? mmdfldir
: pw
-> pw_dir
,
793 mmdflfil
&& *mmdflfil
? mmdflfil
: pw
-> pw_name
);
795 (void) strcpy (maildrop
, pw
-> bb_file
);
798 if (setupaux (guest
) == NOTOK
)
802 if (pop2
!= NOTOK
) { /* in response to pop2 "helo" */
803 pop2
= nmsgs
> 0 ? 1 : 0;
804 return respond ('#', "%d message%s (%d octets)",
805 nmsgs
, nmsgs
!= 1 ? "s" : "", Msgs
[0].m_size
);
810 nmsgs
? "maildrop has %d message%s (%d octets)" : "maildrop empty",
811 nmsgs
, nmsgs
!= 1 ? "s" : "", Msgs
[0].m_size
);
816 static int setupaux (readonly
)
826 if ((dp
= readonly
? fopen (maildrop
, "r") : lkfopen (maildrop
, "r"))
835 return respond (NOTOK
, "unable to %s maildrop: \"%s\"",
836 readonly
? "read" : "lock", maildrop
);
839 if (fstat (fileno (dp
), &st
) != NOTOK
) {
840 mode
= (int) (st
.st_mode
& 0777), mtime
= st
.st_mtime
;
841 msgp
= read_map (maildrop
, (long) st
.st_size
);
844 mode
= 0600, mtime
= 0;
848 if ((msgp
= read_file (msgp
? Msgs
[msgp
].m_stop
: 0L, msgp
+ 1)) < 1)
852 lastseen
= Msgs
[0].m_last
;
853 if(debug
)padvise(NULLCP
,LOG_DEBUG
,"XXX: lastseen=%d",lastseen
);
857 Msgs
[0].m_flags
= readonly
? MREAD
: MNULL
;
859 for (i
= 1; i
<= nmsgs
; i
++) {
860 if (Msgs
[i
].m_size
== 0)
861 Msgs
[i
].m_size
= pmbx_size (i
);
862 Msgs
[0].m_size
+= Msgs
[i
].m_size
;
863 Msgs
[i
].m_flags
= MNULL
;
871 static int read_map (file
, pos
)
877 register struct drop
*pp
,
882 padvise (NULLCP
, LOG_DEBUG
, "read_map (%s, %ld)", file
, pos
);
884 if ((i
= map_read (file
, pos
, &rp
, debug
)) == 0)
889 Msgs
[0].m_last
= rp
-> d_start
;
892 for (pp
= rp
+ 1; i
-- > 0; msgp
++, pp
++) {
893 mp
= &Msgs
[msgp
].m_drop
;
894 mp
-> d_id
= pp
-> d_id
;
895 mp
-> d_size
= pp
-> d_size
;
896 mp
-> d_start
= pp
-> d_start
;
897 mp
-> d_stop
= pp
-> d_stop
;
901 if (Msgs
[0].m_last
> msgp
) {
903 padvise (NULLCP
, LOG_DEBUG
, "lastseen adjusted from %d to %d",
904 Msgs
[0].m_last
, msgp
);
905 Msgs
[0].m_last
= msgp
;
913 static int read_file (pos
, msgp
)
918 register struct drop
*pp
,
923 padvise (NULLCP
, LOG_DEBUG
, "read_file (%ld, %d)",
926 if ((i
= MBX_READ (dp
, pos
, &rp
, debug
)) <= 0)
929 m_gMsgs ((msgp
- 1) + i
);
931 for (pp
= rp
; i
-- > 0; msgp
++, pp
++) {
932 mp
= &Msgs
[msgp
].m_drop
;
934 mp
-> d_size
= pp
-> d_size
;
935 mp
-> d_start
= pp
-> d_start
;
936 mp
-> d_stop
= pp
-> d_stop
;
949 padvise (NULLCP
, LOG_DEBUG
, "m_gMsgs (%d) 0x%x %d",
953 nMsgs
= n
+ MAXFOLDER
/ 2;
954 Msgs
= (struct Msg
*) calloc ((unsigned) (nMsgs
+ 2), sizeof *Msgs
);
956 padios (NULLCP
, "unable to allocate Msgs structure");
963 nMsgs
= n
+ MAXFOLDER
/ 2;
964 Msgs
= (struct Msg
*) realloc ((char *) Msgs
,
965 (unsigned) (nMsgs
+ 2) * sizeof *Msgs
);
967 padios (NULLCP
, "unable to reallocate Msgs structure");
972 static int pmbx_size (m
)
978 (void) fseek (dp
, Msgs
[m
].m_start
, 0);
979 for (i
= 0, pos
= Msgs
[m
].m_stop
- Msgs
[m
].m_start
; pos
> 0; i
++, pos
--)
980 if (fgetc (dp
) == '\n')
990 static int status (vec
)
993 return respond (OK
, "%d %d", nmsgs
- dmsgs
, Msgs
[0].m_size
);
998 static int rdp2 (vec
) /* always returns OK */
1002 if ((pop2
= atoi (vec
[1])) <= 0)
1006 return NOTOK
; /* close 'em down */
1008 if (pop2
<= 0 || pop2
> nmsgs
) {
1010 return respond ('=', "0 no message");
1012 if (Msgs
[pop2
].m_flags
& MDELE
) {
1014 return respond ('=', "0 message %d is deleted", pop2
);
1017 return respond ('=', "%d (message %d)", Msgs
[pop2
].m_size
, pop2
);
1020 static int ack2 (vec
)
1023 if (strcmp (vec
[0], "ackd") == 0) {
1024 Msgs
[pop2
].m_flags
|= MDELE
; /* ignored later if MREAD */
1025 Msgs
[0].m_size
-= Msgs
[pop2
].m_size
;
1029 if (pop2
) { /* a current msg */
1030 rmsgs
++; /* mark this one as read */
1032 pop2
= -1; /* let rdp2 reset */
1033 else if (Msgs
[pop2
].m_flags
& MDELE
)
1034 pop2
= -1; /* let rdp2 reset */
1035 if (pop2
> Msgs
[0].m_last
)
1036 Msgs
[0].m_last
= pop2
;
1038 return rdp2 (vec
); /* vec = { "acks", 0 } */
1041 static int fold (vec
)
1042 register char **vec
;
1048 /* This might work, or it might be a huge security hole. For my purpose,
1049 * it doesn't need to work, so I'm not going to make sure it's OK.
1053 if (quitaux (NULLVP
) == NOTOK
)
1054 return respond ('#', "0 unable to close folder");
1056 (void) sprintf (maildrop
, vec
[1]);
1057 if (setupaux (access (maildrop
, 2) ? 1 : 0) == NOTOK
)
1058 return respond ('#', "0 unable to read %s", maildrop
);
1060 pop2
= nmsgs
> 0 ? 1 : 0;
1061 return respond ('#', "%d message%s in %s (%d octets)",
1062 nmsgs
, nmsgs
!= 1 ? "s" : "", maildrop
, Msgs
[0].m_size
);
1066 respond ('#', "0 unable to change folders");
1071 static int list (vec
)
1072 register char **vec
;
1077 if ((i
= atoi (vec
[1])) <= 0 || i
> nmsgs
)
1078 return respond (NOTOK
, "no such message: \"%s\"", vec
[1]);
1079 if (Msgs
[i
].m_flags
& MDELE
)
1080 return respond (NOTOK
, "message %d is deleted", i
);
1083 return respond (OK
, "%d %d", i
, Msgs
[i
].m_size
);
1086 if (nfs
&& !xtnded
) {
1089 (void) fseek (dp
, Msgs
[i
].m_start
, 0);
1091 switch (scan (dp
, i
, 0, nfs
, 0, 0, 0,
1092 0, NULLCP
, (long) Msgs
[i
].m_size
, 0)) {
1096 if (cp
= index (scanl
, '\n'))
1098 return respond (OK
, "%d %d #%s",
1099 i
, Msgs
[i
].m_size
, scanl
);
1102 return respond (OK
, "%d %d #%*d empty",
1103 i
, Msgs
[i
].m_size
, DMAXFOLDER
, i
);
1110 return respond (OK
, xtnded
? "%d %d %d" : "%d %d",
1111 i
, Msgs
[i
].m_size
, Msgs
[i
].m_id
);
1115 (void) respond (OK
, "%d message%s (%d octets)",
1116 nmsgs
- dmsgs
, nmsgs
- dmsgs
!= 1 ? "s" : "",
1118 for (i
= 1; i
<= nmsgs
; i
++)
1119 if (!(Msgs
[i
].m_flags
& MDELE
)) {
1121 multiline ("%d %d", i
, Msgs
[i
].m_size
);
1124 if (nfs
&& !xtnded
) {
1127 (void) fseek (dp
, Msgs
[i
].m_start
, 0);
1129 switch (scan (dp
, i
, 0, nfs
, 0, 0, 0,
1130 0, NULLCP
, (long) Msgs
[i
].m_size
, 0)) {
1134 if (cp
= index (scanl
, '\n'))
1136 multiline ("%d %d #%s",
1137 i
, Msgs
[i
].m_size
, scanl
);
1141 multiline ("%d %d #%*d empty",
1142 i
, Msgs
[i
].m_size
, DMAXFOLDER
, i
);
1150 multiline (xtnded
? "%d %d %d" : "%d %d",
1151 i
, Msgs
[i
].m_size
, Msgs
[i
].m_id
);
1161 static int retrieve (vec
)
1162 register char **vec
;
1167 char buffer
[BUFSIZ
];
1172 else if (pop2
== NOTOK
) {
1174 if ((i
= atoi (vec
[1])) <= 0 || i
> nmsgs
)
1175 return respond (NOTOK
, "no such message: \"%s\"", vec
[1]);
1176 if (Msgs
[i
].m_flags
& MDELE
)
1177 return respond (NOTOK
, "message %d is deleted", i
);
1179 (void) respond (OK
, "%d octets", Msgs
[i
].m_size
);
1182 else /* if called by pop2, vec = { "retr", 0 } */
1186 for ((void) fseek (dp
, pos
= Msgs
[i
].m_start
, 0);
1187 fgets (buffer
, sizeof buffer
, dp
) != NULL
&& pos
< Msgs
[i
].m_stop
;
1188 pos
+= (long) (cp
- buffer
+ 1)) {
1189 if (*(cp
= buffer
+ strlen (buffer
) - 1) == '\n')
1191 multiline ("%s", buffer
);
1194 if (pop2
== NOTOK
) { /* then multiend */
1198 if (i
> Msgs
[0].m_last
) {
1211 static int delete (vec
)
1212 register char **vec
;
1216 if (Msgs
[0].m_flags
& MREAD
)
1217 return respond (NOTOK
, "maildrop is read-only");
1219 if ((i
= atoi (vec
[1])) <= 0 || i
> nmsgs
)
1220 return respond (NOTOK
, "no such message: \"%s\"", vec
[1]);
1221 if (Msgs
[i
].m_flags
& MDELE
)
1222 return respond (NOTOK
, "message %d is deleted", i
);
1224 Msgs
[i
].m_flags
|= MDELE
;
1225 Msgs
[0].m_size
-= Msgs
[i
].m_size
;
1228 if (i
> Msgs
[0].m_last
)
1231 return respond (OK
, "message %d deleted (%d octets)", i
, Msgs
[i
].m_size
);
1235 static int reset (vec
)
1240 for (i
= 1; i
<= nmsgs
; i
++)
1241 if (Msgs
[i
].m_flags
& MDELE
) {
1242 Msgs
[i
].m_flags
&= ~MDELE
;
1243 Msgs
[0].m_size
+= Msgs
[i
].m_size
;
1247 Msgs
[0].m_last
= lastseen
;
1253 free (scanl
), scanl
= NULL
;
1254 free (nfs
), nfs
= NULL
;
1259 return status (vec
);
1264 static int top (vec
)
1265 register char **vec
;
1273 char buffer
[BUFSIZ
];
1275 if ((i
= atoi (vec
[1])) <= 0 || i
> nmsgs
)
1276 return respond (NOTOK
, "no such message: \"%s\"", vec
[1]);
1277 if (Msgs
[i
].m_flags
& MDELE
)
1278 return respond (NOTOK
, "message %d is deleted", i
);
1279 if ((j
= atoi (vec
[2])) < 0)
1280 return respond (NOTOK
, "bad number: \"%s\"", vec
[2]);
1282 (void) respond (OK
, vec
[0]);
1285 for ((void) fseek (dp
, pos
= Msgs
[i
].m_start
, 0);
1286 fgets (buffer
, sizeof buffer
, dp
) != NULL
&& pos
< Msgs
[i
].m_stop
;
1287 pos
+= (long) (cp
- buffer
+ 1)) {
1288 if (*(cp
= buffer
+ strlen (buffer
) - 1) == '\n')
1297 multiline ("%s", buffer
);
1308 static int last (vec
)
1311 return respond (OK
, "%d is the last msg seen", Msgs
[0].m_last
);
1317 static int xtnd (vec
)
1318 register char **vec
;
1320 make_lower (vec
[1], vec
[1]);
1322 if (strcmp (vec
[1], "bboards") == 0 || strcmp (vec
[1], "archive") == 0)
1324 if (strcmp (vec
[1], "x-bboards") == 0)
1327 if (strcmp (vec
[1], "scan") == 0)
1331 return respond (NOTOK
, "unknown XTND command: \"%s\"", vec
[1]);
1335 static int xtnd1 (vec
)
1336 register char **vec
;
1338 register struct bboard
*bb
;
1341 make_lower (vec
[2], vec
[2]);
1342 if ((bb
= getbbaux (vec
[2])) == NULL
)
1343 return respond (NOTOK
, "unknown BBoard: \"%s\"", vec
[2]);
1345 if (quitaux (NULLVP
) == NOTOK
)
1347 (void) strcpy (maildrop
,
1348 strcmp (vec
[1], "bboards") ? bb
-> bb_archive
: bb
-> bb_file
);
1349 if (setupaux (TRUE
) == NOTOK
)
1352 (void) respond (OK
, "%s", vec
[1]);
1353 multiline ("%s %d", bb
-> bb_name
, bb
-> bb_maxima
);
1356 if (strcmp (vec
[1], "bboards"))
1357 return respond (NOTOK
, "too few arguments to XTND \"%s\"", vec
[1]);
1359 (void) respond (OK
, "%s", vec
[1]);
1360 for (bb
= BBhead
; bb
; bb
= bb
-> bb_next
) {
1362 if (!(bb
-> bb_flags
& BB_INVIS
))
1363 multiline ("%s %d", bb
-> bb_name
, bb
-> bb_maxima
);
1365 while (bb
= getbbaux (NULLCP
))
1366 if (!(bb
-> bb_flags
& BB_INVIS
))
1367 multiline ("%s %d", bb
-> bb_name
, bb
-> bb_maxima
);
1376 static int xtnd2 (vec
)
1377 register char **vec
;
1381 char buffer
[BUFSIZ
];
1382 register struct bboard
*bb
;
1385 return respond (NOTOK
, "too few arguments to XTND \"%s\"", vec
[1]);
1387 make_lower (vec
[2], vec
[2]);
1388 if ((bb
= getbbaux (vec
[2])) == NULL
)
1389 return respond (NOTOK
, "unknown BBoard: \"%s\"", vec
[2]);
1391 (void) respond (OK
, "%s", vec
[1]);
1392 multiline ("%s", bb
-> bb_name
);
1395 for (ap
= bb
-> bb_aka
; *ap
; ap
++) {
1396 (void) sprintf (cp
, cp
!= buffer
? " %s" : "%s", *ap
);
1399 multiline ("%s", buffer
);
1401 multiline ("%s", bb
-> bb_file
);
1402 multiline ("%s", bb
-> bb_archive
);
1403 multiline ("%s", bb
-> bb_info
);
1404 multiline ("%s", bb
-> bb_map
);
1405 multiline ("%s", bb
-> bb_passwd
);
1408 for (ap
= bb
-> bb_leader
; *ap
; ap
++) {
1409 (void) sprintf (cp
, cp
!= buffer
? " %s" : "%s", *ap
);
1412 multiline ("%s", buffer
);
1414 multiline ("%s", bb
-> bb_addr
);
1415 multiline ("%s", bb
-> bb_request
);
1416 multiline ("%s", bb
-> bb_relay
);
1419 for (ap
= bb
-> bb_dist
; *ap
; ap
++) {
1420 (void) sprintf (cp
, cp
!= buffer
? " %s" : "%s", *ap
);
1423 multiline ("%s", buffer
);
1426 multiline ("0%o %d", bb
-> bb_flags
, bb
-> bb_maxima
);
1427 multiline ("%s", bb
-> bb_date
);
1436 static struct bboard
*getbbaux (s
)
1439 register struct bboard
*bb
;
1443 if (setbbinfo (BBOARDS
, BBDB
, 1))
1444 BBtime
= getbbtime ();
1449 for (bb
= BBhead
; bb
; bb
= bb
-> bb_next
)
1450 if (strcmp (bb
-> bb_name
, s
) == 0) {
1452 padvise (NULLCP
, LOG_DEBUG
, "getbbaux: \"%s\" from cache",
1458 while (bb
= getbbent ()) {
1459 if ((bb
= getbbcpy (bb
)) == NULL
)
1462 if (access (bb
-> bb_file
, 04) == NOTOK
&& errno
== EACCES
)
1463 bb
-> bb_flags
|= BB_INVIS
;
1464 bb
-> bb_mtime
= stat (bb
-> bb_info
, &st
) != NOTOK
? st
.st_mtime
: 0L;
1467 BBtail
-> bb_next
= bb
;
1472 if (s
== NULL
|| strcmp (bb
-> bb_name
, s
) == 0) {
1474 padvise (NULLCP
, LOG_DEBUG
, "getbbaux: \"%s\" from scratch",
1485 static getbbmax (bb
)
1486 register struct bboard
*bb
;
1490 char buffer
[BUFSIZ
];
1495 padvise (NULLCP
, LOG_DEBUG
, "getbbmax: \"%s\", 0%o, %d, %s",
1496 bb
-> bb_name
, bb
-> bb_flags
, bb
-> bb_maxima
, bb
-> bb_date
);
1498 if (!(bb
-> bb_flags
& BB_INVIS
)
1499 && access (bb
-> bb_file
, 04) == NOTOK
&& errno
== EACCES
)
1500 bb
-> bb_flags
|= BB_INVIS
;
1502 if (stat (bb
-> bb_info
, &st
) == NOTOK
1503 || bb
-> bb_mtime
== st
.st_mtime
1504 || (fp
= fopen (bb
-> bb_info
, "r")) == NULL
)
1506 bb
-> bb_mtime
= st
.st_mtime
;
1508 if (fgets (buffer
, sizeof buffer
, fp
) && (i
= atoi (buffer
)) > 0)
1509 bb
-> bb_maxima
= i
;
1510 if (!feof (fp
) && fgets (buffer
, sizeof buffer
, fp
)) {
1512 free (bb
-> bb_date
);
1513 if (cp
= index (buffer
, '\n'))
1515 bb
-> bb_date
= getcpy (buffer
);
1521 padvise (NULLCP
, LOG_DEBUG
, "updated: \"%s\", 0%o, %d, %s",
1522 bb
-> bb_name
, bb
-> bb_flags
, bb
-> bb_maxima
, bb
-> bb_date
);
1528 static int xtnd3 (vec
)
1529 register char **vec
;
1532 return respond (NOTOK
, "too few arguments to XTND \"%s\"", vec
[1]);
1533 if ((_sc_width
= atoi (vec
[2])) < WIDTH
/ 2)
1534 _sc_width
= WIDTH
/ 2;
1535 nfs
= new_fs (NULLCP
, vec
[3], FORMAT
);
1537 (void) free (scanl
), scanl
= NULL
;
1539 return respond (OK
, vec
[1]);
1542 int sc_width () { return _sc_width
; }
1548 static int quit (vec
)
1554 d
= dmsgs
, n
= nmsgs
;
1556 if (quitaux (vec
) == NOTOK
)
1561 return respond (OK
, "%s signing off", server
);
1565 return respond (OK
, "%s signing off (maildrop empty)", server
);
1568 n
? "%s signing off (%d message%s, %d octets left)"
1569 : "%s signing off (maildrop empty)",
1570 server
, n
- d
, n
- d
!= 1 ? "s" : "", Msgs
[0].m_size
);
1574 static int quitaux (vec
)
1584 nmsgs
= dmsgs
= rmsgs
= 0;
1585 (void) lkfclose (dp
, maildrop
);
1595 static int quitfile (vec
)
1602 char tmpfil
[BUFSIZ
],
1607 if(debug
)padvise(NULLCP
,LOG_DEBUG
,"XXX: dmsgs=%d rmsgs=%d readonly=%d",
1608 dmsgs
, rmsgs
, Msgs
[0].m_flags
& MREAD
);
1610 if (dmsgs
== 0 || (Msgs
[0].m_flags
& MREAD
))
1613 if (fstat (fileno (dp
), &st
) == NOTOK
)
1614 return respond (NOTOK
, "unable to stat file");
1615 if (mtime
!= st
.st_mtime
)
1616 return respond (NOTOK
, "new messages have arrived, no update");
1617 mode
= (int) (st
.st_mode
& 0777);
1619 if (nmsgs
== dmsgs
) {
1621 i
= truncate (maildrop
, 0);
1623 i
= open (maildrop
, O_WRONLY
| O_TRUNC
);
1624 if (i
!= NOTOK
) (void) close (i
);
1626 (void) unlink (map_name (maildrop
));/* XXX */
1628 return respond (NOTOK
, "unable to zero %s", maildrop
);
1632 (void) strcpy (tmpfil
, m_backup (maildrop
));
1633 if ((md
= mbx_open (tmpfil
, st
.st_uid
, st
.st_gid
, mode
)) == NOTOK
)
1634 { char msgbuf0
[256];
1635 sprintf(msgbuf0
,"unable to create temporary file (%s)",tmpfil
);
1636 return respond (NOTOK
, msgbuf0
);
1639 j
= 0, tmpDR
= Msgs
[0].m_last
;
1640 if(debug
)padvise(NULLCP
,LOG_DEBUG
,"XXX: last=%d",Msgs
[0].m_last
);
1641 for (i
= 1; i
<= nmsgs
; i
++) {
1642 if (!(Msgs
[i
].m_flags
& MDELE
))
1647 if(debug
)padvise(NULLCP
,LOG_DEBUG
,"XXX: last=%d",Msgs
[0].m_last
);
1649 for (i
= 1; i
<= nmsgs
; i
++)
1650 if (!(Msgs
[i
].m_flags
& MDELE
)
1651 && mbx_write (tmpfil
, md
, dp
, Msgs
[i
].m_id
, Msgs
[0].m_last
,
1652 Msgs
[i
].m_start
, Msgs
[i
].m_stop
, TRUE
, debug
)
1654 (void) mbx_close (tmpfil
, md
);
1655 (void) unlink (tmpfil
);
1656 return respond (NOTOK
, "error writing temporary file");
1658 (void) mbx_close (tmpfil
, md
);
1660 if ((i
= rename (tmpfil
, maildrop
)) == OK
) {
1661 (void) strcpy (map1
, map_name (tmpfil
));
1662 (void) strcpy (map2
, map_name (maildrop
));
1663 if (rename (map1
, map2
) == NOTOK
) {
1664 (void) unlink (map1
);
1665 (void) unlink (map2
);
1670 return respond (NOTOK
, "unable to rename maildrop");
1677 static struct vector
*getvector (bp
, vec
)
1682 register struct vector
*v
;
1684 for (i
= 0; i
< NVEC
; i
++) {
1685 while (isspace (*bp
))
1693 for (vec
[i
] = ++bp
; *bp
!= '\0' && *bp
!= '"'; bp
++)
1697 (void) strcpy (bp
, bp
+ 1);
1703 (void) strcpy (bp
- 1, bp
);
1716 while (!isspace (*bp
))
1723 (void) respond (NOTOK
, "too many arguments");
1727 (void) respond (NOTOK
, "null command");
1730 make_lower (vec
[0], vec
[0]);
1732 for (v
= vectors
; v
-> v_cmd
; v
++)
1733 if (strcmp (v
-> v_cmd
, vec
[0]) == 0 && v
-> v_valid
== mystate
) {
1734 if (i
< v
-> v_min
|| v
-> v_max
< i
) {
1735 (void) respond (NOTOK
, "too %s arguments to \"%s\"",
1736 i
< v
-> v_min
? "few" : "many", vec
[0]);
1743 (void) respond (NOTOK
, "unknown command: \"%s\"", vec
[0]);
1751 static int respond (code
, fmt
, a
, b
, c
, d
)
1760 char buffer
[BUFSIZ
];
1764 (void) sprintf (bp
, "%s%s", code
== OK
? "+OK" : "-ERR", fmt
? " " : "");
1770 (void) sprintf (bp
, "%s%s", code
== OK
? "+OK" : "-ERR",
1775 default: /* only happens in pop2 */
1781 (void) sprintf (bp
, fmt
, a
, b
, c
, d
);
1784 putline (buffer
, output
);
1792 static multiline (fmt
, a
, b
, c
, d
)
1800 char buffer
[BUFSIZ
+ TRMLEN
];
1802 (void) strcpy (buffer
, TRM
);
1803 (void) sprintf (cp
= (buffer
+ TRMLEN
), fmt
, a
, b
, c
, d
);
1804 if (strncmp (cp
, TRM
, TRMLEN
) == 0)
1807 putline (cp
, output
);
1811 static multiend () {
1812 putline (TRM
, output
);
1817 static int getline (s
, n
, iop
)
1826 while (--n
> 0 && (c
= fgetc (iop
)) != EOF
) {
1831 if ((*p
++ = c
) == '\n')
1836 if (c
== EOF
&& p
== s
)
1841 padvise (NULLCP
, LOG_DEBUG
, "<--- %s", s
);
1852 static putline (s
, iop
)
1856 (void) fprintf (iop
, "%s\r\n", s
);
1858 padvise (NULLCP
, LOG_DEBUG
, "---> %s", s
);
1860 (void) fflush (iop
);
1866 static TYPESIG
pipeser (sig
, code
, sc
)
1869 struct sigcontext
*sc
;
1871 padvise (NULLCP
, LOG_WARNING
, "lost connection");
1878 /* Some people don't want to use the POP delivery agent with Sendmail
1879 * if they're going to run POP. Sendmail writes maildrops in the old
1880 * UUCP format, and popd doesn't know how to read them. These people
1881 * really should do what the MH manual says -- run the pop delivery
1882 * agent and be done with it. Some things never die.
1884 * A real fix would be to make uip/dropsbr.c should use the same methods
1885 * as sbr/m_getfld.c to determine the format of maildrops and read &
1886 * write them. Unfortunately, it'll take a lot of work to bring it into
1887 * the fold. 20Mar90/JLR
1889 * I really really hate to add this, but this lets stuff popd read
1890 * UUCP style maildrops as well as MMDF (ctrl/A) style maildrops. It was
1891 * contributed by Steve Dempsey <steved@longs.LANCE.ColoState.Edu>.
1893 * Here's what he says:
1895 * Ideally, one should be able to do it with the mmdelim strings, but
1896 * the MH parser is not intelligent enough to do this. You have at
1897 * least a couple of choices:
1899 * - use aliases to deliver mail to POP users (user: user@pop) and
1900 * install the POP delivery agent - should work well with sendmail.
1901 * - fix the POP server!
1903 * We have all mail sent to one machine and users are given two options:
1905 * - MH on any machine.
1906 * - any user agent on the postoffice machine.
1908 * Most of our workstations run xmh and users find that to be sufficient.
1909 * New users are only taught to use MH, and a very few old timers stay
1910 * with BSD mail. In any case, several agents are available at the cost
1911 * of a telnet/rlogin if a user does not like MH.
1913 * I have made the changes to the POP server (MH-6.6/support/pop/popser.c)
1914 * to look for the `\n\nFrom ' delimiter instead of the ^A's, using some
1915 * code from the BSD agent. Context diff is included below. When this
1916 * is installed, you just go back to the normal localmail and get rid of
1917 * slocal completely.
1919 * I have not tried this modification with anything but the MH client,
1920 * but it should work. Nothing in the POP protocol changes; the server
1921 * just has different criteria for delimiting messages in the mailbox.
1922 * If you decide to use this, I'd like to know what happens.
1924 * Steve Dempsey, Center for Computer Assisted Engineering
1925 * Colorado State University, Fort Collins, CO 80523 +1 303 491 0630
1926 * INET: steved@longs.LANCE.ColoState.Edu, dempsey@handel.CS.ColoState.Edu
1927 * boulder!ccncsu!longs.LANCE.ColoState.Edu!steved, ...!ncar!handel!dempsey
1929 /* From: Jim Reid <jim@computer-science.strathclyde.ac.UK>
1931 * MH-6.7 does not support MMDF-style mailboxes with POP as claimed. It
1932 * appears that when code was added to popser.c to support UNIX-style
1933 * mailboxes, the old behaviour was lost. i.e. The new popd worked with
1934 * UNIX-style mailboxes, but not MMDF ones. Users would get "format error"
1935 * error messages if they tried to inc a remote MMDF-style mailbox because
1936 * the pop daemon didn't want to know or like the MMDF message delimiters.
1939 /* So... Now there's an incredible hack in mhconfig.c to define POPUUMBOX
1940 * in support/pop/Makefile if we're using Sendmail. This causes this
1941 * UUCP-mbox reading code to be used here. Ugh. 05Nov90/JLR
1946 /* from dropsbr.c - read from a mailbox - pop server version */
1948 /* ALMOST IDENTICAL to mbx_read */
1950 static int pmbx_read (fp
, pos
, drops
, noisy
)
1953 struct drop
**drops
;
1959 char buffer
[BUFSIZ
];
1960 register struct drop
*cp
,
1965 /* MTR: tsk, tsk, tsk... */
1966 (void) fseek (fp
, pos
, 0);
1967 if (fgets (buffer
, sizeof buffer
, fp
)
1968 && strcmp (buffer
, mmdlm1
) == 0)
1969 return mbx_read (fp
, pos
, drops
, noisy
);
1971 /* get drop storage */
1972 pp
= (struct drop
*) calloc ((unsigned) (len
= MAXFOLDER
), sizeof *dp
);
1975 padvise (NULLCP
, LOG_DEBUG
, "pmbx_read (%d, %ld, %d, %d)",
1976 fp
, pos
,drops
,noisy
);
1980 admonish (NULLCP
, "unable to allocate drop storage");
1984 /* rewind drop file */
1985 (void) fseek (fp
, pos
, 0);
1988 padvise (NULLCP
, LOG_DEBUG
, "rewind maildrop");
1991 for (ep
= (dp
= pp
) + len
- 1; fgets (buffer
, sizeof buffer
, fp
);) {
1994 /* if beginning of msg then mark it */
1996 if (p_ishead(buffer
)) /*(strcmp (buffer, mmdlm1) == 0)*/ {
1997 /* (don't) inc pos to msg start, mark it */
1999 dp
-> d_start
= pos
;
2000 pos
+= strlen(buffer
); /* inc pos after marking head */
2003 /* didn't find it; mark it anyway */
2004 dp
-> d_start
= pos
, pos
+= (long) strlen (buffer
);
2006 /* count newlines and inc size if any found */
2007 for (bp
= buffer
; *bp
; bp
++, size
++)
2012 /* read more lines... */
2013 while (fgets (buffer
, sizeof buffer
, fp
) != NULL
)
2016 if (p_ishead(buffer
)) /*(strcmp (buffer, mmdlm2) == 0)*/ {
2019 (void) fseek (fp
, pos
, 0);
2024 /* add buffer size to pos */
2025 pos
+= (long) strlen (buffer
);
2027 /* count newlines.... */
2028 for (bp
= buffer
; *bp
; bp
++, size
++)
2033 if (dp
-> d_start
!= pos
) {
2034 /* do this if pos was actually incremented; got some text */
2036 dp
-> d_size
= size
; /* save the stuff we got */
2041 /* (don't) advance pos */
2044 /* need more storage.... */
2046 register int curlen
= dp
- pp
;
2048 cp
= (struct drop
*) realloc ((char *) pp
,
2049 (unsigned) (len
+= MAXFOLDER
) * sizeof *pp
);
2052 admonish (NULLCP
, "unable to allocate drop storage");
2056 dp
= cp
+ curlen
, ep
= (pp
= cp
) + len
- 1;
2060 /* return unused stuff */
2069 * The remainder of this file adapted from:
2071 * head.c 5.2 (Berkeley) 6/21/85
2075 char *l_from
; /* The name of the sender */
2076 char *l_tty
; /* His tty string (if any) */
2077 char *l_date
; /* The entire date string */
2082 * See if position in a file is a mail header.
2083 * Return true if yes. Note the extreme pains to
2084 * accomodate all funny formats.
2087 #define NOSTR ((char *) 0) /* Null string pointer */
2088 static char *p_copyin();
2089 static char *p_copy();
2092 static p_ishead(buffer
)
2097 char linebuf
[BUFSIZ
];
2098 char parbuf
[BUFSIZ
];
2100 strcpy(linebuf
,buffer
);
2103 if (linebuf
[0]=='F')
2104 padvise (NULLCP
, LOG_DEBUG
, "ishead: '%s'",linebuf
);
2106 if (strncmp("From ", cp
, 5) != 0)
2109 padvise (NULLCP
, LOG_DEBUG
, "Fromline...");
2111 /* get full header */
2112 p_parse(cp
, &hl
, parbuf
);
2114 if (hl
.l_from
== NOSTR
|| hl
.l_date
== NOSTR
) {
2115 padvise (NULLCP
, LOG_DEBUG
, "Fromline...NODATE");
2119 if (!p_isdate(hl
.l_date
)) {
2120 padvise (NULLCP
, LOG_DEBUG
, "Fromline...BADDATE %s",
2125 /* I guess we got it! */
2126 padvise (NULLCP
, LOG_DEBUG
, "got a head.. ");
2132 * Split a headline into its useful components.
2133 * Copy the line into dynamic string space, then set
2134 * pointers into the copied line in the passed headline
2135 * structure. Actually, it scans.
2138 static p_parse(line
, hl
, pbuf
)
2139 char line
[], pbuf
[];
2140 struct p_hdline
*hl
;
2142 register char *cp
, *dp
;
2145 char * p_nextword();
2154 * Skip the first "word" of the line, which should be "From"
2157 cp
= p_nextword(cp
, word
);
2158 dp
= p_nextword(cp
, word
);
2159 if (!(strcmp(word
, "")==0))
2160 hl
->l_from
= p_copyin(word
, &sp
);
2163 if (strncmp(dp
, "tty", 3) == 0) {
2164 cp
= p_nextword(dp
, word
);
2165 hl
->l_tty
= p_copyin(word
, &sp
);
2167 hl
->l_date
= p_copyin(cp
, &sp
);
2173 hl
->l_date
= p_copyin(dp
, &sp
);
2177 * Copy the string on the left into the string on the right
2178 * and bump the right (reference) string pointer by the length.
2179 * Thus, dynamically allocate space in the right string, copying
2180 * the left string into it.
2184 p_copyin(src
, space
)
2188 register char *cp
, *top
;
2201 * Collect a liberal (space, tab delimited) word into the word buffer
2202 * passed. Also, return a pointer to the next word following that,
2203 * or (empty) if none follow.
2207 p_nextword(wp
, wbuf
)
2210 register char *cp
, *cp2
;
2212 if ((cp
= wp
) == NOSTR
) {
2217 while (!any(*cp
, " \t") && *cp
!= '\0')
2220 while (*cp
!= '\0' && *cp
!= '"')
2227 while (any(*cp
, " \t"))
2235 * Copy str1 to str2, return pointer to null in str2.
2242 register char *s1
, *s2
;
2252 #define L 1 /* A lower case char */
2253 #define S 2 /* A space */
2254 #define D 3 /* A digit */
2255 #define O 4 /* An optional digit or space */
2256 #define C 5 /* A colon */
2257 #define N 6 /* A new line */
2258 #define U 7 /* An upper case char */
2260 static char p_ctypes
[] =
2261 {U
,L
,L
,S
,U
,L
,L
,S
,O
,D
,S
,D
,D
,C
,D
,D
,C
,D
,D
,S
,D
,D
,D
,D
,0};
2262 /* T h u S e p 2 9 1 5 : 2 0 : 1 9 1 9 8 8 */
2264 static char p_tmztyp
[] =
2265 {U
,L
,L
,S
,U
,L
,L
,S
,O
,D
,S
,D
,D
,C
,D
,D
,C
,D
,D
,S
,U
,U
,U
,S
,D
,D
,D
,D
,0};
2266 /* T h u S e p 2 9 1 5 : 2 0 : 1 9 M S T 1 9 8 8 */
2268 static p_isdate(date
)
2274 if (p_cmatch(cp
, p_ctypes
))
2277 return(p_cmatch(cp
, p_tmztyp
));
2281 * Match the given string against the given template.
2282 * Return 1 if they match, 0 if they don't
2285 static p_cmatch(str
, temp
)
2288 register char *cp
, *tp
;
2293 while (*cp
!= '\0' && *tp
!= 0) {
2297 if (c
< 'a' || c
> 'z')
2302 if (c
< 'A' || c
> 'Z')
2317 if (c
!= ' ' && !isdigit(c
))
2332 if ((*cp
!= '\0' && *cp
!= '\n') || *tp
!= 0)