1
2 // ------------------------------------------------------------------
3 // GoldED+
4 // Copyright (C) 1990-1999 Odinn Sorensen
5 // Copyright (C) 1999-2000 Alexander S. Aganichev
6 // ------------------------------------------------------------------
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 // MA 02111-1307 USA
21 // ------------------------------------------------------------------
22 // $Id: gedoss.cpp,v 1.24 2011/02/22 15:44:34 stas_degteff Exp $
23 // ------------------------------------------------------------------
24 // DOS Shell, cleanup, errorhandling etc.
25 // ------------------------------------------------------------------
26
27
28 #include <golded.h>
29 #include <gdirposx.h>
30 #include <gutlos.h>
31 #include <gmoprot.h>
32 #ifdef __UNIX__
33 #include <gkbdunix.h>
34 #endif
35 #ifdef __WIN32__
36 #include <windows.h>
37 extern OSVERSIONINFO WinVer;
38 #endif
39 #include <gdbgerr.h>
40
41
42 // ------------------------------------------------------------------
43
44 extern GPickArealist* PickArealist;
45 extern bool in_arealist;
46 extern uint* areanumbers;
47 extern GMsg* reader_msg;
48
49 // ------------------------------------------------------------------
50 // Clean up the screen, memory and files before exiting to DOS
51
Cleanup(void)52 void Cleanup(void) {
53
54 if(CFG) {
55
56 if(CFG->switches.get(areakeeplast) and startupscan_success)
57 AL.WriteGoldLast();
58
59 // Free msg data
60 if (reader_msg != NULL) {
61 ResetMsg(reader_msg);
62 throw_release(reader_msg);
63 }
64 // Free area data
65 AL.Reset();
66
67 #ifndef GMB_NOXBBS
68 if(find(AL.basetypes, "ADEPTXBBS"))
69 XbbsExit();
70 #endif
71 #ifndef GMB_NOEZY
72 if(find(AL.basetypes, "EZYCOM"))
73 EzycomExit();
74 #endif
75 if(find(AL.basetypes, "OPUS") or find(AL.basetypes, "FTS1"))
76 FidoExit();
77 #ifndef GMB_NOGOLD
78 if(find(AL.basetypes, "GOLDBASE"))
79 GoldExit();
80 #endif
81 #ifndef GMB_NOHUDS
82 if(find(AL.basetypes, "HUDSON"))
83 HudsExit();
84 #endif
85 #ifndef GMB_NOJAM
86 if(find(AL.basetypes, "JAM"))
87 JamExit();
88 #endif
89 #ifndef GMB_NOPCB
90 if(find(AL.basetypes, "PCBOARD"))
91 PcbExit();
92 #endif
93 #ifndef GMB_NOSQSH
94 if(find(AL.basetypes, "SQUISH"))
95 SquishExit();
96 #endif
97 #ifndef GMB_NOWCAT
98 if(find(AL.basetypes, "WILDCAT"))
99 WCatExit();
100 #endif
101 #ifndef GMB_NOSMB
102 if(find(AL.basetypes, "SMB"))
103 SMBExit();
104 #endif
105
106 SearchExit();
107
108 // Free various lists
109 CFG->addressmacro.clear();
110 CFG->aka.clear();
111 CFG->akamatch.clear();
112 CFG->colorname.clear();
113 CFG->event.clear();
114 CFG->externutil.clear();
115 CFG->filealias.clear();
116 CFG->frqext.clear();
117 CFG->frqnodemap.clear();
118 CFG->kludge.clear();
119 CFG->mailinglist.clear();
120 CFG->mappath.clear();
121 CFG->origin.clear();
122 CFG->robotname.clear();
123 CFG->tagline.clear();
124 CFG->tpl.clear();
125 CFG->twitname.clear();
126 CFG->twitsubj.clear();
127 CFG->username.clear();
128 CFG->xlatcharset.clear();
129 CFG->xlatescset.clear();
130 CFG->xlatcharsetalias.clear();
131 CFG->cmdkey.clear();
132 CFG->macro.clear();
133 CFG->unpacker.clear();
134
135 // Free misc data
136 throw_xrelease(CharTable);
137 throw_xrelease(CompTable);
138 throw_xrelease(MNETable);
139 throw_xrelease(I51Table);
140
141 throw_delete(QWK);
142
143 if(errorlevel != EXIT_CFGERR) {
144 if(netpost)
145 TouchFile(AddPath(CFG->areapath, CFG->semaphore.netscan));
146 if(echopost)
147 TouchFile(AddPath(CFG->areapath, CFG->semaphore.echoscan));
148 }
149
150 // Reset border color
151 if (C_BACKB != (BLACK_|_BLACK))
152 gvid->setoverscan(gvid->orig.color.overscan);
153
154 wcloseall(); // Close all windows
155 if(in_arealist) {
156 PickArealist->close_all(); // Unlink hidden area windows
157 throw_release(areanumbers);
158 }
159 whelpundef(); // Disengage the help system
160 kbclear(); // Clear CXL keyboard buffer
161 freonkey(); // Free all onkeys (macros)
162 FreePastebuf(); // Free the internal editor cut'n'paste buffer
163
164 #if !defined(__UNIX__) && !defined(__USE_NCURSES__)
165 if(CFG->screenpalette[16])
166 gvid->setpalette(gvid->orig.color.palette);
167
168 if(gvid->curr.screen.mode != gvid->orig.screen.mode)
169 gvid->setmode(gvid->orig.screen.mode);
170 if(gvid->curr.screen.rows != gvid->orig.screen.rows)
171 gvid->setrows(gvid->orig.screen.rows);
172
173 if(oldscreen) {
174 vrestore(oldscreen);
175 throw_xrelease(oldscreen);
176 }
177 if(CFG->intensecolors)
178 gvid->setintensity(gvid->orig.color.intensity);
179 vcurset(gvid->orig.cursor.start, gvid->orig.cursor.end);
180 #endif
181
182 #ifndef __WIN32__
183 vposset(gvid->orig.cursor.row, 0);
184 vputx(gvid->orig.cursor.row, 0, gvid->orig.color.textattr, ' ', gvid->orig.screen.columns);
185 #endif
186
187 vposset(gvid->orig.cursor.row-1, 0);
188 vcurshow();
189 }
190 throw_xdelete(BodyView);
191 throw_xdelete(HeaderView);
192 throw_xdelete(gvid);
193
194 int smax = MinV((int)GLOG_STORELINES, LOG.storelines);
195 for (int s=0; s<smax; s++)
196 STD_PRINTNL(LOG.storeline[s]);
197
198 if (CFG)
199 {
200 if (LOG.storelines > GLOG_STORELINES)
201 STD_PRINTNL("(See also " << CFG->logfile << ")");
202
203 if (errorlevel > EXIT_NONAME)
204 MakeNoise(SND_S_O_S);
205
206 CfgReset();
207 }
208
209 #if defined(GUTLOS_FUNCS)
210 g_deinit_os();
211 #endif
212
213 // Back to default Ctrl-Break handler
214 signal(SIGINT, SIG_DFL);
215 } // Cleanup()
216
217
218 // ------------------------------------------------------------------
219 // Multipurpose DOS shell function
220
ShellToDos(const char * command,char * message,vattr cls,int cursor,int pause)221 int ShellToDos(const char* command, char* message, vattr cls, int cursor, int pause) {
222
223 if ( !(command && message) ) {
224 LOG.errpointer(__FILE__,__LINE__-3);
225 LOG.printf("! Parameter is NULL pointer: ShellToDos(\"%s\",\"%s\").",
226 command?command:"(NULL)", message?message:"(NULL)");
227 update_statusline(" ERROR! See log. ");
228 return 0;
229 }
230
231 if ( !(*command) ) {
232 LOG.errtest(__FILE__,__LINE__-8);
233 LOG.printf("! ShellToDos(): command is empty, message is: \"%s\"", message);
234 update_statusline("ERROR: Command is empty, can't run!");
235 return 0;
236 }
237
238 int error = 0;
239
240 #if defined(GUTLOS_FUNCS)
241 char ge_temptitle[GMAXTITLE+1];
242 #endif
243
244 #ifndef __UNIX__
245 #ifdef __WIN32__
246 if(WinVer.dwPlatformId != VER_PLATFORM_WIN32_NT)
247 #endif
248 if(strlen(command) > 125) {
249 w_info(" Warning: Command line longer than 125 characters! ");
250 waitkeyt(10000);
251 w_info(NULL);
252 }
253 #endif
254
255 // Put up a wait window
256 if(shellvid)
257 w_info(LNG->Wait);
258
259 #if defined(GUTLOS_FUNCS)
260 g_get_ostitle_name(ge_temptitle);
261 g_set_ostitle_name("OS Shell",0);
262 #endif
263
264 // Close msgbase files
265 int _wasopen = AA->isopen();
266 if(_wasopen)
267 AA->Suspend();
268
269 HandleGEvent(EVTT_DOSSHELL);
270
271 // Change the prompt
272 #ifndef __UNIX__
273 static char prompt[256];
274 static char oldprompt[256];
275
276 if(CFG->switches.get(dosprompt)) {
277 #ifdef __DJGPP__
278 const char* p = getenv("PROMPT");
279 if(p) {
280 strcpy(oldprompt, p);
281 strcpy(stpcpy(prompt, LNG->Prompt), p);
282 setenv("PROMPT", prompt, true);
283 }
284 #else
285 int envn = 0;
286 while (environ[envn] and *environ[envn])
287 {
288 if (strnieql(environ[envn], "PROMPT=", 7))
289 {
290 strcpy(oldprompt, environ[envn]);
291 gsprintf(PRINTF_DECLARE_BUFFER(prompt), "PROMPT=%s%s", LNG->Prompt, *oldprompt ? oldprompt+7 : "");
292 environ[envn] = prompt;
293 break;
294 }
295 envn++;
296 }
297 #endif
298 }
299 #endif
300
301 // Store the screen
302 vsavebuf* scrnbuf = vsave();
303
304 // Store current drive/dir
305 Path orgdir;
306 getcwd(orgdir, sizeof(Path));
307
308 // Set cursor position
309 if(gvid->curr.screen.rows != gvid->orig.screen.rows)
310 gvid->setrows(gvid->orig.screen.rows);
311 if(gvid->curr.screen.mode != gvid->orig.screen.mode)
312 gvid->setmode(gvid->orig.screen.mode);
313
314 // Clear screen
315 if (cls != (BLACK_|_BLACK))
316 vclrscr(cls);
317
318 // Reset border color
319 if (C_BACKB != (BLACK_|_BLACK))
320 gvid->setoverscan(gvid->orig.color.overscan);
321
322 // Turn on the blinking attributes
323 gvid->setintensity(gvid->orig.color.intensity);
324
325 // Restore original palette during the shell
326 if(CFG->screenpalette[16])
327 gvid->setpalette(gvid->orig.color.palette);
328
329 #if defined(__USE_NCURSES__)
330 def_prog_mode();
331 reset_shell_mode();
332 #elif defined(__UNIX__)
333 gkbd_tty_reset();
334 #endif
335
336 // Return cursor into 1st column
337 if (cls != (BLACK_|_BLACK)) puts("");
338 // Write message on screen
339 if(*message) puts(message);
340
341 // Turn on cursor
342 int yy, xx;
343 if(cursor) {
344 vposget(&yy, &xx);
345 vcurset(gvid->orig.cursor.start, gvid->orig.cursor.end);
346 vcurshow();
347 }
348
349 HandleGEvent(EVTT_BREAKLOOP);
350
351 // Shell return value
352 int status = -1;
353
354 // Shell using the regular RTL function
355 #ifndef __CYGWIN__
356 status = system(command);
357 #else
358 // Get executable and parameters
359 char* _arg_v[3];
360
361 char* _pars = "";
362 char _xfn[256] = ""; // Call command interpreter
363 if(strnieql(command, "/c", 2))
364 _pars = strskip_wht(command+2);
365 else {
366 _pars = strpbrk(command, " \t");
367 if(_pars) {
368 ++_pars++;
369 strxcpy(_xfn, command, _pars-command);
370 _pars = strskip_wht(_pars);
371 }
372 else
373 _xfn = command;
374 }
375 _arg_v[0] = _xfn;
376 _arg_v[1] = _pars;
377 _arg_v[2] = NULL;
378 status = spawnvpe(P_WAIT, _xfn, _arg_v, environ);
379 #endif
380
381 if(status == -1)
382 error = errno;
383
384 if(status != -1)
385 status = 0;
386
387 // Restore console settings
388 #ifdef __USE_NCURSES__
389 reset_prog_mode();
390 clearok(stdscr, TRUE);
391 #else
392 gkbd.Init();
393 #endif
394
395 // Pause if needed
396 if(pause) {
397 if((pause > 0) or (status != 0))
398 kbxget();
399 }
400
401 // Restore current directory
402 gchdir(orgdir);
403
404 // Restore video mode and rows
405 if(CFG->screensize > 0xFF)
406 gvid->setmode(CFG->screensize >> 8);
407 else if(CFG->screensize)
408 gvid->setrows(CFG->screensize);
409
410 // Restore cursor position and form
411 if(cursor) {
412 vposset(yy+1, xx);
413 vcurhide();
414 }
415
416 // Restore screen
417 if(scrnbuf) {
418 vrestore(scrnbuf);
419 throw_xrelease(scrnbuf);
420 } else
421 vclrscr();
422
423 // Restore screen intensity
424 gvid->setintensity(CFG->intensecolors);
425
426 // Restore border color
427 if (C_BACKB != (BLACK_|_BLACK))
428 gvid->setoverscan(C_BACKB);
429
430 // Set palette if changes were specified
431 if(CFG->screenpalette[16])
432 gvid->setpalette(CFG->screenpalette);
433
434 // Restore prompt
435 #ifndef __UNIX__
436 if(CFG->switches.get(dosprompt)) {
437 #ifdef __DJGPP__
438 setenv("PROMPT", oldprompt, true);
439 #else
440 int envn = 0;
441 while(environ[envn] and *environ[envn]) {
442 if(strnieql(environ[envn], "PROMPT=", 7)) {
443 environ[envn] = oldprompt;
444 break;
445 }
446 envn++;
447 }
448 #endif
449 }
450 #endif
451
452 // Re-open msgbase
453 if(_wasopen)
454 AA->Resume();
455
456 // Remove the wait window
457 if(shellvid)
458 w_info(NULL);
459
460 // Popup error message
461 if(error) {
462 switch(errno) {
463 case E2BIG: w_info("Argument list too long!"); break;
464 case EACCES: w_info("Permission denied!"); break;
465 case EAGAIN: w_info("Ressource temporarily unavailable!"); break;
466 case EBADF: w_info("Bad file descriptor!"); break;
467 case EBUSY: w_info("Resource busy!"); break;
468 case ECHILD: w_info("No child processes!"); break;
469 case EEXIST: w_info("File exists!"); break;
470 case EFAULT: w_info("Bad address!"); break;
471 case EFBIG: w_info("File too large!"); break;
472 case EINTR: w_info("Interrupted system call!"); break;
473 case EINVAL: w_info("Invalid argument!"); break;
474 case EISDIR: w_info("Is a directory!"); break;
475 case EMFILE: w_info("Too many open files!"); break;
476 case ENFILE: w_info("Too many open files in system!"); break;
477 case ENOENT: w_info("No such file or directory!"); break;
478 case ENOEXEC: w_info("Unable to execute file!"); break;
479 case ENOMEM: w_info("Not enough memory!"); break;
480 default:
481 w_info("error during shelling");
482 }
483 waitkeyt(10000);
484 w_info(NULL);
485 }
486
487 // Reset tick values to avoid triggering screenblanker or timeout
488 gkbdtickpressreset();
489 gkbdtickvaluereset();
490
491 #if defined(GUTLOS_FUNCS)
492 g_set_ostitle_name(ge_temptitle, 1);
493 g_set_osicon();
494 #endif
495
496 return status;
497 } // ShellToDos()
498
499
500 // ------------------------------------------------------------------
501
Unpack(const char * archive)502 const char* Unpack(const char* archive) {
503
504 if ( !archive ) {
505 LOG.errpointer(__FILE__,__LINE__-3);
506 LOG.printf("! Parameter is NULL pointer: Unpack(NULL).");
507 update_statusline(" ERROR! See log. ");
508 return NULL;
509 }
510
511 if ( ! *archive ) {
512 LOG.errtest(__FILE__,__LINE__-8);
513 LOG.printf("! Unpack(): archive file name is empty.");
514 update_statusline(" ERROR: archive file name is empty ");
515 return NULL;
516 }
517
518 static Path newname;
519 const char *filename = CleanFilename(archive);
520
521 std::vector< std::pair<std::string, std::string> >::iterator i;
522 for(i = CFG->unpacker.begin(); i != CFG->unpacker.end(); i++) {
523 int dots;
524 const char *ext, *myext;
525 for(dots = 0, ext = i->first.c_str() - 1; ext != NULL; dots++)
526 ext = strchr(ext+1, '.');
527 for(myext = filename + strlen(filename); (myext != filename) and (dots != 0); dots--) {
528 do
529 --myext;
530 while((myext != filename) and (myext[0] != '.'));
531 }
532 if(dots or not strieql(myext+1, i->first.c_str()))
533 continue;
534
535 Path newdir;
536 mktemp(strxcpy(newdir, AddPath(CFG->temppath, "GDXXXXXX"), sizeof(Path)));
537 mkdir(newdir, S_IWUSR);
538 char cmdline[1024];
539 strxcpy(cmdline, i->second.c_str(), sizeof(cmdline));
540 std::string archive_truename = archive;
541 maketruepath(archive_truename);
542 strxcpy(newname, archive_truename.c_str(), sizeof(Path));
543 strchg(newname, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR);
544 strischg(cmdline, "@file", newname);
545 // Store current drive/dir and change it to the temporary
546 Path orgdir;
547 getcwd(orgdir, sizeof(Path));
548 gchdir(newdir);
549 // Now unpack it
550 ShellToDos(cmdline, "", LGREY_|_BLACK, 0, -1);
551 // Restore current directory
552 gchdir(orgdir);
553 strxcpy(newname, AddPath(AddBackslash(newdir), filename), sizeof(Path));
554 newname[strlen(newname) - (i->first.length() + 1)] = NUL;
555 return newname;
556 }
557
558 return NULL;
559 } // Unpack()
560
561
562 // ------------------------------------------------------------------
563
CleanUnpacked(const char * unpacked)564 void CleanUnpacked(const char* unpacked) {
565
566 gposixdir d(unpacked);
567 const gdirentry *de;
568 std::string removeme;
569 if(is_dir(unpacked)) {
570 while((de = d.nextentry("*", true)) != NULL) {
571 removeme = de->dirname;
572 removeme += GOLD_SLASH_CHR;
573 removeme += de->name;
574 if(is_dir(removeme.c_str()))
575 rmdir(removeme.c_str());
576 else
577 remove(removeme.c_str());
578 }
579 }
580 Path tmpdir, tmpdir2;
581 strxcpy(tmpdir2, unpacked, sizeof(Path));
582 StripBackslash(tmpdir2);
583 extractdirname(tmpdir, tmpdir2);
584 d.cd(tmpdir);
585 while((de = d.nextentry("*", true)) != NULL) {
586 removeme = de->dirname;
587 removeme += GOLD_SLASH_CHR;
588 removeme += de->name;
589 if(is_dir(removeme.c_str()))
590 rmdir(removeme.c_str());
591 else
592 remove(removeme.c_str());
593 }
594 rmdir(tmpdir);
595 } // CleanUnpacked()
596
597 // ------------------------------------------------------------------
598 // Error exit function
599
ErrorExit(int type)600 void ErrorExit(int type) {
601
602 static int in_error_exit = false;
603
604 if(not in_error_exit++) {
605
606 error_exit = type;
607
608 if(type) {
609
610 HandleGEvent(EVTT_ERRORFATAL);
611
612 if(_in_editor) {
613 LOG.printf("+ TIP: If you were writing a msg and want to recover it,");
614 LOG.printf("+ try looking in the %s file.", AddPath(CFG->goldpath, EDIT->File()));
615 }
616
617 // Dump the function tracker log
618 #if defined(GFTRK_ENABLE)
619 __gftrk_log();
620 #endif
621
622 if(type != 9)
623 errorlevel = EXIT_ERRORS;
624 else if(type == 5)
625 errorlevel = 100;
626 else
627 errorlevel = EXIT_CFGERR;
628
629 exit(errorlevel);
630 }
631
632 exit(EXIT_OK);
633 }
634 } // ErrorExit()
635
636
637 // ------------------------------------------------------------------
638
639