
/*  Aileron.c: misc. functions and program entry point 
 *
 *  This file is part of Aileron, a WINGs email client. 
 *
 *  Copyright (c) 1999 - 2001 Nwanua Elumeze
 *
 *  This program is wfree 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.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


#include "Aileron.h"
#include <signal.h>
#include <sys/wait.h>


/* until it's in WINGs (groupleader) */
#include "WINGs/WINGsP.h"

void createTmpdir(void) 
{
  char *option;
  mode_t  mode = umask(0);
  struct stat status;

  umask(mode);
  mode = 0777777^mode;


  Aileron.tmpdir = NULL;

  option = WMGetUDStringForKey(Aileron.defaultsDB, "TemporaryDirectory");
  if(option) { 
    Aileron.tmpdir = wstrdup(option);
  } else { 
    Aileron.tmpdir = wstrdup("/tmp/Aileron.");
    Aileron.tmpdir = wstrappend(Aileron.tmpdir, myusername());
  }

mkTMP:
  if (stat(Aileron.tmpdir, &status)!=0) {
    if (mkdir(Aileron.tmpdir, mode & 0700) != 0) {
    char *newtmp;
    char *s = wstrdup(Aileron.tmpdir);

    s = wstrappend(s, "  could not be created\n");
    s = wstrappend(s, "Check that you are permitted to create it.");

    newtmp = WMRunInputPanel(Aileron.screen, NULL, 
      "Temporary Directory", s, Aileron.tmpdir, "Set", "Quit");

    if(!newtmp) 
      QuitAileron();
 
    if(Aileron.tmpdir) 
      wfree(Aileron.tmpdir);
    Aileron.tmpdir = wstrdup(newtmp);
    wfree(newtmp);
    goto mkTMP;
    } 

  }else{ 
    if(!S_ISDIR(status.st_mode)) { 
    /* clobber the file */
    unlink(Aileron.tmpdir);
    goto mkTMP;
    }
  }

  WMSetUDStringForKey(Aileron.defaultsDB, Aileron.tmpdir, "TemporaryDirectory");
}


void removeTmpDir(char *path) 
{
  struct dirent *dentry;
  DIR *dir;
  struct stat status;
  char pbuf[PATH_MAX+16];

  if(!path || !(dir = opendir(path)))
    return;

  if (stat(path, &status)!=0) {
    return;

  } else {
    while ((dentry = readdir(dir))) {
      if (strcmp(dentry->d_name, ".")==0 
        || strcmp(dentry->d_name, "..")==0 )
        continue;

      strcpy(pbuf, path);
      if (strcmp(path, "/")!=0)
        strcat(pbuf, "/");

      strcat(pbuf, dentry->d_name);

      if (stat(pbuf, &status)!=0) {
        continue;

      } else {
        if(S_ISDIR(status.st_mode))  {
          removeTmpDir(pbuf);
        } else {
          unlink(pbuf);
  } } } }
    
  closedir(dir);
  rmdir(path);
}


void QuitAileron(void)
{   
  int i, n;
  
  Aileron.aileronQuitting = True;
  
  n = WMGetBagItemCount((Aileron.openMboxes));
  for(i=0; i<n; i++) { 
    char *name = GetMailBoxName(WMGetFromBag(Aileron.openMboxes, i));
    CloseMailBox(name);
  }
  WMEmptyBag(Aileron.openMboxes);

  n = WMGetBagItemCount((Aileron.openComposers));
  for(i=0; i<n; i++) { 
    CloseComposer(WMGetFromBag(Aileron.openComposers, i));
  }
  WMEmptyBag(Aileron.openMboxes);

  if(Aileron.tmpdir) { 
    WMSetUDStringForKey(Aileron.defaultsDB, Aileron.tmpdir, 
       "TemporaryDirectory");
    removeTmpDir(Aileron.tmpdir);
    wfree(Aileron.tmpdir);
  }

  SaveAddresses();
  XCloseDisplay(Aileron.display);

  signal(SIGKILL, SIG_DFL);
  signal(SIGTRAP, SIG_DFL);
  signal(SIGBUS,  SIG_DFL);
  signal(SIGSEGV, SIG_DFL);

  signal(SIGQUIT, SIG_DFL);
  signal(SIGHUP,  SIG_DFL);
  signal(SIGINT,  SIG_DFL);
  signal(SIGTERM, SIG_DFL);
  signal(SIGUSR2, SIG_DFL);

  exit(0);
}   


WMButton* CreateBlendedButton(WMWidget *parent, WMButtonType type,
  const char *text, const char *imagefile)
{   
  WMButton *button; 
  RColor greycolor, whitecolor;
  WMColor *color;
  WMPixmap *greyxpm, *whitexpm;
  char *iconpath;
  
  color = WMGrayColor(Aileron.screen);
  greycolor.red = WMRedComponentOfColor(color) >> 8;
  greycolor.green = WMGreenComponentOfColor(color) >> 8;
  greycolor.blue = WMBlueComponentOfColor(color) >> 8;
  greycolor.alpha = 0;
  WMReleaseColor(color);
  
  color = WMWhiteColor(Aileron.screen);
  whitecolor.red = WMRedComponentOfColor(color) >> 8;
  whitecolor.green = WMGreenComponentOfColor(color) >> 8;
  whitecolor.blue = WMBlueComponentOfColor(color) >> 8;
  whitecolor.alpha = 0;
  Aileron.whiteColor = color;
  
  if(type == WBTMomentaryChange) {
    button = WMCreateCustomButton(parent, WBBPushChangeMask);
  } else {
    button = WMCreateCustomButton(parent, WBBPushInMask | 
      WBBPushChangeMask | WBBSpringLoadedMask | WBBPushLightMask);
  }
  
  iconpath = WMPathForResourceOfType( (char *)imagefile, "images/win");
  if(iconpath) {
    greyxpm = WMCreateBlendedPixmapFromFile(Aileron.screen,
      (char *)iconpath, &greycolor);
    whitexpm = WMCreateBlendedPixmapFromFile(Aileron.screen,
      (char *)iconpath, &whitecolor);
    WMSetButtonImage(button, greyxpm);
    WMSetButtonAltImage(button, whitexpm);
    WMSetButtonImagePosition(button, WIPAbove);
    
    WMReleasePixmap(greyxpm);
    WMReleasePixmap(whitexpm);
    free(iconpath);
  }
  
  WMSetButtonText(button, (char *)text);
  WMSetButtonFont(button, Aileron.buttonfont);
  WMResizeWidget(button, 64, 64);

  return button;
}   


void buildAesthetics(void)
{
  RColor greycolor, whitecolor;
  WMColor *color;
  WMPixmap *pixmap;
  char *iconpath;

  /* don't release colors if you plan to use the GCs in the future:
paintSummaries */
  color = WMWhiteColor(Aileron.screen);
  Aileron.whitegc = WMColorGC(color);

  color = WMBlackColor(Aileron.screen);
  Aileron.blackgc = WMColorGC(color);

  color = WMCreateNamedColor(Aileron.screen, "grey", False);
  Aileron.greygc = WMColorGC(color);

  color = WMCreateNamedColor(Aileron.screen, "slategrey", False);
  Aileron.darkgreygc = WMColorGC(color); 

  color = WMGrayColor(Aileron.screen);
  greycolor.red = WMRedComponentOfColor(color) >> 8;
  greycolor.green = WMGreenComponentOfColor(color) >> 8;
  greycolor.blue = WMBlueComponentOfColor(color) >> 8;
  WMReleaseColor(color);

  
  color = WMWhiteColor(Aileron.screen);
  whitecolor.red = WMRedComponentOfColor(color) >> 8;
  whitecolor.green = WMGreenComponentOfColor(color) >> 8;
  whitecolor.blue = WMBlueComponentOfColor(color) >> 8;
  WMReleaseColor(color);
  
  Aileron.npix_w = WMCreateBlendedPixmapFromFile(Aileron.screen,
    WMPathForResourceOfType("new-flag.tif", "images/win"), &whitecolor);
    
  Aileron.mpix_w = WMCreateBlendedPixmapFromFile(Aileron.screen,
    WMPathForResourceOfType("mime-flag.tif", "images/win"), &whitecolor);
    
  Aileron.apix_w = WMCreateBlendedPixmapFromFile(Aileron.screen,
    WMPathForResourceOfType("answered-flag.tif", "images/win"),
    &whitecolor);     

  Aileron.npix_g = WMCreateBlendedPixmapFromFile(Aileron.screen,
    WMPathForResourceOfType("new-flag.tif", "images/win"), &greycolor);
    
  Aileron.mpix_g = WMCreateBlendedPixmapFromFile(Aileron.screen,
    WMPathForResourceOfType("mime-flag.tif", "images/win"), &greycolor);
    
  Aileron.apix_g = WMCreateBlendedPixmapFromFile(Aileron.screen,
    WMPathForResourceOfType("answered-flag.tif", "images/win"),
    &greycolor);
    

  Aileron.listfont = WMSystemFontOfSize(Aileron.screen, 12);

  iconpath = WMPathForResourceOfType("mailboxes.tif", "images/win");
  if(iconpath) {
    pixmap = WMCreatePixmapFromFile(Aileron.screen, iconpath);
    if(pixmap) { 
      WMSetApplicationIconPixmap(Aileron.screen, pixmap);
      WMReleasePixmap(pixmap);
    }
    free(iconpath);
     
  }
  
  
  iconpath = WMPathForResourceOfType("generic-sound.tif", "images/filetypes");  
  if(iconpath) {
    Aileron.SoundIcon = 
      WMCreatePixmapFromFile(Aileron.screen, iconpath);
    free(iconpath);
  } else Aileron.SoundIcon = NULL;
  
  iconpath = WMPathForResourceOfType("file-generic-gnustep.tif",
    "images/filetypes");
  if(iconpath) {
    Aileron.ApplicationIcon = 
      WMCreatePixmapFromFile(Aileron.screen, iconpath);
    free(iconpath); 
  } else Aileron.ApplicationIcon = NULL;
  
  
  iconpath = WMPathForResourceOfType("file-dot-jpg.tif", "images/filetypes");
  if(iconpath) {
    Aileron.ImageIcon = 
      WMCreatePixmapFromFile(Aileron.screen, iconpath);
    free(iconpath);
  } else  Aileron.ImageIcon = NULL;

  iconpath = WMPathForResourceOfType("file-dot-mov.tif", "images/filetypes");
  if(iconpath) {
    Aileron.MovieIcon = 
      WMCreatePixmapFromFile(Aileron.screen, iconpath);
    free(iconpath);
  } else Aileron.MovieIcon = NULL;
  
  iconpath = WMPathForResourceOfType("generic-text.tif", "images/filetypes");
  if(iconpath) {
    Aileron.UnknownIcon = 
      WMCreatePixmapFromFile(Aileron.screen, iconpath);
    free(iconpath);
  } else Aileron.UnknownIcon = NULL;
  
  iconpath = WMPathForResourceOfType("compose.tif", "images/win");
  if (iconpath) {
    Aileron.ComposerImage = 
      WMCreatePixmapFromFile(Aileron.screen, iconpath);
    free(iconpath); 
  }  else Aileron.ComposerImage = NULL; 

  Aileron.buttonfont = WMSystemFontOfSize(Aileron.screen, 10);
}


int
RunAlertPanel(char *title, char *msg,
  char *defaultButton, char *alternateButton, char *otherButton)
{
  int w = WMScreenWidth(Aileron.screen);
  int h = WMScreenHeight(Aileron.screen); 
  int result;

  WMAlertPanel *alert = WMCreateAlertPanel(Aileron.screen, NULL,
    title, msg, defaultButton, alternateButton, otherButton);

  WMSetWindowTitle(alert->win, "Aileron: Alert!");
  WMRealizeWidget(alert->win);
  WMMapSubwidgets(alert->win);
  WMMoveWidget(alert->win, w/4, h/4);
  WMMapWidget(alert->win); 
  WMRunModalLoop(Aileron.screen, W_VIEW(alert->win));
  
  result = alert->result;
  WMDestroyAlertPanel(alert);
  return result;
}  

/* fill passwd entries in the WMTextField and misc pointers
   with NULLs so passwd may not be gleaned from a core dump */
char *
RunPasswordPanel(WMScreen *scrPtr, WMWindow *owner, char *title,
  char *msg, char *defaultText, char *okButton, char *cancelButton,
  char *name)
{
  WMInputPanel *panel;
  char *tmp = NULL;
  int px, py;
  WMView *view;
    
  panel = WMCreateInputPanel(scrPtr, owner, title, msg, defaultText,
    okButton, cancelButton);
  WMSetTextFieldSecure(panel->text, True);
  view = WMWidgetView(panel->win);
  tmp = wstrdup("Aileron: ");
  tmp = wstrappend(tmp, name);
  WMSetWindowTitle(panel->win, tmp);
  wfree(tmp);
  tmp = NULL;
    
  if (owner) {
    WMView *oview = WMWidgetView(owner);
    WMPoint pt = WMGetViewScreenPosition(oview);

    px = (W_VIEW_WIDTH(oview)-W_VIEW_WIDTH(view))/2;
    py = (W_VIEW_HEIGHT(oview)-W_VIEW_HEIGHT(view))/2;
        
    px += pt.x;
    py += pt.y;
  } else {
    px = (W_VIEW_WIDTH(scrPtr->rootView)-W_VIEW_WIDTH(view))/2;
    py = (W_VIEW_HEIGHT(scrPtr->rootView)-W_VIEW_HEIGHT(view))/2;
  }   

  WMSetWindowInitialPosition(panel->win, px, py);
  WMMapWidget(panel->win);
  WMRunModalLoop(scrPtr, W_VIEW(panel->win));
   
  if (panel->result == WAPRDefault) {
    char *erase = NULL;
    int len;
    
    tmp = WMGetTextFieldText(panel->text);
    len = strlen(tmp);
    if(len >= 1) { 
      erase = wmalloc(len+1);
      memset(erase, '*', len);
      erase[len] = 0;
      WMSetTextFieldText(panel->text, erase);
      wfree(erase);
    }
  }
    
  WMDestroyInputPanel(panel);
    
  return tmp;
}   


static void parseArgs(int argc, char **argv)
{

  if(argc > 1) {
    int f;
    
    if(!strcmp(argv[1], "-c")) {
      if(argc < 3) { 
        printf("usage: Aileron [mailbox1 mailbox2 ... "
          "| -c address1 address2 ...]\n");
        exit(-1);
      }
      for(f=2; f < argc; f++) 
        ComposeMessageTo(argv[f]);

    } else {
      for(f=1; f < argc; f++) 
        OpenMailBox(argv[f]);
    }
    
  } else {
    if(!OpenDefaultMailBoxes())
      RunMailboxesPanel();
  }

}



static void catchEvents(GETS_DATA *md, unsigned long count)
{
#if 0
  XEvent event;

  WMNextEvent(Aileron.display, &event);
  WMHandleEvent(&event);
  /* WMProcessEvent(Aileron.appContext, &event); */
#endif
}

/*
  handle hang up signal (SIGUSR2) caused when another client 
  (not necessarily Aileron or pine) accesses this mailbox
*/

static int
handleXIO(Display *xio_dpy)
{
    Aileron.display = NULL;
    return 0; 
}   


static void
kill_signal(int sig)
{
  exit(-1);
}   

static void
usr2_signal (int sig)
{   
printf("DEBUG: usr2_signal: need correct mbox\n");
  MarkMailBoxAsReadOnly(Aileron.mbox, True);
}

static void
quit_signal ()
{
  QuitAileron();
}


void mm_critical(MAILSTREAM *stream)
{
  stream = stream; /* For compiler complaints that this isn't used */
}

void mm_nocritical(MAILSTREAM *stream)
{
  stream = stream; /* For compiler complaints that this isn't used */
}

static void
init_signals()
{
    
    signal(SIGKILL, kill_signal);
    signal(SIGTRAP, kill_signal);
    signal(SIGBUS,  kill_signal);
    signal(SIGSEGV, kill_signal);

    signal(SIGQUIT, quit_signal);
    signal(SIGHUP, quit_signal);
    signal(SIGINT, quit_signal);
    signal(SIGTERM, quit_signal);
    
    signal(SIGUSR2, usr2_signal);

    /* handle X shutdowns and such */
    XSetIOErrorHandler(handleXIO);
}   



int main(int argc, char **argv)
{
  char tmp[128], *contextname = tmp;
  XClassHint *classHint;

  
  init_signals();
  WMInitializeApplication("Aileron", &argc, argv);

  Aileron.display = XOpenDisplay(NULL);
  if (!Aileron.display) {
    errno = EPERM;
    perror("Open Display");
    exit(1);
  }

  Aileron.screen = WMCreateScreen(Aileron.display,
    DefaultScreen(Aileron.display));

  Aileron.leader =  Aileron.screen->groupLeader;

  Aileron.appContext = WMAppCreateWithMain(Aileron.display, 
    DefaultScreen(Aileron.display), Aileron.leader);
  
  Aileron.windowTable = WMCreateHashTable(WMStringHashCallbacks);
  XStoreName(Aileron.display, Aileron.leader, "Aileron:");

  classHint = XAllocClassHint();
  classHint->res_name = "Aileron";
  classHint->res_class = "Aileron";
  XSetClassHint(Aileron.display, Aileron.leader, classHint);
  

  Aileron.xContext = XUniqueContext();
  Aileron.openMboxes = WMCreateBag(2);
  Aileron.openComposers = WMCreateBag(2);
  Aileron.mbox = Aileron.composer = NULL; 
  Aileron.cORm = 0;
  Aileron.aileronQuitting = False;
  Aileron.mboxLocked = False;
  Aileron.prefsChanged = False;
  Aileron.mboxesCreated = False;
  Aileron.addressesCreated = False;
  Aileron.findCreated = False;
  Aileron.infoCreated = False;
  Aileron.gplCreated = False;
  Aileron.helpCreated = False;
  Aileron.shiftHeld = False;
  Aileron.mouseWithinSumary = False;
  Aileron.ignoreError = False;
  Aileron.textIsPlain = False;
  Aileron.errorMsg = NULL;
  Aileron.copiedfont = NULL;
  Aileron.rulermargins = NULL;

  Aileron.selectedStream = NULL;
  Aileron.selectionText = NULL;
  Aileron.selectedMessage = 0;

  Aileron.defaultsDB = WMGetStandardUserDefaults();
  if(!WMGetUDStringForKey(Aileron.defaultsDB, "TemporaryDirectory")) { 

    char *iconpath = WMPathForResourceOfType("mailboxes.xpm", "images/icon");

    if(iconpath) {
      FILE *pipe;
      char *command = wstrdup("cp ");
      
      command = wstrappend(command, iconpath);
      command = wstrappend(command, " ");
      command = wstrappend(command, wgethomedir());
      command = wstrappend(command, 
        "/GNUstep/.AppInfo/WindowMaker/Aileron.Aileron.xpm");

      if(!(pipe = popen(command, "w"))) {
        wfree(command);
      }

      pclose(pipe);
      wfree(command);
      wfree(iconpath);
     }

    WMSetBalloonEnabled(Aileron.screen, True);
  } else {
    WMSetBalloonEnabled(Aileron.screen, 
      WMGetUDBoolForKey(Aileron.defaultsDB, "BalloonHelp"));
  }

  createTmpdir();
  buildAesthetics();
  BuildMainMenu();
  WMRealizeMenus(Aileron.appContext);


  mail_link(&unixdriver);
  mail_link(&mmdfdriver);
  mail_link(&dummydriver);
  mail_link(&imapdriver);
  mail_link(&pop3driver);
  mail_link(&mhdriver);
  auth_link(&auth_log);

  parseArgs(argc, argv);
  (void) mail_parameters(NULL, SET_READPROGRESS, (void *)catchEvents);


  while(1) {
    XEvent event;
    
    WMNextEvent(Aileron.display, &event);
    WMHandleEvent(&event);
    WMProcessEvent(Aileron.appContext, &event);

    switch(event.type) {

      case FocusIn: {
        if(!XFindContext(Aileron.display, event.xfocus.window,
          Aileron.xContext, (XPointer *) &contextname)) {

          if(!strncmp(contextname, "MBOX", 4)) {
            if(!Aileron.mboxLocked)
              Aileron.mbox = WMHashGet(Aileron.windowTable, &contextname[4]);
              Aileron.cORm = 1;
              ChangeFindPanelForContext();

          } else if(strstr(contextname, "CMPSR")) {

            Aileron.composer = 
              WMHashGet(Aileron.windowTable, contextname);
            Aileron.cORm = 0;
            ChangeFindPanelForContext();
          } 
        }
      }
      case FocusOut:
        break;
    }     
  }   
  
  return 0;
}   


WMTextField *NewTextField(WMWidget *w, char *text,
  int pos_x, int pos_y, int size_x, int size_y)
{   
  WMTextField *textfield = WMCreateTextField(w);
  
  WMResizeWidget(textfield, size_x, size_y);
  WMMoveWidget(textfield, pos_x, pos_y);
  if(text)
    WMSetTextFieldText(textfield, text);
  return textfield;
}   

WMLabel *NewLabel(WMWidget *w, char *name,
  int pos_x, int pos_y, int size_x, int size_y)
{   
  WMLabel *label  = WMCreateLabel(w);
  
  WMResizeWidget(label, size_x, size_y);
  WMMoveWidget(label, pos_x, pos_y);
  if (name)
    WMSetLabelText(label, name);
    
  return label;
}


void 
FSErrorhandler(char *title, char *path, int errornumber)
{
  char string[201];
  
  if(!title || !path)
    return;
    
  snprintf(string, 200, path);
  
  switch (errno) {
    case EACCES: sprintf(string, "This operation was not permitted "
      "by the file system.\nCheck that you do have permission to "
      "effect changes here."); 
    break;

    case ENOENT: snprintf(string, 200, "%s\ndoes not exist.", path); 
    break;

    case ENOMEM: sprintf(string, "Insufficient memory available.");
    break;

    case EBUSY: sprintf(string, "%s\nFolder might currently be in "
      "use by another application.\nVerify this and try again.", path);
    break;    

    case EEXIST: sprintf(string, "'%s'\nalready exists.", path);
    break;

    case EROFS: 
      snprintf(string, 200, 
        "'%s'\nis on a read-only filesystem.", path); 
    break;

    case EINVAL:  
      snprintf(string, 200, 
        "'%s'\nis not a symbolic link.", path); 
    break;

    case ENOTEMPTY:
      snprintf(string, 200, "%s\nThis folder contains "
        "at least one mailbox.\nPlease delete all "
        "mailboxes within this folder first!", path);
     break;

    default: sprintf(string, "Cannot complete action for"
                " some unknown reason");
  }
  
  RunAlertPanel(title, string,"I understand", NULL, NULL);

}



void
sigchildhandler(int n)
{
  int result;

  waitpid(0, &result, WNOHANG);
}

#if 0
static void insertMIMEType()
{
}

haveanother hashtable for attachements with mime types then search 
using desc to obtain mime type...
#endif

void OpenFile(WMTextDelegate *self, char *description)
{
printf("OpenFile [%s]\n", description);
#if 0
  WMWindow *owner;
#if 0
  int i, nelem;
  proplist_t dic, keys, key, val;
, *ftype;
  char *option;
#endif

  if(!description)
    return;

  if(Aileron.cORm) 
    owner = GetMailBoxWindow(Aileron.mbox);
   else 
    owner = NULL;//GetComposerWindow(Aileron.composer);

  if(!owner)
    return;
 
#if 0
  if(!(dic = WMGetUDObjectForKey(Aileron.defaultsDB, "MIMEHandlers"))) {

    goto 
  ftype = getFileTypeForDescription(description);
  if(!ftype) {
printf("no description, how sad\n");
    return;
  }
#endif

   RunAlertPanel("Open Attachment",
    "Due to lack of time (I'm a full time grad student with a job), this\n"
    "file will simply be saved in the directory you chose to save \n"
    "attachments... in the near future, MIME support will be complete.",
    "No problem", "Nwanua sux", NULL);
  SaveAllAttachments(Aileron.mbox);

#if 0
   {
     WMSavePanel *panel = WMGetSavePanel(Aileron.screen);
     if(WMRunModalFilePanelForDirectory(panel, NULL,
       description, NULL, NULL)) {
         WMGetFilePanelFileName(panel);
		}} else {
 
    pid_t pid;
    printf("application %s\n", application);
    signal(SIGCHLD, sigchildhandler);
    if ((pid=fork())==0) {
      char *argv[] = {application, description, NULL};
    
      execvp(argv[0], argv);
      exit(10);
    }
printf("returned\n");
     }
    //wfree(application);

  }
#endif
#endif
}


Bool
FileExists(char *filename)
{
  struct stat stat_buf;

  if (!filename)
    return 0;

/* also check for perms, etc... */
  return (stat(filename, &stat_buf)==0);
}



char *SetEntity(WMWindow *owner, char *entity, int isDir,
  char *warning, int setDefault)
{
  char *entityPath = NULL;
  char *path = NULL; 
  struct stat status;
  WMOpenPanel *panel;
  
  if(!entity || !warning)
    return NULL;
  
_setEntityAgain:
  panel  = WMGetOpenPanel(Aileron.screen);
  path = WMGetUDStringForKey(Aileron.defaultsDB, entity);
  
  WMSetFilePanelAutoCompletion(panel, True);
  if (WMRunModalFilePanelForDirectory(panel, owner,
   path? path:"/tmp", NULL, NULL)) {
    
    entityPath = WMGetFilePanelFileName(panel);
    if (entityPath) { 
      if (stat(entityPath, &status) != 0) {
        RunAlertPanel(warning,
          isDir?"The folder does not exist."
               :"The file does not exist.",
          "I understand", NULL, NULL);
        WMFreeFilePanel(panel); 
        wfree(entityPath);
        goto _setEntityAgain;
      } 
        
      if (isDir?!S_ISDIR(status.st_mode):S_ISDIR(status.st_mode)) {
        RunAlertPanel(warning,
          isDir?"The chosen entity is not a folder."
               :"The chosen entity is not a regular file.",
          "I understand", NULL, NULL);
        //WMFreeFilePanel(panel);
        wfree(entityPath);
        goto _setEntityAgain;
      } 
        
      if(setDefault)
        WMSetUDStringForKey(Aileron.defaultsDB, entityPath, entity);
      WMFreeFilePanel(panel);
      /* free this */
      return entityPath;
    } 
  } 
  
  WMFreeFilePanel(panel);
  return NULL;
} 


void EnterSelection(void)
{
  int l;
  char *fetched = XFetchBuffer(Aileron.display, &l, 0);

  if(fetched && l>0) {
    if(Aileron.selectionText)
      wfree(Aileron.selectionText);

    Aileron.selectionText = wstrdup(fetched);
    XFree(fetched);
  }
}

