|
|
1.1 root 1: /* getmsg.cpp */
2:
3: /* Synchronet message retrieval functions */
4:
5: /* $Id: getmsg.cpp,v 1.3 2000/12/11 23:03:16 rswindell Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: /***********************************************************************/
39: /* Functions that do i/o with messages (posts/mail/auto) or their data */
40: /***********************************************************************/
41:
42: #include "sbbs.h"
43:
44: #define LZH TRUE
45:
46: void lfputs(char HUGE16 *buf, FILE *fp)
47: {
48: while(*buf) {
49: fputc(*buf,fp);
50: buf++; }
51: }
52:
53: /****************************************************************************/
54: /* Loads an SMB message from the open msg base the fastest way possible */
55: /* first by offset, and if that's the wrong message, then by number. */
56: /* Returns 1 if the message was loaded and left locked, otherwise */
57: /****************************************************************************/
58: int sbbs_t::loadmsg(smbmsg_t *msg, ulong number)
59: {
60: char str[128];
61: int i;
62:
63: if(msg->idx.offset) { /* Load by offset if specified */
64:
65: if((i=smb_lockmsghdr(&smb,msg))!=0) {
66: errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);
67: return(0); }
68:
69: i=smb_getmsghdr(&smb,msg);
70: if(!i && msg->hdr.number==number)
71: return(1);
72:
73: /* Wrong offset */
74:
75: if(!i) {
76: smb_freemsgmem(msg);
77: msg->total_hfields=0; }
78:
79: smb_unlockmsghdr(&smb,msg); }
80:
81: msg->hdr.number=number;
82: if((i=smb_getmsgidx(&smb,msg))!=0) /* Message is deleted */
83: return(0);
84: if((i=smb_lockmsghdr(&smb,msg))!=0) {
85: errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);
86: return(0); }
87: if((i=smb_getmsghdr(&smb,msg))!=0) {
88: sprintf(str,"(%06lX) #%lu/%lu %s",msg->idx.offset,msg->idx.number
89: ,number,smb.file);
90: smb_unlockmsghdr(&smb,msg);
91: errormsg(WHERE,ERR_READ,str,i,smb.last_error);
92: return(0); }
93: return(msg->total_hfields);
94: }
95:
96:
97: void sbbs_t::show_msgattr(ushort attr)
98: {
99:
100: bprintf(text[MsgAttr]
101: ,attr&MSG_PRIVATE ? "Private " :nulstr
102: ,attr&MSG_READ ? "Read " :nulstr
103: ,attr&MSG_DELETE ? "Deleted " :nulstr
104: ,attr&MSG_KILLREAD ? "Kill " :nulstr
105: ,attr&MSG_ANONYMOUS ? "Anonymous " :nulstr
106: ,attr&MSG_LOCKED ? "Locked " :nulstr
107: ,attr&MSG_PERMANENT ? "Permanent " :nulstr
108: ,attr&MSG_MODERATED ? "Moderated " :nulstr
109: ,attr&MSG_VALIDATED ? "Validated " :nulstr
110: ,attr&MSG_REPLIED ? "Replied " :nulstr
111: ,nulstr
112: ,nulstr
113: ,nulstr
114: ,nulstr
115: ,nulstr
116: ,nulstr
117: );
118: }
119:
120: /****************************************************************************/
121: /* Displays a message header to the screen */
122: /****************************************************************************/
123: void sbbs_t::show_msghdr(smbmsg_t* msg)
124: {
125: char *sender=NULL;
126: int i;
127:
128: attr(LIGHTGRAY);
129: if(useron.misc&CLRSCRN)
130: outchar(FF);
131: else
132: CRLF;
133: bprintf(text[MsgSubj],msg->subj);
134: if(msg->hdr.attr)
135: show_msgattr(msg->hdr.attr);
136:
137: bprintf(text[MsgTo],msg->to);
138: if(msg->to_ext)
139: bprintf(text[MsgToExt],msg->to_ext);
140: if(msg->to_net.addr)
141: bprintf(text[MsgToNet],msg->to_net.type==NET_FIDO
142: ? faddrtoa(*(faddr_t *)msg->to_net.addr) : msg->to_net.addr);
143: if(!(msg->hdr.attr&MSG_ANONYMOUS) || SYSOP) {
144: bprintf(text[MsgFrom],msg->from);
145: if(msg->from_ext)
146: bprintf(text[MsgFromExt],msg->from_ext);
147: if(msg->from_net.addr && !strchr(msg->from,'@'))
148: bprintf(text[MsgFromNet],msg->from_net.type==NET_FIDO
149: ? faddrtoa(*(faddr_t *)msg->from_net.addr)
150: : msg->from_net.addr); }
151: bprintf(text[MsgDate]
152: ,timestr((time_t *)&msg->hdr.when_written.time)
153: ,zonestr(msg->hdr.when_written.zone));
154:
155: CRLF;
156:
157: for(i=0;i<msg->total_hfields;i++) {
158: if(msg->hfield[i].type==SENDER)
159: sender=(char *)msg->hfield_dat[i];
160: if(msg->hfield[i].type==FORWARDED && sender)
161: bprintf(text[ForwardedFrom],sender
162: ,timestr((time_t *)msg->hfield_dat[i])); }
163:
164: /* Debug stuff
165: if(SYSOP) {
166: bprintf("\1n\1c\r\nAux : \1h%08lX",msg->hdr.auxattr);
167: bprintf("\1n\1c\r\nNum : \1h%lu",msg->hdr.number); }
168: */
169:
170: CRLF;
171: }
172:
173: #if !LZH
174:
175: /****************************************************************************/
176: /* Displays message header and text (if not deleted) */
177: /****************************************************************************/
178: void sbbs_t::show_msg(smbmsg_t msg, long mode)
179: {
180: ushort xlat;
181: int i;
182:
183: show_msghdr(msg);
184: for(i=0;i<msg.hdr.total_dfields;i++)
185: switch(msg.dfield[i].type) {
186: case TEXT_BODY:
187: case TEXT_TAIL:
188: smb_fseek(smb.sdt_fp,msg.hdr.offset+msg.dfield[i].offset
189: ,SEEK_SET);
190: smb_fread(&xlat,2,1,smb.sdt_fp);
191: if(xlat!=XLAT_NONE) /* no translations supported */
192: continue;
193: putmsg_fp(smb.sdt_fp,msg.dfield[i].length-2,mode);
194: CRLF;
195: break; }
196: }
197:
198: #else
199:
200: /****************************************************************************/
201: /* Displays message header and text (if not deleted) */
202: /****************************************************************************/
203: void sbbs_t::show_msg(smbmsg_t* msg, long mode)
204: {
205: uchar *inbuf,*lzhbuf;
206: ushort xlat;
207: int i,lzh;
208: long lzhlen,length;
209:
210: show_msghdr(msg);
211: for(i=0;i<msg->hdr.total_dfields;i++)
212: switch(msg->dfield[i].type) {
213: case TEXT_BODY:
214: case TEXT_TAIL:
215: fseek(smb.sdt_fp,msg->hdr.offset+msg->dfield[i].offset
216: ,SEEK_SET);
217: fread(&xlat,2,1,smb.sdt_fp);
218: lzh=0;
219: if(xlat==XLAT_LZH) {
220: lzh=1;
221: fread(&xlat,2,1,smb.sdt_fp); }
222: if(xlat!=XLAT_NONE) /* no translations supported */
223: continue;
224: if(lzh) {
225: length=msg->dfield[i].length-4;
226: if((inbuf=(uchar *)MALLOC(length))==NULL) {
227: errormsg(WHERE,ERR_ALLOC,nulstr,length);
228: continue; }
229: fread(inbuf,length,1,smb.sdt_fp);
230: lzhlen=*(long *)inbuf;
231: /**
232: if(SYSOP)
233: bprintf("Decoding %lu bytes of LZH into %lu bytes of text "
234: "(%d%% compression)"
235: ,length,lzhlen
236: ,(int)(((float)(lzhlen-length)/lzhlen)*100.0));
237: **/
238: if((lzhbuf=(uchar *)MALLOC(lzhlen+2L))==NULL) {
239: FREE(inbuf);
240: errormsg(WHERE,ERR_ALLOC,nulstr,lzhlen+2L);
241: continue; }
242: lzh_decode(inbuf,length,lzhbuf);
243: lzhbuf[lzhlen]=0;
244: // CRLF;
245: putmsg((char *)lzhbuf,P_NOATCODES);
246: FREE(lzhbuf);
247: FREE(inbuf); }
248: else
249: putmsg_fp(smb.sdt_fp,msg->dfield[i].length-2,mode);
250: CRLF;
251: break; }
252: }
253:
254: #endif
255:
256: void sbbs_t::quotemsg(smbmsg_t* msg, int tails)
257: {
258: char str[256];
259:
260: sprintf(str,"%sQUOTES.TXT",cfg.node_dir);
261: remove(str);
262: msgtotxt(msg,str,0,tails);
263: }
264:
265:
266: /****************************************************************************/
267: /* Writes message header and text data to a text file */
268: /****************************************************************************/
269: void sbbs_t::msgtotxt(smbmsg_t* msg, char *str, int header, int tails)
270: {
271: char HUGE16 *buf;
272: int i;
273: FILE *out;
274:
275: if((out=fnopen(&i,str,O_WRONLY|O_CREAT|O_APPEND))==NULL) {
276: errormsg(WHERE,ERR_OPEN,str,0);
277: return; }
278: if(header) {
279: fprintf(out,"\r\n");
280: fprintf(out,"Subj : %s\r\n",msg->subj);
281: fprintf(out,"To : %s",msg->to);
282: if(msg->to_ext)
283: fprintf(out," #%s",msg->to_ext);
284: if(msg->to_net.addr)
285: fprintf(out," (%s)",msg->to_net.type==NET_FIDO
286: ? faddrtoa(*(faddr_t *)msg->to_net.addr) : msg->to_net.addr);
287: fprintf(out,"\r\nFrom : %s",msg->from);
288: if(msg->from_ext && !(msg->hdr.attr&MSG_ANONYMOUS))
289: fprintf(out," #%s",msg->from_ext);
290: if(msg->from_net.addr)
291: fprintf(out," (%s)",msg->from_net.type==NET_FIDO
292: ? faddrtoa(*(faddr_t *)msg->from_net.addr)
293: : msg->from_net.addr);
294: fprintf(out,"\r\nDate : %.24s %s"
295: ,timestr((time_t *)&msg->hdr.when_written.time)
296: ,zonestr(msg->hdr.when_written.zone));
297: fprintf(out,"\r\n\r\n"); }
298:
299: buf=smb_getmsgtxt(&smb,msg,tails);
300: if(buf!=NULL) {
301: lfputs(buf,out);
302: LFREE(buf);
303: } else if(smb_getmsgdatlen(msg)>2)
304: errormsg(WHERE,ERR_READ,smb.file,smb_getmsgdatlen(msg));
305: fclose(out);
306: }
307:
308:
309: /****************************************************************************/
310: /* Returns total number of posts in a sub-board */
311: /****************************************************************************/
312: ulong sbbs_t::getposts(uint subnum)
313: {
314: char str[128];
315: ulong l;
316:
317: sprintf(str,"%s%s.sid",cfg.sub[subnum]->data_dir,cfg.sub[subnum]->code);
318: l=flength(str);
319: if((long)l==-1)
320: return(0);
321: return(l/sizeof(idxrec_t));
322: }
323:
324: /****************************************************************************/
325: /* Returns message number posted at or after time */
326: /****************************************************************************/
327: ulong sbbs_t::getmsgnum(uint subnum, time_t t)
328: {
329: int i;
330: ulong l,total,bot,top;
331: smbmsg_t msg;
332:
333: if(!t)
334: return(0);
335:
336: sprintf(smb.file,"%s%s",cfg.sub[subnum]->data_dir,cfg.sub[subnum]->code);
337: smb.retry_time=cfg.smb_retry_time;
338: if((i=smb_open(&smb))!=0) {
339: errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
340: return(0); }
341:
342: total=filelength(fileno(smb.sid_fp))/sizeof(idxrec_t);
343:
344: if(!total) { /* Empty base */
345: smb_close(&smb);
346: return(0); }
347:
348: if((i=smb_locksmbhdr(&smb))!=0) {
349: smb_close(&smb);
350: errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);
351: return(0); }
352:
353: if((i=smb_getlastidx(&smb,&msg.idx))!=0) {
354: smb_close(&smb);
355: errormsg(WHERE,ERR_READ,smb.file,i,smb.last_error);
356: return(0); }
357:
358: if((time_t)msg.idx.time<=t) {
359: smb_close(&smb);
360: return(msg.idx.number); }
361:
362: bot=0;
363: top=total;
364: l=total/2; /* Start at middle index */
365: clearerr(smb.sid_fp);
366: while(1) {
367: fseek(smb.sid_fp,l*sizeof(idxrec_t),SEEK_SET);
368: if(!fread(&msg.idx,sizeof(idxrec_t),1,smb.sid_fp))
369: break;
370: if(bot==top-1)
371: break;
372: if((time_t)msg.idx.time>t) {
373: top=l;
374: l=bot+((top-bot)/2);
375: continue; }
376: if((time_t)msg.idx.time<t) {
377: bot=l;
378: l=top-((top-bot)/2);
379: continue; }
380: break; }
381: smb_close(&smb);
382: return(msg.idx.number);
383: }
384:
385: /****************************************************************************/
386: /* Returns the time of the message number pointed to by 'ptr' */
387: /****************************************************************************/
388: time_t sbbs_t::getmsgtime(uint subnum, ulong ptr)
389: {
390: int i;
391: smbmsg_t msg;
392: idxrec_t lastidx;
393:
394: sprintf(smb.file,"%s%s",cfg.sub[subnum]->data_dir,cfg.sub[subnum]->code);
395: smb.retry_time=cfg.smb_retry_time;
396: if((i=smb_open(&smb))!=0) {
397: errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
398: return(0); }
399: if(!filelength(fileno(smb.sid_fp))) { /* Empty base */
400: smb_close(&smb);
401: return(0); }
402: msg.offset=0;
403: msg.hdr.number=0;
404: if(smb_getmsgidx(&smb,&msg)) { /* Get first message index */
405: smb_close(&smb);
406: return(0); }
407: if(!ptr || msg.idx.number>=ptr) { /* ptr is before first message */
408: smb_close(&smb);
409: return(msg.idx.time); } /* so return time of first msg */
410:
411: if(smb_getlastidx(&smb,&lastidx)) { /* Get last message index */
412: smb_close(&smb);
413: return(0); }
414: if(lastidx.number<ptr) { /* ptr is after last message */
415: smb_close(&smb);
416: return(lastidx.time); } /* so return time of last msg */
417:
418: msg.idx.time=0;
419: msg.hdr.number=ptr;
420: if(!smb_getmsgidx(&smb,&msg)) {
421: smb_close(&smb);
422: return(msg.idx.time); }
423:
424: if(ptr-msg.idx.number < lastidx.number-ptr) {
425: msg.offset=0;
426: msg.idx.number=0;
427: while(msg.idx.number<ptr) {
428: msg.hdr.number=0;
429: if(smb_getmsgidx(&smb,&msg) || msg.idx.number>=ptr)
430: break;
431: msg.offset++; }
432: smb_close(&smb);
433: return(msg.idx.time); }
434:
435: ptr--;
436: while(ptr) {
437: msg.hdr.number=ptr;
438: if(!smb_getmsgidx(&smb,&msg))
439: break;
440: ptr--; }
441: smb_close(&smb);
442: return(msg.idx.time);
443: }
444:
445:
446: /****************************************************************************/
447: /* Returns the total number of msgs in the sub-board and sets 'ptr' to the */
448: /* number of the last message in the sub (0) if no messages. */
449: /****************************************************************************/
450: ulong sbbs_t::getlastmsg(uint subnum, ulong *ptr, time_t *t)
451: {
452: int i;
453: ulong total;
454: idxrec_t idx;
455:
456: if(ptr)
457: (*ptr)=0;
458: if(t)
459: (*t)=0;
460: if(subnum>=cfg.total_subs)
461: return(0);
462:
463: sprintf(smb.file,"%s%s",cfg.sub[subnum]->data_dir,cfg.sub[subnum]->code);
464: smb.retry_time=cfg.smb_retry_time;
465: if((i=smb_open(&smb))!=0) {
466: errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
467: return(0); }
468:
469: if(!filelength(fileno(smb.sid_fp))) { /* Empty base */
470: smb_close(&smb);
471: return(0); }
472: if((i=smb_locksmbhdr(&smb))!=0) {
473: smb_close(&smb);
474: errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);
475: return(0); }
476: if((i=smb_getlastidx(&smb,&idx))!=0) {
477: smb_close(&smb);
478: errormsg(WHERE,ERR_READ,smb.file,i,smb.last_error);
479: return(0); }
480: total=filelength(fileno(smb.sid_fp))/sizeof(idxrec_t);
481: smb_unlocksmbhdr(&smb);
482: smb_close(&smb);
483: if(ptr)
484: (*ptr)=idx.number;
485: if(t)
486: (*t)=idx.time;
487: return(total);
488: }
489:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.