getmsg.cpp 20 KB
Newer Older
1
2
3
/* Synchronet message retrieval functions */

/* $Id$ */
4
// vi: tabstop=4
5
6
7
8
9

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
rswindell's avatar
rswindell committed
10
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 *																			*
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

/***********************************************************************/
/* Functions that do i/o with messages (posts/mail/auto) or their data */
/***********************************************************************/

#include "sbbs.h"
42
#include "utf8.h"
43
44
45
46

/****************************************************************************/
/* Loads an SMB message from the open msg base the fastest way possible 	*/
/* first by offset, and if that's the wrong message, then by number.        */
47
/* Returns >=0 if the message was loaded and left locked, otherwise < 0.	*/
48
49
50
/* !WARNING!: If you're going to write the msg index back to disk, you must */
/* Call this function with a msg->idx.offset of 0 (so msg->offset will be	*/
/* initialized correctly)													*/
51
52
53
54
55
56
57
58
/****************************************************************************/
int sbbs_t::loadmsg(smbmsg_t *msg, ulong number)
{
	char str[128];
	int i;

	if(msg->idx.offset) {				/* Load by offset if specified */

59
		if((i=smb_lockmsghdr(&smb,msg)) != SMB_SUCCESS) {
60
			errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);
61
			return i;
rswindell's avatar
rswindell committed
62
		}
63
64

		i=smb_getmsghdr(&smb,msg);
65
66
		if(i==SMB_SUCCESS) {
			if(msg->hdr.number==number)
67
				return msg->total_hfields;
68
			/* Wrong offset  */
69
			smb_freemsgmem(msg);
rswindell's avatar
rswindell committed
70
		}
71

72
		smb_unlockmsghdr(&smb,msg);
rswindell's avatar
rswindell committed
73
	}
74
75

	msg->hdr.number=number;
76
	if((i=smb_getmsgidx(&smb,msg))!=SMB_SUCCESS)				 /* Message is deleted */
77
		return i;
78
	if((i=smb_lockmsghdr(&smb,msg))!=SMB_SUCCESS) {
79
		errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);
80
		return i;
rswindell's avatar
rswindell committed
81
	}
82
	if((i=smb_getmsghdr(&smb,msg))!=SMB_SUCCESS) {
83
		SAFEPRINTF4(str,"(%06" PRIX32 ") #%" PRIu32 "/%lu %s",msg->idx.offset,msg->idx.number
84
85
86
			,number,smb.file);
		smb_unlockmsghdr(&smb,msg);
		errormsg(WHERE,ERR_READ,str,i,smb.last_error);
87
		return i;
rswindell's avatar
rswindell committed
88
	}
89
	return msg->total_hfields;
90
91
}

rswindell's avatar
rswindell committed
92
/* Synchronized with atcode()! */
rswindell's avatar
rswindell committed
93
void sbbs_t::show_msgattr(smbmsg_t* msg)
94
{
rswindell's avatar
rswindell committed
95
96
97
	uint16_t attr = msg->hdr.attr;
	uint16_t poll = attr&MSG_POLL_VOTE_MASK;
	uint32_t auxattr = msg->hdr.auxattr;
98
	uint32_t netattr = msg->hdr.netattr;
99
100
101

	bprintf(text[MsgAttr]
		,attr&MSG_PRIVATE	? "Private  "   :nulstr
102
		,attr&MSG_SPAM		? "SPAM  "      :nulstr
103
104
105
106
107
108
109
110
111
		,attr&MSG_READ		? "Read  "      :nulstr
		,attr&MSG_DELETE	? "Deleted  "   :nulstr
		,attr&MSG_KILLREAD	? "Kill  "      :nulstr
		,attr&MSG_ANONYMOUS ? "Anonymous  " :nulstr
		,attr&MSG_LOCKED	? "Locked  "    :nulstr
		,attr&MSG_PERMANENT ? "Permanent  " :nulstr
		,attr&MSG_MODERATED ? "Moderated  " :nulstr
		,attr&MSG_VALIDATED ? "Validated  " :nulstr
		,attr&MSG_REPLIED	? "Replied  "	:nulstr
112
		,attr&MSG_NOREPLY	? "NoReply  "	:nulstr
rswindell's avatar
rswindell committed
113
114
		,poll == MSG_POLL	? "Poll  "		:nulstr
		,poll == MSG_POLL && auxattr&POLL_CLOSED ? "(Closed)  "	:nulstr
115
116
117
		,auxattr&(MSG_FILEATTACH|MSG_MIMEATTACH) ? "Attach  "   :nulstr
		,netattr&MSG_SENT						 ? "Sent  "		:nulstr
		,netattr&MSG_INTRANSIT					 ? "InTransit  ":nulstr
118
119
120
		);
}

121
122
123
124
125
126
127
128
129
130
131
132
/* Returns a CP437 text.dat string converted to UTF-8, when appropriate */
const char* sbbs_t::msghdr_text(const smbmsg_t* msg, uint index)
{
	if(msg == NULL || !(msg->hdr.auxattr & MSG_HFIELDS_UTF8))
		return text[index];

	if(cp437_to_utf8_str(text[index], msghdr_utf8_text, sizeof(msghdr_utf8_text), /* min-char-val: */'\x80') < 1)
		return text[index];

	return msghdr_utf8_text;
}

133
134
135
/****************************************************************************/
/* Displays a message header to the screen                                  */
/****************************************************************************/
136
void sbbs_t::show_msghdr(smb_t* smb, smbmsg_t* msg, const char* subject, const char* from, const char* to)
137
{
138
	char	str[MAX_PATH+1];
139
	char	age[64];
140
141
	char	*sender=NULL;
	int 	i;
rswindell's avatar
rswindell committed
142
	smb_t	saved_smb = this->smb;
143
	long	pmode = 0;
144

145
146
	if(smb != NULL)
		this->smb = *smb;	// Needed for @-codes and JS bbs.smb_* properties
rswindell's avatar
rswindell committed
147
	if(msg != NULL) {
148
		current_msg = msg;		// Needed for @-codes and JS bbs.msg_* properties
rswindell's avatar
rswindell committed
149
150
151
		current_msg_subj = msg->subj;
		current_msg_from = msg->from;
		current_msg_to = msg->to;
152
153
		if(msg->hdr.auxattr & MSG_HFIELDS_UTF8)
			pmode |= P_UTF8;
rswindell's avatar
rswindell committed
154
155
156
157
158
159
160
	}
	if(subject != NULL)
		current_msg_subj = subject;
	if(from != NULL)
		current_msg_from = from;
	if(to != NULL)
		current_msg_to = to;
161

rswindell's avatar
rswindell committed
162
163
164
165
166
167
168
	attr(LIGHTGRAY);
	if(!tos) {
		if(useron.misc&CLRSCRN)
			outchar(FF);
		else
			CRLF;
	}
169
	msghdr_tos = tos;
170
	if(!menu("msghdr", P_NOERROR)) {
171
		bprintf(pmode, msghdr_text(msg, MsgSubj), current_msg_subj);
172
173
		if(msg->tags && *msg->tags)
			bprintf(text[MsgTags], msg->tags);
174
		if(msg->hdr.attr || msg->hdr.netattr || (msg->hdr.auxattr & ~MSG_HFIELDS_UTF8))
175
			show_msgattr(msg);
rswindell's avatar
rswindell committed
176
		if(current_msg_to != NULL && *current_msg_to != 0) {
177
			bprintf(pmode, msghdr_text(msg, MsgTo), current_msg_to);
178
179
180
181
182
			if(msg->to_net.addr!=NULL)
				bprintf(text[MsgToNet],smb_netaddrstr(&msg->to_net,str));
			if(msg->to_ext)
				bprintf(text[MsgToExt],msg->to_ext);
		}
183
184
		if(msg->cc_list != NULL)
			bprintf(text[MsgCarbonCopyList], msg->cc_list);
rswindell's avatar
rswindell committed
185
		if(current_msg_from != NULL && (!(msg->hdr.attr&MSG_ANONYMOUS) || SYSOP)) {
186
			bprintf(pmode, msghdr_text(msg, MsgFrom), current_msg_from);
187
188
			if(msg->from_ext)
				bprintf(text[MsgFromExt],msg->from_ext);
rswindell's avatar
rswindell committed
189
			if(msg->from_net.addr!=NULL && (current_msg_from == NULL || strchr(current_msg_from,'@')==NULL))
190
				bprintf(text[MsgFromNet],smb_netaddrstr(&msg->from_net,str));
191
192
193
194
195
196
197
198
199
200
		}
		if(!(msg->hdr.attr&MSG_POLL) && (msg->upvotes || msg->downvotes))
			bprintf(text[MsgVotes]
				,msg->upvotes, msg->user_voted==1 ? text[PollAnswerChecked] : nulstr
				,msg->downvotes, msg->user_voted==2 ? text[PollAnswerChecked] : nulstr
				,msg->upvotes - msg->downvotes);
		bprintf(text[MsgDate]
			,timestr(msg->hdr.when_written.time)
			,smb_zonestr(msg->hdr.when_written.zone,NULL)
			,age_of_posted_item(age, sizeof(age), msg->hdr.when_written.time - (smb_tzutc(msg->hdr.when_written.zone) * 60)));
rswindell's avatar
rswindell committed
201
		bputs(text[MsgHdrBodySeparator]);
202
	}
203
204
205
206
207
	for(i=0;i<msg->total_hfields;i++) {
		if(msg->hfield[i].type==SENDER)
			sender=(char *)msg->hfield_dat[i];
		if(msg->hfield[i].type==FORWARDED && sender)
			bprintf(text[ForwardedFrom],sender
208
				,timestr(*(time32_t *)msg->hfield_dat[i]));
209
	}
rswindell's avatar
rswindell committed
210
	this->smb = saved_smb;
rswindell's avatar
rswindell committed
211
212
213
	current_msg_subj = NULL;
	current_msg_from = NULL;
	current_msg_to = NULL;
214
215
216
217
218
}

/****************************************************************************/
/* Displays message header and text (if not deleted)                        */
/****************************************************************************/
rswindell's avatar
rswindell committed
219
bool sbbs_t::show_msg(smb_t* smb, smbmsg_t* msg, long p_mode, post_t* post)
220
{
rswindell's avatar
rswindell committed
221
	char*	txt;
222

223
	if((msg->hdr.type == SMB_MSG_TYPE_NORMAL && post != NULL && (post->upvotes || post->downvotes))
224
		|| msg->hdr.type == SMB_MSG_TYPE_POLL)
rswindell's avatar
rswindell committed
225
226
		msg->user_voted = smb_voted_already(smb, msg->hdr.number
					,cfg.sub[smb->subnum]->misc&SUB_NAME ? useron.name : useron.alias, NET_NONE, NULL);
227

rswindell's avatar
rswindell committed
228
	show_msghdr(smb, msg);
229

rswindell's avatar
rswindell committed
230
	if(msg->hdr.type == SMB_MSG_TYPE_POLL && post != NULL && smb->subnum < cfg.total_subs) {
rswindell's avatar
rswindell committed
231
232
		char* answer;
		int longest_answer = 0;
rswindell's avatar
rswindell committed
233

234
235
236
237
238
239
240
241
242
		int comments=0;
		for(int i = 0; i < msg->total_hfields; i++)
			if(msg->hfield[i].type == SMB_COMMENT) {
				bprintf("%s\r\n", (char*)msg->hfield_dat[i]);
				comments++;
			}
		if(comments)
			CRLF;

rswindell's avatar
rswindell committed
243
244
245
246
247
248
249
250
251
252
253
254
255
		for(int i = 0; i < msg->total_hfields; i++) {
			if(msg->hfield[i].type != SMB_POLL_ANSWER)
				continue;
			answer = (char*)msg->hfield_dat[i];
			int len = strlen(answer);
			if(len > longest_answer)
				longest_answer = len;
		}
		unsigned answers = 0;
		for(int i = 0; i < msg->total_hfields; i++) {
			if(msg->hfield[i].type != SMB_POLL_ANSWER)
				continue;
			answer = (char*)msg->hfield_dat[i];
256
			float pct = post->total_votes ? ((float)post->votes[answers] / post->total_votes)*100.0F : 0.0F;
rswindell's avatar
rswindell committed
257
258
259
260
261
262
			char str[128];
			int width = longest_answer;
			if(width < cols/3) width = cols/3;
			else if(width > cols-20)
				width = cols-20;
			bprintf(text[PollAnswerNumber], answers+1);
rswindell's avatar
rswindell committed
263
264
265
			bool results_visible = false;
			if((msg->hdr.auxattr&POLL_RESULTS_MASK) == POLL_RESULTS_OPEN)
				results_visible = true;
266
			else if((msg->from_net.type == NET_NONE && sub_op(smb->subnum))
rswindell's avatar
rswindell committed
267
				|| smb_msg_is_from(msg, cfg.sub[smb->subnum]->misc&SUB_NAME ? useron.name : useron.alias, NET_NONE, NULL))
rswindell's avatar
rswindell committed
268
269
270
271
				results_visible = true;
			else if((msg->hdr.auxattr&POLL_RESULTS_MASK) == POLL_RESULTS_CLOSED)
				results_visible = (msg->hdr.auxattr&POLL_CLOSED) ? true : false;
			else if((msg->hdr.auxattr&POLL_RESULTS_MASK) != POLL_RESULTS_SECRET)
272
				results_visible = msg->user_voted ? true : false;
rswindell's avatar
rswindell committed
273
			if(results_visible) {
274
275
				safe_snprintf(str, sizeof(str), text[PollAnswerFmt]
					,width, width, answer, post->votes[answers], pct);
276
				backfill(str, pct, cfg.color[clr_votes_full], cfg.color[clr_votes_empty]);
277
				if(msg->user_voted&(1<<answers))
278
279
					bputs(text[PollAnswerChecked]);
			} else {
280
				attr(cfg.color[clr_votes_empty]);
281
282
				bputs(answer);
			}
rswindell's avatar
rswindell committed
283
			CRLF;
rswindell's avatar
rswindell committed
284
285
			answers++;
		}
286
		if(!msg->user_voted && !(useron.misc&EXPERT) && !(msg->hdr.auxattr&POLL_CLOSED) && !(useron.rest&FLAG('V')))
rswindell's avatar
rswindell committed
287
			mnemonics(text[VoteInThisPollNow]);
rswindell's avatar
rswindell committed
288
		return true;
rswindell's avatar
rswindell committed
289
	}
rswindell's avatar
rswindell committed
290
291
292
293
	if((txt=smb_getmsgtxt(smb, msg, 0)) == NULL)
		return false;
	char* p = txt;
	if(!(console&CON_RAW_IN)) {
294
295
		if(strstr(txt, "\x1b[") == NULL)	// Don't word-wrap raw ANSI text
			p_mode|=P_WORDWRAP;
rswindell's avatar
rswindell committed
296
297
298
299
		p = smb_getplaintext(msg, txt);
		if(p == NULL)
			p = txt;
		else
300
301
302
			bprintf(text[MIMEDecodedPlainTextFmt]
				, msg->text_charset == NULL ? "unspecified (US-ASCII)" : msg->text_charset
				, msg->text_subtype);
303
	}
rswindell's avatar
rswindell committed
304
305
	truncsp(p);
	SKIP_CRLF(p);
306
307
308
309
310
	if(smb_msg_is_utf8(msg)) {
		if(!term_supports(UTF8))
			utf8_normalize_str(txt);
		p_mode |= P_UTF8;
	}
311
	if(smb->subnum < cfg.total_subs) {
312
		p_mode |= cfg.sub[smb->subnum]->pmode;
313
314
		p_mode &= ~cfg.sub[smb->subnum]->n_pmode;
	}
rswindell's avatar
rswindell committed
315
316
317
318
319
320
321
322
323
324
	putmsg(p, p_mode, msg->columns);
	smb_freemsgtxt(txt);
	if(column)
		CRLF;
	if((txt=smb_getmsgtxt(smb,msg,GETMSGTXT_TAIL_ONLY))==NULL)
		return false;

	putmsg(txt, p_mode&(~P_WORDWRAP));
	smb_freemsgtxt(txt);
	return true;
325
326
}

327
328
329
330
331
332
333
334
335
336
337
void sbbs_t::download_msg_attachments(smb_t* smb, smbmsg_t* msg, bool del)
{
	char str[256];
	char fpath[MAX_PATH+1];
	char* txt;
	int attachment_index = 0;
	bool found = true;
	while((txt=smb_getmsgtxt(smb, msg, 0)) != NULL && found) {
		char filename[MAX_PATH+1] = {0};
		uint32_t filelen = 0;
		uint8_t* filedata;
338
		if((filedata = smb_getattachment(msg, txt, filename, sizeof(filename), &filelen, attachment_index++)) != NULL
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
			&& filename[0] != 0 && filelen > 0) {
			char tmp[32];
			SAFEPRINTF2(str, text[DownloadAttachedFileQ], filename, ultoac(filelen,tmp));
			if(!noyes(str)) {
				SAFEPRINTF2(fpath, "%s%s", cfg.temp_dir, filename);
				FILE* fp = fopen(fpath, "wb");
				if(fp == NULL)
					errormsg(WHERE, ERR_OPEN, fpath, 0);
				else {
					int result = fwrite(filedata, filelen, 1, fp);
					fclose(fp);
					if(!result)
						errormsg(WHERE, ERR_WRITE, fpath, filelen);
					else
						sendfile(fpath, useron.prot, "attachment");
				}
			}
		} else
			found = false;
		smb_freemsgtxt(txt);
	}

	if(msg->hdr.auxattr&MSG_FILEATTACH) {  /* Attached file */
		smb_getmsgidx(smb, msg);
		SAFECOPY(str, msg->subj);					/* filenames (multiple?) in title */
		char *p,*tp,*sp,ch;
		tp=str;
		while(online) {
			p=strchr(tp,' ');
			if(p) *p=0;
			sp=strrchr(tp,'/');              /* sp is slash pointer */
			if(!sp) sp=strrchr(tp,'\\');
			if(sp) tp=sp+1;
			file_t	fd;
rswindell's avatar
rswindell committed
373
			fd.dir=cfg.total_dirs+1;			/* temp dir for file attachments */
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
			padfname(tp,fd.name);
			SAFEPRINTF3(fpath,"%sfile/%04u.in/%s"  /* path is path/fname */
				,cfg.data_dir, msg->idx.to, tp);
			if(!fexistcase(fpath) && msg->idx.from)
				SAFEPRINTF3(fpath,"%sfile/%04u.out/%s"  /* path is path/fname */
					,cfg.data_dir, msg->idx.from,tp);
			long length=(long)flength(fpath);
			if(length<1)
				bprintf(text[FileDoesNotExist], tp);
			else if(!(useron.exempt&FLAG('T')) && cur_cps && !SYSOP
				&& length/(long)cur_cps>(time_t)timeleft)
				bputs(text[NotEnoughTimeToDl]);
			else {
				char 	tmp[512];
				int		i;
				SAFEPRINTF2(str, text[DownloadAttachedFileQ]
					,tp,ultoac(length,tmp));
				if(length>0L && text[DownloadAttachedFileQ][0] && yesno(str)) {
					{	/* Remote User */
						xfer_prot_menu(XFER_DOWNLOAD);
						mnemonics(text[ProtocolOrQuit]);
						strcpy(str,"Q");
						for(i=0;i<cfg.total_prots;i++)
							if(cfg.prot[i]->dlcmd[0]
								&& chk_ar(cfg.prot[i]->ar,&useron,&client)) {
								sprintf(tmp,"%c",cfg.prot[i]->mnemonic);
400
								strcat(str,tmp);
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
							}
						ch=(char)getkeys(str,0);
						for(i=0;i<cfg.total_prots;i++)
							if(cfg.prot[i]->dlcmd[0] && ch==cfg.prot[i]->mnemonic
								&& chk_ar(cfg.prot[i]->ar,&useron,&client))
								break;
						if(i<cfg.total_prots) {
							int error = protocol(cfg.prot[i], XFER_DOWNLOAD, fpath, nulstr, false);
							if(checkprotresult(cfg.prot[i],error,&fd)) {
								if(del)
									remove(fpath);
								logon_dlb+=length;	/* Update stats */
								logon_dls++;
								useron.dls=(ushort)adjustuserrec(&cfg,useron.number
									,U_DLS,5,1);
								useron.dlb=adjustuserrec(&cfg,useron.number
									,U_DLB,10,length);
								bprintf(text[FileNBytesSent]
									,fd.name,ultoac(length,tmp));
								SAFEPRINTF(str
									,"downloaded attached file: %s"
									,fd.name);
423
								logline("D-",str);
424
							}
425
426
427
428
							autohangup();
						}
					}
				}
429
430
431
432
			}
			if(!p)
				break;
			tp=p+1;
433
			while(*tp==' ') tp++;
434
435
436
		}
		// Remove the *.in directory, only if its empty
		SAFEPRINTF2(fpath, "%sfile/%04u.in", cfg.data_dir, msg->idx.to);
437
		rmdir(fpath);
438
439
440
	}
}

441
442
443
/****************************************************************************/
/* Writes message header and text data to a text file						*/
/****************************************************************************/
rswindell's avatar
rswindell committed
444
bool sbbs_t::msgtotxt(smb_t* smb, smbmsg_t* msg, const char *fname, bool header, ulong gettxt_mode)
445
{
deuce's avatar
deuce committed
446
	char	*buf;
447
	char	tmp[128];
448
449
450
	int 	i;
	FILE	*out;

rswindell's avatar
rswindell committed
451
452
	if((out=fnopen(&i,fname,O_WRONLY|O_CREAT|O_APPEND))==NULL) {
		errormsg(WHERE,ERR_OPEN,fname,0);
453
		return false;
454
	}
455
456
457
458
459
	if(header) {
		fprintf(out,"\r\n");
		fprintf(out,"Subj : %s\r\n",msg->subj);
		fprintf(out,"To   : %s",msg->to);
		if(msg->to_net.addr)
460
			fprintf(out," (%s)",smb_netaddrstr(&msg->to_net,tmp));
461
462
		if(msg->to_ext)
			fprintf(out," #%s",msg->to_ext);
463
464
465
466
		fprintf(out,"\r\nFrom : %s",msg->from);
		if(msg->from_ext && !(msg->hdr.attr&MSG_ANONYMOUS))
			fprintf(out," #%s",msg->from_ext);
		if(msg->from_net.addr)
467
			fprintf(out," (%s)",smb_netaddrstr(&msg->from_net,tmp));
468
		fprintf(out,"\r\nDate : %.24s %s"
469
			,timestr(msg->hdr.when_written.time)
470
			,smb_zonestr(msg->hdr.when_written.zone,NULL));
471
		fprintf(out,"\r\n\r\n");
472
	}
473

rswindell's avatar
rswindell committed
474
475
	bool result = false;
	buf=smb_getmsgtxt(smb, msg, gettxt_mode);
476
	if(buf!=NULL) {
477
		strip_invalid_attr(buf);
478
		fputs(buf,out);
479
		smb_freemsgtxt(buf);
rswindell's avatar
rswindell committed
480
		result = true;
481
	} else if(smb_getmsgdatlen(msg)>2)
rswindell's avatar
rswindell committed
482
		errormsg(WHERE,ERR_READ,smb->file,smb_getmsgdatlen(msg));
483
	fclose(out);
rswindell's avatar
rswindell committed
484
	return result;
485
486
487
488
489
490
491
}

/****************************************************************************/
/* Returns message number posted at or after time							*/
/****************************************************************************/
ulong sbbs_t::getmsgnum(uint subnum, time_t t)
{
rswindell's avatar
rswindell committed
492
493
494
    int			i;
	smb_t		smb;
	idxrec_t	idx;
495
496
497
498

	if(!t)
		return(0);

rswindell's avatar
rswindell committed
499
500
	ZERO_VAR(smb);
	SAFEPRINTF2(smb.file,"%s%s",cfg.sub[subnum]->data_dir,cfg.sub[subnum]->code);
501
	smb.retry_time=cfg.smb_retry_time;
502
	smb.subnum=subnum;
503
	if((i=smb_open_index(&smb)) != SMB_SUCCESS) {
504
		errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
505
		return 0;
506
	}
507
	int result = smb_getmsgidx_by_time(&smb, &idx, t);
508
	smb_close(&smb);
509
510
511
	if(result >= SMB_SUCCESS)
		return idx.number - 1;
	return ~0;
512
513
514
515
516
517
518
}

/****************************************************************************/
/* Returns the time of the message number pointed to by 'ptr'               */
/****************************************************************************/
time_t sbbs_t::getmsgtime(uint subnum, ulong ptr)
{
rswindell's avatar
rswindell committed
519
520
521
522
	int 		i;
	smb_t		smb;
	smbmsg_t	msg;
	idxrec_t	lastidx;
523

rswindell's avatar
rswindell committed
524
525
	ZERO_VAR(smb);
	SAFEPRINTF2(smb.file,"%s%s",cfg.sub[subnum]->data_dir,cfg.sub[subnum]->code);
526
	smb.retry_time=cfg.smb_retry_time;
527
	smb.subnum=subnum;
528
529
	if((i=smb_open(&smb))!=0) {
		errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
530
		return(0);
531
	}
532
533
	if(!filelength(fileno(smb.sid_fp))) {			/* Empty base */
		smb_close(&smb);
534
		return(0);
535
	}
536
537
538
539
	msg.offset=0;
	msg.hdr.number=0;
	if(smb_getmsgidx(&smb,&msg)) {				/* Get first message index */
		smb_close(&smb);
540
		return(0);
541
	}
542
543
	if(!ptr || msg.idx.number>=ptr) {			/* ptr is before first message */
		smb_close(&smb);
544
545
		return(msg.idx.time);   				/* so return time of first msg */
	}
546
547
548

	if(smb_getlastidx(&smb,&lastidx)) { 			 /* Get last message index */
		smb_close(&smb);
549
		return(0);
550
	}
551
552
	if(lastidx.number<ptr) {					/* ptr is after last message */
		smb_close(&smb);
553
554
		return(lastidx.time);	 				/* so return time of last msg */
	}
555
556
557
558
559

	msg.idx.time=0;
	msg.hdr.number=ptr;
	if(!smb_getmsgidx(&smb,&msg)) {
		smb_close(&smb);
560
		return(msg.idx.time);
561
	}
562
563
564
565
566
567
568
569

	if(ptr-msg.idx.number < lastidx.number-ptr) {
		msg.offset=0;
		msg.idx.number=0;
		while(msg.idx.number<ptr) {
			msg.hdr.number=0;
			if(smb_getmsgidx(&smb,&msg) || msg.idx.number>=ptr)
				break;
570
			msg.offset++;
571
		}
572
		smb_close(&smb);
573
		return(msg.idx.time);
574
	}
575
576
577
578
579
580

	ptr--;
	while(ptr) {
		msg.hdr.number=ptr;
		if(!smb_getmsgidx(&smb,&msg))
			break;
581
		ptr--;
582
	}
583
584
585
586
587
588
589
590
591
	smb_close(&smb);
	return(msg.idx.time);
}


/****************************************************************************/
/* Returns the total number of msgs in the sub-board and sets 'ptr' to the  */
/* number of the last message in the sub (0) if no messages.				*/
/****************************************************************************/
deuce's avatar
deuce committed
592
ulong sbbs_t::getlastmsg(uint subnum, uint32_t *ptr, time_t *t)
593
594
595
{
	int 		i;
	ulong		total;
rswindell's avatar
rswindell committed
596
	smb_t		smb;
597
598
599
600
601
602
603
604
605
	idxrec_t	idx;

	if(ptr)
		(*ptr)=0;
	if(t)
		(*t)=0;
	if(subnum>=cfg.total_subs)
		return(0);

rswindell's avatar
rswindell committed
606
607
	ZERO_VAR(smb);
	SAFEPRINTF2(smb.file,"%s%s",cfg.sub[subnum]->data_dir,cfg.sub[subnum]->code);
608
	smb.retry_time=cfg.smb_retry_time;
609
	smb.subnum=subnum;
610
611
	if((i=smb_open(&smb))!=0) {
		errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
612
		return(0);
613
	}
614
615
616

	if(!filelength(fileno(smb.sid_fp))) {			/* Empty base */
		smb_close(&smb);
617
		return(0);
618
	}
619
620
621
	if((i=smb_locksmbhdr(&smb))!=0) {
		smb_close(&smb);
		errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);
622
		return(0);
623
	}
624
625
626
	if((i=smb_getlastidx(&smb,&idx))!=0) {
		smb_close(&smb);
		errormsg(WHERE,ERR_READ,smb.file,i,smb.last_error);
627
		return(0);
628
	}
629
	total=(long)filelength(fileno(smb.sid_fp))/sizeof(idxrec_t);
630
631
632
633
634
635
636
637
638
	smb_unlocksmbhdr(&smb);
	smb_close(&smb);
	if(ptr)
		(*ptr)=idx.number;
	if(t)
		(*t)=idx.time;
	return(total);
}