|
|
1.1 root 1: /* smbadd.c */
2:
3: /* Synchronet message base (SMB) high-level "add message" function */
4:
5: /* $Id: smbadd.c,v 1.13 2004/12/29 10:13:55 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 2004 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This library is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details: lgpl.txt or *
18: * http://www.fsf.org/copyleft/lesser.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 <time.h>
39: #include "smblib.h"
40: #include "genwrap.h"
41: #include "crc32.h"
42:
43: /****************************************************************************/
44: /****************************************************************************/
45: int SMBCALL smb_addmsg(smb_t* smb, smbmsg_t* msg, int storage, long dupechk_hashes
46: ,ushort xlat, const uchar* body, const uchar* tail)
47: {
48: uchar* lzhbuf=NULL;
49: long lzhlen;
50: int retval;
51: size_t n;
52: size_t l,length;
53: size_t taillen=0;
54: size_t bodylen=0;
55: size_t chklen=0;
56: long offset;
57: ulong crc=0xffffffff;
58: hash_t found;
59: hash_t** hashes=NULL; /* This is a NULL-terminated list of hashes */
60: smbmsg_t remsg;
61:
62: if(!SMB_IS_OPEN(smb)) {
63: safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
64: return(SMB_ERR_NOT_OPEN);
65: }
66:
67: if(filelength(fileno(smb->shd_fp))<1) { /* Create it if it doesn't exist */
68: /* smb->status.max_crcs, max_msgs, max_age, and attr should be pre-initialized */
69: if((retval=smb_create(smb))!=SMB_SUCCESS)
70: return(retval);
71: }
72:
73: if(!smb->locked && smb_locksmbhdr(smb)!=SMB_SUCCESS)
74: return(SMB_ERR_LOCK);
75:
76: msg->hdr.total_dfields = 0;
77:
78: /* try */
79: do {
80:
81: if((retval=smb_getstatus(smb))!=SMB_SUCCESS)
82: break;
83:
84: msg->hdr.number=smb->status.last_msg+1;
85: hashes=smb_msghashes(msg,body);
86:
87: if(smb_findhash(smb, hashes, &found, dupechk_hashes, /* mark? */FALSE)==SMB_SUCCESS) {
88: safe_snprintf(smb->last_error,sizeof(smb->last_error)
89: ,"duplicate %s: %s found in message #%lu"
90: ,smb_hashsourcetype(found.source)
91: ,smb_hashsource(msg,found.source)
92: ,found.number);
93: retval=SMB_DUPE_MSG;
94: break;
95: }
96:
97: if(tail!=NULL && (taillen=strlen(tail))>0)
98: taillen+=sizeof(xlat); /* xlat string terminator */
99:
100: if(body!=NULL && (bodylen=strlen(body))>0) {
101:
102: /* Remove white-space from end of message text */
103: chklen=bodylen;
104: while(chklen && body[chklen-1]<=' ')
105: chklen--;
106:
107: /* Calculate CRC-32 of message text (before encoding, if any) */
108: if(smb->status.max_crcs && dupechk_hashes&(1<<SMB_HASH_SOURCE_BODY)) {
109: for(l=0;l<chklen;l++)
110: crc=ucrc32(body[l],crc);
111: crc=~crc;
112:
113: /* Add CRC to CRC history (and check for duplicates) */
114: if((retval=smb_addcrc(smb,crc))!=SMB_SUCCESS)
115: break;
116: }
117:
118: bodylen+=sizeof(xlat); /* xlat string terminator */
119:
120: /* LZH compress? */
121: if(xlat==XLAT_LZH && bodylen+taillen>=SDT_BLOCK_LEN
122: && (lzhbuf=(uchar *)malloc(bodylen*2))!=NULL) {
123: lzhlen=lzh_encode((uchar*)body,bodylen-sizeof(xlat),lzhbuf);
124: if(lzhlen>1
125: && smb_datblocks(lzhlen+(sizeof(xlat)*2)+taillen)
126: < smb_datblocks(bodylen+taillen)) {
127: bodylen=lzhlen+(sizeof(xlat)*2); /* Compressible */
128: body=lzhbuf;
129: } else
130: xlat=XLAT_NONE;
131: } else
132: xlat=XLAT_NONE;
133: }
134:
135: length=bodylen+taillen;
136:
137: if(length) {
138:
139: if(length&0x80000000) {
140: sprintf(smb->last_error,"message length: 0x%lX",length);
141: retval=SMB_ERR_DAT_LEN;
142: break;
143: }
144:
145: /* Allocate Data Blocks */
146: if(smb->status.attr&SMB_HYPERALLOC) {
147: offset=smb_hallocdat(smb);
148: storage=SMB_HYPERALLOC;
149: } else {
150: if((retval=smb_open_da(smb))!=SMB_SUCCESS)
151: break;
152: if(storage==SMB_FASTALLOC)
153: offset=smb_fallocdat(smb,length,1);
154: else { /* SMB_SELFPACK */
155: offset=smb_allocdat(smb,length,1);
156: storage=SMB_SELFPACK;
157: }
158: smb_close_da(smb);
159: }
160:
161: if(offset<0) {
162: retval=offset;
163: break;
164: }
165: msg->hdr.offset=offset;
166:
167: smb_fseek(smb->sdt_fp,offset,SEEK_SET);
168:
169: if(bodylen) {
170: if((retval=smb_dfield(msg,TEXT_BODY,bodylen))!=SMB_SUCCESS)
171: break;
172:
173: if(xlat!=XLAT_NONE) { /* e.g. XLAT_LZH */
174: if(smb_fwrite(smb,&xlat,sizeof(xlat),smb->sdt_fp)!=sizeof(xlat)) {
175: safe_snprintf(smb->last_error,sizeof(smb->last_error)
176: ,"%d '%s' writing body xlat string"
177: ,get_errno(),STRERROR(get_errno()));
178: retval=SMB_ERR_WRITE;
179: break;
180: }
181: bodylen-=sizeof(xlat);
182: }
183: xlat=XLAT_NONE; /* xlat string terminator */
184: if(smb_fwrite(smb,&xlat,sizeof(xlat),smb->sdt_fp)!=sizeof(xlat)) {
185: safe_snprintf(smb->last_error,sizeof(smb->last_error)
186: ,"%d '%s' writing body xlat terminator"
187: ,get_errno(),STRERROR(get_errno()));
188: retval=SMB_ERR_WRITE;
189: break;
190: }
191: bodylen-=sizeof(xlat);
192:
193: if(smb_fwrite(smb,body,bodylen,smb->sdt_fp)!=bodylen) {
194: safe_snprintf(smb->last_error,sizeof(smb->last_error)
195: ,"%d '%s' writing body (%ld bytes)"
196: ,get_errno(),STRERROR(get_errno())
197: ,bodylen);
198: retval=SMB_ERR_WRITE;
199: break;
200: }
201: }
202:
203: if(taillen) {
204: if((retval=smb_dfield(msg,TEXT_TAIL,taillen))!=SMB_SUCCESS)
205: break;
206:
207: xlat=XLAT_NONE; /* xlat string terminator */
208: if(smb_fwrite(smb,&xlat,sizeof(xlat),smb->sdt_fp)!=sizeof(xlat)) {
209: safe_snprintf(smb->last_error,sizeof(smb->last_error)
210: ,"%d '%s' writing tail xlat terminator"
211: ,get_errno(),STRERROR(get_errno()));
212: retval=SMB_ERR_WRITE;
213: break;
214: }
215:
216: if(smb_fwrite(smb,tail,taillen-sizeof(xlat),smb->sdt_fp)!=taillen-sizeof(xlat)) {
217: safe_snprintf(smb->last_error,sizeof(smb->last_error)
218: ,"%d '%s' writing tail (%ld bytes)"
219: ,get_errno(),STRERROR(get_errno())
220: ,taillen-sizeof(xlat));
221: retval=SMB_ERR_WRITE;
222: break;
223: }
224: }
225:
226: for(l=length;l%SDT_BLOCK_LEN;l++) {
227: if(smb_fputc(0,smb->sdt_fp)!=0)
228: break;
229: }
230: if(l%SDT_BLOCK_LEN) {
231: safe_snprintf(smb->last_error,sizeof(smb->last_error)
232: ,"%d '%s' writing data padding"
233: ,get_errno(),STRERROR(get_errno()));
234: retval=SMB_ERR_WRITE;
235: break;
236: }
237:
238: fflush(smb->sdt_fp);
239: }
240:
241: if(msg->hdr.when_imported.time==0) {
242: msg->hdr.when_imported.time=time(NULL);
243: msg->hdr.when_imported.zone=0; /* how do we detect system TZ? */
244: }
245: if(msg->hdr.when_written.time==0) /* Uninitialized */
246: msg->hdr.when_written = msg->hdr.when_imported;
247: smb_init_idx(smb,msg);
248:
249: /* Look-up thread_back if RFC822 Reply-ID was specified */
250: if(msg->hdr.thread_back==0 && msg->reply_id!=NULL) {
251: if(smb_getmsgidx_by_msgid(smb,&remsg,msg->reply_id)==SMB_SUCCESS)
252: msg->hdr.thread_back=remsg.idx.number; /* needed for threading backward */
253: }
254:
255: /* Look-up thread_back if FTN REPLY was specified */
256: if(msg->hdr.thread_back==0 && msg->ftn_reply!=NULL) {
257: if(smb_getmsghdr_by_ftnid(smb,&remsg,msg->ftn_reply)==SMB_SUCCESS)
258: msg->hdr.thread_back=remsg.idx.number; /* needed for threading backward */
259: }
260:
261: /* Auto-thread linkage */
262: if(msg->hdr.thread_back) {
263: memset(&remsg,0,sizeof(remsg));
264: remsg.hdr.number=msg->hdr.thread_back;
265: if((retval=smb_getmsgidx(smb, &remsg))!=SMB_SUCCESS) /* invalid thread origin */
266: break;
267:
268: if((retval=smb_lockmsghdr(smb,&remsg))!=SMB_SUCCESS)
269: break;
270:
271: if((retval=smb_getmsghdr(smb, &remsg))!=SMB_SUCCESS) {
272: smb_unlockmsghdr(smb, &remsg);
273: break;
274: }
275:
276: /* Add RFC-822 Reply-ID if original message has RFC Message-ID */
277: if(msg->reply_id==NULL && remsg.id!=NULL
278: && (retval=smb_hfield_str(msg,RFC822REPLYID,remsg.id))!=SMB_SUCCESS)
279: break;
280:
281: /* Add FidoNet Reply if original message has FidoNet MSGID */
282: if(msg->ftn_reply==NULL && remsg.ftn_msgid!=NULL
283: && (retval=smb_hfield_str(msg,FIDOREPLYID,remsg.ftn_msgid))!=SMB_SUCCESS)
284: break;
285:
286: retval=smb_updatethread(smb, &remsg, msg->hdr.number);
287: smb_unlockmsghdr(smb, &remsg);
288: smb_freemsgmem(&remsg);
289:
290: if(retval!=SMB_SUCCESS)
291: break;
292: }
293:
294: if(smb_addhashes(smb,hashes,/* skip_marked? */FALSE)==SMB_SUCCESS)
295: msg->flags|=MSG_FLAG_HASHED;
296: if(msg->to==NULL) /* no recipient, don't add header (required for bulkmail) */
297: break;
298:
299: retval=smb_addmsghdr(smb,msg,storage); /* calls smb_unlocksmbhdr() */
300:
301: } while(0);
302: /* finally */
303:
304: if(retval!=SMB_SUCCESS)
305: smb_freemsg_dfields(smb,msg,1);
306:
307: if(smb->locked)
308: smb_unlocksmbhdr(smb);
309: FREE_AND_NULL(lzhbuf);
310: FREE_LIST(hashes,n);
311:
312: return(retval);
313: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.