|
|
1.1 root 1: /* readmsgs.cpp */
2:
3: /* Synchronet public message reading function */
4:
5: /* $Id: readmsgs.cpp,v 1.33 2006/02/02 08:35:14 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 2006 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: #include "sbbs.h"
39:
40: int sbbs_t::sub_op(uint subnum)
41: {
42: return(SYSOP || (cfg.sub[subnum]->op_ar[0] && chk_ar(cfg.sub[subnum]->op_ar,&useron)));
43: }
44:
45:
46: long sbbs_t::listmsgs(uint subnum, long mode, post_t *post, long i, long posts)
47: {
48: char ch;
49: smbmsg_t msg;
50: long listed=0;
51:
52: bputs(text[MailOnSystemLstHdr]);
53: msg.total_hfields=0;
54: for(;i<posts && !msgabort();i++) {
55: if(msg.total_hfields)
56: smb_freemsgmem(&msg);
57: msg.total_hfields=0;
58: msg.idx.offset=post[i].offset;
59: if(!loadmsg(&msg,post[i].number))
60: break;
61: smb_unlockmsghdr(&smb,&msg);
62: if(mode&SCAN_NEW && msg.hdr.number<=subscan[subnum].ptr)
63: continue;
64: if(msg.hdr.attr&MSG_DELETE)
65: ch='-';
66: else if((!stricmp(msg.to,useron.alias) || !stricmp(msg.to,useron.name))
67: && !(msg.hdr.attr&MSG_READ))
68: ch='!';
69: else if(msg.hdr.number>subscan[subnum].ptr)
70: ch='*';
71: else
72: ch=' ';
73: bprintf(text[SubMsgLstFmt],(long)i+1
74: ,msg.hdr.attr&MSG_ANONYMOUS && !sub_op(subnum)
75: ? text[Anonymous] : msg.from
76: ,msg.to
77: ,ch
78: ,msg.subj);
79: smb_freemsgmem(&msg);
80: msg.total_hfields=0;
81: listed++;
82: }
83:
84: return(listed);
85: }
86:
87: char *binstr(uchar *buf, ushort length)
88: {
89: static char str[512];
90: char tmp[128];
91: int i;
92:
93: str[0]=0;
94: for(i=0;i<length;i++)
95: if(buf[i] && (buf[i]<' ' || buf[i]>=0x7f)
96: && buf[i]!='\r' && buf[i]!='\n' && buf[i]!='\t')
97: break;
98: if(i==length) /* not binary */
99: return((char*)buf);
100: for(i=0;i<length;i++) {
101: sprintf(tmp,"%02X ",buf[i]);
102: strcat(str,tmp);
103: }
104: return(str);
105: }
106:
107:
108: void sbbs_t::msghdr(smbmsg_t* msg)
109: {
110: int i;
111:
112: CRLF;
113:
114: /* variable fields */
115: for(i=0;i<msg->total_hfields;i++)
116: bprintf("%-16.16s %s\r\n"
117: ,smb_hfieldtype(msg->hfield[i].type)
118: ,binstr((uchar *)msg->hfield_dat[i],msg->hfield[i].length));
119:
120: /* fixed fields */
121: bprintf("%-16.16s %s %s\r\n","when_written"
122: ,timestr((time_t *)&msg->hdr.when_written.time), smb_zonestr(msg->hdr.when_written.zone,NULL));
123: bprintf("%-16.16s %s %s\r\n","when_imported"
124: ,timestr((time_t *)&msg->hdr.when_imported.time), smb_zonestr(msg->hdr.when_imported.zone,NULL));
125: bprintf("%-16.16s %04Xh\r\n","type" ,msg->hdr.type);
126: bprintf("%-16.16s %04Xh\r\n","version" ,msg->hdr.version);
127: bprintf("%-16.16s %04Xh\r\n","attr" ,msg->hdr.attr);
128: bprintf("%-16.16s %08lXh\r\n","auxattr" ,msg->hdr.auxattr);
129: bprintf("%-16.16s %08lXh\r\n","netattr" ,msg->hdr.netattr);
130: bprintf("%-16.16s %ld\r\n" ,"number" ,msg->hdr.number);
131: bprintf("%-16.16s %06lXh\r\n","header offset" ,msg->idx.offset);
132: bprintf("%-16.16s %u\r\n" ,"header length" ,msg->hdr.length);
133:
134: /* optional fixed fields */
135: if(msg->hdr.thread_back)
136: bprintf("%-16.16s %ld\r\n" ,"thread_back" ,msg->hdr.thread_back);
137: if(msg->hdr.thread_next)
138: bprintf("%-16.16s %ld\r\n" ,"thread_next" ,msg->hdr.thread_next);
139: if(msg->hdr.thread_first)
140: bprintf("%-16.16s %ld\r\n" ,"thread_first" ,msg->hdr.thread_first);
141: if(msg->hdr.delivery_attempts)
142: bprintf("%-16.16s %hu\r\n" ,"delivery_attempts",msg->hdr.delivery_attempts);
143: if(msg->hdr.times_downloaded)
144: bprintf("%-16.16s %lu\r\n" ,"times_downloaded" ,msg->hdr.times_downloaded);
145: if(msg->hdr.last_downloaded)
146: bprintf("%-16.16s %s\r\n" ,"last_downloaded" ,timestr((time_t*)&msg->hdr.last_downloaded));
147:
148: /* convenience integers */
149: if(msg->expiration)
150: bprintf("%-16.16s %s\r\n" ,"expiration"
151: ,timestr((time_t *)&msg->expiration));
152: if(msg->priority)
153: bprintf("%-16.16s %lu\r\n" ,"priority" ,msg->priority);
154: if(msg->cost)
155: bprintf("%-16.16s %lu\r\n" ,"cost" ,msg->cost);
156:
157: bprintf("%-16.16s %06lXh\r\n" ,"data offset" ,msg->hdr.offset);
158: for(i=0;i<msg->hdr.total_dfields;i++)
159: bprintf("data field[%u] %s, offset %lu, length %lu\r\n"
160: ,i
161: ,smb_dfieldtype(msg->dfield[i].type)
162: ,msg->dfield[i].offset
163: ,msg->dfield[i].length);
164: }
165:
166: /****************************************************************************/
167: /****************************************************************************/
168: post_t * sbbs_t::loadposts(long *posts, uint subnum, ulong ptr, long mode)
169: {
170: char name[128];
171: ushort aliascrc,namecrc,sysop;
172: int i,skip;
173: ulong l=0,total,alloc_len;
174: smbmsg_t msg;
175: idxrec_t idx;
176: post_t *post;
177:
178: if(posts==NULL)
179: return(NULL);
180:
181: (*posts)=0;
182:
183: if((i=smb_locksmbhdr(&smb))!=0) { /* Be sure noone deletes or */
184: errormsg(WHERE,ERR_LOCK,smb.file,i); /* adds while we're reading */
185: return(NULL);
186: }
187:
188: total=filelength(fileno(smb.sid_fp))/sizeof(idxrec_t); /* total msgs in sub */
189:
190: if(!total) { /* empty */
191: smb_unlocksmbhdr(&smb);
192: return(NULL);
193: }
194:
195: strcpy(name,useron.name);
196: strlwr(name);
197: namecrc=crc16(name,0);
198: strcpy(name,useron.alias);
199: strlwr(name);
200: aliascrc=crc16(name,0);
201: sysop=crc16("sysop",0);
202:
203: rewind(smb.sid_fp);
204:
205: alloc_len=sizeof(post_t)*total;
206: #ifdef __OS2__
207: while(alloc_len%4096)
208: alloc_len++;
209: #endif
210: if((post=(post_t *)malloc(alloc_len))==NULL) { /* alloc for max */
211: smb_unlocksmbhdr(&smb);
212: errormsg(WHERE,ERR_ALLOC,smb.file,sizeof(post_t *)*cfg.sub[subnum]->maxmsgs);
213: return(NULL);
214: }
215: while(!feof(smb.sid_fp)) {
216: skip=0;
217: if(smb_fread(&smb, &idx,sizeof(idx),smb.sid_fp) != sizeof(idx))
218: break;
219:
220: if(idx.number==0) /* invalid message number, ignore */
221: continue;
222:
223: if(idx.number<=ptr)
224: continue;
225:
226: if(idx.attr&MSG_READ && mode&LP_UNREAD) /* Skip read messages */
227: continue;
228:
229: if(idx.attr&MSG_DELETE) { /* Pre-flagged */
230: if(mode&LP_REP) /* Don't include deleted msgs in REP pkt */
231: continue;
232: if(!(cfg.sys_misc&SM_SYSVDELM)) /* Noone can view deleted msgs */
233: continue;
234: if(!(cfg.sys_misc&SM_USRVDELM) /* Users can't view deleted msgs */
235: && !sub_op(subnum)) /* not sub-op */
236: continue;
237: if(!sub_op(subnum) /* not sub-op */
238: && idx.from!=namecrc && idx.from!=aliascrc) /* not for you */
239: continue;
240: }
241:
242: if(idx.attr&MSG_MODERATED && !(idx.attr&MSG_VALIDATED)
243: && (mode&LP_REP || !sub_op(subnum)))
244: break;
245:
246: if(idx.attr&MSG_PRIVATE && !(mode&LP_PRIVATE)
247: && !sub_op(subnum) && !(useron.rest&FLAG('Q'))) {
248: if(idx.to!=namecrc && idx.from!=namecrc
249: && idx.to!=aliascrc && idx.from!=aliascrc
250: && (useron.number!=1 || idx.to!=sysop))
251: continue;
252: if(!smb_lockmsghdr(&smb,&msg)) {
253: if(!smb_getmsghdr(&smb,&msg)) {
254: if(stricmp(msg.to,useron.alias)
255: && stricmp(msg.from,useron.alias)
256: && stricmp(msg.to,useron.name)
257: && stricmp(msg.from,useron.name)
258: && (useron.number!=1 || stricmp(msg.to,"sysop")
259: || msg.from_net.type))
260: skip=1;
261: smb_freemsgmem(&msg);
262: }
263: smb_unlockmsghdr(&smb,&msg);
264: }
265: if(skip)
266: continue;
267: }
268:
269:
270: if(!(mode&LP_BYSELF) && (idx.from==namecrc || idx.from==aliascrc)) {
271: msg.idx=idx;
272: if(!smb_lockmsghdr(&smb,&msg)) {
273: if(!smb_getmsghdr(&smb,&msg)) {
274: if(!stricmp(msg.from,useron.alias)
275: || !stricmp(msg.from,useron.name))
276: skip=1;
277: smb_freemsgmem(&msg);
278: }
279: smb_unlockmsghdr(&smb,&msg);
280: }
281: if(skip)
282: continue;
283: }
284:
285: if(!(mode&LP_OTHERS)) {
286: if(idx.to!=namecrc && idx.to!=aliascrc
287: && (useron.number!=1 || idx.to!=sysop))
288: continue;
289: msg.idx=idx;
290: if(!smb_lockmsghdr(&smb,&msg)) {
291: if(!smb_getmsghdr(&smb,&msg)) {
292: if(stricmp(msg.to,useron.alias) && stricmp(msg.to,useron.name)
293: && (useron.number!=1 || stricmp(msg.to,"sysop")
294: || msg.from_net.type))
295: skip=1;
296: smb_freemsgmem(&msg);
297: }
298: smb_unlockmsghdr(&smb,&msg);
299: }
300: if(skip)
301: continue;
302: }
303:
304: memcpy(&post[l],&idx,sizeof(idx));
305: l++;
306: }
307: smb_unlocksmbhdr(&smb);
308: if(!l)
309: FREE_AND_NULL(post);
310:
311: (*posts)=l;
312: return(post);
313: }
314:
315: static int get_start_msg(sbbs_t* sbbs, smb_t* smb)
316: {
317: int i,j=smb->curmsg+1;
318:
319: if(j<smb->msgs)
320: j++;
321: else
322: j=1;
323: sbbs->bprintf(sbbs->text[StartWithN],j);
324: if((i=sbbs->getnum(smb->msgs))<0)
325: return(i);
326: if(i==0)
327: return(j-1);
328: return(i-1);
329: }
330:
331: /****************************************************************************/
332: /* Reads posts on subboard sub. 'mode' determines new-posts only, browse, */
333: /* or continuous read. */
334: /* Returns 0 if normal completion, 1 if aborted. */
335: /* Called from function main_sec */
336: /****************************************************************************/
337: int sbbs_t::scanposts(uint subnum, long mode, char *find)
338: {
339: char str[256],str2[256],do_find=true,mismatches=0
340: ,done=0,domsg=1,*buf,*p;
341: char find_buf[128];
342: char tmp[128];
343: int i;
344: uint usub,ugrp,reads=0;
345: uint lp=0;
346: long org_mode=mode;
347: ulong msgs,last,l;
348: post_t *post;
349: smbmsg_t msg;
350:
351: cursubnum=subnum; /* for ARS */
352: if(!chk_ar(cfg.sub[subnum]->read_ar,&useron)) {
353: bprintf("\1n\r\nYou can't read messages on %s %s\r\n"
354: ,cfg.grp[cfg.sub[subnum]->grp]->sname,cfg.sub[subnum]->sname);
355: return(0);
356: }
357: msg.total_hfields=0; /* init to NULL, specify not-allocated */
358: if(!(mode&SCAN_CONST))
359: lncntr=0;
360: if((msgs=getlastmsg(subnum,&last,0))==0) {
361: if(mode&(SCAN_NEW|SCAN_TOYOU))
362: bprintf(text[NScanStatusFmt]
363: ,cfg.grp[cfg.sub[subnum]->grp]->sname,cfg.sub[subnum]->lname,0L,0L);
364: else
365: bprintf(text[NoMsgsOnSub]
366: ,cfg.grp[cfg.sub[subnum]->grp]->sname,cfg.sub[subnum]->sname);
367: return(0);
368: }
369: if(mode&SCAN_NEW && subscan[subnum].ptr>=last && !(mode&SCAN_BACK)) {
370: if(subscan[subnum].ptr>last)
371: subscan[subnum].ptr=subscan[subnum].last=last;
372: bprintf(text[NScanStatusFmt]
373: ,cfg.grp[cfg.sub[subnum]->grp]->sname,cfg.sub[subnum]->lname,0L,msgs);
374: return(0);
375: }
376:
377: if((i=smb_stack(&smb,SMB_STACK_PUSH))!=0) {
378: errormsg(WHERE,ERR_OPEN,cfg.sub[subnum]->code,i);
379: return(0);
380: }
381: sprintf(smb.file,"%s%s",cfg.sub[subnum]->data_dir,cfg.sub[subnum]->code);
382: smb.retry_time=cfg.smb_retry_time;
383: smb.subnum=subnum;
384: if((i=smb_open(&smb))!=0) {
385: errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
386: smb_stack(&smb,SMB_STACK_POP);
387: return(0);
388: }
389:
390: if(!(mode&SCAN_TOYOU)
391: && (!mode || mode&SCAN_FIND || !(subscan[subnum].cfg&SUB_CFG_YSCAN)))
392: lp=LP_BYSELF|LP_OTHERS;
393: if(mode&SCAN_TOYOU)
394: lp|=LP_UNREAD;
395: post=loadposts(&smb.msgs,subnum,0,lp);
396: if(mode&SCAN_NEW) { /* Scanning for new messages */
397: for(smb.curmsg=0;smb.curmsg<smb.msgs;smb.curmsg++)
398: if(subscan[subnum].ptr<post[smb.curmsg].number)
399: break;
400: bprintf(text[NScanStatusFmt]
401: ,cfg.grp[cfg.sub[subnum]->grp]->sname,cfg.sub[subnum]->lname,smb.msgs-smb.curmsg,msgs);
402: if(!smb.msgs) { /* no messages at all */
403: smb_close(&smb);
404: smb_stack(&smb,SMB_STACK_POP);
405: return(0);
406: }
407: if(smb.curmsg==smb.msgs) { /* no new messages */
408: if(!(mode&SCAN_BACK)) {
409: if(post)
410: free(post);
411: smb_close(&smb);
412: smb_stack(&smb,SMB_STACK_POP);
413: return(0);
414: }
415: smb.curmsg=smb.msgs-1;
416: }
417: }
418: else {
419: if(mode&SCAN_TOYOU)
420: bprintf(text[NScanStatusFmt]
421: ,cfg.grp[cfg.sub[subnum]->grp]->sname,cfg.sub[subnum]->lname,smb.msgs,msgs);
422: if(!smb.msgs) {
423: if(!(mode&SCAN_TOYOU))
424: bprintf(text[NoMsgsOnSub]
425: ,cfg.grp[cfg.sub[subnum]->grp]->sname,cfg.sub[subnum]->sname);
426: smb_close(&smb);
427: smb_stack(&smb,SMB_STACK_POP);
428: return(0);
429: }
430: if(mode&SCAN_FIND) {
431: bprintf(text[SearchSubFmt]
432: ,cfg.grp[cfg.sub[subnum]->grp]->sname,cfg.sub[subnum]->lname,smb.msgs);
433: domsg=1;
434: smb.curmsg=0;
435: }
436: else if(mode&SCAN_TOYOU)
437: smb.curmsg=0;
438: else {
439: for(smb.curmsg=0;smb.curmsg<smb.msgs;smb.curmsg++)
440: if(post[smb.curmsg].number>=subscan[subnum].last)
441: break;
442: if(smb.curmsg==smb.msgs)
443: smb.curmsg=smb.msgs-1;
444:
445: domsg=1;
446: }
447: }
448:
449: if(useron.misc&RIP)
450: menu("msgscan");
451:
452: if((i=smb_locksmbhdr(&smb))!=0) {
453: smb_close(&smb);
454: errormsg(WHERE,ERR_LOCK,smb.file,i);
455: smb_stack(&smb,SMB_STACK_POP);
456: return(0);
457: }
458: if((i=smb_getstatus(&smb))!=0) {
459: smb_close(&smb);
460: errormsg(WHERE,ERR_READ,smb.file,i);
461: smb_stack(&smb,SMB_STACK_POP);
462: return(0);
463: }
464: smb_unlocksmbhdr(&smb);
465: last=smb.status.last_msg;
466:
467: action=NODE_RMSG;
468: if(mode&SCAN_CONST) { /* update action */
469: getnodedat(cfg.node_num,&thisnode,1);
470: thisnode.action=NODE_RMSG;
471: putnodedat(cfg.node_num,&thisnode);
472: }
473: while(online && !done) {
474:
475: action=NODE_RMSG;
476:
477: if(mode&(SCAN_CONST|SCAN_FIND) && sys_status&SS_ABORT)
478: break;
479:
480: if(post==NULL) /* Been unloaded */
481: post=loadposts(&smb.msgs,subnum,0,lp); /* So re-load */
482:
483: if(!smb.msgs) {
484: done=1;
485: continue;
486: }
487:
488: while(smb.curmsg>=smb.msgs) smb.curmsg--;
489:
490: for(ugrp=0;ugrp<usrgrps;ugrp++)
491: if(usrgrp[ugrp]==cfg.sub[subnum]->grp)
492: break;
493: for(usub=0;usub<usrsubs[ugrp];usub++)
494: if(usrsub[ugrp][usub]==subnum)
495: break;
496: usub++;
497: ugrp++;
498:
499: msg.idx.offset=post[smb.curmsg].offset;
500: msg.idx.number=post[smb.curmsg].number;
501: msg.idx.to=post[smb.curmsg].to;
502: msg.idx.from=post[smb.curmsg].from;
503: msg.idx.subj=post[smb.curmsg].subj;
504:
505: if((i=smb_locksmbhdr(&smb))!=0) {
506: errormsg(WHERE,ERR_LOCK,smb.file,i);
507: break;
508: }
509: if((i=smb_getstatus(&smb))!=0) {
510: smb_unlocksmbhdr(&smb);
511: errormsg(WHERE,ERR_READ,smb.file,i);
512: break;
513: }
514: smb_unlocksmbhdr(&smb);
515:
516: if(smb.status.last_msg!=last) { /* New messages */
517: last=smb.status.last_msg;
518: if(post) {
519: free((void *)post);
520: }
521: post=loadposts(&smb.msgs,subnum,0,lp); /* So re-load */
522: if(!smb.msgs)
523: break;
524: for(smb.curmsg=0;smb.curmsg<smb.msgs;smb.curmsg++)
525: if(post[smb.curmsg].number==msg.idx.number)
526: break;
527: if(smb.curmsg>(smb.msgs-1))
528: smb.curmsg=(smb.msgs-1);
529: continue;
530: }
531:
532: if(msg.total_hfields)
533: smb_freemsgmem(&msg);
534: msg.total_hfields=0;
535:
536: if(!loadmsg(&msg,post[smb.curmsg].number)) {
537: if(mismatches>5) { /* We can't do this too many times in a row */
538: errormsg(WHERE,ERR_CHK,smb.file,post[smb.curmsg].number);
539: break;
540: }
541: if(post)
542: free(post);
543: post=loadposts(&smb.msgs,subnum,0,lp);
544: if(!smb.msgs)
545: break;
546: if(smb.curmsg>(smb.msgs-1))
547: smb.curmsg=(smb.msgs-1);
548: mismatches++;
549: continue;
550: }
551: smb_unlockmsghdr(&smb,&msg);
552:
553: mismatches=0;
554:
555: if(domsg && !(sys_status&SS_ABORT)) {
556:
557: if(do_find && mode&SCAN_FIND) { /* Find text in messages */
558: buf=smb_getmsgtxt(&smb,&msg,GETMSGTXT_ALL);
559: if(!buf) {
560: if(smb.curmsg<smb.msgs-1)
561: smb.curmsg++;
562: else if(org_mode&SCAN_FIND)
563: done=1;
564: else if(smb.curmsg>=smb.msgs-1)
565: domsg=0;
566: continue;
567: }
568: strupr((char *)buf);
569: if(!strstr((char *)buf,find) && !strstr(msg.subj,find)) {
570: free(buf);
571: if(smb.curmsg<smb.msgs-1)
572: smb.curmsg++;
573: else if(org_mode&SCAN_FIND)
574: done=1;
575: else if(smb.curmsg>=smb.msgs-1)
576: domsg=0;
577: continue;
578: }
579: free(buf);
580: }
581:
582: if(mode&SCAN_CONST)
583: bprintf(text[ZScanPostHdr],ugrp,usub,smb.curmsg+1,smb.msgs);
584:
585: if(!reads && mode)
586: CRLF;
587:
588: show_msg(&msg
589: ,msg.from_ext && !strcmp(msg.from_ext,"1") && !msg.from_net.type
590: ? 0:P_NOATCODES);
591:
592: reads++; /* number of messages actually read during this sub-scan */
593:
594: /* Message is to this user and hasn't been read, so flag as read */
595: if((!stricmp(msg.to,useron.name) || !stricmp(msg.to,useron.alias)
596: || (useron.number==1 && !stricmp(msg.to,"sysop")
597: && !msg.from_net.type))
598: && !(msg.hdr.attr&MSG_READ)) {
599: if(msg.total_hfields)
600: smb_freemsgmem(&msg);
601: msg.total_hfields=0;
602: msg.idx.offset=0;
603: if(!smb_locksmbhdr(&smb)) { /* Lock the entire base */
604: if(loadmsg(&msg,msg.idx.number)) {
605: msg.hdr.attr|=MSG_READ;
606: msg.idx.attr=msg.hdr.attr;
607: if((i=smb_putmsg(&smb,&msg))!=0)
608: errormsg(WHERE,ERR_WRITE,smb.file,i);
609: smb_unlockmsghdr(&smb,&msg);
610: }
611: smb_unlocksmbhdr(&smb);
612: }
613: if(!msg.total_hfields) { /* unsuccessful reload */
614: domsg=0;
615: continue;
616: }
617: }
618:
619: subscan[subnum].last=post[smb.curmsg].number;
620:
621: if(subscan[subnum].ptr<post[smb.curmsg].number && !(mode&SCAN_TOYOU)) {
622: posts_read++;
623: subscan[subnum].ptr=post[smb.curmsg].number;
624: }
625: }
626: else domsg=1;
627: if(mode&SCAN_CONST) {
628: if(smb.curmsg<smb.msgs-1) smb.curmsg++;
629: else done=1;
630: continue;
631: }
632: if(useron.misc&WIP)
633: menu("msgscan");
634: ASYNC;
635: bprintf(text[ReadingSub],ugrp,cfg.grp[cfg.sub[subnum]->grp]->sname
636: ,usub,cfg.sub[subnum]->sname,smb.curmsg+1,smb.msgs);
637: sprintf(str,"ABCDEFILMPQRTY?<>[]{}-+.,");
638: if(sub_op(subnum))
639: strcat(str,"O");
640: do_find=true;
641: l=getkeys(str,smb.msgs);
642: if(l&0x80000000L) {
643: if((long)l==-1) { /* ctrl-c */
644: if(msg.total_hfields)
645: smb_freemsgmem(&msg);
646: if(post)
647: free(post);
648: smb_close(&smb);
649: smb_stack(&smb,SMB_STACK_POP);
650: return(1);
651: }
652: smb.curmsg=(l&~0x80000000L)-1;
653: do_find=false;
654: continue;
655: }
656: switch(l) {
657: case 'A':
658: case 'R':
659: if((char)l==(cfg.sys_misc&SM_RA_EMU ? 'A' : 'R')) {
660: do_find=false; /* re-read last message */
661: break;
662: }
663: /* Reply to last message */
664: domsg=0;
665: if(!chk_ar(cfg.sub[subnum]->post_ar,&useron)) {
666: bputs(text[CantPostOnSub]);
667: break;
668: }
669: quotemsg(&msg,0);
670: FREE_AND_NULL(post);
671: postmsg(subnum,&msg,WM_QUOTE);
672: if(mode&SCAN_TOYOU)
673: domsg=1;
674: break;
675: case 'B': /* Skip sub-board */
676: if(mode&SCAN_NEW && !noyes(text[RemoveFromNewScanQ]))
677: subscan[subnum].cfg&=~SUB_CFG_NSCAN;
678: if(msg.total_hfields)
679: smb_freemsgmem(&msg);
680: if(post)
681: free(post);
682: smb_close(&smb);
683: smb_stack(&smb,SMB_STACK_POP);
684: return(0);
685: case 'C': /* Continuous */
686: mode|=SCAN_CONST;
687: if(smb.curmsg<smb.msgs-1) smb.curmsg++;
688: else done=1;
689: break;
690: case 'D': /* Delete message on sub-board */
691: domsg=0;
692: if(!sub_op(subnum)) {
693: if(!(cfg.sub[subnum]->misc&SUB_DEL)) {
694: bputs(text[CantDeletePosts]);
695: domsg=0;
696: break;
697: }
698: if(cfg.sub[subnum]->misc&SUB_DELLAST && smb.curmsg!=(smb.msgs-1)) {
699: bputs("\1n\r\nCan only delete last message.\r\n");
700: domsg=0;
701: break;
702: }
703: if(stricmp(cfg.sub[subnum]->misc&SUB_NAME
704: ? useron.name : useron.alias, msg.from)
705: && stricmp(cfg.sub[subnum]->misc&SUB_NAME
706: ? useron.name : useron.alias, msg.to)) {
707: bprintf(text[YouDidntPostMsgN],smb.curmsg+1);
708: break;
709: }
710: }
711: if(msg.hdr.attr&MSG_PERMANENT) {
712: bputs("\1n\r\nMessage is marked permanent.\r\n");
713: domsg=0;
714: break;
715: }
716:
717: FREE_AND_NULL(post);
718:
719: if(msg.total_hfields)
720: smb_freemsgmem(&msg);
721: msg.total_hfields=0;
722: msg.idx.offset=0;
723: if(smb_locksmbhdr(&smb)==SMB_SUCCESS) { /* Lock the entire base */
724: if(loadmsg(&msg,msg.idx.number)) {
725: msg.idx.attr^=MSG_DELETE;
726: msg.hdr.attr=msg.idx.attr;
727: if((i=smb_putmsg(&smb,&msg))!=0)
728: errormsg(WHERE,ERR_WRITE,smb.file,i);
729: smb_unlockmsghdr(&smb,&msg);
730: if(i==0 && msg.idx.attr&MSG_DELETE) {
731: sprintf(str,"%s removed post from %s %s"
732: ,useron.alias
733: ,cfg.grp[cfg.sub[subnum]->grp]->sname,cfg.sub[subnum]->lname);
734: logline("P-",str);
735: if(!stricmp(cfg.sub[subnum]->misc&SUB_NAME
736: ? useron.name : useron.alias, msg.from))
737: useron.posts=(ushort)adjustuserrec(&cfg,useron.number
738: ,U_POSTS,5,-1);
739: }
740: }
741: smb_unlocksmbhdr(&smb);
742: }
743: domsg=1;
744: if((cfg.sys_misc&SM_SYSVDELM // anyone can view delete msgs
745: || (cfg.sys_misc&SM_USRVDELM // sys/subops can view deleted msgs
746: && sub_op(subnum)))
747: && smb.curmsg<smb.msgs-1)
748: smb.curmsg++;
749: if(smb.curmsg>=smb.msgs)
750: done=1;
751: break;
752: case 'E': /* edit last post */
753: if(!sub_op(subnum)) {
754: if(!(cfg.sub[subnum]->misc&SUB_EDIT)) {
755: bputs("\1n\r\nCan't edit messages on this message base.\r\n");
756: // bputs(text[CantDeletePosts]);
757: domsg=0;
758: break;
759: }
760: if(cfg.sub[subnum]->misc&SUB_EDITLAST && smb.curmsg!=(smb.msgs-1)) {
761: bputs("\1n\r\nCan only edit last message.\r\n");
762: domsg=0;
763: break;
764: }
765: if(stricmp(cfg.sub[subnum]->misc&SUB_NAME
766: ? useron.name : useron.alias, msg.from)) {
767: bprintf(text[YouDidntPostMsgN],smb.curmsg+1);
768: domsg=0;
769: break;
770: }
771: }
772: FREE_AND_NULL(post);
773: editmsg(&msg,subnum);
774: break;
775: case 'F': /* find text in messages */
776: domsg=0;
777: mode&=~SCAN_FIND; /* turn off find mode */
778: if((i=get_start_msg(this,&smb))<0)
779: break;
780: bputs(text[SearchStringPrompt]);
781: if(!getstr(find_buf,40,K_LINE|K_UPPER))
782: break;
783: if(yesno(text[DisplaySubjectsOnlyQ]))
784: searchposts(subnum,post,(long)i,smb.msgs,find_buf);
785: else {
786: smb.curmsg=i;
787: find=find_buf;
788: mode|=SCAN_FIND;
789: domsg=1;
790: }
791: break;
792: case 'I': /* Sub-board information */
793: domsg=0;
794: subinfo(subnum);
795: break;
796: case 'L': /* List messages */
797: domsg=0;
798: if((i=get_start_msg(this,&smb))<0)
799: break;
800: listmsgs(subnum,0,post,i,smb.msgs);
801: sys_status&=~SS_ABORT;
802: break;
803: case 'M': /* Reply to last post in mail */
804: domsg=0;
805: if(msg.hdr.attr&MSG_ANONYMOUS && !sub_op(subnum)) {
806: bputs(text[CantReplyToAnonMsg]);
807: break;
808: }
809: if(!sub_op(subnum) && msg.hdr.attr&MSG_PRIVATE
810: && stricmp(msg.to,useron.name)
811: && stricmp(msg.to,useron.alias))
812: break;
813: sprintf(str2,text[Regarding]
814: ,msg.subj
815: ,timestr((time_t *)&msg.hdr.when_written.time));
816: if(msg.from_net.addr==NULL)
817: strcpy(str,msg.from);
818: else if(msg.from_net.type==NET_FIDO)
819: sprintf(str,"%s@%s",msg.from
820: ,smb_faddrtoa((faddr_t *)msg.from_net.addr,tmp));
821: else if(msg.from_net.type==NET_INTERNET)
822: strcpy(str,(char *)msg.from_net.addr);
823: else
824: sprintf(str,"%s@%s",msg.from,(char *)msg.from_net.addr);
825: bputs(text[Email]);
826: if(!getstr(str,60,K_EDIT|K_AUTODEL))
827: break;
828:
829: FREE_AND_NULL(post);
830: quotemsg(&msg,1);
831: if(msg.from_net.type==NET_INTERNET && strchr(str,'@'))
832: inetmail(str,msg.subj,WM_QUOTE|WM_NETMAIL);
833: else {
834: p=strrchr(str,'@');
835: if(p) /* FidoNet or QWKnet */
836: netmail(str,msg.subj,WM_QUOTE);
837: else {
838: i=atoi(str);
839: if(!i) {
840: if(cfg.sub[subnum]->misc&SUB_NAME)
841: i=userdatdupe(0,U_NAME,LEN_NAME,str,0);
842: else
843: i=matchuser(&cfg,str,TRUE /* sysop_alias */);
844: }
845: email(i,str2,msg.subj,WM_EMAIL|WM_QUOTE);
846: }
847: }
848: break;
849: case 'P': /* Post message on sub-board */
850: domsg=0;
851: if(!chk_ar(cfg.sub[subnum]->post_ar,&useron))
852: bputs(text[CantPostOnSub]);
853: else {
854: FREE_AND_NULL(post);
855: postmsg(subnum,0,0);
856: }
857: break;
858: case 'Q': /* Quit */
859: if(msg.total_hfields)
860: smb_freemsgmem(&msg);
861: if(post)
862: free(post);
863: smb_close(&smb);
864: smb_stack(&smb,SMB_STACK_POP);
865: return(1);
866: case 'T': /* List titles of next ten messages */
867: domsg=0;
868: if(!smb.msgs)
869: break;
870: if(smb.curmsg>=smb.msgs-1) {
871: done=1;
872: break;
873: }
874: i=smb.curmsg+11;
875: if(i>smb.msgs)
876: i=smb.msgs;
877: listmsgs(subnum,0,post,smb.curmsg+1,i);
878: smb.curmsg=i-1;
879: if(subscan[subnum].ptr<post[smb.curmsg].number)
880: subscan[subnum].ptr=post[smb.curmsg].number;
881: break;
882: case 'Y': /* Your messages */
883: domsg=0;
884: showposts_toyou(post,0,smb.msgs);
885: break;
886: case '-':
887: if(smb.curmsg>0) smb.curmsg--;
888: do_find=false;
889: break;
890: case 'O': /* Operator commands */
891: while(online) {
892: if(!(useron.misc&EXPERT))
893: menu("sysmscan");
894: bprintf("\r\n\1y\1hOperator: \1w");
895: strcpy(str,"?CEHMPQUV");
896: if(SYSOP)
897: strcat(str,"S");
898: switch(getkeys(str,0)) {
899: case '?':
900: if(useron.misc&EXPERT)
901: menu("sysmscan");
902: continue;
903: case 'P': /* Purge user */
904: purgeuser(cfg.sub[subnum]->misc&SUB_NAME
905: ? userdatdupe(0,U_NAME,LEN_NAME,msg.from,0)
906: : matchuser(&cfg,msg.from,FALSE));
907: break;
908: case 'C': /* Change message attributes */
909: i=chmsgattr(msg.hdr.attr);
910: if(msg.hdr.attr==i)
911: break;
912: if(msg.total_hfields)
913: smb_freemsgmem(&msg);
914: msg.total_hfields=0;
915: msg.idx.offset=0;
916: if(smb_locksmbhdr(&smb)==SMB_SUCCESS) { /* Lock the entire base */
917: if(loadmsg(&msg,msg.idx.number)) {
918: msg.hdr.attr=msg.idx.attr=i;
919: if((i=smb_putmsg(&smb,&msg))!=0)
920: errormsg(WHERE,ERR_WRITE,smb.file,i);
921: smb_unlockmsghdr(&smb,&msg);
922: }
923: smb_unlocksmbhdr(&smb);
924: }
925: break;
926: case 'E': /* edit last post */
927: FREE_AND_NULL(post);
928: editmsg(&msg,subnum);
929: break;
930: case 'H': /* View message header */
931: msghdr(&msg);
932: domsg=0;
933: break;
934: case 'M': /* Move message */
935: domsg=0;
936: FREE_AND_NULL(post);
937: if(msg.total_hfields)
938: smb_freemsgmem(&msg);
939: msg.total_hfields=0;
940: msg.idx.offset=0;
941: if(smb_locksmbhdr(&smb)==SMB_SUCCESS) { /* Lock the entire base */
942: if(!loadmsg(&msg,msg.idx.number)) {
943: errormsg(WHERE,ERR_READ,smb.file,msg.idx.number);
944: break;
945: }
946: sprintf(str,text[DeletePostQ],msg.hdr.number,msg.subj);
947: if(movemsg(&msg,subnum) && yesno(str)) {
948: msg.idx.attr|=MSG_DELETE;
949: msg.hdr.attr=msg.idx.attr;
950: if((i=smb_putmsg(&smb,&msg))!=0)
951: errormsg(WHERE,ERR_WRITE,smb.file,i);
952: }
953: smb_unlockmsghdr(&smb,&msg);
954: }
955: smb_unlocksmbhdr(&smb);
956: break;
957:
958: case 'Q':
959: break;
960: case 'S': /* Save/Append message to another file */
961: /* 05/26/95
962: if(!yesno(text[SaveMsgToFile]))
963: break;
964: */
965: bputs(text[FileToWriteTo]);
966: if(getstr(str,40,K_LINE))
967: msgtotxt(&msg,str,1,1);
968: break;
969: case 'U': /* User edit */
970: useredit(cfg.sub[subnum]->misc&SUB_NAME
971: ? userdatdupe(0,U_NAME,LEN_NAME,msg.from,0)
972: : matchuser(&cfg,msg.from,TRUE /* sysop_alias */));
973: break;
974: case 'V': /* Validate message */
975: if(msg.total_hfields)
976: smb_freemsgmem(&msg);
977: msg.total_hfields=0;
978: msg.idx.offset=0;
979: if(smb_locksmbhdr(&smb)==SMB_SUCCESS) { /* Lock the entire base */
980: if(loadmsg(&msg,msg.idx.number)) {
981: msg.idx.attr|=MSG_VALIDATED;
982: msg.hdr.attr=msg.idx.attr;
983: if((i=smb_putmsg(&smb,&msg))!=0)
984: errormsg(WHERE,ERR_WRITE,smb.file,i);
985: smb_unlockmsghdr(&smb,&msg);
986: }
987: smb_unlocksmbhdr(&smb);
988: }
989: break;
990: default:
991: continue;
992: }
993: break;
994: }
995: break;
996: case '.': /* Thread forward */
997: l=msg.hdr.thread_first;
998: if(!l) l=msg.hdr.thread_next;
999: if(!l) {
1000: domsg=0;
1001: break;
1002: }
1003: for(i=0;i<smb.msgs;i++)
1004: if(l==post[i].number)
1005: break;
1006: if(i<smb.msgs)
1007: smb.curmsg=i;
1008: do_find=false;
1009: break;
1010: case ',': /* Thread backwards */
1011: if(!msg.hdr.thread_back) {
1012: domsg=0;
1013: break;
1014: }
1015: for(i=0;i<smb.msgs;i++)
1016: if(msg.hdr.thread_back==post[i].number)
1017: break;
1018: if(i<smb.msgs)
1019: smb.curmsg=i;
1020: do_find=false;
1021: break;
1022: case '>': /* Search Title forward */
1023: for(i=smb.curmsg+1;i<smb.msgs;i++)
1024: if(post[i].subj==msg.idx.subj)
1025: break;
1026: if(i<smb.msgs)
1027: smb.curmsg=i;
1028: else
1029: domsg=0;
1030: do_find=false;
1031: break;
1032: case '<': /* Search Title backward */
1033: for(i=smb.curmsg-1;i>-1;i--)
1034: if(post[i].subj==msg.idx.subj)
1035: break;
1036: if(i>-1)
1037: smb.curmsg=i;
1038: else
1039: domsg=0;
1040: do_find=false;
1041: break;
1042: case '}': /* Search Author forward */
1043: strcpy(str,msg.from);
1044: for(i=smb.curmsg+1;i<smb.msgs;i++)
1045: if(post[i].from==msg.idx.from)
1046: break;
1047: if(i<smb.msgs)
1048: smb.curmsg=i;
1049: else
1050: domsg=0;
1051: do_find=false;
1052: break;
1053: case '{': /* Search Author backward */
1054: strcpy(str,msg.from);
1055: for(i=smb.curmsg-1;i>-1;i--)
1056: if(post[i].from==msg.idx.from)
1057: break;
1058: if(i>-1)
1059: smb.curmsg=i;
1060: else
1061: domsg=0;
1062: do_find=false;
1063: break;
1064: case ']': /* Search To User forward */
1065: strcpy(str,msg.to);
1066: for(i=smb.curmsg+1;i<smb.msgs;i++)
1067: if(post[i].to==msg.idx.to)
1068: break;
1069: if(i<smb.msgs)
1070: smb.curmsg=i;
1071: else
1072: domsg=0;
1073: do_find=false;
1074: break;
1075: case '[': /* Search To User backward */
1076: strcpy(str,msg.to);
1077: for(i=smb.curmsg-1;i>-1;i--)
1078: if(post[i].to==msg.idx.to)
1079: break;
1080: if(i>-1)
1081: smb.curmsg=i;
1082: else
1083: domsg=0;
1084: do_find=false;
1085: break;
1086: case 0: /* Carriage return - Next Message */
1087: case '+':
1088: if(smb.curmsg<smb.msgs-1) smb.curmsg++;
1089: else done=1;
1090: break;
1091: case '?':
1092: menu("msgscan");
1093: domsg=0;
1094: break; } }
1095: if(msg.total_hfields)
1096: smb_freemsgmem(&msg);
1097: if(post)
1098: free(post);
1099: if(!(org_mode&(SCAN_CONST|SCAN_TOYOU|SCAN_FIND)) && !(cfg.sub[subnum]->misc&SUB_PONLY)
1100: && reads && chk_ar(cfg.sub[subnum]->post_ar,&useron)
1101: && !(useron.rest&FLAG('P'))) {
1102: sprintf(str,text[Post],cfg.grp[cfg.sub[subnum]->grp]->sname
1103: ,cfg.sub[subnum]->lname);
1104: if(!noyes(str))
1105: postmsg(subnum,0,0);
1106: }
1107: smb_close(&smb);
1108: smb_stack(&smb,SMB_STACK_POP);
1109: return(0);
1110: }
1111:
1112: /****************************************************************************/
1113: /* This function lists all messages in sub-board */
1114: /* Returns number of messages found/displayed. */
1115: /****************************************************************************/
1116: long sbbs_t::listsub(uint subnum, long mode, long start, char* search)
1117: {
1118: int i;
1119: long posts;
1120: long displayed;
1121: post_t *post;
1122:
1123: if((i=smb_stack(&smb,SMB_STACK_PUSH))!=0) {
1124: errormsg(WHERE,ERR_OPEN,cfg.sub[subnum]->code,i);
1125: return(0);
1126: }
1127: SAFEPRINTF2(smb.file,"%s%s",cfg.sub[subnum]->data_dir,cfg.sub[subnum]->code);
1128: smb.retry_time=cfg.smb_retry_time;
1129: smb.subnum=subnum;
1130: if((i=smb_open(&smb))!=0) {
1131: errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
1132: smb_stack(&smb,SMB_STACK_POP);
1133: return(0);
1134: }
1135: post=loadposts(&posts,subnum,0,LP_BYSELF|LP_OTHERS);
1136: bprintf(text[SearchSubFmt]
1137: ,cfg.grp[cfg.sub[subnum]->grp]->sname,cfg.sub[subnum]->lname,posts /* total? */);
1138: if(mode&SCAN_FIND)
1139: displayed=searchposts(subnum, post, start, posts, search);
1140: else if(mode&SCAN_TOYOU)
1141: displayed=showposts_toyou(post, start, posts);
1142: else
1143: displayed=listmsgs(subnum, mode, post, start, posts);
1144: if(posts)
1145: free(post);
1146: smb_close(&smb);
1147: smb_stack(&smb,SMB_STACK_POP);
1148:
1149: return(displayed);
1150: }
1151:
1152: /****************************************************************************/
1153: /* Will search the messages pointed to by 'msg' for the occurance of the */
1154: /* string 'search' and display any messages (number of message, author and */
1155: /* title). 'msgs' is the total number of valid messages. */
1156: /* Returns number of messages found. */
1157: /****************************************************************************/
1158: long sbbs_t::searchposts(uint subnum, post_t *post, long start, long posts
1159: , char *search)
1160: {
1161: char *buf,ch;
1162: long l,found=0;
1163: smbmsg_t msg;
1164:
1165: msg.total_hfields=0;
1166: for(l=start;l<posts && !msgabort();l++) {
1167: msg.idx.offset=post[l].offset;
1168: if(!loadmsg(&msg,post[l].number))
1169: continue;
1170: smb_unlockmsghdr(&smb,&msg);
1171: buf=smb_getmsgtxt(&smb,&msg,GETMSGTXT_ALL);
1172: if(!buf) {
1173: smb_freemsgmem(&msg);
1174: continue;
1175: }
1176: strupr((char *)buf);
1177: if(strstr((char *)buf,search) || strstr(msg.subj,search)) {
1178: if(!found)
1179: CRLF;
1180: if(msg.hdr.attr&MSG_DELETE)
1181: ch='-';
1182: else if((!stricmp(msg.to,useron.alias) || !stricmp(msg.to,useron.name))
1183: && !(msg.hdr.attr&MSG_READ))
1184: ch='!';
1185: else if(msg.hdr.number>subscan[subnum].ptr)
1186: ch='*';
1187: else
1188: ch=' ';
1189: bprintf(text[SubMsgLstFmt],l+1
1190: ,(msg.hdr.attr&MSG_ANONYMOUS) && !sub_op(subnum) ? text[Anonymous]
1191: : msg.from
1192: ,msg.to
1193: ,ch
1194: ,msg.subj);
1195: found++;
1196: }
1197: free(buf);
1198: smb_freemsgmem(&msg);
1199: }
1200:
1201: return(found);
1202: }
1203:
1204: /****************************************************************************/
1205: /* Will search the messages pointed to by 'msg' for message to the user on */
1206: /* Returns number of messages found. */
1207: /****************************************************************************/
1208: long sbbs_t::showposts_toyou(post_t *post, ulong start, long posts)
1209: {
1210: char str[128];
1211: ushort namecrc,aliascrc,sysop;
1212: long l,found;
1213: smbmsg_t msg;
1214:
1215: strcpy(str,useron.alias);
1216: strlwr(str);
1217: aliascrc=crc16(str,0);
1218: strcpy(str,useron.name);
1219: strlwr(str);
1220: namecrc=crc16(str,0);
1221: sysop=crc16("sysop",0);
1222: msg.total_hfields=0;
1223: for(l=start,found=0;l<posts && !msgabort();l++) {
1224:
1225: if((useron.number!=1 || post[l].to!=sysop)
1226: && post[l].to!=aliascrc && post[l].to!=namecrc)
1227: continue;
1228:
1229: if(msg.total_hfields)
1230: smb_freemsgmem(&msg);
1231: msg.total_hfields=0;
1232: msg.idx.offset=post[l].offset;
1233: if(!loadmsg(&msg,post[l].number))
1234: continue;
1235: smb_unlockmsghdr(&smb,&msg);
1236: if((useron.number==1 && !stricmp(msg.to,"sysop") && !msg.from_net.type)
1237: || !stricmp(msg.to,useron.alias) || !stricmp(msg.to,useron.name)) {
1238: if(!found)
1239: CRLF;
1240: found++;
1241: bprintf(text[SubMsgLstFmt],l+1
1242: ,(msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP
1243: ? text[Anonymous] : msg.from
1244: ,msg.to
1245: ,msg.hdr.attr&MSG_DELETE ? '-' : msg.hdr.attr&MSG_READ ? ' ' : '*'
1246: ,msg.subj);
1247: }
1248: }
1249:
1250: if(msg.total_hfields)
1251: smb_freemsgmem(&msg);
1252:
1253: return(found);
1254: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.