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