/*
 * xmail - X window system interface to the mail program
 *
 * Copyright 1990,1991,1992 by National Semiconductor Corporation
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of National Semiconductor Corporation not
 * be used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.
 *
 * NATIONAL SEMICONDUCTOR CORPORATION MAKES NO REPRESENTATIONS ABOUT THE
 * SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS"
 * WITHOUT EXPRESS OR IMPLIED WARRANTY.  NATIONAL SEMICONDUCTOR CORPORATION
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO
 * EVENT SHALL NATIONAL SEMICONDUCTOR CORPORATION BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * Author:  Michael C. Wagnitz - National Semiconductor Corporation
 *
 */

#include "global.h"
#include <sys/stat.h>

#ifndef	S_ISDIR
#define	S_ISDIR(m)	(((m)&S_IFMT) == S_IFDIR)
#endif

#ifdef USE_DIRENT
#include <dirent.h>
#else
#include <sys/dir.h>
#endif


/*
** @(#)SetDirectory() - Create popup list of directory folder names
*/
/* ARGSUSED */
void
SetDirectory(w, event, params, num_params)
Widget		w;
XEvent		*event;
String		*params;
Cardinal	*num_params;
{
 int		depth, label_width, n, total, x, y;
 char		buf[BUFSIZ], tmp[BUFSIZ], trans[BUFSIZ];
 String		ep, name, path, s, List, *ftbl;
 Widget		menu, layout, bw, above, to_left;
 Arg		args[8];
 DIR		*dirp;
 struct	stat	st_buf;
#ifdef USE_DIRENT
 struct dirent	*dp;
#else
 struct direct	*dp;
#endif

 static String	dir_Trans = "<Btn1Down>: SetDirectory(%s, %s, %d)";
 static String	m_Trans   = "<Leave>: MenuPopdown(%s)";
 static String	b_Trans   = "<Enter>: set()\n<Leave>: unset()\n<Btn3Up>: MyNotify(%d) MenuPopdown(%s)";

 static XtCallbackRec callbacks[] = {
        { (XtCallbackProc) GetFolderName, NULL },
        { NULL,          NULL }
       };


 name = params[0];
 path = params[1];
 (void) sscanf(params[2], "%d", &depth);

 depth      += 1;
 label_width = 0;

     /*
     ** To avoid problems later on with XtNameToWidget, don't create a
     ** menu if the name contains either a dot (.) or an asterisk (*).
     */
 for (s = name; *s; s++)
     if (strchr(".*", *s) != NULL) break;

 menu = XtNameToWidget(w, name);
 if (*s == '\0' && menu == NULL) {	/* no dot or asterisk and no menu yet */
    SetCursor(WATCH);
    (void) sprintf(trans, m_Trans, name);
    XtSetArg(args[0], XtNtranslations, XtParseTranslationTable(trans));
    menu = XtCreatePopupShell(name, overrideShellWidgetClass, w, args, ONE);

    XtSetArg(args[0], XtNdefaultDistance, 1);
    layout = XtCreateManagedWidget("menu", formWidgetClass, menu, args, ONE);
    /*
    ** Copy folder names into a list
    */
    n = BUFSIZ;					/* start with a BUFSIZ block */
    List = (String) XtMalloc((unsigned) n);
    List[0] = '\0';

    if ((dirp = opendir(path)) == NULL)
       XtError("xmail cannot access directory name passed to SetDirectory()");

    for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
        if (dp->d_name[0] != '.') {		/* skip parent and dot files */
           if ((int)strlen(List) + (int)strlen(dp->d_name) + 2 >= n) {
              n += BUFSIZ;
              List = (String) XtRealloc(List, (unsigned) n);
             }
           if (List[0]) (void) strcat(List, " ");
           (void) strcat(List, dp->d_name);
          }
    (void) closedir(dirp);

    List = (String) XtRealloc(List, (unsigned) strlen(List) + 2);

    if (List[0]) {			/* if directory isn't empty... */
       /*
       ** Store pointers to folder names in a table array for sorting
       */
       for (total=1, s=List; *s; s++)	/* count number of names in the List */
           if (*s == ' ') total++;	/* (increase the folder name count) */
       ftbl = (String *) XtMalloc((unsigned) (total + 2) * sizeof(String *));
       x = n = 0;
       ep = &List[(int)strlen(List)];	/* Find the end of this array */
       for (s = List; s < ep; s++) {	/* stuff word pointers into a table */
           while ((s+n < ep) && *(s+n) != ' ') n++;
           if (s+n < ep) *(s+n) = '\0';	/* mark off the end of this name */
           ftbl[x++] = s;		/* save this pointer in our table */
           s += n;			/* find start of next folder name */
           n  = 0;
          }
       ftbl[x] = NULL;			/* NULL terminate our table */
       /*
       ** (quick) sort our table into ascending alphabetical order
       */
       if (total > 1)
       qsort((char *)ftbl, total, sizeof(char *), str_compare);
       /*
       ** Then, determine label width by finding longest entry in our table
       */
       for (x = n = 0; n < total && ftbl[n]; n++)
           if ((int)strlen(ftbl[n]) > (int)strlen(ftbl[x])) x = n;

       label_width = XTextWidth(XMail.buttonFont, ftbl[x], strlen(ftbl[x]));
      }

    if (label_width) {
       (void) sprintf(trans, b_Trans, depth, name);

       XtSetArg(args[0], XtNtranslations, XtParseTranslationTable(trans));
       XtSetArg(args[1], XtNwidth, label_width + 12);
       XtSetArg(args[2], XtNfont, XMail.buttonFont);
       XtSetArg(args[3], XtNcallback, callbacks);
/*
** create the menu buttons
*/
       bw = above = to_left = NULL;
       for (x = 0; x < total; x++) {
           (void) sprintf(buf, "%s/%s", path, ftbl[x]);
           (void) strncpy(tmp, ftbl[x], BUFSIZ);
/*
           ** If this folder is also a directory, add a trailing slash '/'
*/
           if (stat(buf, &st_buf) == 0)		/* IF exists and is readable */
	      if (S_ISDIR(st_buf.st_mode) && LASTCH(tmp) != '/')
                 (void) strcat(tmp, "/");	/* If a directory mark it so */

           XtSetArg(args[4], XtNlabel, tmp);
           XtSetArg(args[5], XtNfromHoriz, to_left);
           if (! to_left)			/* (else keep current value) */
              XtSetArg(args[6], XtNfromVert, above);

           bw = XtCreateManagedWidget("menubutton",commandWidgetClass,layout,args,7);

           if (to_left == NULL) above = bw;
           if ((x+1) % 3 == 0)			/* make box three items wide */
              to_left = NULL;
           else to_left = bw;

           if (LASTCH(tmp) != '/')
              AddInfoHandler(bw, Folder_Info[1]);
           else {
/*
              ** This is a directory.  Add a button popup menu for its files.
*/
              (void) sprintf(trans, dir_Trans, tmp, buf, depth);
              XtOverrideTranslations(bw, XtParseTranslationTable(trans));
              AddInfoHandler(bw, Folder_Info[2]);
             }
          } /* end - for each name in the folder table */
      } /* end - if there exists at least one folder name */
/*
** If no buttons were created for this menu, destroy the widget.
*/
    if (! label_width)
       XtDestroyWidget(menu);
    SetCursor(NORMAL);
    XtFree((String) ftbl);
    XtFree((String) List);
   } /* end - if menu had not yet been created */
/*
** If menu exists, pop it up, after setting x,y coordinates
*/
 menu = XtNameToWidget(w, name);

 if (! menu || menu->core.being_destroyed)
    XBell(XtDisplay(toplevel), 33);
 else {
    SetPopup(w, event, params, num_params);
    /*
    ** Mark folders with new messages by changing the background Pixmap
    */
    SetNewness(XtNameToWidget(menu, "*menu"), path);

    XtSetArg(args[0], XtNy, &y);
    XtGetValues(menu, args, ONE);

    y -= XMail.menuY;	/* don't offset menu below cursor */

    XtSetArg(args[0], XtNy, y);
    XtSetValues(menu, args , ONE);

    XtPopup(menu, XtGrabNone);
   }
} /* SetDirectory */
