1 /*$Id: ezmlm-idx.c,v 1.29 1999/10/29 02:49:14 lindberg Exp $*/
2 /*$Name: ezmlm-idx-040 $*/
19 #include "readwrite.h"
28 #define FATAL "ezmlm-idx: fatal: "
30 char strnum
[FMT_ULONG
];
33 stralloc fnadir
= {0};
45 int flagdate
= 0; /* use 'Received:' header by default, =1 -> 'Date:' */
47 /* for reading index and in ezmlm-idx for reading message */
49 static char inbuf
[1024];
56 stralloc subject
= {0};
57 stralloc author
= {0};
58 stralloc authmail
= {0};
59 stralloc received
= {0};
60 stralloc prefix
= {0};
61 stralloc charset
= {0};
63 struct strerr index_err
;
68 substdio ss0
= SUBSTDIO_FDBUF(read
,0,buf0
,sizeof(buf0
));
72 strerr_die1x(100,"ezmlm-idx: usage: ezmlm-idx [-dDF] [-f msg] dir");
78 strerr_die2x(100,FATAL
,ERR_NOMEM
);
81 int idx_get_trimsubject()
83 /* reads an open message from 'fd', extracts the subject (if any), and */
84 /* returns the subject in 'sub', the author in 'author', and the received */
85 /* rfc822 date to 'received'. 'fatal' is a program-specific error string. */
86 /* returns: 0 - no reply no prefix */
87 /* 1 - reply no prefix */
88 /* 2 - prefix no reply */
89 /* 3 - reply & prefix */
90 /* No terminal '\n' in any of the strallocs! */
96 int foundreceived
= 0;
100 unsigned int pos
,pos1
;
102 substdio_fdbuf(&ssin
,read
,fd
,inbuf
,sizeof(inbuf
));
104 if (getln(&ssin
,&line
,&match
,'\n') == -1)
105 strerr_die2x(111,FATAL
,ERR_READ_INPUT
);
109 if (*line
.s
== ' ' || *line
.s
== '\t') {
112 if (!stralloc_cat(&subject
,&line
)) die_nomem();
114 if (!stralloc_cat(&author
,&line
)) die_nomem();
118 if (!foundsubject
&& case_startb(line
.s
,line
.len
,"Subject:")) {
119 if (!stralloc_copyb(&subject
,line
.s
+8,line
.len
-8)) die_nomem();
122 } else if (!foundfrom
&& case_startb(line
.s
,line
.len
,"From:")) {
123 if (!stralloc_copyb(&author
,line
.s
+5,line
.len
-5)) die_nomem();
126 } else if (!flagdate
&& !foundreceived
&&
127 case_startb(line
.s
,line
.len
,"Received:")) {
128 pos
= byte_chr(line
.s
,line
.len
,';');
130 if (!stralloc_copyb(&received
,line
.s
+pos
+2,line
.len
- pos
- 3))
133 } else if (flagdate
&& !foundreceived
&&
134 case_startb(line
.s
,line
.len
,"Date:")) {
135 if (line
.len
< 22) continue; /* illegal */
136 pos
= 6 + byte_chr(line
.s
+6,line
.len
-6,',');
140 while (line
.s
[pos
] == ' ' || line
.s
[pos
] == '\t') ++pos
; /* dd */
142 while (++pos1
< line
.len
&& line
.s
[pos1
] != ' '); /* mo */
144 if (!stralloc_copyb(&received
,line
.s
+pos
,pos1
- pos
))
145 die_nomem(); /* '01 Jun ' */
146 if (pos1
+ 2 < line
.len
) {
147 if (line
.s
[pos1
+ 2] == ' ') { /* 2-digit */
148 if (line
.s
[pos1
] >= '7') { /* >= 70 */
149 if (!stralloc_cats(&received
,"19")) die_nomem();
150 } else if (!stralloc_cats(&received
,"20")) die_nomem();
151 pos
= pos1
+ 3; /* 2 digit */
153 pos
= pos1
+ 5; /* 4 digit */
154 if (pos
< line
.len
) {
155 pos
+= byte_chr(line
.s
+pos
,line
.len
-pos
,' '); /* after time */
156 if (pos
< line
.len
) {
158 while (line
.s
[pos
] != ' ' && line
.s
[pos
] != '\n') ++pos
;
160 pos
= line
.len
- 1; /* no zone. Illegal; better than 0 */
161 if (!stralloc_catb(&received
,line
.s
+pos1
,pos
- pos1
))
167 received
.len
= 0; /* bad format - scrap */
175 concatHDR(subject
.s
,subject
.len
,&lines
,FATAL
); /* make 1 line */
176 decodeHDR(lines
.s
,lines
.len
,&line
,charset
.s
,FATAL
); /* decode mime */
177 r
= unfoldHDR(line
.s
,line
.len
,&subject
,charset
.s
,&prefix
,1,FATAL
);
192 unsigned long msgnum
= 0L;
193 unsigned long msgmax
;
196 while ((opt
= getopt(argc
,argv
,"dDf:FvV")) != opteof
)
198 case 'd': flagdate
= 1; break;
199 case 'D': flagdate
= 0; break;
200 case 'f': if (optarg
) (void) scan_ulong(optarg
,&msgnum
); break;
201 case 'F': msgnum
= 0L;
203 case 'V': strerr_die2x(0,"ezmlm-archive version: ",EZIDX_VERSION
);
204 default: die_usage();
207 if (!dir
) die_usage();
209 if (chdir(dir
) == -1)
210 strerr_die4sys(100,FATAL
,ERR_SWITCH
,dir
,": ");
214 /* obtain lock to write index files */
215 fdlock
= open_append("lock");
217 strerr_die2sys(100,FATAL
,ERR_OPEN_LOCK
);
218 if (lock_ex(fdlock
) == -1)
219 strerr_die2sys(100,FATAL
,ERR_OBTAIN_LOCK
);
221 getconf_line(&charset
,"charset",0,FATAL
,dir
);
222 if (!stralloc_0(&charset
)) die_nomem();
224 getconf_line(&prefix
,"prefix",0,FATAL
,dir
);
225 /* support rfc2047-encoded prefix */
226 decodeHDR(prefix
.s
,prefix
.len
,&line
,charset
.s
,FATAL
);
227 unfoldHDR(line
.s
,line
.len
,&prefix
,charset
.s
,&dummy
,0,FATAL
);
228 /* need only decoded one */
230 /* Get message number */
231 switch(slurp("num",&num
,32)) {
233 strerr_die4sys(100,FATAL
,ERR_READ
,dir
,"/num: ");
235 strerr_die4x(100,FATAL
,dir
,"/num",ERR_NOEXIST
);
237 if (!stralloc_0(&num
)) die_nomem();
238 scan_ulong(num
.s
,&msgmax
);
239 if (msgnum
> msgmax
) _exit(0);
241 msgnum
= (msgnum
/ 100) * 100 - 1;
243 while (++msgnum
<= msgmax
) {
244 if (msgnum
== 1 || !(msgnum
% 100)) {
245 if (!stralloc_copys(&fnadir
,"archive/")) die_nomem();
246 if (!stralloc_catb(&fnadir
,strnum
,fmt_ulong(strnum
,msgnum
/ 100)))
248 if (!stralloc_copy(&fnifn
,&fnadir
)) die_nomem();
249 if (!stralloc_copy(&fnif
,&fnadir
)) die_nomem();
250 if (!stralloc_cats(&fnif
,"/index")) die_nomem();
251 if (!stralloc_cats(&fnifn
,"/indexn")) die_nomem();
252 if (!stralloc_0(&fnadir
)) die_nomem();
253 if (!stralloc_0(&fnifn
)) die_nomem();
254 if (!stralloc_0(&fnif
)) die_nomem();
256 /* May not exist, so be nice and make it */
257 if (mkdir(fnadir
.s
,0755) == -1)
258 if (errno
!= error_exist
)
259 strerr_die4sys(100,FATAL
,ERR_CREATE
,fnadir
.s
,": ");
262 fdindexn
= open_trunc(fnifn
.s
);
264 strerr_die4sys(100,FATAL
,ERR_WRITE
,fnifn
.s
,": ");
266 /* set up buffers for index */
267 substdio_fdbuf(&ssindex
,write
,fdindexn
,indexbuf
,sizeof(indexbuf
));
269 /* Get subject without the 'Subject: ' */
270 /* make sure there is one */
273 if (!stralloc_copys(&fnaf
,fnadir
.s
)) die_nomem();
274 if (!stralloc_cats(&fnaf
,"/")) die_nomem();
275 if (!stralloc_catb(&fnaf
,strnum
,
276 fmt_uint0(strnum
,(unsigned int) (msgnum
% 100),2))) die_nomem();
277 if (!stralloc_0(&fnaf
)) die_nomem();
278 fd
= open_read(fnaf
.s
);
280 if (errno
!= error_noent
)
281 strerr_die4sys(100,FATAL
,ERR_READ
,fnaf
.s
,": ");
282 } else if (fstat(fd
,&st
) == -1 || (!(st
.st_mode
& 0100)))
285 subject
.len
= 0; /* clear in case they're missing in msg */
288 r
= idx_get_trimsubject();
290 if (!stralloc_copyb(&line
,strnum
,fmt_ulong(strnum
,msgnum
))) die_nomem();
291 if (!stralloc_cats(&line
,": ")) die_nomem();
292 makehash(subject
.s
,subject
.len
,hash
);
293 if (!stralloc_catb(&line
,hash
,HASHLEN
)) die_nomem();
294 if (!stralloc_cats(&line
," ")) die_nomem();
295 if (r
& 1) /* reply */
296 if (!stralloc_cats(&line
,"Re: ")) die_nomem();
297 if (!stralloc_cat(&line
,&subject
)) die_nomem();
298 if (!stralloc_cats(&line
,"\n\t")) die_nomem();
299 if (!stralloc_cat(&line
,&received
)) die_nomem();
300 if (!stralloc_cats(&line
,";")) die_nomem();
302 concatHDR(author
.s
,author
.len
,&lines
,FATAL
);
303 mkauthhash(lines
.s
,lines
.len
,hash
);
304 if (!stralloc_catb(&line
,hash
,HASHLEN
)) die_nomem();
306 decodeHDR(cp
,author_name(&cp
,lines
.s
,lines
.len
),&author
,charset
.s
,FATAL
);
307 (void) unfoldHDR(author
.s
,author
.len
,&lines
,charset
.s
,&prefix
,0,FATAL
);
309 if (!stralloc_cats(&line
," ")) die_nomem();
310 if (!stralloc_cat(&line
,&lines
)) die_nomem();
311 if (!stralloc_cats(&line
,"\n")) die_nomem();
312 if (substdio_put(&ssindex
,line
.s
,line
.len
) == -1)
313 strerr_die4sys(100,FATAL
,ERR_WRITE
,fnifn
.s
, ": ");
316 if (!((msgnum
+ 1) % 100) ||
317 (msgnum
== msgmax
)) { /* last in this set */
318 if (substdio_flush(&ssindex
) == -1)
319 strerr_die4sys(100,FATAL
,ERR_FLUSH
,fnifn
.s
, ": ");
320 if (fsync(fdindexn
) == -1)
321 strerr_die4sys(100,FATAL
,ERR_SYNC
,fnifn
.s
, ": ");
322 if (fchmod(fdindexn
,MODE_ARCHIVE
| 0700) == -1)
323 strerr_die4sys(100,FATAL
,ERR_WRITE
,fnifn
.s
, ": ");
324 if (close(fdindexn
) == -1)
325 strerr_die4sys(100,FATAL
,ERR_CLOSE
,fnifn
.s
,": ");
326 if (rename(fnifn
.s
,fnif
.s
) == -1)
327 strerr_die4x(111,FATAL
,ERR_MOVE
,fnifn
.s
,": ");
330 fd
= open_append("indexed");
332 strerr_die4sys(100,FATAL
,ERR_CREATE
,dir
,"/indexed: ");