getmsg.cpp 19.5 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
		);
}

/****************************************************************************/
/* Displays a message header to the screen                                  */
/****************************************************************************/
124
void sbbs_t::show_msghdr(smb_t* smb, smbmsg_t* msg, const char* subject, const char* from, const char* to)
125
{
126
	char	str[MAX_PATH+1];
127
	char	age[64];
128
129
	char	*sender=NULL;
	int 	i;
rswindell's avatar
rswindell committed
130
	smb_t	saved_smb = this->smb;
131

132
133
	if(smb != NULL)
		this->smb = *smb;	// Needed for @-codes and JS bbs.smb_* properties
rswindell's avatar
rswindell committed
134
	if(msg != NULL) {
135
		current_msg = msg;		// Needed for @-codes and JS bbs.msg_* properties
rswindell's avatar
rswindell committed
136
137
138
139
140
141
142
143
144
145
		current_msg_subj = msg->subj;
		current_msg_from = msg->from;
		current_msg_to = msg->to;
	}
	if(subject != NULL)
		current_msg_subj = subject;
	if(from != NULL)
		current_msg_from = from;
	if(to != NULL)
		current_msg_to = to;
146

rswindell's avatar
rswindell committed
147
148
149
150
151
152
153
	attr(LIGHTGRAY);
	if(!tos) {
		if(useron.misc&CLRSCRN)
			outchar(FF);
		else
			CRLF;
	}
154
	msghdr_tos = tos;
155
	if(!menu("msghdr", P_NOERROR)) {
rswindell's avatar
rswindell committed
156
		bprintf(text[MsgSubj], current_msg_subj);
157
158
		if(msg->tags && *msg->tags)
			bprintf(text[MsgTags], msg->tags);
159
		if(msg->hdr.attr || msg->hdr.netattr || msg->hdr.auxattr)
160
			show_msgattr(msg);
rswindell's avatar
rswindell committed
161
162
		if(current_msg_to != NULL && *current_msg_to != 0) {
			bprintf(text[MsgTo], current_msg_to);
163
164
165
166
167
			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);
		}
168
169
		if(msg->cc_list != NULL)
			bprintf(text[MsgCarbonCopyList], msg->cc_list);
rswindell's avatar
rswindell committed
170
171
		if(current_msg_from != NULL && (!(msg->hdr.attr&MSG_ANONYMOUS) || SYSOP)) {
			bprintf(text[MsgFrom], current_msg_from);
172
173
			if(msg->from_ext)
				bprintf(text[MsgFromExt],msg->from_ext);
rswindell's avatar
rswindell committed
174
			if(msg->from_net.addr!=NULL && (current_msg_from == NULL || strchr(current_msg_from,'@')==NULL))
175
				bprintf(text[MsgFromNet],smb_netaddrstr(&msg->from_net,str));
176
177
178
179
180
181
182
183
184
185
		}
		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
186
		bputs(text[MsgHdrBodySeparator]);
187
	}
188
189
190
191
192
	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
193
				,timestr(*(time32_t *)msg->hfield_dat[i]));
194
	}
rswindell's avatar
rswindell committed
195
	this->smb = saved_smb;
rswindell's avatar
rswindell committed
196
197
198
	current_msg_subj = NULL;
	current_msg_from = NULL;
	current_msg_to = NULL;
199
200
201
202
203
}

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

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

rswindell's avatar
rswindell committed
213
	show_msghdr(smb, msg);
214

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

219
220
221
222
223
224
225
226
227
		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
228
229
230
231
232
233
234
235
236
237
238
239
240
		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];
241
			float pct = post->total_votes ? ((float)post->votes[answers] / post->total_votes)*100.0F : 0.0F;
rswindell's avatar
rswindell committed
242
243
244
245
246
247
			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
248
249
250
			bool results_visible = false;
			if((msg->hdr.auxattr&POLL_RESULTS_MASK) == POLL_RESULTS_OPEN)
				results_visible = true;
251
			else if((msg->from_net.type == NET_NONE && sub_op(smb->subnum))
rswindell's avatar
rswindell committed
252
				|| smb_msg_is_from(msg, cfg.sub[smb->subnum]->misc&SUB_NAME ? useron.name : useron.alias, NET_NONE, NULL))
rswindell's avatar
rswindell committed
253
254
255
256
				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)
257
				results_visible = msg->user_voted ? true : false;
rswindell's avatar
rswindell committed
258
			if(results_visible) {
259
260
				safe_snprintf(str, sizeof(str), text[PollAnswerFmt]
					,width, width, answer, post->votes[answers], pct);
261
				backfill(str, pct, cfg.color[clr_votes_full], cfg.color[clr_votes_empty]);
262
				if(msg->user_voted&(1<<answers))
263
264
					bputs(text[PollAnswerChecked]);
			} else {
265
				attr(cfg.color[clr_votes_empty]);
266
267
				bputs(answer);
			}
rswindell's avatar
rswindell committed
268
			CRLF;
rswindell's avatar
rswindell committed
269
270
			answers++;
		}
271
		if(!msg->user_voted && !(useron.misc&EXPERT) && !(msg->hdr.auxattr&POLL_CLOSED) && !(useron.rest&FLAG('V')))
rswindell's avatar
rswindell committed
272
			mnemonics(text[VoteInThisPollNow]);
rswindell's avatar
rswindell committed
273
		return true;
rswindell's avatar
rswindell committed
274
	}
rswindell's avatar
rswindell committed
275
276
277
278
	if((txt=smb_getmsgtxt(smb, msg, 0)) == NULL)
		return false;
	char* p = txt;
	if(!(console&CON_RAW_IN)) {
279
280
		if(strstr(txt, "\x1b[") == NULL)	// Don't word-wrap raw ANSI text
			p_mode|=P_WORDWRAP;
rswindell's avatar
rswindell committed
281
282
283
284
		p = smb_getplaintext(msg, txt);
		if(p == NULL)
			p = txt;
		else
285
286
287
			bprintf(text[MIMEDecodedPlainTextFmt]
				, msg->text_charset == NULL ? "unspecified (US-ASCII)" : msg->text_charset
				, msg->text_subtype);
288
	}
rswindell's avatar
rswindell committed
289
290
	truncsp(p);
	SKIP_CRLF(p);
291
292
293
294
295
	if(smb_msg_is_utf8(msg)) {
		if(!term_supports(UTF8))
			utf8_normalize_str(txt);
		p_mode |= P_UTF8;
	}
296
	if(smb->subnum < cfg.total_subs) {
297
		p_mode |= cfg.sub[smb->subnum]->pmode;
298
299
		p_mode &= ~cfg.sub[smb->subnum]->n_pmode;
	}
rswindell's avatar
rswindell committed
300
301
302
303
304
305
306
307
308
309
	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;
310
311
}

312
313
314
315
316
317
318
319
320
321
322
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;
323
		if((filedata = smb_getattachment(msg, txt, filename, sizeof(filename), &filelen, attachment_index++)) != NULL
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
			&& 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
358
			fd.dir=cfg.total_dirs+1;			/* temp dir for file attachments */
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
			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);
385
								strcat(str,tmp);
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
							}
						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);
408
								logline("D-",str);
409
							}
410
411
412
413
							autohangup();
						}
					}
				}
414
415
416
417
			}
			if(!p)
				break;
			tp=p+1;
418
			while(*tp==' ') tp++;
419
420
421
		}
		// Remove the *.in directory, only if its empty
		SAFEPRINTF2(fpath, "%sfile/%04u.in", cfg.data_dir, msg->idx.to);
422
		rmdir(fpath);
423
424
425
	}
}

426
427
428
/****************************************************************************/
/* Writes message header and text data to a text file						*/
/****************************************************************************/
rswindell's avatar
rswindell committed
429
bool sbbs_t::msgtotxt(smb_t* smb, smbmsg_t* msg, const char *fname, bool header, ulong gettxt_mode)
430
{
deuce's avatar
deuce committed
431
	char	*buf;
432
	char	tmp[128];
433
434
435
	int 	i;
	FILE	*out;

rswindell's avatar
rswindell committed
436
437
	if((out=fnopen(&i,fname,O_WRONLY|O_CREAT|O_APPEND))==NULL) {
		errormsg(WHERE,ERR_OPEN,fname,0);
438
		return false;
439
	}
440
441
442
443
444
	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)
445
			fprintf(out," (%s)",smb_netaddrstr(&msg->to_net,tmp));
446
447
		if(msg->to_ext)
			fprintf(out," #%s",msg->to_ext);
448
449
450
451
		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)
452
			fprintf(out," (%s)",smb_netaddrstr(&msg->from_net,tmp));
453
		fprintf(out,"\r\nDate : %.24s %s"
454
			,timestr(msg->hdr.when_written.time)
455
			,smb_zonestr(msg->hdr.when_written.zone,NULL));
456
		fprintf(out,"\r\n\r\n");
457
	}
458

rswindell's avatar
rswindell committed
459
460
	bool result = false;
	buf=smb_getmsgtxt(smb, msg, gettxt_mode);
461
	if(buf!=NULL) {
462
		strip_invalid_attr(buf);
463
		fputs(buf,out);
464
		smb_freemsgtxt(buf);
rswindell's avatar
rswindell committed
465
		result = true;
466
	} else if(smb_getmsgdatlen(msg)>2)
rswindell's avatar
rswindell committed
467
		errormsg(WHERE,ERR_READ,smb->file,smb_getmsgdatlen(msg));
468
	fclose(out);
rswindell's avatar
rswindell committed
469
	return result;
470
471
472
473
474
475
476
}

/****************************************************************************/
/* Returns message number posted at or after time							*/
/****************************************************************************/
ulong sbbs_t::getmsgnum(uint subnum, time_t t)
{
rswindell's avatar
rswindell committed
477
478
479
    int			i;
	smb_t		smb;
	idxrec_t	idx;
480
481
482
483

	if(!t)
		return(0);

rswindell's avatar
rswindell committed
484
485
	ZERO_VAR(smb);
	SAFEPRINTF2(smb.file,"%s%s",cfg.sub[subnum]->data_dir,cfg.sub[subnum]->code);
486
	smb.retry_time=cfg.smb_retry_time;
487
	smb.subnum=subnum;
488
	if((i=smb_open_index(&smb)) != SMB_SUCCESS) {
489
		errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
490
		return 0;
491
	}
492
	int result = smb_getmsgidx_by_time(&smb, &idx, t);
493
	smb_close(&smb);
494
495
496
	if(result >= SMB_SUCCESS)
		return idx.number - 1;
	return ~0;
497
498
499
500
501
502
503
}

/****************************************************************************/
/* 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
504
505
506
507
	int 		i;
	smb_t		smb;
	smbmsg_t	msg;
	idxrec_t	lastidx;
508

rswindell's avatar
rswindell committed
509
510
	ZERO_VAR(smb);
	SAFEPRINTF2(smb.file,"%s%s",cfg.sub[subnum]->data_dir,cfg.sub[subnum]->code);
511
	smb.retry_time=cfg.smb_retry_time;
512
	smb.subnum=subnum;
513
514
	if((i=smb_open(&smb))!=0) {
		errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
515
		return(0);
516
	}
517
518
	if(!filelength(fileno(smb.sid_fp))) {			/* Empty base */
		smb_close(&smb);
519
		return(0);
520
	}
521
522
523
524
	msg.offset=0;
	msg.hdr.number=0;
	if(smb_getmsgidx(&smb,&msg)) {				/* Get first message index */
		smb_close(&smb);
525
		return(0);
526
	}
527
528
	if(!ptr || msg.idx.number>=ptr) {			/* ptr is before first message */
		smb_close(&smb);
529
530
		return(msg.idx.time);   				/* so return time of first msg */
	}
531
532
533

	if(smb_getlastidx(&smb,&lastidx)) { 			 /* Get last message index */
		smb_close(&smb);
534
		return(0);
535
	}
536
537
	if(lastidx.number<ptr) {					/* ptr is after last message */
		smb_close(&smb);
538
539
		return(lastidx.time);	 				/* so return time of last msg */
	}
540
541
542
543
544

	msg.idx.time=0;
	msg.hdr.number=ptr;
	if(!smb_getmsgidx(&smb,&msg)) {
		smb_close(&smb);
545
		return(msg.idx.time);
546
	}
547
548
549
550
551
552
553
554

	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;
555
			msg.offset++;
556
		}
557
		smb_close(&smb);
558
		return(msg.idx.time);
559
	}
560
561
562
563
564
565

	ptr--;
	while(ptr) {
		msg.hdr.number=ptr;
		if(!smb_getmsgidx(&smb,&msg))
			break;
566
		ptr--;
567
	}
568
569
570
571
572
573
574
575
576
	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
577
ulong sbbs_t::getlastmsg(uint subnum, uint32_t *ptr, time_t *t)
578
579
580
{
	int 		i;
	ulong		total;
rswindell's avatar
rswindell committed
581
	smb_t		smb;
582
583
584
585
586
587
588
589
590
	idxrec_t	idx;

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

rswindell's avatar
rswindell committed
591
592
	ZERO_VAR(smb);
	SAFEPRINTF2(smb.file,"%s%s",cfg.sub[subnum]->data_dir,cfg.sub[subnum]->code);
593
	smb.retry_time=cfg.smb_retry_time;
594
	smb.subnum=subnum;
595
596
	if((i=smb_open(&smb))!=0) {
		errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
597
		return(0);
598
	}
599
600
601

	if(!filelength(fileno(smb.sid_fp))) {			/* Empty base */
		smb_close(&smb);
602
		return(0);
603
	}
604
605
606
	if((i=smb_locksmbhdr(&smb))!=0) {
		smb_close(&smb);
		errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);
607
		return(0);
608
	}
609
610
611
	if((i=smb_getlastidx(&smb,&idx))!=0) {
		smb_close(&smb);
		errormsg(WHERE,ERR_READ,smb.file,i,smb.last_error);
612
		return(0);
613
	}
614
	total=(long)filelength(fileno(smb.sid_fp))/sizeof(idxrec_t);
615
616
617
618
619
620
621
622
623
	smb_unlocksmbhdr(&smb);
	smb_close(&smb);
	if(ptr)
		(*ptr)=idx.number;
	if(t)
		(*t)=idx.time;
	return(total);
}