prntfile.cpp 7.33 KB
Newer Older
1
/* prntfile.cpp */
2
// vi: tabstop=4
3
4
5
6
7
8
9
10
11

/* Synchronet file print/display routines */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
12
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
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
 *																			*
 * 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.	*
 ****************************************************************************/

#include "sbbs.h"
40
#include "utf8.h"
41

42
43
44
45
#ifndef PRINTFILE_MAX_LINE_LEN
#define PRINTFILE_MAX_LINE_LEN (1024*1024)
#endif

46
47
48
49
50
/****************************************************************************/
/* Prints a file remotely and locally, interpreting ^A sequences, checks    */
/* for pauses, aborts and ANSI. 'str' is the path of the file to print      */
/* Called from functions menu and text_sec                                  */
/****************************************************************************/
rswindell's avatar
rswindell committed
51
bool sbbs_t::printfile(const char* fname, long mode, long org_cols)
52
{
53
	char* buf;
54
	char fpath[MAX_PATH+1];
55
	char* p;
rswindell's avatar
rswindell committed
56
	int file;
57
	BOOL rip=FALSE;
rswindell's avatar
rswindell committed
58
	long l,length,savcon=console;
59
60
	FILE *stream;

61
62
63
	SAFECOPY(fpath, fname);
	fexistcase(fpath);
	p=getfext(fpath);
64
	if(p!=NULL) {
65
		if(stricmp(p,".rip")==0) {
rswindell's avatar
rswindell committed
66
			rip=TRUE;
rswindell's avatar
rswindell committed
67
			mode|=P_NOPAUSE;
68
69
		} else if(stricmp(p, ".seq") == 0) {
			mode |= P_PETSCII;
70
71
		} else if(stricmp(p, ".utf8") == 0) {
			mode |= P_UTF8;
rswindell's avatar
rswindell committed
72
		}
73
	}
74

75
	if(mode&P_NOABORT || rip) {
76
77
		if(online==ON_REMOTE && console&CON_R_ECHO) {
			rioctl(IOCM|ABORT);
rswindell's avatar
rswindell committed
78
79
80
81
			rioctl(IOCS|ABORT); 
		}
		sys_status&=~SS_ABORT; 
	}
82

83
	if(!(mode&P_NOCRLF) && !tos && !rip) {
84
		CRLF;
85
	}
86

87
	if((stream=fnopen(&file,fpath,O_RDONLY|O_DENYNONE))==NULL) {
88
89
		if(!(mode&P_NOERROR)) {
			lprintf(LOG_NOTICE,"!Error %d (%s) opening: %s"
90
				,errno,strerror(errno),fpath);
91
			bputs(text[FileNotFound]);
92
			if(SYSOP) bputs(fpath);
93
94
95
			CRLF;
		}
		return false; 
rswindell's avatar
rswindell committed
96
	}
97

98
	length=(long)filelength(file);
99
	if(length<0) {
rswindell's avatar
rswindell committed
100
		fclose(stream);
101
		errormsg(WHERE,ERR_CHK,fpath,length);
102
		return false;
rswindell's avatar
rswindell committed
103
	}
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

	if(mode&P_OPENCLOSE) {
		if((buf=(char*)malloc(length+1L))==NULL) {
			fclose(stream);
			errormsg(WHERE,ERR_ALLOC,fpath,length+1L);
			return false; 
		}
		l=lread(file,buf,length);
		fclose(stream);
		if(l!=length)
			errormsg(WHERE,ERR_READ,fpath,length);
		else {
			buf[l]=0;
			if((mode&P_UTF8) && !term_supports(UTF8))
				utf8_normalize_str(buf);
			putmsg(buf,mode,org_cols);
		}
		free(buf);
	} else {	// Line-at-a-time mode
		if(length > PRINTFILE_MAX_LINE_LEN)
			length = PRINTFILE_MAX_LINE_LEN;
		if((buf=(char*)malloc(length+1L))==NULL) {
			fclose(stream);
			errormsg(WHERE,ERR_ALLOC,fpath,length+1L);
			return false; 
		}
		while(!feof(stream) && !msgabort()) {
			if(fgets(buf, length-1, stream) == NULL)
				break;
			buf[length] = 0;
			if((mode&P_UTF8) && !term_supports(UTF8))
				utf8_normalize_str(buf);
			putmsg(buf, mode, org_cols);
		}
		free(buf);
rswindell's avatar
rswindell committed
139
		fclose(stream);
rswindell's avatar
rswindell committed
140
	}
141

142
	if((mode&P_NOABORT || rip) && online==ON_REMOTE) {
143
		SYNC;
rswindell's avatar
rswindell committed
144
145
		rioctl(IOSM|ABORT); 
	}
146
147
148
	if(rip)
		ansi_getlines();
	console=savcon;
149
	return true;
rswindell's avatar
rswindell committed
150
}
151

rswindell's avatar
rswindell committed
152
bool sbbs_t::printtail(const char* fname, int lines, long mode, long org_cols)
153
{
rswindell's avatar
rswindell committed
154
	char*	buf;
155
	char	fpath[MAX_PATH+1];
rswindell's avatar
rswindell committed
156
157
158
	char*	p;
	int		file,cur=0;
	long	length,l;
159

160
161
	SAFECOPY(fpath, fname);
	fexistcase(fpath);
162
163
164
	if(mode&P_NOABORT) {
		if(online==ON_REMOTE) {
			rioctl(IOCM|ABORT);
rswindell's avatar
rswindell committed
165
166
167
168
			rioctl(IOCS|ABORT); 
		}
		sys_status&=~SS_ABORT; 
	}
169
	if(!tos) {
rswindell's avatar
rswindell committed
170
171
		CRLF; 
	}
172
	if((file=nopen(fpath,O_RDONLY|O_DENYNONE))==-1) {
173
174
		if(!(mode&P_NOERROR)) {
			lprintf(LOG_NOTICE,"!Error %d (%s) opening: %s"
175
				,errno,strerror(errno),fpath);
176
			bputs(text[FileNotFound]);
177
			if(SYSOP) bputs(fpath);
178
179
180
			CRLF;
		}
		return false; 
rswindell's avatar
rswindell committed
181
	}
182
	length=(long)filelength(file);
rswindell's avatar
rswindell committed
183
184
	if(length<0) {
		close(file);
185
		errormsg(WHERE,ERR_CHK,fpath,length);
186
		return false;
rswindell's avatar
rswindell committed
187
	}
deuce's avatar
deuce committed
188
	if((buf=(char*)malloc(length+1L))==NULL) {
189
		close(file);
190
		errormsg(WHERE,ERR_ALLOC,fpath,length+1L);
191
		return false; 
rswindell's avatar
rswindell committed
192
	}
193
194
	l=lread(file,buf,length);
	close(file);
rswindell's avatar
rswindell committed
195
	if(l!=length)
196
		errormsg(WHERE,ERR_READ,fpath,length);
rswindell's avatar
rswindell committed
197
198
199
200
201
202
203
204
205
206
207
208
	else {
		buf[l]=0;
		p=(buf+l)-1;
		if(*p==LF) p--;
		while(*p && p>buf) {
			if(*p==LF)
				cur++;
			if(cur>=lines) {
				p++;
				break; 
			}
			p--; 
rswindell's avatar
rswindell committed
209
		}
rswindell's avatar
rswindell committed
210
		putmsg(p,mode,org_cols);
rswindell's avatar
rswindell committed
211
	}
212
213
	if(mode&P_NOABORT && online==ON_REMOTE) {
		SYNC;
rswindell's avatar
rswindell committed
214
215
		rioctl(IOSM|ABORT); 
	}
deuce's avatar
deuce committed
216
	free(buf);
217
	return true;
218
219
220
}

/****************************************************************************/
221
/* Displays a menu file (e.g. from the text/menu directory)                 */
222
/****************************************************************************/
223
bool sbbs_t::menu(const char *code, long mode)
224
{
225
226
227
    char path[MAX_PATH+1];
	const char *next= "msg";
	const char *last = "asc";
228
229
230

	sys_status&=~SS_ABORT;
	if(menu_file[0])
231
		SAFECOPY(path,menu_file);
232
	else {
rswindell's avatar
rswindell committed
233
		long term = term_supports();
234
235
236
237
238
239
240
241
242
243
244
245
		do {
			if((term&RIP) && menu_exists(code, "rip", path))
				break;
			if((term&(ANSI|COLOR)) == ANSI && menu_exists(code, "mon", path))
				break;
			if((term&ANSI) && menu_exists(code, "ans", path))
				break;
			if((term&PETSCII) && menu_exists(code, "seq", path))
				break;
			if(term&NO_EXASCII) {
				next = "asc";
				last = "msg";
rswindell's avatar
rswindell committed
246
			}
247
248
249
250
			if(menu_exists(code, next, path))
				break;
			menu_exists(code, last, path);
		} while(0);
251
	}
252

253
	mode |= P_OPENCLOSE | P_CPM_EOF;
254
255
	if(column == 0)
		mode |= P_NOCRLF;
256
	return printfile(path, mode);
257
258
}

259
bool sbbs_t::menu_exists(const char *code, const char* ext, char* path)
260
{
261
262
263
	char pathbuf[MAX_PATH+1];
	if(path == NULL)
		path = pathbuf;
264

265
266
267
268
269
270
271
272
273
	if(menu_file[0]) {
		strncpy(path, menu_file, MAX_PATH);
		return fexistcase(path) ? true : false;
	}

	/* Either <menu>.asc or <menu>.msg is required */
	if(ext == NULL)
		return menu_exists(code, "asc", path)
			|| menu_exists(code, "msg", path);
274

275
276
277
278
279
280
281
	char prefix[MAX_PATH];
	if(isfullpath(code))
		SAFECOPY(prefix, code);
	else {
		backslash(menu_dir);
		SAFEPRINTF3(prefix, "%smenu/%s%s", cfg.text_dir, menu_dir, code);
	}
282
	safe_snprintf(path, MAX_PATH, "%s.%lucol.%s", prefix, cols, ext);
rswindell's avatar
rswindell committed
283
284
	if(fexistcase(path))
		return true;
285
	safe_snprintf(path, MAX_PATH, "%s.%s", prefix, ext);
deuce's avatar
deuce committed
286
287
	return fexistcase(path) ? true : false;
}