1 |
|
|
/* $OpenBSD: cmd1.c,v 1.29 2011/04/06 11:36:26 miod Exp $ */ |
2 |
|
|
/* $NetBSD: cmd1.c,v 1.9 1997/07/09 05:29:48 mikel Exp $ */ |
3 |
|
|
|
4 |
|
|
/*- |
5 |
|
|
* Copyright (c) 1980, 1993 |
6 |
|
|
* The Regents of the University of California. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* Redistribution and use in source and binary forms, with or without |
9 |
|
|
* modification, are permitted provided that the following conditions |
10 |
|
|
* are met: |
11 |
|
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer in the |
15 |
|
|
* documentation and/or other materials provided with the distribution. |
16 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
17 |
|
|
* may be used to endorse or promote products derived from this software |
18 |
|
|
* without specific prior written permission. |
19 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
21 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
24 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
28 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
29 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 |
|
|
* SUCH DAMAGE. |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
#include "rcv.h" |
34 |
|
|
#include "extern.h" |
35 |
|
|
|
36 |
|
|
/* |
37 |
|
|
* Mail -- a mail program |
38 |
|
|
* |
39 |
|
|
* User commands. |
40 |
|
|
*/ |
41 |
|
|
|
42 |
|
|
/* |
43 |
|
|
* Print the current active headings. |
44 |
|
|
* Don't change dot if invoker didn't give an argument. |
45 |
|
|
*/ |
46 |
|
|
|
47 |
|
|
static int screen; |
48 |
|
|
static volatile sig_atomic_t gothdrint; |
49 |
|
|
|
50 |
|
|
int |
51 |
|
|
headers(void *v) |
52 |
|
|
{ |
53 |
|
|
int *msgvec = v; |
54 |
|
|
int n, mesg, flag, size; |
55 |
|
|
struct message *mp; |
56 |
|
|
struct sigaction act, oact; |
57 |
|
|
sigset_t oset; |
58 |
|
|
|
59 |
|
|
size = screensize(); |
60 |
|
|
n = msgvec[0]; |
61 |
|
|
if (n != 0 && size > 0) |
62 |
|
|
screen = (n-1)/size; |
63 |
|
|
if (screen < 0) |
64 |
|
|
screen = 0; |
65 |
|
|
mp = &message[screen * size]; |
66 |
|
|
if (mp >= &message[msgCount]) |
67 |
|
|
mp = &message[msgCount - size]; |
68 |
|
|
if (mp < &message[0]) |
69 |
|
|
mp = &message[0]; |
70 |
|
|
flag = 0; |
71 |
|
|
mesg = mp - &message[0]; |
72 |
|
|
if (dot != &message[n-1]) |
73 |
|
|
dot = mp; |
74 |
|
|
sigemptyset(&act.sa_mask); |
75 |
|
|
act.sa_flags = SA_RESTART; |
76 |
|
|
act.sa_handler = hdrint; |
77 |
|
|
if (sigaction(SIGINT, NULL, &oact) == 0 && |
78 |
|
|
oact.sa_handler != SIG_IGN) { |
79 |
|
|
(void)sigaction(SIGINT, &act, &oact); |
80 |
|
|
(void)sigprocmask(SIG_UNBLOCK, &intset, &oset); |
81 |
|
|
} |
82 |
|
|
for (gothdrint = 0; !gothdrint && mp < &message[msgCount]; mp++) { |
83 |
|
|
mesg++; |
84 |
|
|
if (mp->m_flag & MDELETED) |
85 |
|
|
continue; |
86 |
|
|
if (flag++ >= size) |
87 |
|
|
break; |
88 |
|
|
printhead(mesg); |
89 |
|
|
} |
90 |
|
|
if (gothdrint) { |
91 |
|
|
fflush(stdout); |
92 |
|
|
fputs("\nInterrupt\n", stderr); |
93 |
|
|
} |
94 |
|
|
if (oact.sa_handler != SIG_IGN) { |
95 |
|
|
(void)sigprocmask(SIG_SETMASK, &oset, NULL); |
96 |
|
|
(void)sigaction(SIGINT, &oact, NULL); |
97 |
|
|
} |
98 |
|
|
if (flag == 0) { |
99 |
|
|
puts("No more mail."); |
100 |
|
|
return(1); |
101 |
|
|
} |
102 |
|
|
return(0); |
103 |
|
|
} |
104 |
|
|
|
105 |
|
|
/* |
106 |
|
|
* Scroll to the next/previous screen |
107 |
|
|
*/ |
108 |
|
|
int |
109 |
|
|
scroll(void *v) |
110 |
|
|
{ |
111 |
|
|
char *arg = v; |
112 |
|
|
int size, maxscreen; |
113 |
|
|
int cur[1]; |
114 |
|
|
|
115 |
|
|
cur[0] = 0; |
116 |
|
|
size = screensize(); |
117 |
|
|
maxscreen = 0; |
118 |
|
|
if (size > 0) |
119 |
|
|
maxscreen = (msgCount - 1) / size; |
120 |
|
|
switch (*arg) { |
121 |
|
|
case 0: |
122 |
|
|
case '+': |
123 |
|
|
if (screen >= maxscreen) { |
124 |
|
|
puts("On last screenful of messages"); |
125 |
|
|
return(0); |
126 |
|
|
} |
127 |
|
|
screen++; |
128 |
|
|
break; |
129 |
|
|
|
130 |
|
|
case '-': |
131 |
|
|
if (screen <= 0) { |
132 |
|
|
puts("On first screenful of messages"); |
133 |
|
|
return(0); |
134 |
|
|
} |
135 |
|
|
screen--; |
136 |
|
|
break; |
137 |
|
|
|
138 |
|
|
default: |
139 |
|
|
printf("Unrecognized scrolling command \"%s\"\n", arg); |
140 |
|
|
return(1); |
141 |
|
|
} |
142 |
|
|
return(headers(cur)); |
143 |
|
|
} |
144 |
|
|
|
145 |
|
|
/* |
146 |
|
|
* Compute screen size. |
147 |
|
|
*/ |
148 |
|
|
int |
149 |
|
|
screensize(void) |
150 |
|
|
{ |
151 |
|
|
int s; |
152 |
|
|
char *cp; |
153 |
|
|
|
154 |
|
|
if ((cp = value("screen")) != NULL && (s = atoi(cp)) > 0) |
155 |
|
|
return(s); |
156 |
|
|
return(screenheight - 4); |
157 |
|
|
} |
158 |
|
|
|
159 |
|
|
/* |
160 |
|
|
* Print out the headlines for each message |
161 |
|
|
* in the passed message list. |
162 |
|
|
*/ |
163 |
|
|
int |
164 |
|
|
from(void *v) |
165 |
|
|
{ |
166 |
|
|
int *msgvec = v; |
167 |
|
|
int *ip; |
168 |
|
|
|
169 |
|
|
for (ip = msgvec; *ip != 0; ip++) |
170 |
|
|
printhead(*ip); |
171 |
|
|
if (--ip >= msgvec) |
172 |
|
|
dot = &message[*ip - 1]; |
173 |
|
|
return(0); |
174 |
|
|
} |
175 |
|
|
|
176 |
|
|
/* |
177 |
|
|
* Print out the header of a specific message. |
178 |
|
|
* This is a slight improvement to the standard one. |
179 |
|
|
*/ |
180 |
|
|
void |
181 |
|
|
printhead(int mesg) |
182 |
|
|
{ |
183 |
|
|
struct message *mp; |
184 |
|
|
char headline[LINESIZE], *subjline, dispc, curind; |
185 |
|
|
char visname[LINESIZE], vissub[LINESIZE]; |
186 |
|
|
char pbuf[LINESIZE]; |
187 |
|
|
char fmtline[LINESIZE]; |
188 |
|
|
const char *fmt; |
189 |
|
|
struct headline hl; |
190 |
|
|
char *name; |
191 |
|
|
char *to, *from; |
192 |
|
|
struct name *np; |
193 |
|
|
char **ap; |
194 |
|
|
|
195 |
|
|
mp = &message[mesg-1]; |
196 |
|
|
(void)readline(setinput(mp), headline, LINESIZE, NULL); |
197 |
|
|
if ((subjline = hfield("subject", mp)) == NULL && |
198 |
|
|
(subjline = hfield("subj", mp)) == NULL) |
199 |
|
|
subjline = ""; |
200 |
|
|
/* |
201 |
|
|
* Bletch! |
202 |
|
|
*/ |
203 |
|
|
curind = dot == mp ? '>' : ' '; |
204 |
|
|
dispc = ' '; |
205 |
|
|
if (mp->m_flag & MSAVED) |
206 |
|
|
dispc = '*'; |
207 |
|
|
if (mp->m_flag & MPRESERVE) |
208 |
|
|
dispc = 'P'; |
209 |
|
|
if ((mp->m_flag & (MREAD|MNEW)) == MNEW) |
210 |
|
|
dispc = 'N'; |
211 |
|
|
if ((mp->m_flag & (MREAD|MNEW)) == 0) |
212 |
|
|
dispc = 'U'; |
213 |
|
|
if (mp->m_flag & MBOX) |
214 |
|
|
dispc = 'M'; |
215 |
|
|
parse(headline, &hl, pbuf); |
216 |
|
|
from = nameof(mp, 0); |
217 |
|
|
to = skin(hfield("to", mp)); |
218 |
|
|
np = extract(from, GTO); |
219 |
|
|
np = delname(np, myname); |
220 |
|
|
if (altnames) |
221 |
|
|
for (ap = altnames; *ap; ap++) |
222 |
|
|
np = delname(np, *ap); |
223 |
|
|
if (np) |
224 |
|
|
/* not from me */ |
225 |
|
|
name = value("show-rcpt") != NULL && to ? to : from; |
226 |
|
|
else |
227 |
|
|
/* from me - show TO */ |
228 |
|
|
name = value("showto") != NULL && to ? to : from; |
229 |
|
|
strnvis(visname, name, sizeof(visname), VIS_SAFE|VIS_NOSLASH); |
230 |
|
|
if (name == to) |
231 |
|
|
fmt = "%c%c%3d TO %-14.14s %16.16s %4d/%-5d %s"; |
232 |
|
|
else |
233 |
|
|
fmt = "%c%c%3d %-17.17s %16.16s %4d/%-5d %s"; |
234 |
|
|
strnvis(vissub, subjline, sizeof(vissub), VIS_SAFE|VIS_NOSLASH); |
235 |
|
|
/* hl.l_date was sanity-checked when read in. */ |
236 |
|
|
snprintf(fmtline, sizeof(fmtline), fmt, curind, dispc, mesg, visname, |
237 |
|
|
hl.l_date, mp->m_lines, mp->m_size, vissub); |
238 |
|
|
printf("%.*s\n", screenwidth, fmtline); |
239 |
|
|
} |
240 |
|
|
|
241 |
|
|
/* |
242 |
|
|
* Print out the value of dot. |
243 |
|
|
*/ |
244 |
|
|
int |
245 |
|
|
pdot(void *v) |
246 |
|
|
{ |
247 |
|
|
printf("%d\n", (int)(dot - &message[0] + 1)); |
248 |
|
|
return(0); |
249 |
|
|
} |
250 |
|
|
|
251 |
|
|
/* |
252 |
|
|
* Print out all the possible commands. |
253 |
|
|
*/ |
254 |
|
|
int |
255 |
|
|
pcmdlist(void *v) |
256 |
|
|
{ |
257 |
|
|
extern const struct cmd cmdtab[]; |
258 |
|
|
const struct cmd *cp; |
259 |
|
|
int cc; |
260 |
|
|
|
261 |
|
|
puts("Commands are:"); |
262 |
|
|
for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) { |
263 |
|
|
cc += strlen(cp->c_name) + 2; |
264 |
|
|
if (cc > 72) { |
265 |
|
|
putchar('\n'); |
266 |
|
|
cc = strlen(cp->c_name) + 2; |
267 |
|
|
} |
268 |
|
|
if ((cp+1)->c_name != NULL) |
269 |
|
|
printf("%s, ", cp->c_name); |
270 |
|
|
else |
271 |
|
|
puts(cp->c_name); |
272 |
|
|
} |
273 |
|
|
return(0); |
274 |
|
|
} |
275 |
|
|
|
276 |
|
|
/* |
277 |
|
|
* Pipe message to command |
278 |
|
|
*/ |
279 |
|
|
int |
280 |
|
|
pipeit(void *ml, void *sl) |
281 |
|
|
{ |
282 |
|
|
int *msgvec = ml; |
283 |
|
|
char *cmd = sl; |
284 |
|
|
|
285 |
|
|
return(type1(msgvec, cmd, 0, 0)); |
286 |
|
|
} |
287 |
|
|
|
288 |
|
|
/* |
289 |
|
|
* Paginate messages, honor ignored fields. |
290 |
|
|
*/ |
291 |
|
|
int |
292 |
|
|
more(void *v) |
293 |
|
|
{ |
294 |
|
|
int *msgvec = v; |
295 |
|
|
return(type1(msgvec, NULL, 1, 1)); |
296 |
|
|
} |
297 |
|
|
|
298 |
|
|
/* |
299 |
|
|
* Paginate messages, even printing ignored fields. |
300 |
|
|
*/ |
301 |
|
|
int |
302 |
|
|
More(void *v) |
303 |
|
|
{ |
304 |
|
|
int *msgvec = v; |
305 |
|
|
|
306 |
|
|
return(type1(msgvec, NULL, 0, 1)); |
307 |
|
|
} |
308 |
|
|
|
309 |
|
|
/* |
310 |
|
|
* Type out messages, honor ignored fields. |
311 |
|
|
*/ |
312 |
|
|
int |
313 |
|
|
type(void *v) |
314 |
|
|
{ |
315 |
|
|
int *msgvec = v; |
316 |
|
|
|
317 |
|
|
return(type1(msgvec, NULL, 1, 0)); |
318 |
|
|
} |
319 |
|
|
|
320 |
|
|
/* |
321 |
|
|
* Type out messages, even printing ignored fields. |
322 |
|
|
*/ |
323 |
|
|
int |
324 |
|
|
Type(void *v) |
325 |
|
|
{ |
326 |
|
|
int *msgvec = v; |
327 |
|
|
|
328 |
|
|
return(type1(msgvec, NULL, 0, 0)); |
329 |
|
|
} |
330 |
|
|
|
331 |
|
|
/* |
332 |
|
|
* Type out the messages requested. |
333 |
|
|
*/ |
334 |
|
|
int |
335 |
|
|
type1(int *msgvec, char *cmd, int doign, int page) |
336 |
|
|
{ |
337 |
|
|
int nlines, *ip, restoreterm; |
338 |
|
|
struct message *mp; |
339 |
|
|
struct termios tbuf; |
340 |
|
|
char *cp; |
341 |
|
|
FILE *obuf; |
342 |
|
|
|
343 |
|
|
obuf = stdout; |
344 |
|
|
restoreterm = 0; |
345 |
|
|
|
346 |
|
|
/* |
347 |
|
|
* start a pipe if needed. |
348 |
|
|
*/ |
349 |
|
|
if (cmd) { |
350 |
|
|
restoreterm = (tcgetattr(fileno(stdin), &tbuf) == 0); |
351 |
|
|
obuf = Popen(cmd, "w"); |
352 |
|
|
if (obuf == NULL) { |
353 |
|
|
warn("%s", cmd); |
354 |
|
|
obuf = stdout; |
355 |
|
|
} |
356 |
|
|
} else if (value("interactive") != NULL && |
357 |
|
|
(page || (cp = value("crt")) != NULL)) { |
358 |
|
|
nlines = 0; |
359 |
|
|
if (!page) { |
360 |
|
|
for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) |
361 |
|
|
nlines += message[*ip - 1].m_lines; |
362 |
|
|
} |
363 |
|
|
if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) { |
364 |
|
|
restoreterm = (tcgetattr(fileno(stdin), &tbuf) == 0); |
365 |
|
|
cp = value("PAGER"); |
366 |
|
|
obuf = Popen(cp, "w"); |
367 |
|
|
if (obuf == NULL) { |
368 |
|
|
warn("%s", cp); |
369 |
|
|
obuf = stdout; |
370 |
|
|
} |
371 |
|
|
} |
372 |
|
|
} |
373 |
|
|
|
374 |
|
|
/* |
375 |
|
|
* Send messages to the output. |
376 |
|
|
*/ |
377 |
|
|
for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) { |
378 |
|
|
mp = &message[*ip - 1]; |
379 |
|
|
touch(mp); |
380 |
|
|
dot = mp; |
381 |
|
|
if (cmd == NULL && value("quiet") == NULL) |
382 |
|
|
fprintf(obuf, "Message %d:\n", *ip); |
383 |
|
|
if (sendmessage(mp, obuf, doign ? ignore : 0, NULL) == -1) |
384 |
|
|
break; |
385 |
|
|
} |
386 |
|
|
|
387 |
|
|
if (obuf != stdout) { |
388 |
|
|
(void)Pclose(obuf); |
389 |
|
|
if (restoreterm) |
390 |
|
|
(void)tcsetattr(fileno(stdin), TCSADRAIN, &tbuf); |
391 |
|
|
} |
392 |
|
|
return(0); |
393 |
|
|
} |
394 |
|
|
|
395 |
|
|
/* |
396 |
|
|
* Print the top so many lines of each desired message. |
397 |
|
|
* The number of lines is taken from the variable "toplines" |
398 |
|
|
* and defaults to 5. |
399 |
|
|
*/ |
400 |
|
|
int |
401 |
|
|
top(void * v) |
402 |
|
|
{ |
403 |
|
|
int *msgvec = v; |
404 |
|
|
int *ip; |
405 |
|
|
struct message *mp; |
406 |
|
|
int c, topl, lines, lineb; |
407 |
|
|
char *valtop, linebuf[LINESIZE]; |
408 |
|
|
FILE *ibuf; |
409 |
|
|
|
410 |
|
|
topl = 5; |
411 |
|
|
valtop = value("toplines"); |
412 |
|
|
if (valtop != NULL) { |
413 |
|
|
topl = atoi(valtop); |
414 |
|
|
if (topl < 0 || topl > 10000) |
415 |
|
|
topl = 5; |
416 |
|
|
} |
417 |
|
|
lineb = 1; |
418 |
|
|
for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { |
419 |
|
|
mp = &message[*ip - 1]; |
420 |
|
|
touch(mp); |
421 |
|
|
dot = mp; |
422 |
|
|
if (value("quiet") == NULL) |
423 |
|
|
printf("Message %d:\n", *ip); |
424 |
|
|
ibuf = setinput(mp); |
425 |
|
|
c = mp->m_lines; |
426 |
|
|
if (!lineb) |
427 |
|
|
putchar('\n'); |
428 |
|
|
for (lines = 0; lines < c && lines <= topl; lines++) { |
429 |
|
|
if (readline(ibuf, linebuf, sizeof(linebuf), NULL) < 0) |
430 |
|
|
break; |
431 |
|
|
puts(linebuf); |
432 |
|
|
lineb = blankline(linebuf); |
433 |
|
|
} |
434 |
|
|
} |
435 |
|
|
return(0); |
436 |
|
|
} |
437 |
|
|
|
438 |
|
|
/* |
439 |
|
|
* Touch all the given messages so that they will |
440 |
|
|
* get mboxed. |
441 |
|
|
*/ |
442 |
|
|
int |
443 |
|
|
stouch(void *v) |
444 |
|
|
{ |
445 |
|
|
int *msgvec = v; |
446 |
|
|
int *ip; |
447 |
|
|
|
448 |
|
|
for (ip = msgvec; *ip != 0; ip++) { |
449 |
|
|
dot = &message[*ip-1]; |
450 |
|
|
dot->m_flag |= MTOUCH; |
451 |
|
|
dot->m_flag &= ~MPRESERVE; |
452 |
|
|
} |
453 |
|
|
return(0); |
454 |
|
|
} |
455 |
|
|
|
456 |
|
|
/* |
457 |
|
|
* Make sure all passed messages get mboxed. |
458 |
|
|
*/ |
459 |
|
|
int |
460 |
|
|
mboxit(void *v) |
461 |
|
|
{ |
462 |
|
|
int *msgvec = v; |
463 |
|
|
int *ip; |
464 |
|
|
|
465 |
|
|
for (ip = msgvec; *ip != 0; ip++) { |
466 |
|
|
dot = &message[*ip-1]; |
467 |
|
|
dot->m_flag |= MTOUCH|MBOX; |
468 |
|
|
dot->m_flag &= ~MPRESERVE; |
469 |
|
|
} |
470 |
|
|
return(0); |
471 |
|
|
} |
472 |
|
|
|
473 |
|
|
/* |
474 |
|
|
* List the folders the user currently has. |
475 |
|
|
*/ |
476 |
|
|
int |
477 |
|
|
folders(void *v) |
478 |
|
|
{ |
479 |
|
|
char *files = (char *)v; |
480 |
|
|
char dirname[PATHSIZE]; |
481 |
|
|
char cmd[BUFSIZ]; |
482 |
|
|
|
483 |
|
|
if (getfold(dirname, sizeof(dirname)) < 0) |
484 |
|
|
strlcpy(dirname, "$HOME", sizeof(dirname)); |
485 |
|
|
|
486 |
|
|
snprintf(cmd, sizeof(cmd), "cd %s; %s %s", dirname, value("LISTER"), |
487 |
|
|
files && *files ? files : ""); |
488 |
|
|
|
489 |
|
|
(void)run_command(value("SHELL"), 0, -1, -1, "-c", cmd, NULL); |
490 |
|
|
return(0); |
491 |
|
|
} |
492 |
|
|
|
493 |
|
|
/* |
494 |
|
|
* Update the mail file with any new messages that have |
495 |
|
|
* come in since we started reading mail. |
496 |
|
|
*/ |
497 |
|
|
int |
498 |
|
|
inc(void *v) |
499 |
|
|
{ |
500 |
|
|
int nmsg, mdot; |
501 |
|
|
|
502 |
|
|
nmsg = incfile(); |
503 |
|
|
|
504 |
|
|
if (nmsg == 0) { |
505 |
|
|
puts("No new mail."); |
506 |
|
|
} else if (nmsg > 0) { |
507 |
|
|
mdot = newfileinfo(msgCount - nmsg); |
508 |
|
|
dot = &message[mdot - 1]; |
509 |
|
|
} else { |
510 |
|
|
puts("\"inc\" command failed..."); |
511 |
|
|
} |
512 |
|
|
|
513 |
|
|
return(0); |
514 |
|
|
} |
515 |
|
|
|
516 |
|
|
/* |
517 |
|
|
* User hit ^C while printing the headers. |
518 |
|
|
*/ |
519 |
|
|
void |
520 |
|
|
hdrint(int s) |
521 |
|
|
{ |
522 |
|
|
|
523 |
|
|
gothdrint = 1; |
524 |
|
|
} |