"Fossies" - the Fresh Open Source Software Archive

Member "xfe-1.43.2/src/Properties.cpp" (30 Apr 2019, 74885 Bytes) of package /linux/privat/xfe-1.43.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Properties.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.43.1_vs_1.43.2.

    1 // Properties box
    2 
    3 #include "config.h"
    4 #include "i18n.h"
    5 
    6 #include <stdio.h>
    7 #include <stdlib.h>
    8 #include <sys/stat.h>
    9 #include <sys/wait.h>
   10 #include <unistd.h>
   11 #include <string.h>
   12 #include <time.h>
   13 #include <errno.h>
   14 #include <signal.h>
   15 #include <pwd.h>
   16 #include <grp.h>
   17 #if defined(linux)
   18 #include <mntent.h>
   19 #endif
   20 
   21 #include <fx.h>
   22 #include <fxkeys.h>
   23 #include <FXPNGIcon.h>
   24 
   25 #include "xfedefs.h"
   26 #include "icons.h"
   27 #include "xfeutils.h"
   28 #include "File.h"
   29 #include "DialogBox.h"
   30 #include "FileDialog.h"
   31 #include "FilePanel.h"
   32 #include "XFileExplorer.h"
   33 #include "MessageBox.h"
   34 #include "Properties.h"
   35 
   36 
   37 
   38 // Global variables
   39 extern FXMainWindow* mainWindow;
   40 extern FXStringDict* fsdevices;
   41 extern FXString      xdgdatahome;
   42 
   43 
   44 // Map
   45 FXDEFMAP(PermFrame) PermFrameMap[] = {};
   46 
   47 // Object implementation
   48 FXIMPLEMENT(PermFrame, FXVerticalFrame, PermFrameMap, ARRAYNUMBER(PermFrameMap))
   49 
   50 PermFrame::PermFrame(FXComposite* parent, FXObject* target) :
   51     FXVerticalFrame(parent, FRAME_RAISED)
   52 {
   53     FXHorizontalFrame* accessframe = new FXHorizontalFrame(this, LAYOUT_FILL_X|LAYOUT_FILL_Y);
   54     FXHorizontalFrame* chmodframe = new FXHorizontalFrame(this, LAYOUT_FILL_X|LAYOUT_FILL_Y);
   55 
   56     // Permissions
   57     FXGroupBox* group1 = new FXGroupBox(accessframe, _("User"), GROUPBOX_TITLE_LEFT|FRAME_GROOVE|LAYOUT_FILL_X);
   58 
   59     ur = new FXCheckButton(group1, _("Read"), target, PropertiesBox::ID_RUSR);
   60     uw = new FXCheckButton(group1, _("Write"), target, PropertiesBox::ID_WUSR);
   61     ux = new FXCheckButton(group1, _("Execute"), target, PropertiesBox::ID_XUSR);
   62     FXGroupBox* group2 = new FXGroupBox(accessframe, _("Group"), GROUPBOX_TITLE_LEFT|FRAME_GROOVE|LAYOUT_FILL_X);
   63     gr = new FXCheckButton(group2, _("Read"), target, PropertiesBox::ID_RGRP);
   64     gw = new FXCheckButton(group2, _("Write"), target, PropertiesBox::ID_WGRP);
   65     gx = new FXCheckButton(group2, _("Execute"), target, PropertiesBox::ID_XGRP);
   66     FXGroupBox* group3 = new FXGroupBox(accessframe, _("Others"), GROUPBOX_TITLE_LEFT|FRAME_GROOVE|LAYOUT_FILL_X);
   67     or_ = new FXCheckButton(group3, _("Read"), target, PropertiesBox::ID_ROTH);
   68     ow = new FXCheckButton(group3, _("Write"), target, PropertiesBox::ID_WOTH);
   69     ox = new FXCheckButton(group3, _("Execute"), target, PropertiesBox::ID_XOTH);
   70     FXGroupBox* group4 = new FXGroupBox(accessframe, _("Special"), GROUPBOX_TITLE_LEFT|FRAME_GROOVE|LAYOUT_FILL_X);
   71     suid = new FXCheckButton(group4, _("Set UID"), target, PropertiesBox::ID_SUID);
   72     sgid = new FXCheckButton(group4, _("Set GID"), target, PropertiesBox::ID_SGID);
   73     svtx = new FXCheckButton(group4, _("Sticky"), target, PropertiesBox::ID_SVTX);
   74 
   75     // Owner
   76     FXGroupBox* group5 = new FXGroupBox(chmodframe, _("Owner"), GROUPBOX_TITLE_LEFT|FRAME_GROOVE|LAYOUT_FILL_X|LAYOUT_FILL_Y);
   77     new FXLabel(group5, _("User"));
   78     user = new FXComboBox(group5, 5, NULL, 0, COMBOBOX_STATIC|LAYOUT_FILL_X);
   79     user->setNumVisible(5);
   80     new FXLabel(group5, _("Group"));
   81     grp = new FXComboBox(group5, 5, NULL, 0, COMBOBOX_STATIC|LAYOUT_FILL_X);
   82     grp->setNumVisible(5);
   83 
   84     // User names (sorted in ascending order)
   85     struct passwd* pwde;
   86     while ((pwde = getpwent()))
   87     {
   88         user->appendItem(pwde->pw_name);
   89     }
   90     endpwent();
   91     user->setSortFunc(FXList::ascending);
   92     user->sortItems();
   93 
   94     // Group names (sorted in ascending order)
   95     struct group* grpe;
   96     while ((grpe = getgrent()))
   97     {
   98         grp->appendItem(grpe->gr_name);
   99     }
  100     endgrent();
  101     grp->setSortFunc(FXList::ascending);
  102     grp->sortItems();
  103 
  104     // Initializations
  105     cmd = 0;
  106     flt = 0;
  107 
  108     // Command
  109     FXGroupBox* group6 = new FXGroupBox(chmodframe, _("Command"), GROUPBOX_TITLE_LEFT|FRAME_GROOVE|LAYOUT_FILL_X|LAYOUT_FILL_Y);
  110     FXMatrix*   matrix6 = new FXMatrix(group6, 2, MATRIX_BY_COLUMNS|LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y);
  111     cmd_radiotarget.connect(cmd);
  112     set = new FXRadioButton(matrix6, _("Set marked"), &cmd_radiotarget, FXDataTarget::ID_OPTION+PropertiesBox::ID_SET);
  113     rec = new FXCheckButton(matrix6, _("Recursively"), NULL, 0);
  114     clear = new FXRadioButton(matrix6, _("Clear marked"), &cmd_radiotarget, FXDataTarget::ID_OPTION+PropertiesBox::ID_CLEAR);
  115     flt_radiotarget.connect(flt);
  116     all = new FXRadioButton(matrix6, _("Files and folders"), &flt_radiotarget, FXDataTarget::ID_OPTION+PropertiesBox::ID_ALL);
  117     add = new FXRadioButton(matrix6, _("Add marked"), &cmd_radiotarget, FXDataTarget::ID_OPTION+PropertiesBox::ID_ADD);
  118     dironly = new FXRadioButton(matrix6, _("Folders only"), &flt_radiotarget, FXDataTarget::ID_OPTION+PropertiesBox::ID_DIRONLY);
  119     own = new FXCheckButton(matrix6, _("Owner only"), NULL, 0);
  120     fileonly = new FXRadioButton(matrix6, _("Files only"), &flt_radiotarget, FXDataTarget::ID_OPTION+PropertiesBox::ID_FILEONLY);
  121 }
  122 
  123 
  124 // Map
  125 FXDEFMAP(PropertiesBox) PropertiesBoxMap[] =
  126 {
  127     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_ACCEPT_SINGLE, PropertiesBox::onCmdAcceptSingle),
  128     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_ACCEPT_MULT, PropertiesBox::onCmdAcceptMult),
  129     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_CANCEL, PropertiesBox::onCmdCancel),
  130     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_RUSR, PropertiesBox::onCmdCheck),
  131     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_WUSR, PropertiesBox::onCmdCheck),
  132     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_XUSR, PropertiesBox::onCmdCheck),
  133     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_RGRP, PropertiesBox::onCmdCheck),
  134     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_WGRP, PropertiesBox::onCmdCheck),
  135     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_XGRP, PropertiesBox::onCmdCheck),
  136     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_ROTH, PropertiesBox::onCmdCheck),
  137     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_WOTH, PropertiesBox::onCmdCheck),
  138     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_XOTH, PropertiesBox::onCmdCheck),
  139     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_SUID, PropertiesBox::onCmdCheck),
  140     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_SGID, PropertiesBox::onCmdCheck),
  141     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_SVTX, PropertiesBox::onCmdCheck),
  142     FXMAPFUNC(SEL_UPDATE, 0, PropertiesBox::onUpdSizeAndPerm),
  143     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_SET, PropertiesBox::onCmdCommand),
  144     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_CLEAR, PropertiesBox::onCmdCommand),
  145     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_ADD, PropertiesBox::onCmdCommand),
  146     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_DIRONLY, PropertiesBox::onCmdFilter),
  147     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_FILEONLY, PropertiesBox::onCmdFilter),
  148     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_ALL, PropertiesBox::onCmdFilter),
  149     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_BIG_ICON, PropertiesBox::onCmdBrowseIcon),
  150     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_MINI_ICON, PropertiesBox::onCmdBrowseIcon),
  151     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_BROWSE_OPEN, PropertiesBox::onCmdBrowse),
  152     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_BROWSE_VIEW, PropertiesBox::onCmdBrowse),
  153     FXMAPFUNC(SEL_COMMAND, PropertiesBox::ID_BROWSE_EDIT, PropertiesBox::onCmdBrowse),
  154     FXMAPFUNC(SEL_KEYPRESS, 0, PropertiesBox::onCmdKeyPress),
  155     FXMAPFUNC(SEL_CHORE, PropertiesBox::ID_WATCHPROCESS, PropertiesBox::onWatchProcess),
  156 #ifdef STARTUP_NOTIFICATION
  157     FXMAPFUNC(SEL_UPDATE, PropertiesBox::ID_SNDISABLE, PropertiesBox::onUpdSnDisable),
  158 #endif
  159 };
  160 
  161 // Object implementation
  162 FXIMPLEMENT(PropertiesBox, DialogBox, PropertiesBoxMap, ARRAYNUMBER(PropertiesBoxMap))
  163 
  164 // Construct window for one file
  165 PropertiesBox::PropertiesBox(FXWindow* win, FXString file, FXString path) : DialogBox(win, _("Properties"), DECOR_TITLE|DECOR_BORDER|DECOR_MAXIMIZE|DECOR_STRETCHABLE|DECOR_CLOSE)
  166 {
  167     FXulong     filesize;
  168     FXString    mod, changed, accessed;
  169     FXString    grpid, usrid;
  170     FXLabel*    sizelabel = NULL;
  171     struct stat linfo;
  172     FXString    type = "", extension, extension2, fileassoc;
  173     FXbool      isLink, isBrokenLink;
  174     FXString    pathname, referredpath;
  175     char        mnttype[64], used[64], avail[64], pctr[64], size[64];
  176     char        buf[MAXPATHLEN+1];
  177     FXString    hsize;
  178     FILE*       p;
  179 
  180     // Trash locations
  181     trashfileslocation = xdgdatahome + PATHSEPSTRING TRASHFILESPATH;
  182     trashinfolocation = xdgdatahome + PATHSEPSTRING TRASHINFOPATH;
  183 
  184     // Buttons
  185     FXHorizontalFrame* buttons = new FXHorizontalFrame(this, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X, 0, 0, 0, 0, 10, 10, 5, 5);
  186 
  187     // Contents
  188     FXVerticalFrame* contents = new FXVerticalFrame(this, LAYOUT_SIDE_TOP|FRAME_NONE|LAYOUT_FILL_X|LAYOUT_FILL_Y);
  189 
  190     // Accept
  191     if (file != "..")
  192     {
  193         FXButton* ok = new FXButton(buttons, _("&Accept"), NULL, this, PropertiesBox::ID_ACCEPT_SINGLE, FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT|LAYOUT_CENTER_Y, 0, 0, 0, 0, 20, 20);
  194         ok->addHotKey(KEY_Return);
  195     }
  196 
  197     // Cancel
  198     new FXButton(buttons, _("&Cancel"), NULL, this, PropertiesBox::ID_CANCEL, FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT|LAYOUT_CENTER_Y, 0, 0, 0, 0, 20, 20);
  199 
  200     // Switcher
  201     FXTabBook* tabbook = new FXTabBook(contents, NULL, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_RIGHT);
  202 
  203     // First item is General
  204     new FXTabItem(tabbook, _("&General"), NULL);
  205     FXPacker*        genpack = new FXPacker(tabbook, FRAME_RAISED);
  206     FXGroupBox*      generalgroup = new FXGroupBox(genpack, FXString::null, FRAME_NONE|LAYOUT_FILL_X|LAYOUT_FILL_Y);
  207     FXVerticalFrame* generalframe = new FXVerticalFrame(generalgroup, LAYOUT_FILL_X|LAYOUT_FILL_Y);
  208 
  209     // Second item is Access Permissions
  210     FXTabItem* permtab = new FXTabItem(tabbook, _("&Permissions"), NULL);
  211     perm = new PermFrame(tabbook, this);
  212 
  213     // Permission tab is disabled for parent directory
  214     if (file == "..")
  215     {
  216         permtab->disable();
  217     }
  218 
  219     // Third tab - file associations
  220     FXTabItem*       fassoctab = new FXTabItem(tabbook, _("&File Associations"), NULL);
  221     FXPacker*        fassocpack = new FXPacker(tabbook, FRAME_RAISED);
  222     FXGroupBox*      fassocgroup = new FXGroupBox(fassocpack, FXString::null, FRAME_NONE|LAYOUT_FILL_X|LAYOUT_FILL_Y);
  223     FXVerticalFrame* contassoc = new FXVerticalFrame(fassocgroup, LAYOUT_FILL_X|LAYOUT_FILL_Y);
  224     FXMatrix*        matrix = new FXMatrix(contassoc, 3, MATRIX_BY_COLUMNS|LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y);
  225     fassoctab->disable();
  226     new FXLabel(matrix, _("Extension:"), NULL, JUSTIFY_LEFT|LAYOUT_FILL_COLUMN|LAYOUT_FILL_ROW|LAYOUT_CENTER_Y);
  227 
  228     // Use a read-only FXTextField instead of a FXLabel, to allow long strings
  229     ext = new FXTextField(matrix, 20, NULL, 0, JUSTIFY_LEFT|LAYOUT_FILL_COLUMN|LAYOUT_FILL_ROW|LAYOUT_CENTER_Y|TEXTFIELD_READONLY|_TEXTFIELD_NOFRAME);
  230     ext->setBackColor(getApp()->getBaseColor());
  231 
  232     new FXLabel(matrix, "", NULL, 0);
  233 
  234     new FXLabel(matrix, _("Description:"), NULL, JUSTIFY_LEFT|LAYOUT_FILL_COLUMN|LAYOUT_FILL_ROW|LAYOUT_CENTER_Y);
  235     descr = new FXTextField(matrix, 30, NULL, 0, FRAME_THICK|FRAME_SUNKEN|LAYOUT_FILL_COLUMN|LAYOUT_FILL_ROW|LAYOUT_FILL_X|LAYOUT_CENTER_Y);
  236     new FXLabel(matrix, "", NULL, 0);
  237 
  238     new FXLabel(matrix, _("Open:"), NULL, JUSTIFY_LEFT|LAYOUT_FILL_COLUMN|LAYOUT_FILL_ROW|LAYOUT_CENTER_Y);
  239     open = new FXTextField(matrix, 30, NULL, 0, FRAME_THICK|FRAME_SUNKEN|LAYOUT_FILL_COLUMN|LAYOUT_FILL_ROW|LAYOUT_FILL_X|LAYOUT_CENTER_Y);
  240     new FXButton(matrix, _("\tSelect file..."), filedialogicon, this, ID_BROWSE_OPEN, FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT|LAYOUT_FILL_X|LAYOUT_CENTER_Y, 0, 0, 0, 0, 10, 10);
  241 
  242     int is_ar = false;
  243 
  244     FXString viewlbl = _("View:");
  245     FXString editlbl = _("Edit:");
  246 
  247     extension = file.rafter('.', 1).lower();
  248     if ((extension == "gz") || (extension == "tgz") || (extension == "tar") || (extension == "taz") || (extension == "bz2") ||
  249         (extension == "tbz2") || (extension == "tbz") || (extension == "xz") || (extension == "txz") || (extension == "zip") ||
  250         (extension == "7z") || (extension == "Z") || (extension == "lzh") || (extension == "rar") ||
  251         (extension == "ace") || (extension == "arj"))
  252     {
  253         is_ar = true; // archive
  254         viewlbl = _("Extract:");
  255     }
  256 #if defined(linux)
  257     else if (extension == "rpm")
  258     {
  259         editlbl = _("Install/Upgrade:");
  260     }
  261 #endif
  262     new FXLabel(matrix, viewlbl, NULL, JUSTIFY_LEFT|LAYOUT_FILL_COLUMN|LAYOUT_FILL_ROW|LAYOUT_CENTER_Y);
  263     view = new FXTextField(matrix, 30, NULL, 0, FRAME_THICK|FRAME_SUNKEN|LAYOUT_FILL_COLUMN|LAYOUT_FILL_ROW|LAYOUT_FILL_X|LAYOUT_CENTER_Y);
  264     new FXButton(matrix, _("\tSelect file..."), filedialogicon, this, ID_BROWSE_VIEW, FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT|LAYOUT_FILL_X|LAYOUT_CENTER_Y, 0, 0, 0, 0, 10, 10);
  265 
  266     if (!is_ar)
  267     {
  268         new FXLabel(matrix, editlbl, NULL, JUSTIFY_LEFT|LAYOUT_FILL_COLUMN|LAYOUT_FILL_ROW|LAYOUT_CENTER_Y);
  269         edit = new FXTextField(matrix, 30, NULL, 0, FRAME_THICK|FRAME_SUNKEN|LAYOUT_FILL_COLUMN|LAYOUT_FILL_ROW|LAYOUT_FILL_X|LAYOUT_CENTER_Y);
  270         new FXButton(matrix, _("\tSelect file..."), filedialogicon, this, ID_BROWSE_EDIT, FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT|LAYOUT_FILL_X|LAYOUT_CENTER_Y, 0, 0, 0, 0, 10, 10);
  271     }
  272     else
  273     {
  274         edit = NULL;
  275     }
  276 
  277     new FXLabel(matrix, _("Big Icon:"), NULL, JUSTIFY_LEFT|LAYOUT_FILL_COLUMN|LAYOUT_FILL_ROW|LAYOUT_CENTER_Y);
  278     bigic = new FXTextField(matrix, 30, NULL, 0, FRAME_THICK|FRAME_SUNKEN|LAYOUT_FILL_COLUMN|LAYOUT_FILL_ROW|LAYOUT_FILL_X|LAYOUT_CENTER_Y);
  279     bigicbtn = new FXButton(matrix, _("\tSelect file..."), filedialogicon, this, ID_BIG_ICON, FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT|LAYOUT_FILL_X|LAYOUT_CENTER_Y, 0, 0, 0, 0, 10, 10);
  280 
  281     new FXLabel(matrix, _("Mini Icon:"), NULL, JUSTIFY_LEFT|LAYOUT_FILL_COLUMN|LAYOUT_FILL_ROW|LAYOUT_CENTER_Y);
  282     miniic = new FXTextField(matrix, 30, NULL, 0, FRAME_THICK|FRAME_SUNKEN|LAYOUT_FILL_COLUMN|LAYOUT_FILL_ROW|LAYOUT_FILL_X|LAYOUT_CENTER_Y);
  283     miniicbtn = new FXButton(matrix, _("\tSelect file..."), filedialogicon, this, ID_MINI_ICON, FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_RIGHT|LAYOUT_CENTER_Y, 0, 0, 0, 0, 10, 10);
  284 
  285     // File name
  286     new FXLabel(generalframe, _("Name"), NULL, JUSTIFY_LEFT);
  287     input = new FXTextField(generalframe, 60, NULL, 0, FRAME_THICK|FRAME_SUNKEN|LAYOUT_SIDE_TOP|LAYOUT_FILL_X);
  288 
  289     // Complete file path name
  290     pathname = path+PATHSEPSTRING+file;
  291     parentdir = path;
  292     filename = file;
  293 
  294     // Unused in this case
  295     files = NULL;
  296     paths = NULL;
  297 
  298     // Initialize mount point flag
  299     isMountpoint = false;
  300 
  301     // Warn if non UTF-8 file name
  302     if (!isUtf8(pathname.text(), pathname.length()))
  303     {
  304         new FXLabel(generalframe, _("=> Warning: file name is not UTF-8 encoded!"), NULL, LAYOUT_LEFT|LAYOUT_CENTER_Y|LAYOUT_FILL_ROW);
  305     }
  306 
  307     // Get file/link stat info
  308     if (lstatrep(pathname.text(), &linfo) != 0)
  309     {
  310         return;
  311     }
  312 
  313     // Obtain user name
  314     usrid = FXSystem::userName(linfo.st_uid);
  315 
  316     // Obtain group name
  317     grpid = FXSystem::groupName(linfo.st_gid);
  318     perm->user->setText(usrid);
  319     perm->grp->setText(grpid);
  320     oldgrp = grpid;
  321     oldusr = usrid;
  322 
  323     // Test if link or broken link
  324     // When valid link, get the referred file path
  325     isLink = S_ISLNK(linfo.st_mode);
  326     isBrokenLink = false;
  327     if (isLink)
  328     {
  329         // Broken link
  330         struct stat info;
  331         if (statrep(pathname.text(), &info) != 0)
  332         {
  333             isBrokenLink = true;
  334         }
  335 
  336         // Get the path name of the linked file
  337         referredpath = ::readLink(pathname);
  338     }
  339 
  340     orig_mode = linfo.st_mode;
  341 
  342     // Initialize exec flag
  343     executable = false;
  344 
  345     // Read time format
  346     FXString timeformat = getApp()->reg().readStringEntry("SETTINGS", "time_format", DEFAULT_TIME_FORMAT);
  347 
  348     // Mod time of the file / link
  349     mod = FXSystem::time(timeformat.text(), linfo.st_mtime);
  350 
  351     // Change time of the file / link
  352     changed = FXSystem::time(timeformat.text(), linfo.st_ctime);
  353 
  354     // Accessed time of the file / link
  355     accessed = FXSystem::time(timeformat.text(), linfo.st_atime);
  356 
  357     // Size of the file / link
  358     filesize = (FXulong)linfo.st_size;
  359 
  360     // Is it a directory?
  361     nbseldirs = 0;
  362     isDirectory = S_ISDIR(linfo.st_mode);
  363     if (isDirectory)
  364     {
  365         // Directory path
  366         FXString dirpath = FXPath::absolute(parentdir, file);
  367 
  368 #if defined(linux)
  369         FILE*          mtab = setmntent(MTAB_PATH, "r");
  370         struct mntent* mnt;
  371         if (mtab)
  372         {
  373             while ((mnt = getmntent(mtab)))
  374             {
  375                 if (!streq(mnt->mnt_type, MNTTYPE_IGNORE) && !streq(mnt->mnt_type, MNTTYPE_SWAP))
  376                 {
  377                     if (streq(mnt->mnt_dir, dirpath.text()))
  378                     {
  379                         isMountpoint = true;
  380                         snprintf(buf, sizeof(buf)-1, _("Filesystem (%s)"), mnt->mnt_fsname);
  381                         type = buf;
  382                         strlcpy(mnttype, mnt->mnt_type, strlen(mnt->mnt_type)+1);
  383                     }
  384                 }
  385             }
  386             endmntent(mtab);
  387         }
  388 #endif
  389         // If it is a mount point
  390         if (isMountpoint)
  391         {
  392             // Caution : use the -P option to be POSIX compatible!
  393             snprintf(buf, sizeof(buf)-1, "df -P -B 1 '%s'", pathname.text());
  394             p = popen(buf, "r");
  395             FXbool success = true;
  396             if (fgets(buf, sizeof(buf), p) == NULL)
  397             {
  398                 success = false;
  399             }
  400             if (fgets(buf, sizeof(buf), p) == NULL)
  401             {
  402                 success = false;
  403             }
  404             if (success)
  405             {
  406                 strtok(buf, " ");
  407                 strtok(NULL, " ");
  408                 char* pstr;
  409                 pstr = strtok(NULL, " ");
  410                 strlcpy(used, pstr, strlen(pstr)+1);  // get used
  411                 pstr = strtok(NULL, " ");
  412                 strlcpy(avail, pstr, strlen(pstr)+1); // get available
  413                 pstr = strtok(NULL, " ");
  414                 strlcpy(pctr, pstr, strlen(pstr)+1);  // get percentage
  415             }
  416             else
  417             {
  418                 strlcpy(used, "", 1);
  419                 strlcpy(avail, "", 1);
  420                 strlcpy(pctr, "", 1);
  421             }
  422             pclose(p);
  423         }
  424 
  425         // If it is a folder
  426         else
  427         {
  428             type = _("Folder");
  429             nbseldirs = 1;
  430         }
  431     }
  432 
  433     else if (S_ISCHR(linfo.st_mode))
  434     {
  435         type = _("Character Device");
  436     }
  437     else if (S_ISBLK(linfo.st_mode))
  438     {
  439         type = _("Block Device");
  440     }
  441     else if (S_ISFIFO(linfo.st_mode))
  442     {
  443         type = _("Named Pipe");
  444     }
  445     else if (S_ISSOCK(linfo.st_mode))
  446     {
  447         type = _("Socket");
  448     }
  449 
  450     // Regular file or link
  451     else
  452     {
  453         // Try to use association table
  454         extension2 = FXPath::name(pathname).rafter('.', 2).lower();
  455         if ((extension2 == "tar.gz") || (extension2 == "tar.bz2") || (extension2 == "tar.xz") || (extension2 == "tar.z"))
  456         {
  457             extension = extension2;
  458         }
  459         else
  460         {
  461             extension = FXPath::name(pathname).rafter('.', 1).lower();
  462         }
  463 
  464         if (extension != "")
  465         {
  466             fileassoc = getApp()->reg().readStringEntry("FILETYPES", extension.text(), "");
  467         }
  468 
  469         // If we have an association
  470         if (!fileassoc.empty())
  471         {
  472             FXString c;
  473             type = fileassoc.section(';', 1);
  474             if (type == "")
  475             {
  476                 if (linfo.st_mode&(S_IXUSR|S_IXGRP|S_IXOTH))
  477                 {
  478                     type = _("Executable");
  479                     executable = true;
  480                 }
  481                 else
  482                 {
  483                     type = _("Document");
  484                 }
  485             }
  486             ext->setText(extension);
  487             c = fileassoc.section(';', 0);
  488             descr->setText(fileassoc.section(';', 1));
  489             open->setText(c.section(',', 0));
  490             view->setText(c.section(',', 1));
  491             if (edit)
  492             {
  493                 edit->setText(c.section(',', 2));
  494             }
  495             bigic->setText(fileassoc.section(';', 2));
  496             miniic->setText(fileassoc.section(';', 3));
  497             if (!isLink)
  498             {
  499                 fassoctab->enable();
  500             }
  501 
  502             // Load big and mini icons
  503             FXString iconpath = getApp()->reg().readStringEntry("SETTINGS", "iconpath", DEFAULTICONPATH);
  504 
  505             FXIcon* bigicon = loadiconfile(getApp(), iconpath, bigic->getText());
  506             if (bigicon)
  507             {
  508                 bigicbtn->setIcon(bigicon);
  509             }
  510 
  511             FXIcon* miniicon = loadiconfile(getApp(), iconpath, miniic->getText());
  512             if (miniicon)
  513             {
  514                 miniicbtn->setIcon(miniicon);
  515             }
  516         }
  517         else
  518         {
  519             ext->setText(extension);
  520             if (linfo.st_mode&(S_IXUSR|S_IXGRP|S_IXOTH))
  521             {
  522                 type = _("Executable");
  523                 executable = true;
  524             }
  525             else
  526             {
  527                 type = _("Document");
  528             }
  529             if (!isLink)
  530             {
  531                 fassoctab->enable();
  532             }
  533         }
  534     }
  535 
  536     // Modify file type for broken links
  537     if (isBrokenLink)
  538     {
  539         type = _("Broken link");
  540     }
  541 
  542     // For links, get the file type of the referred file
  543     else if (isLink)
  544     {
  545         struct stat info;
  546         if (statrep(referredpath.text(), &info) == 0)
  547         {
  548             // Folder
  549             if (S_ISDIR(info.st_mode))
  550             {
  551                 type = _("Folder");
  552             }
  553 
  554             // File
  555             else
  556             {
  557                 // Try to use association table
  558                 extension2 = FXPath::name(referredpath).rafter('.', 2).lower();
  559                 if ((extension2 == "tar.gz") || (extension2 == "tar.bz2") || (extension2 == "tar.xz") || (extension2 == "tar.z"))
  560                 {
  561                     extension = extension2;
  562                 }
  563                 else
  564                 {
  565                     extension = FXPath::name(referredpath).rafter('.', 1).lower();
  566                 }
  567 
  568                 if (extension != "")
  569                 {
  570                     fileassoc = getApp()->reg().readStringEntry("FILETYPES", extension.text(), "");
  571                 }
  572 
  573                 // If we have an association
  574                 if (!fileassoc.empty())
  575                 {
  576                     type = fileassoc.section(';', 1);
  577                 }
  578 
  579                 // No association
  580                 else
  581                 {
  582                     if (S_ISCHR(info.st_mode))
  583                     {
  584                         type = _("Character Device");
  585                     }
  586                     else if (S_ISBLK(info.st_mode))
  587                     {
  588                         type = _("Block Device");
  589                     }
  590                     else if (S_ISFIFO(info.st_mode))
  591                     {
  592                         type = _("Named Pipe");
  593                     }
  594                     else if (S_ISSOCK(info.st_mode))
  595                     {
  596                         type = _("Socket");
  597                     }
  598                     else if (info.st_mode&(S_IXUSR|S_IXGRP|S_IXOTH))
  599                     {
  600                         type = _("Executable");
  601                         executable = true;
  602                     }
  603                     else
  604                     {
  605                         type = _("Document");
  606                     }
  607                 }
  608             }
  609         }
  610         type = _("Link to ")+type;
  611     }
  612 
  613     // Parent directory name not editable
  614     if (file == "..")
  615     {
  616         input->setEditable(false);
  617     }
  618 
  619     // Root directory name not editable
  620     if ((file == "") && (path == ROOTDIR))
  621     {
  622         input->setText(ROOTDIR);
  623         input->setEditable(false);
  624     }
  625     else
  626     {
  627         input->setText(file);
  628     }
  629 
  630     input->setFocus();
  631 
  632     // Set permissions
  633     perm->ur->setCheck((linfo.st_mode & S_IRUSR) ? true : false);
  634     perm->uw->setCheck((linfo.st_mode & S_IWUSR) ? true : false);
  635     perm->ux->setCheck((linfo.st_mode & S_IXUSR) ? true : false);
  636 
  637     perm->gr->setCheck((linfo.st_mode & S_IRGRP) ? true : false);
  638     perm->gw->setCheck((linfo.st_mode & S_IWGRP) ? true : false);
  639     perm->gx->setCheck((linfo.st_mode & S_IXGRP) ? true : false);
  640 
  641     perm->or_->setCheck((linfo.st_mode & S_IROTH) ? true : false);
  642     perm->ow->setCheck((linfo.st_mode & S_IWOTH) ? true : false);
  643     perm->ox->setCheck((linfo.st_mode & S_IXOTH) ? true : false);
  644 
  645     perm->suid->setCheck((linfo.st_mode & S_ISUID) ? true : false);
  646     perm->sgid->setCheck((linfo.st_mode & S_ISGID) ? true : false);
  647     perm->svtx->setCheck((linfo.st_mode & S_ISVTX) ? true : false);
  648 
  649     perm->set->setCheck();
  650     perm->all->setCheck();
  651 
  652     FXLabel* mtType = NULL, *mtUsed = NULL, *mtFree = NULL, *fileType = NULL, *fileChanged = NULL, *fileAccessed = NULL, *fileModified = NULL;
  653     FXbool   isInTrash = false;
  654 
  655     fileSize = NULL;
  656 
  657     // Properties are different for mount points
  658     if (isMountpoint)
  659     {
  660         FXGroupBox* mtgroup = new FXGroupBox(generalframe, _("Mount point"), GROUPBOX_TITLE_LEFT|FRAME_GROOVE|LAYOUT_FILL_X);
  661         FXMatrix*   mtmatrix = new FXMatrix(mtgroup, 2, MATRIX_BY_COLUMNS|LAYOUT_FILL_X|LAYOUT_FILL_Y);
  662         new FXLabel(mtmatrix, _("Mount type:"), NULL, LAYOUT_LEFT|JUSTIFY_LEFT);
  663         fileType = new FXLabel(mtmatrix, FXString::null, NULL, LAYOUT_LEFT|LAYOUT_FILL_COLUMN|JUSTIFY_LEFT);
  664         new FXLabel(mtmatrix, _("Used:"), NULL, LAYOUT_LEFT);
  665         mtUsed = new FXLabel(mtmatrix, FXString::null, NULL, LAYOUT_LEFT|LAYOUT_FILL_COLUMN|JUSTIFY_LEFT);
  666         new FXLabel(mtmatrix, _("Free:"), NULL, LAYOUT_LEFT);
  667         mtFree = new FXLabel(mtmatrix, FXString::null, NULL, LAYOUT_LEFT|LAYOUT_FILL_COLUMN|JUSTIFY_LEFT);
  668         new FXLabel(mtmatrix, _("File system:"), NULL, LAYOUT_LEFT);
  669         mtType = new FXLabel(mtmatrix, FXString::null, NULL, LAYOUT_LEFT|LAYOUT_FILL_COLUMN|JUSTIFY_LEFT);
  670         new FXLabel(mtmatrix, _("Location:"), NULL, LAYOUT_LEFT);
  671         location = new TextLabel(mtmatrix, 30, 0, 0, LAYOUT_LEFT|LAYOUT_CENTER_Y|LAYOUT_FILL_ROW|FRAME_NONE);
  672         location->setBackColor(getApp()->getBaseColor());
  673     }
  674     else
  675     {
  676         FXGroupBox* attrgroup = new FXGroupBox(generalframe, _("Properties"), GROUPBOX_TITLE_LEFT|FRAME_GROOVE|LAYOUT_FILL_X);
  677         FXMatrix*   attrmatrix = new FXMatrix(attrgroup, 2, MATRIX_BY_COLUMNS|LAYOUT_FILL_X|LAYOUT_FILL_Y);
  678         new FXLabel(attrmatrix, _("Type:"), NULL, LAYOUT_LEFT);
  679         fileType = new FXLabel(attrmatrix, FXString::null, NULL, LAYOUT_LEFT|LAYOUT_FILL_COLUMN|JUSTIFY_LEFT);
  680         sizelabel = new FXLabel(attrmatrix, _("Total size:"), NULL, LAYOUT_LEFT);
  681         fileSize = new FXLabel(attrmatrix, "\n", NULL, LAYOUT_LEFT|LAYOUT_FILL_COLUMN|JUSTIFY_LEFT);
  682         new FXLabel(attrmatrix, FXString::null, NULL, LAYOUT_LEFT|JUSTIFY_LEFT);
  683         fileSizeDetails = new FXLabel(attrmatrix, FXString::null, NULL, LAYOUT_LEFT|JUSTIFY_LEFT);
  684         new FXLabel(attrmatrix, _("Location:"), NULL, LAYOUT_LEFT);
  685         location = new TextLabel(attrmatrix, 30, 0, 0, LAYOUT_LEFT|LAYOUT_CENTER_Y|LAYOUT_FILL_ROW|FRAME_NONE);
  686         location->setBackColor(getApp()->getBaseColor());
  687 
  688         if (isLink & !isBrokenLink)
  689         {
  690             new FXLabel(attrmatrix, _("Link to:"), NULL, LAYOUT_LEFT);
  691             linkto = new FXLabel(attrmatrix, FXString::null, NULL, LAYOUT_LEFT|LAYOUT_FILL_COLUMN);
  692         }
  693         else if (isBrokenLink)
  694         {
  695             new FXLabel(attrmatrix, _("Broken link to:"), NULL, LAYOUT_LEFT);
  696             linkto = new FXLabel(attrmatrix, FXString::null, NULL, LAYOUT_LEFT|LAYOUT_FILL_COLUMN);
  697         }
  698 
  699         // If the file is in the trash can
  700         if (parentdir.left(trashfileslocation.length()) == trashfileslocation)
  701         {
  702             isInTrash = true;
  703 
  704             new FXLabel(attrmatrix, _("Original location:"), NULL, LAYOUT_LEFT);
  705             origlocation = new FXLabel(attrmatrix, FXString::null, NULL, LAYOUT_LEFT|LAYOUT_FILL_COLUMN);
  706         }
  707 
  708         FXGroupBox* timegroup = new FXGroupBox(generalframe, _("File Time"), GROUPBOX_TITLE_LEFT|FRAME_GROOVE|LAYOUT_FILL_X);
  709         FXMatrix*   timematrix = new FXMatrix(timegroup, 2, MATRIX_BY_COLUMNS|LAYOUT_FILL_X|LAYOUT_FILL_Y);
  710         new FXLabel(timematrix, _("Last Modified:"), NULL, LAYOUT_LEFT);
  711         fileModified = new FXLabel(timematrix, FXString::null, NULL, LAYOUT_LEFT|LAYOUT_FILL_COLUMN);
  712         new FXLabel(timematrix, _("Last Changed:"), NULL, LAYOUT_LEFT);
  713         fileChanged = new FXLabel(timematrix, FXString::null, NULL, LAYOUT_LEFT|LAYOUT_FILL_COLUMN);
  714         new FXLabel(timematrix, _("Last Accessed:"), NULL, LAYOUT_LEFT);
  715         fileAccessed = new FXLabel(timematrix, FXString::null, NULL, LAYOUT_LEFT|LAYOUT_FILL_COLUMN);
  716 
  717 #ifdef STARTUP_NOTIFICATION
  718         sngroup = new FXGroupBox(generalframe, _("Startup Notification"), GROUPBOX_TITLE_LEFT|FRAME_GROOVE|LAYOUT_FILL_X);
  719         snbutton = new FXCheckButton(sngroup, _("Disable startup notification for this executable"), this, ID_SNDISABLE);
  720 
  721         sndisable_prev = false;
  722         FXString snexcepts = getApp()->reg().readStringEntry("OPTIONS", "startup_notification_exceptions", "");
  723         if (snexcepts != "")
  724         {
  725             FXString entry;
  726             for (int i = 0; ; i++)
  727             {
  728                 entry = snexcepts.section(':', i);
  729                 if (streq(entry.text(), ""))
  730                 {
  731                     break;
  732                 }
  733                 if (streq(entry.text(), filename.text()))
  734                 {
  735                     sndisable_prev = true;
  736                     break;
  737                 }
  738             }
  739         }
  740         snbutton->setCheck(sndisable_prev);
  741 #endif
  742 
  743         // If the file is in the trash can
  744         if (isInTrash)
  745         {
  746             new FXLabel(timematrix, _("Deletion Date:"), NULL, LAYOUT_LEFT);
  747             deletiondate = new FXLabel(timematrix, FXString::null, NULL, LAYOUT_LEFT|LAYOUT_FILL_COLUMN);
  748         }
  749     }
  750 
  751     // File or mount type
  752     fileType->setText(type.text());
  753 
  754     // Parent directory
  755     FXString text = parentdir;
  756 
  757     // Insert line breaks if text has one line and more than allowed number of characters
  758     if ((text.find('\n') < 0) && (text.length() > MAX_MESSAGE_LENGTH))
  759     {
  760         // Insert \n in the message every MAX_MESSAGE_LENGTH chars
  761         int nb = text.length()/MAX_MESSAGE_LENGTH;
  762         for (int n = 1; n <= nb; n++)
  763         {
  764             text.insert(n*MAX_MESSAGE_LENGTH, '\n');
  765         }
  766     }
  767 
  768     // Set location text
  769     location->setNumColumns(text.length());
  770     location->setText(text);
  771 
  772     // Referred file for valid or broken link
  773     if (isLink)
  774     {
  775         linkto->setText(referredpath);
  776     }
  777 
  778     // If directory
  779     if (isDirectory)
  780     {
  781         // if mount point
  782         if (isMountpoint)
  783         {
  784             hsize = ::hSize(used);
  785             snprintf(size, sizeof(size)-1, "%s (%s)", hsize.text(), pctr);
  786             mtUsed->setText(size);
  787             hsize = ::hSize(avail);
  788             mtFree->setText(hsize);
  789             mtType->setText(mnttype);
  790         }
  791         // if folder
  792         else
  793         {
  794             fileModified->setText(mod);
  795             fileChanged->setText(changed);
  796             fileAccessed->setText(accessed);
  797         }
  798     }
  799     // Regular file
  800     else
  801     {
  802 #if __WORDSIZE == 64
  803         snprintf(size, sizeof(size)-1, "%lu", filesize);
  804 #else
  805         snprintf(size, sizeof(size)-1, "%llu", filesize);
  806 #endif
  807         hsize = ::hSize(size);
  808 #if __WORDSIZE == 64
  809         snprintf(size, sizeof(size)-1, _("%s (%lu bytes)"), hsize.text(), filesize);
  810 #else
  811         snprintf(size, sizeof(size)-1, _("%s (%llu bytes)"), hsize.text(), filesize);
  812 #endif
  813         sizelabel->setText(_("Size:"));
  814         fileSize->setText(size);
  815         fileModified->setText(mod);
  816         fileChanged->setText(changed);
  817         fileAccessed->setText(accessed);
  818     }
  819 
  820     // If the file is in the trash can
  821     if (isInTrash)
  822     {
  823         // Obtain trash base name and sub path
  824         FXString subpath = parentdir+PATHSEPSTRING;
  825         subpath.erase(0, trashfileslocation.length()+1);
  826         FXString trashbasename = subpath.before('/');
  827         if (trashbasename == "")
  828         {
  829             trashbasename = FXPath::name(pathname);
  830         }
  831         subpath.erase(0, trashbasename.length());
  832 
  833         // Read the .trashinfo file
  834         FILE*    fp;
  835         char     line[1024];
  836         FXString origpath = "", delstr = "";
  837         FXlong   deldate = 0;
  838         FXbool   success = true;
  839         FXString trashinfopathname = trashinfolocation+PATHSEPSTRING+trashbasename+".trashinfo";
  840         if ((fp = fopen(trashinfopathname.text(), "r")) != NULL)
  841         {
  842             // Read the first three lines and get the strings
  843             if (fgets(line, sizeof(line), fp) == NULL)
  844             {
  845                 success = false;
  846             }
  847             if (fgets(line, sizeof(line), fp) == NULL)
  848             {
  849                 success = false;
  850             }
  851             if (success)
  852             {
  853                 origpath = line;
  854                 origpath = origpath.after('=');
  855                 origpath = origpath.before('\n');
  856             }
  857             if (fgets(line, sizeof(line), fp) == NULL)
  858             {
  859                 success = false;
  860             }
  861             if (success)
  862             {
  863                 delstr = line;
  864                 delstr = delstr.after('=');
  865                 delstr = delstr.before('\n');
  866             }
  867             fclose(fp);
  868         }
  869 
  870         // Eventually include sub path in the original path
  871         if (subpath == "")
  872         {
  873             origpath = origpath+subpath;
  874         }
  875         else
  876         {
  877             origpath = origpath+subpath+FXPath::name(pathname);
  878         }
  879 
  880         // Convert date
  881         deldate = deltime(delstr);
  882         if (deldate != 0)
  883         {
  884             delstr = FXSystem::time(timeformat.text(), deldate);
  885         }
  886 
  887         // Maybe there is no deletion information
  888         if (delstr != "")
  889         {
  890             origlocation->setText(origpath);
  891             deletiondate->setText(delstr);
  892         }
  893     }
  894 
  895     mode = orig_mode;
  896     perm->cmd = PropertiesBox::ID_SET;
  897     perm->flt = PropertiesBox::ID_ALL;
  898     files = &file;
  899     source = file;
  900     num = 1;
  901 
  902     descr_prev = descr->getText();
  903     open_prev = open->getText();
  904     view_prev = view->getText();
  905     if (edit)
  906     {
  907         edit_prev = edit->getText();
  908     }
  909     bigic_prev = bigic->getText();
  910     miniic_prev = miniic->getText();
  911 
  912     // Flag used to avoid computing recursive size more than once
  913     recsize = true;
  914 
  915     // Class variable initializations
  916     origlocation = NULL;
  917     deletiondate = NULL;
  918     name_encoding = NULL;
  919     username = NULL;
  920     grpname = NULL;
  921     pid = -1;
  922     totaldirsize = 0;
  923     totalnbfiles = 0;
  924     totalnbsubdirs = 0;
  925 }
  926 
  927 
  928 // Construct window for multiple files
  929 PropertiesBox::PropertiesBox(FXWindow* win, FXString* file, int n, FXString* path) : DialogBox(win, _("Properties"), DECOR_TITLE|DECOR_BORDER|DECOR_MAXIMIZE|DECOR_STRETCHABLE|DECOR_CLOSE)
  930 {
  931     struct stat linfo;
  932     FXString    grpid, usrid;
  933     FXString    type, extension, extension2, fileassoc;
  934     char        buf[MAXPATHLEN+1];
  935     int         i, nbselfiles = 0, dotdot = 0;
  936     FXbool      firstfile = true;
  937 
  938     isDirectory = false;
  939     nbseldirs = 0;
  940 
  941     // Buttons
  942     FXHorizontalFrame* buttons = new FXHorizontalFrame(this, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X, 0, 0, 0, 0, 10, 10, 5, 5);
  943 
  944     // Contents
  945     FXVerticalFrame* contents = new FXVerticalFrame(this, LAYOUT_SIDE_TOP|FRAME_NONE|LAYOUT_FILL_X|LAYOUT_FILL_Y);
  946 
  947     // Accept
  948     FXButton* ok = new FXButton(buttons, _("&Accept"), NULL, this, PropertiesBox::ID_ACCEPT_MULT, FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT|LAYOUT_CENTER_Y, 0, 0, 0, 0, 20, 20);
  949     ok->addHotKey(KEY_Return);
  950 
  951     // Cancel
  952     new FXButton(buttons, _("&Cancel"), NULL, this, PropertiesBox::ID_CANCEL, FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT|LAYOUT_CENTER_Y, 0, 0, 0, 0, 20, 20);
  953 
  954     // Switcher
  955     FXTabBook* tabbook = new FXTabBook(contents, NULL, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_RIGHT);
  956 
  957     // First item is General
  958     new FXTabItem(tabbook, _("&General"), NULL);
  959     FXVerticalFrame* generalframe = new FXVerticalFrame(tabbook, FRAME_RAISED);
  960     FXGroupBox*      attrgroup = new FXGroupBox(generalframe, _("Properties"), GROUPBOX_TITLE_LEFT|FRAME_GROOVE|LAYOUT_FILL_X|LAYOUT_FILL_Y);
  961     FXMatrix*        attrmatrix = new FXMatrix(attrgroup, 2, MATRIX_BY_COLUMNS|LAYOUT_FILL_X|LAYOUT_FILL_Y);
  962     new FXLabel(attrmatrix, _("Selection:"), NULL, LAYOUT_LEFT|JUSTIFY_LEFT);
  963     FXLabel* filesSelected = new FXLabel(attrmatrix, FXString::null, NULL, LAYOUT_LEFT|JUSTIFY_LEFT);
  964     new FXLabel(attrmatrix, FXString::null, NULL, LAYOUT_LEFT|JUSTIFY_LEFT);
  965     FXLabel* filesSelectedDetails = new FXLabel(attrmatrix, FXString::null, NULL, LAYOUT_LEFT|JUSTIFY_LEFT);
  966     new FXLabel(attrmatrix, _("Type:"), NULL, LAYOUT_LEFT|JUSTIFY_LEFT);
  967     FXLabel* filesType = new FXLabel(attrmatrix, FXString::null, NULL, LAYOUT_LEFT|JUSTIFY_LEFT);
  968     new FXLabel(attrmatrix, _("Total size:"), NULL, LAYOUT_LEFT|JUSTIFY_LEFT);
  969     fileSize = new FXLabel(attrmatrix, FXString::null, NULL, LAYOUT_LEFT|JUSTIFY_LEFT);
  970     new FXLabel(attrmatrix, FXString::null, NULL, LAYOUT_LEFT|JUSTIFY_LEFT);
  971     fileSizeDetails = new FXLabel(attrmatrix, FXString::null, NULL, LAYOUT_LEFT|JUSTIFY_LEFT);
  972 
  973     // Second item is Access Permissions
  974     new FXTabItem(tabbook, _("&Permissions"), NULL);
  975     perm = new PermFrame(tabbook, this);
  976 
  977     // Get file/link info of the first file of the list
  978     // This is used as a guess for the username, group and permissions of the whole list
  979     FXString pathname = path[0]+PATHSEPSTRING+file[0];
  980     if (lstatrep(pathname.text(), &linfo) != 0)
  981     {
  982         return;
  983     }
  984 
  985     // Obtain user name
  986     usrid = FXSystem::userName(linfo.st_uid);
  987 
  988     // Obtain group name
  989     grpid = FXSystem::groupName(linfo.st_gid);
  990 
  991     orig_mode = linfo.st_mode;
  992 
  993     perm->ur->setCheck((linfo.st_mode & S_IRUSR) ? true : false);
  994     perm->uw->setCheck((linfo.st_mode & S_IWUSR) ? true : false);
  995     perm->ux->setCheck((linfo.st_mode & S_IXUSR) ? true : false);
  996 
  997     perm->gr->setCheck((linfo.st_mode & S_IRGRP) ? true : false);
  998     perm->gw->setCheck((linfo.st_mode & S_IWGRP) ? true : false);
  999     perm->gx->setCheck((linfo.st_mode & S_IXGRP) ? true : false);
 1000 
 1001     perm->or_->setCheck((linfo.st_mode & S_IROTH) ? true : false);
 1002     perm->ow->setCheck((linfo.st_mode & S_IWOTH) ? true : false);
 1003     perm->ox->setCheck((linfo.st_mode & S_IXOTH) ? true : false);
 1004 
 1005     perm->suid->setCheck((linfo.st_mode & S_ISUID) ? true : false);
 1006     perm->sgid->setCheck((linfo.st_mode & S_ISGID) ? true : false);
 1007     perm->svtx->setCheck((linfo.st_mode & S_ISVTX) ? true : false);
 1008 
 1009     perm->add->setCheck();
 1010     perm->all->setCheck();
 1011 
 1012     perm->user->setText(usrid);
 1013     perm->grp->setText(grpid);
 1014 
 1015     mode = orig_mode;
 1016     perm->cmd = PropertiesBox::ID_SET;
 1017     perm->flt = PropertiesBox::ID_ALL;
 1018     files = file;
 1019     paths = path;
 1020     source = "";
 1021     num = n;
 1022 
 1023     // Number of selected files / directories and file type
 1024     for (i = 0; i < num; i++)
 1025     {
 1026         FXString pathname = paths[i]+PATHSEPSTRING+files[i];
 1027         if (lstatrep(pathname.text(), &linfo) != 0)
 1028         {
 1029             continue;
 1030         }
 1031 
 1032         // Special case of the ".." directory
 1033         if (files[i] == "..")
 1034         {
 1035             dotdot = 1;
 1036             continue;
 1037         }
 1038 
 1039         // Is it a directory?
 1040         isDirectory = S_ISDIR(linfo.st_mode);
 1041         if (isDirectory)
 1042         {
 1043             nbseldirs++;
 1044         }
 1045 
 1046         else // Regular file
 1047         {
 1048             nbselfiles++;
 1049 
 1050             // Try to use association table
 1051             extension2 = files[i].rafter('.', 2).lower();
 1052             if ((extension2 == "tar.gz") || (extension2 == "tar.bz2") || (extension2 == "tar.xz") || (extension2 == "tar.z"))
 1053             {
 1054                 extension = extension2;
 1055             }
 1056             else
 1057             {
 1058                 extension = extension = files[i].rafter('.', 1).lower();
 1059             }
 1060 
 1061             if (extension != "")
 1062             {
 1063                 fileassoc = getApp()->reg().readStringEntry("FILETYPES", extension.text(), "");
 1064             }
 1065 
 1066             // Keep the first encountered type
 1067             if (firstfile)
 1068             {
 1069                 // If we have an association
 1070                 if (!fileassoc.empty())
 1071                 {
 1072                     type = fileassoc.section(';', 1);
 1073                 }
 1074                 else
 1075                 {
 1076                     type = _("Document");
 1077                 }
 1078                 firstfile = false;
 1079             }
 1080             else
 1081             {
 1082                 // If we have an association
 1083                 if (!fileassoc.empty())
 1084                 {
 1085                     if (fileassoc.section(';', 1) != type)
 1086                     {
 1087                         type = _("Multiple types");
 1088                     }
 1089                 }
 1090                 else
 1091                 {
 1092                     if (type != _("Document"))
 1093                     {
 1094                         type = _("Multiple types");
 1095                     }
 1096                 }
 1097             }
 1098         }
 1099     }
 1100 
 1101     // Special cases of the file type
 1102     if (nbselfiles == 0)
 1103     {
 1104         type = _("Folder");
 1105     }
 1106 
 1107     if ((nbseldirs >= 1) && (nbselfiles >= 1))
 1108     {
 1109         type = _("Multiple types");
 1110     }
 1111 
 1112     // Number of selected files
 1113     snprintf(buf, sizeof(buf)-1, _("%d items"), num);
 1114     filesSelected->setText(buf);
 1115 
 1116     if (nbselfiles <= 1 && nbseldirs+dotdot <= 1)
 1117     {
 1118         snprintf(buf, sizeof(buf)-1, _("%d file, %d folder"), nbselfiles, nbseldirs+dotdot);
 1119     }
 1120     else if (nbselfiles <= 1 && nbseldirs+dotdot > 1)
 1121     {
 1122         snprintf(buf, sizeof(buf)-1, _("%d file, %d folders"), nbselfiles, nbseldirs+dotdot);
 1123     }
 1124     else if (nbselfiles > 1 && nbseldirs+dotdot <= 1)
 1125     {
 1126         snprintf(buf, sizeof(buf)-1, _("%d files, %d folder"), nbselfiles, nbseldirs+dotdot);
 1127     }
 1128     else
 1129     {
 1130         snprintf(buf, sizeof(buf)-1, _("%d files, %d folders"), nbselfiles, nbseldirs+dotdot);
 1131     }
 1132 
 1133     filesSelectedDetails->setText(buf);
 1134 
 1135     // Display type of selected files
 1136     filesType->setText(type);
 1137 
 1138     // Flag used to avoid computing recursive size more than once
 1139     recsize = true;
 1140 
 1141     // Class variable initializations
 1142     executable = false;
 1143     isMountpoint = false;
 1144 #ifdef STARTUP_NOTIFICATION
 1145     snbutton = NULL;
 1146     sngroup = NULL;
 1147     sndisable_prev = false;
 1148 #endif
 1149     input = NULL;
 1150     username = NULL;
 1151     grpname = NULL;
 1152     open = NULL;
 1153     view = NULL;
 1154     edit = NULL;
 1155     descr = NULL;
 1156     bigic = NULL;
 1157     bigicbtn = NULL;
 1158     miniic = NULL;
 1159     miniicbtn = NULL;
 1160     location = NULL;
 1161     origlocation = NULL;
 1162     linkto = NULL;
 1163     deletiondate = NULL;
 1164     ext = NULL;
 1165     name_encoding = NULL;
 1166     pid = -1;
 1167     totaldirsize = 0;
 1168     totalnbfiles = 0;
 1169     totalnbsubdirs = 0;
 1170 }
 1171 
 1172 
 1173 // Make window
 1174 void PropertiesBox::create()
 1175 {
 1176     DialogBox::create();
 1177 }
 1178 
 1179 
 1180 // Dialog for single selected file
 1181 long PropertiesBox::onCmdAcceptSingle(FXObject* o, FXSelector s, void* p)
 1182 {
 1183     char**   str = NULL;
 1184     int      rc = 0;
 1185     File*    f = NULL;
 1186     char     file[MAXPATHLEN];
 1187     FXString oldfileassoc, fileassoc, op, v, e;
 1188 
 1189     FXbool confirm = false;
 1190     
 1191 #ifdef STARTUP_NOTIFICATION
 1192     if (executable && snbutton->getCheck() != sndisable_prev)
 1193     {
 1194         confirm = true;
 1195     }
 1196 #endif
 1197     
 1198     FXbool cond;
 1199     if (edit) // Condition is not the same if edit exist or not
 1200     {
 1201         cond = (open->getText() != open_prev || view->getText() != view_prev || edit->getText() != edit_prev ||
 1202                 descr->getText() != descr_prev || bigic->getText() != bigic_prev || miniic->getText() != miniic_prev);
 1203     }
 1204     else
 1205     {
 1206         cond = (open->getText() != open_prev || view->getText() != view_prev || descr->getText() != descr_prev ||
 1207                 bigic->getText() != bigic_prev || miniic->getText() != miniic_prev);
 1208     }
 1209     
 1210     if (cond)
 1211     {
 1212         confirm = true;
 1213     }
 1214 
 1215     // Source and target path names
 1216     FXString targetpath;
 1217     FXString sourcepath = parentdir+"/"+source;
 1218     FXString target = input->getText();
 1219     FXString targetparentdir = FXPath::directory(target);
 1220     if (targetparentdir == "")
 1221     {
 1222         targetparentdir = parentdir;
 1223         targetpath = targetparentdir+"/"+target;
 1224     }
 1225     else
 1226     {
 1227         targetpath = target;
 1228     }
 1229 
 1230     if (source != target)
 1231     {
 1232         confirm = true;
 1233     }
 1234 
 1235     if ((oldgrp != perm->grp->getText()) || (oldusr != perm->user->getText()) || perm->rec->getCheck())
 1236     {
 1237         confirm = true;
 1238     }
 1239 
 1240     if (!perm->own->getCheck() && ((mode != orig_mode) || perm->rec->getCheck()))
 1241     {
 1242         confirm = true;
 1243     }
 1244 
 1245     FXbool confirm_properties = getApp()->reg().readUnsignedEntry("OPTIONS", "confirm_properties", true);
 1246 
 1247     if (confirm == true && confirm_properties == true)
 1248     {
 1249         FXString message;
 1250         if (::isDirectory(sourcepath))
 1251         {
 1252             message = _("Change properties of the selected folder?");
 1253         }
 1254         else
 1255         {
 1256             message = _("Change properties of the selected file?");
 1257         }
 1258 
 1259         MessageBox box(this, _("Confirm Change Properties"), message, bigattribicon, BOX_OK_CANCEL|DECOR_TITLE|DECOR_BORDER);
 1260 
 1261 
 1262         if (box.execute(PLACEMENT_CURSOR) != BOX_CLICKED_OK)
 1263         {
 1264             return(0);
 1265         }
 1266     }
 1267 
 1268     // Kill child process, if exists
 1269     if (pid >0)
 1270     {
 1271         kill(pid, SIGTERM);
 1272         
 1273         pid = -1;
 1274 
 1275         totaldirsize = 0;
 1276         totalnbfiles = 0;
 1277         totalnbsubdirs = 0;
 1278     
 1279         getApp()->removeChore(this, ID_WATCHPROCESS);
 1280     }
 1281 
 1282 #ifdef STARTUP_NOTIFICATION
 1283     // If file is an executable file
 1284     if (executable)
 1285     {
 1286         FXbool sndisable = snbutton->getCheck();
 1287         if (sndisable != sndisable_prev)
 1288         {
 1289             // List of startup notification exceptions
 1290             FXString snexcepts = getApp()->reg().readStringEntry("OPTIONS", "startup_notification_exceptions", "");
 1291 
 1292             // Add to list if not already present
 1293             if (sndisable)
 1294             {
 1295                 FXbool notinlist = true;
 1296                 if (snexcepts != "")
 1297                 {
 1298                     FXString entry;
 1299                     for (int i = 0; ; i++)
 1300                     {
 1301                         entry = snexcepts.section(':', i);
 1302                         if (streq(entry.text(), ""))
 1303                         {
 1304                             break;
 1305                         }
 1306                         if (streq(entry.text(), filename.text()))
 1307                         {
 1308                             notinlist = false;
 1309                             break;
 1310                         }
 1311                     }
 1312                 }
 1313 
 1314                 if (notinlist)
 1315                 {
 1316                     snexcepts += filename + ":";
 1317                 }
 1318             }
 1319 
 1320             // Remove from list if already present
 1321             else
 1322             {
 1323                 FXbool inlist = false;
 1324                 int    pos = 0;
 1325                 if (snexcepts != "")
 1326                 {
 1327                     FXString entry;
 1328                     for (int i = 0; ; i++)
 1329                     {
 1330                         entry = snexcepts.section(':', i);
 1331                         if (streq(entry.text(), ""))
 1332                         {
 1333                             break;
 1334                         }
 1335                         if (streq(entry.text(), filename.text()))
 1336                         {
 1337                             inlist = true;
 1338                             break;
 1339                         }
 1340                         pos += entry.length()+1;
 1341                     }
 1342                 }
 1343 
 1344                 if (inlist)
 1345                 {
 1346                     snexcepts.erase(pos, filename.length()+1);
 1347                 }
 1348             }
 1349 
 1350             // Write updated list to the registry
 1351             getApp()->reg().writeStringEntry("OPTIONS", "startup_notification_exceptions", snexcepts.text());
 1352             getApp()->reg().write();
 1353         }
 1354     }
 1355 #endif
 1356 
 1357     if (cond)
 1358     {
 1359         op = open->getText();
 1360         v = view->getText();
 1361         if (!v.empty())
 1362         {
 1363             v = "," + v;
 1364         }
 1365         if (edit)
 1366         {
 1367             e = edit->getText();
 1368             if (!e.empty())
 1369             {
 1370                 e = "," + e;
 1371             }
 1372         }
 1373 
 1374         fileassoc = ext->getText();
 1375         fileassoc += "=";
 1376         fileassoc += op + v + e + ";";
 1377         fileassoc += descr->getText() + ";";
 1378         fileassoc += bigic->getText() + ";" + miniic->getText() + ";;";
 1379 
 1380         if (ext->getText() != "")
 1381         {
 1382             oldfileassoc = getApp()->reg().readStringEntry("FILETYPES", ext->getText().text(), "");
 1383             if ((oldfileassoc == "") || (fileassoc.section('=', 1) != oldfileassoc))
 1384             {
 1385                 FXString command = fileassoc.section('=', 1);
 1386                 getApp()->reg().writeStringEntry("FILETYPES", ext->getText().text(), command.text());
 1387 
 1388                 // Handle file association
 1389                 str = new char* [2];
 1390                 str[0] = new char[strlen(ext->getText().text())+1];
 1391                 str[1] = new char[strlen(command.text())+1];
 1392                 strlcpy(str[0], ext->getText().text(), ext->getText().length()+1);
 1393                 strlcpy(str[1], command.text(), command.length()+1);
 1394                 mainWindow->handle(this, FXSEL(SEL_COMMAND, XFileExplorer::ID_FILE_ASSOC), str);
 1395             }
 1396         }
 1397     }
 1398 
 1399     if ( target == "" || target == ".." || target == "." )
 1400     {
 1401         MessageBox::warning(this, BOX_OK, _("Warning"), _("Invalid file name, operation cancelled"));
 1402         input->setText(source);
 1403         return(0);
 1404     }
 1405 
 1406     // Rename file if necessary
 1407     if (source != target)
 1408     {
 1409         // Target name contains '/'
 1410         if (target.contains(PATHSEPCHAR))
 1411         {
 1412             if (::isDirectory(sourcepath))
 1413             {
 1414                 MessageBox::warning(this, BOX_OK, _("Warning"), _("The / character is not allowed in folder names, operation cancelled"));
 1415             }
 1416             else
 1417             {
 1418                 MessageBox::warning(this, BOX_OK, _("Warning"), _("The / character is not allowed in file names, operation cancelled"));
 1419             }
 1420             input->setText(source);
 1421             return(0);
 1422         }
 1423 
 1424         // Source path is not writable
 1425         if (!::isWritable(sourcepath))
 1426         {
 1427             MessageBox::error(this, BOX_OK_SU, _("Error"), _("Can't write to %s: Permission denied"), source.text());
 1428             return(0);
 1429         }
 1430 
 1431         // Target parent directory doesn't exist or is not writable
 1432         if (!::exists(targetparentdir))
 1433         {
 1434             MessageBox::error(this, BOX_OK, _("Error"), _("Folder %s doesn't exist"), targetparentdir.text());
 1435             return(0);
 1436         }
 1437         if (!::isWritable(targetparentdir))
 1438         {
 1439             MessageBox::error(this, BOX_OK_SU, _("Error"), _("Can't write to %s: Permission denied"), targetparentdir.text());
 1440             return(0);
 1441         }
 1442 
 1443         // Rename file or directory
 1444         else
 1445         {
 1446             File* f;
 1447             f = new File(this, _("File rename"), RENAME);
 1448             f->create();
 1449             f->rename(sourcepath, targetpath);
 1450             delete f;
 1451         }
 1452     }
 1453 
 1454     // Change perm
 1455 
 1456     // Caution : chown must be done *before* chmod because chown can clear suid and sgid bits
 1457 
 1458     // Chown only if user or group have changed or recursive flag is set
 1459     rc = 0;
 1460     if ((oldgrp != perm->grp->getText()) || (oldusr != perm->user->getText()) || perm->rec->getCheck())
 1461     {
 1462         f = new File(this, _("File owner"), CHOWN);
 1463         f->create();
 1464 
 1465         uid_t          uid = 32768;
 1466         gid_t          gid = 32768;
 1467         struct passwd* pwde;
 1468         while ((pwde = getpwent()))
 1469         {
 1470             if (perm->user->getText() == pwde->pw_name)
 1471             {
 1472                 uid = pwde->pw_uid;
 1473             }
 1474         }
 1475         endpwent();
 1476 
 1477         struct group* grpe;
 1478         while ((grpe = getgrent()))
 1479         {
 1480             if (perm->grp->getText() == grpe->gr_name)
 1481             {
 1482                 gid = grpe->gr_gid;
 1483             }
 1484         }
 1485         endgrent();
 1486 
 1487         // Wait cursor
 1488         getApp()->beginWaitCursor();
 1489 
 1490         // Perform chown on the selected file or directory
 1491         errno = 0;
 1492         rc = f->chown((char*)targetpath.text(), file, uid, gid, perm->rec->getCheck(), perm->dironly->getCheck(), perm->fileonly->getCheck());
 1493         int errcode = errno;
 1494 
 1495         // If action is cancelled in progress dialog
 1496         if (f->isCancelled())
 1497         {
 1498             f->hideProgressDialog();
 1499             MessageBox::error(this, BOX_OK, _("Warning"), _("Change owner cancelled!"));
 1500             delete f;
 1501             getApp()->endWaitCursor();
 1502             return(0);
 1503         }
 1504         getApp()->endWaitCursor();
 1505 
 1506         // Handle chown errors
 1507         if (rc)
 1508         {
 1509             f->hideProgressDialog();
 1510             if (errcode)
 1511             {
 1512                 MessageBox::error(this, BOX_OK, _("Error"), _("Chown in %s failed: %s"), file, strerror(errcode));
 1513             }
 1514             else
 1515             {
 1516                 MessageBox::error(this, BOX_OK, _("Error"), _("Chown in %s failed"), file);
 1517             }
 1518             delete f;
 1519             return(0);
 1520         }
 1521         delete f;
 1522     }
 1523 
 1524     // Chmod if owner only is not set and permissions are changed or recursive flag is set
 1525     if (!perm->own->getCheck() && ((mode != orig_mode) || perm->rec->getCheck()))
 1526     {
 1527         if (perm->suid->getCheck() || perm->sgid->getCheck() || perm->svtx->getCheck())
 1528         {
 1529             if (BOX_CLICKED_CANCEL == MessageBox::warning(this, BOX_OK_CANCEL, _("Warning"), _("Setting special permissions could be unsafe! Is that you really want to do?")))
 1530             {
 1531                 return(0);
 1532             }
 1533         }
 1534 
 1535         struct stat linfo;
 1536         mode_t m;
 1537         
 1538         // Cannot stat target
 1539         if (lstatrep(targetpath.text(), &linfo) != 0)
 1540         {
 1541             MessageBox::error(this, BOX_OK, _("Error"), _("Chmod in %s failed: %s"), file, strerror(errno));
 1542             return(0);
 1543         }
 1544 
 1545         f = new File(this, _("File permissions"), CHMOD);
 1546         f->create();
 1547 
 1548         switch (perm->cmd)
 1549         {
 1550         case PropertiesBox::ID_ADD:
 1551             m = linfo.st_mode|mode;
 1552             break;
 1553 
 1554         case PropertiesBox::ID_CLEAR:
 1555             m = linfo.st_mode & ~mode;
 1556             break;
 1557 
 1558         case PropertiesBox::ID_SET:
 1559             m = mode;
 1560             break;
 1561 
 1562         default:
 1563             delete f;
 1564             return(0);
 1565         }
 1566 
 1567         // Wait cursor
 1568         getApp()->beginWaitCursor();
 1569 
 1570         // Perform chmod on the selected file or directory
 1571         errno = 0;
 1572         rc = f->chmod((char*)targetpath.text(), file, m, perm->rec->getCheck(), perm->dironly->getCheck(), perm->fileonly->getCheck());
 1573         int errcode = errno;
 1574 
 1575         // If action is cancelled in progress dialog
 1576         if (f->isCancelled())
 1577         {
 1578             f->hideProgressDialog();
 1579             MessageBox::error(this, BOX_OK, _("Warning"), _("Change file permissions cancelled!"));
 1580             delete f;
 1581             getApp()->endWaitCursor();
 1582             return(0);
 1583         }
 1584         getApp()->endWaitCursor();
 1585 
 1586         // Handle chmod errors
 1587         if (rc)
 1588         {
 1589             f->hideProgressDialog();
 1590             if (errcode)
 1591             {
 1592                 MessageBox::error(this, BOX_OK, _("Error"), _("Chmod in %s failed: %s"), file, strerror(errcode));
 1593             }
 1594             else
 1595             {
 1596                 MessageBox::error(this, BOX_OK, _("Error"), _("Chmod in %s failed"), file);
 1597             }
 1598             delete f;
 1599             return(0);
 1600         }
 1601         delete f;
 1602     }
 1603 
 1604     DialogBox::onCmdAccept(o, s, p);
 1605 
 1606     // Redraw file lists
 1607     ((XFileExplorer*)mainWindow)->deselectAll();
 1608     ((XFileExplorer*)mainWindow)->refreshPanels();
 1609 
 1610     // Delete object
 1611     delete this;
 1612 
 1613     return(1);
 1614 }
 1615 
 1616 
 1617 // Dialog for multiple selected files
 1618 long PropertiesBox::onCmdAcceptMult(FXObject* o, FXSelector s, void* p)
 1619 {
 1620     int   rc = 0, i;
 1621     File* f = NULL;
 1622     char  file[MAXPATHLEN];
 1623 
 1624     FXbool confirm_properties = getApp()->reg().readUnsignedEntry("OPTIONS", "confirm_properties", true);
 1625 
 1626     if (confirm_properties)
 1627     {
 1628         MessageBox box(this, _("Confirm Change Properties"), _("Apply permissions to the selected items?"), bigattribicon, BOX_OK_CANCEL|DECOR_TITLE|DECOR_BORDER);
 1629         if (box.execute(PLACEMENT_CURSOR) != BOX_CLICKED_OK)
 1630         {
 1631             return(0);
 1632         }
 1633     }
 1634 
 1635     // Kill child process, if exists
 1636     if (pid >0)
 1637     {
 1638         kill(pid, SIGTERM);
 1639         
 1640         pid = -1;
 1641 
 1642         totaldirsize = 0;
 1643         totalnbfiles = 0;
 1644         totalnbsubdirs = 0;
 1645     
 1646         getApp()->removeChore(this, ID_WATCHPROCESS);
 1647     }
 1648 
 1649     // Caution : chown must be done *before* chmod because chown can clear suid and sgid bits
 1650 
 1651     // Chown
 1652     rc = 0;
 1653     f = new File(this, _("File owner"), CHOWN);
 1654     f->create();
 1655 
 1656     // Wait cursor
 1657     getApp()->beginWaitCursor();
 1658 
 1659     for (i = 0; i < num; i++)
 1660     {
 1661         struct stat linfo;
 1662         FXString    pathname = FXPath::absolute(paths[i], files[i]);
 1663         if (lstatrep(pathname.text(), &linfo) != 0)
 1664         {
 1665             continue;
 1666         }
 1667 
 1668         uid_t          uid = 32768;
 1669         gid_t          gid = 32768;
 1670         struct passwd* pwde;
 1671         while ((pwde = getpwent()))
 1672         {
 1673             if (perm->user->getText() == pwde->pw_name)
 1674             {
 1675                 uid = pwde->pw_uid;
 1676             }
 1677         }
 1678         endpwent();
 1679 
 1680         struct group* grpe;
 1681         while ((grpe = getgrent()))
 1682         {
 1683             if (perm->grp->getText() == grpe->gr_name)
 1684             {
 1685                 gid = grpe->gr_gid;
 1686             }
 1687         }
 1688         endgrent();
 1689 
 1690         errno = 0;
 1691         if (files[i] != "..")
 1692         {
 1693             rc = f->chown((char*)pathname.text(), file, uid, gid, perm->rec->getCheck(), perm->dironly->getCheck(), perm->fileonly->getCheck());
 1694         }
 1695         int errcode = errno;
 1696 
 1697         // If action is cancelled in progress dialog
 1698         if (f->isCancelled())
 1699         {
 1700             f->hideProgressDialog();
 1701             MessageBox::error(this, BOX_OK, _("Warning"), _("Change owner cancelled!"));
 1702             delete f;
 1703             getApp()->endWaitCursor();
 1704             return(0);
 1705         }
 1706 
 1707         // Handle chown errors
 1708         if (rc)
 1709         {
 1710             f->hideProgressDialog();
 1711             if (errcode)
 1712             {
 1713                 MessageBox::error(this, BOX_OK, _("Error"), _("Chown in %s failed: %s"), file, strerror(errcode));
 1714             }
 1715             else
 1716             {
 1717                 MessageBox::error(this, BOX_OK, _("Error"), _("Chown in %s failed"), file);
 1718             }
 1719             delete f;
 1720             getApp()->endWaitCursor();
 1721             return(0);
 1722         }
 1723     }
 1724     delete f;
 1725     getApp()->endWaitCursor();
 1726 
 1727     // Chmod if owner only is not set
 1728     if (!perm->own->getCheck())
 1729     {
 1730         if (perm->suid->getCheck() || perm->sgid->getCheck() || perm->svtx->getCheck())
 1731         {
 1732             if (BOX_CLICKED_CANCEL == MessageBox::warning(this, BOX_OK_CANCEL, _("Warning"), _("Setting special permissions could be unsafe! Is that you really want to do?")))
 1733             {
 1734                 return(0);
 1735             }
 1736         }
 1737 
 1738         f = new File(this, _("File permissions"), CHMOD);
 1739         f->create();
 1740 
 1741         // Wait cursor
 1742         getApp()->beginWaitCursor();
 1743 
 1744         for (i = 0; i < num; i++)
 1745         {
 1746             struct stat linfo;
 1747             mode_t      m;
 1748 
 1749             FXString pathname = FXPath::absolute(paths[i], files[i]);
 1750             if (lstatrep(pathname.text(), &linfo) != 0)
 1751             {
 1752                 continue;
 1753             }
 1754 
 1755             switch (perm->cmd)
 1756             {
 1757             case PropertiesBox::ID_ADD:
 1758                 m = linfo.st_mode|mode;
 1759                 break;
 1760 
 1761             case PropertiesBox::ID_CLEAR:
 1762                 m = linfo.st_mode & ~mode;
 1763                 break;
 1764 
 1765             case PropertiesBox::ID_SET:
 1766                 m = mode;
 1767                 break;
 1768 
 1769             default:
 1770                 delete f;
 1771                 getApp()->endWaitCursor();
 1772                 return(0);
 1773             }
 1774 
 1775             if ((files[i] != "..") && !perm->own->getCheck())
 1776             {
 1777                 errno = 0;
 1778                 rc = f->chmod((char*)pathname.text(), file, m, perm->rec->getCheck(), perm->dironly->getCheck(), perm->fileonly->getCheck());
 1779                 int errcode = errno;
 1780 
 1781                 // If action is cancelled in progress dialog
 1782                 if (f->isCancelled())
 1783                 {
 1784                     f->hideProgressDialog();
 1785                     MessageBox::error(this, BOX_OK, _("Warning"), _("Change file(s) permissions cancelled!"));
 1786                     delete f;
 1787                     getApp()->endWaitCursor();
 1788                     return(0);
 1789                 }
 1790 
 1791                 // Handle chmod errors
 1792                 if (rc)
 1793                 {
 1794                     f->hideProgressDialog();
 1795                     if (errcode)
 1796                     {
 1797                         MessageBox::error(this, BOX_OK, _("Error"), _("Chmod in %s failed: %s"), file, strerror(errcode));
 1798                     }
 1799                     else
 1800                     {
 1801                         MessageBox::error(this, BOX_OK, _("Error"), _("Chmod in %s failed"), file);
 1802                     }
 1803                     delete f;
 1804                     getApp()->endWaitCursor();
 1805                     return(0);
 1806                 }
 1807             }
 1808         }
 1809         delete f;
 1810         getApp()->endWaitCursor();
 1811     }
 1812 
 1813     DialogBox::onCmdAccept(o, s, p);
 1814 
 1815     // Redraw the file lists
 1816     ((XFileExplorer*)mainWindow)->deselectAll();
 1817     ((XFileExplorer*)mainWindow)->refreshPanels();
 1818     
 1819     delete[]files;
 1820     delete[]paths;
 1821     delete this;
 1822 
 1823     return(1);
 1824 }
 1825 
 1826 
 1827 // Cancel dialog
 1828 long PropertiesBox::onCmdCancel(FXObject* o, FXSelector s, void* p)
 1829 {
 1830     // Kill child process, if exists
 1831     if (pid >0)
 1832     {
 1833         kill(pid, SIGTERM);
 1834         
 1835         pid = -1;
 1836         
 1837         totaldirsize = 0;
 1838         totalnbfiles = 0;
 1839         totalnbsubdirs = 0;
 1840 
 1841         getApp()->removeChore(this, ID_WATCHPROCESS);
 1842     }
 1843 
 1844     DialogBox::onCmdCancel(o, s, p);
 1845 
 1846     delete this;
 1847 
 1848     return(1);
 1849 }
 1850 
 1851 
 1852 long PropertiesBox::onCmdCommand(FXObject* o, FXSelector s, void* p)
 1853 {
 1854     perm->cmd = FXSELID(s);
 1855     return(1);
 1856 }
 1857 
 1858 
 1859 long PropertiesBox::onCmdFilter(FXObject* o, FXSelector s, void* p)
 1860 {
 1861     perm->flt = FXSELID(s);
 1862     return(1);
 1863 }
 1864 
 1865 
 1866 long PropertiesBox::onCmdCheck(FXObject* o, FXSelector s, void* p)
 1867 {
 1868     int xmode = 0;
 1869 
 1870     switch (FXSELID(s))
 1871     {
 1872     case PropertiesBox::ID_RUSR:
 1873         xmode = S_IRUSR;
 1874         break;
 1875 
 1876     case PropertiesBox::ID_WUSR:
 1877         xmode = S_IWUSR;
 1878         break;
 1879 
 1880     case PropertiesBox::ID_XUSR:
 1881         xmode = S_IXUSR;
 1882         break;
 1883 
 1884     case PropertiesBox::ID_RGRP:
 1885         xmode = S_IRGRP;
 1886         break;
 1887 
 1888     case PropertiesBox::ID_WGRP:
 1889         xmode = S_IWGRP;
 1890         break;
 1891 
 1892     case PropertiesBox::ID_XGRP:
 1893         xmode = S_IXGRP;
 1894         break;
 1895 
 1896     case PropertiesBox::ID_ROTH:
 1897         xmode = S_IROTH;
 1898         break;
 1899 
 1900     case PropertiesBox::ID_WOTH:
 1901         xmode = S_IWOTH;
 1902         break;
 1903 
 1904     case PropertiesBox::ID_XOTH:
 1905         xmode = S_IXOTH;
 1906         break;
 1907 
 1908     case PropertiesBox::ID_SUID:
 1909         xmode = S_ISUID;
 1910         break;
 1911 
 1912     case PropertiesBox::ID_SGID:
 1913         xmode = S_ISGID;
 1914         break;
 1915 
 1916     case PropertiesBox::ID_SVTX:
 1917         xmode = S_ISVTX;
 1918         break;
 1919     }
 1920     FXCheckButton* ch = (FXCheckButton*)o;
 1921     if (!ch->getCheck())
 1922     {
 1923         mode &= ~xmode;
 1924     }
 1925     else
 1926     {
 1927         mode |= xmode;
 1928     }
 1929 
 1930     return(1);
 1931 }
 1932 
 1933 
 1934 long PropertiesBox::onCmdBrowse(FXObject* o, FXSelector s, void* p)
 1935 {
 1936     FileDialog  browseProgram(this, _("Select an executable file"));
 1937     const char* patterns[] =
 1938     {
 1939         _("All files"), "*", NULL
 1940     };
 1941 
 1942     browseProgram.setFilename(ROOTDIR);
 1943     browseProgram.setPatternList(patterns);
 1944     browseProgram.setSelectMode(SELECT_FILE_EXISTING);
 1945     if (browseProgram.execute())
 1946     {
 1947         FXString path = browseProgram.getFilename();
 1948         switch (FXSELID(s))
 1949         {
 1950         case ID_BROWSE_OPEN:
 1951             open->setText(FXPath::name(path));
 1952             break;
 1953 
 1954         case ID_BROWSE_VIEW:
 1955             view->setText(FXPath::name(path));
 1956             break;
 1957 
 1958         case ID_BROWSE_EDIT:
 1959             if (edit)
 1960             {
 1961                 edit->setText(FXPath::name(path));
 1962             }
 1963             break;
 1964         }
 1965     }
 1966     return(1);
 1967 }
 1968 
 1969 
 1970 long PropertiesBox::onCmdBrowseIcon(FXObject* o, FXSelector s, void* p)
 1971 {
 1972     FXString icon;
 1973 
 1974     if (FXSELID(s) == ID_BIG_ICON)
 1975     {
 1976         icon = bigic->getText();
 1977     }
 1978     else
 1979     {
 1980         icon = miniic->getText();
 1981     }
 1982 
 1983     FXString    iconpath = getApp()->reg().readStringEntry("SETTINGS", "iconpath", DEFAULTICONPATH);
 1984     const char* patterns[] =
 1985     {
 1986         _("PNG Images"), "*.png",
 1987         _("GIF Images"), "*.gif",
 1988         _("BMP Images"), "*.bmp", NULL
 1989     };
 1990     FileDialog browseIcon(this, _("Select an icon file"));
 1991     browseIcon.setFilename(iconpath+PATHSEPSTRING+icon);
 1992     browseIcon.setPatternList(patterns);
 1993     browseIcon.setSelectMode(SELECT_FILE_EXISTING);
 1994     if (browseIcon.execute())
 1995     {
 1996         FXString path;
 1997 
 1998         path = browseIcon.getFilename();
 1999         if (!::exists(path))
 2000         {
 2001             return(0);
 2002         }
 2003         if (FXSELID(s) == ID_BIG_ICON)
 2004         {
 2005             // Load big icon
 2006             bigic->setText(path);
 2007 
 2008             FXIcon* bigicon = loadiconfile(getApp(), path, bigic->getText());
 2009             if (bigicon)
 2010             {
 2011                 bigicbtn->setIcon(bigicon);
 2012             }
 2013         }
 2014         else
 2015         {
 2016             // Load mini icon
 2017             miniic->setText(path);
 2018 
 2019             FXIcon* miniicon = loadiconfile(getApp(), path, miniic->getText());
 2020             miniicbtn->setIcon(miniicon);
 2021         }
 2022     }
 2023     return(1);
 2024 }
 2025 
 2026 
 2027 // Watch progress of child process
 2028 long PropertiesBox::onWatchProcess(FXObject*, FXSelector, void*)
 2029 {
 2030     char buf[1024];
 2031     char size[256];
 2032     int nread;
 2033 
 2034 
 2035     FXString strbuf, hsize;
 2036     FXString dsize, subdirs, files;
 2037     FXuint nbsubdirs=0, nbfiles;
 2038     FXulong dirsize;
 2039 
 2040     if ((waitpid(pid, NULL, WNOHANG) == 0))
 2041     {
 2042         // Child is still running, just wait
 2043         getApp()->addChore(this, ID_WATCHPROCESS);
 2044 
 2045         // Read data from the running child (first, set I-O to non-blocking)
 2046         int pflags;
 2047         if ((pflags = fcntl(pipes[0], F_GETFL)) >= 0)
 2048         {
 2049             pflags |= O_NONBLOCK;
 2050             if (fcntl(pipes[0], F_SETFL, pflags) >= 0)
 2051             {
 2052                 // Now read the data from the pipe
 2053                 while ((nread = read(pipes[0], buf, sizeof(buf)-1)) > 0)
 2054                 {
 2055                     buf[nread] = '\0';
 2056 
 2057                     // Get last string between two slashes
 2058                     // or before the slash if there is only one
 2059                     strbuf = buf;
 2060                     strbuf = strbuf.rbefore('/');
 2061                     if (strbuf.rfind('/') >= 0)
 2062                     {
 2063                         strbuf=strbuf.rafter('/');
 2064                     }
 2065                     
 2066                     dsize = strbuf.section(' ',0);
 2067                     files = strbuf.section(' ',1);
 2068                     subdirs = strbuf.section(' ',2);
 2069 
 2070                     hsize = ::hSize((char*)dsize.text());
 2071 
 2072                     // Directory size, number of files, number of sub directories
 2073                     dirsize = FXULongVal(dsize);
 2074                     nbfiles = FXUIntVal(files);
 2075                     nbsubdirs = FXUIntVal(subdirs);
 2076                     if (nbsubdirs > 0)
 2077                     {
 2078                         nbsubdirs--;
 2079                     }
 2080 
 2081 #if __WORDSIZE == 64
 2082                     snprintf(size,sizeof(size)-1,_("%s (%lu bytes)"),hsize.text(),dirsize);        
 2083 #else
 2084                     snprintf(size,sizeof(size)-1,_("%s (%llu bytes)"),hsize.text(),dirsize);        
 2085 #endif  
 2086                     fileSize->setText(size);
 2087 
 2088                     if (nbfiles-nbsubdirs-nbseldirs <= 1 && nbsubdirs <= 1)
 2089                     {
 2090                         snprintf(size, sizeof(size)-1, _("%u file, %u subfolder"), nbfiles-nbsubdirs-nbseldirs, nbsubdirs);                 
 2091                     }
 2092                     else if (nbfiles-nbsubdirs-nbseldirs <= 1 && nbsubdirs > 1)
 2093                     {
 2094                         snprintf(size, sizeof(size)-1, _("%u file, %u subfolders"), nbfiles-nbsubdirs-nbseldirs, nbsubdirs);                    
 2095                     }
 2096                     else if (nbfiles-nbsubdirs-nbseldirs > 1 && nbsubdirs <= 1)
 2097                     {
 2098                         snprintf(size, sizeof(size)-1, _("%u files, %u subfolder"), nbfiles-nbsubdirs-nbseldirs, nbsubdirs);                    
 2099                     }
 2100                     else
 2101                     {
 2102                         snprintf(size, sizeof(size)-1, _("%u files, %u subfolders"), nbfiles-nbsubdirs-nbseldirs, nbsubdirs);                   
 2103                     }
 2104 
 2105                     fileSizeDetails->setText(size);
 2106 
 2107                     if (nread < (int)(sizeof(buf)-1))
 2108                     {
 2109                         break;
 2110                     }
 2111                 }
 2112             }
 2113         }
 2114     }
 2115 
 2116     else
 2117     {
 2118         // Child has finished.
 2119         // Read data from the finished child
 2120         while ((nread = read(pipes[0], buf, sizeof(buf)-1)) > 0)
 2121         {
 2122             buf[nread] = '\0';
 2123 
 2124             // Get last string between two slashes
 2125             strbuf = buf;
 2126             strbuf = strbuf.rbefore('/');
 2127 
 2128             if (strbuf.rfind('/') >= 0)
 2129             {
 2130                 strbuf = strbuf.rafter('/');
 2131                 
 2132                 dsize = strbuf.section(' ',0);
 2133                 files = strbuf.section(' ',1);
 2134                 subdirs = strbuf.section(' ',2);
 2135                 
 2136                 hsize = ::hSize((char*)dsize.text());
 2137                 
 2138                 // Directory size, number of files, number of sub directories
 2139                 dirsize = FXULongVal(dsize);
 2140                 nbfiles = FXUIntVal(files);
 2141                 nbsubdirs = FXUIntVal(subdirs);
 2142                 if (nbsubdirs >0)
 2143                 {
 2144                     nbsubdirs--;
 2145                 }
 2146 
 2147 #if __WORDSIZE == 64
 2148                 snprintf(size,sizeof(size)-1,_("%s (%lu bytes)"),hsize.text(),dirsize);        
 2149 #else
 2150                 snprintf(size,sizeof(size)-1,_("%s (%llu bytes)"),hsize.text(),dirsize);        
 2151 #endif
 2152                 fileSize->setText(size);
 2153 
 2154                 if (nbfiles-nbsubdirs-nbseldirs <= 1 && nbsubdirs <= 1)
 2155                 {
 2156                     snprintf(size, sizeof(size)-1, _("%u file, %u subfolder"), nbfiles-nbsubdirs-nbseldirs, nbsubdirs);                 
 2157                 }
 2158                 else if (nbfiles-nbsubdirs-nbseldirs <= 1 && nbsubdirs > 1)
 2159                 {
 2160                     snprintf(size, sizeof(size)-1, _("%u file, %u subfolders"), nbfiles-nbsubdirs-nbseldirs, nbsubdirs);                    
 2161                 }
 2162                 else if (nbfiles-nbsubdirs-nbseldirs > 1 && nbsubdirs <= 1)
 2163                 {
 2164                     snprintf(size, sizeof(size)-1, _("%u files, %u subfolder"), nbfiles-nbsubdirs-nbseldirs, nbsubdirs);                    
 2165                 }
 2166                 else
 2167                 {
 2168                     snprintf(size, sizeof(size)-1, _("%u files, %u subfolders"), nbfiles-nbsubdirs-nbseldirs, nbsubdirs);                   
 2169                 }
 2170 
 2171                 fileSizeDetails->setText(size);
 2172             }
 2173 
 2174             if (nread < (int)(sizeof(buf)-1))
 2175             {
 2176                 break;
 2177             }
 2178         }
 2179 
 2180         // Close pipes
 2181         ::close(pipes[0]);
 2182         ::close(pipes[1]);   
 2183     }
 2184 
 2185     return(1);
 2186 }
 2187 
 2188 
 2189 // Update recursive directory size and permissions
 2190 long PropertiesBox::onUpdSizeAndPerm(FXObject* o, FXSelector s, void* p)
 2191 {
 2192     // Update recursive size only one time
 2193     if (recsize)
 2194     {
 2195         char buf[MAXPATHLEN+1];
 2196         FXString hsize;
 2197 
 2198         // Single file
 2199         if (num == 1)
 2200         {
 2201             // Directory but not mount point
 2202             if (isDirectory && !isMountpoint)
 2203             {
 2204                 FXuint  nbfiles=0, nbsubdirs=0;
 2205                 FXulong dirsize=0;
 2206 
 2207                 FXString dirpath = FXPath::absolute(parentdir, filename);
 2208                 strlcpy(buf, dirpath.text(), dirpath.length()+1);
 2209 
 2210                 // Open pipes to communicate with child process
 2211                 if (pipe(pipes) == -1)
 2212                 {
 2213                     perror("pipe");
 2214                     exit(EXIT_FAILURE);
 2215                 }
 2216 
 2217                 // Create child process
 2218                 pid = fork();
 2219                 
 2220                 if (pid == -1)
 2221                 {
 2222                     perror("fork");
 2223                     exit(EXIT_FAILURE);
 2224                 }
 2225                 if (pid == 0) // Child
 2226                 {
 2227                     if (nbsubdirs > 0)
 2228                     {
 2229                         nbsubdirs--;
 2230                     }
 2231                     
 2232                     pathsize(buf, &nbfiles, &nbsubdirs, &dirsize, pipes);
 2233 
 2234                     _exit(EXIT_SUCCESS);
 2235                 }
 2236                 else // Parent
 2237                 {
 2238                     // Make sure we get called so we can check when child has finished
 2239                     getApp()->addChore(this, ID_WATCHPROCESS);
 2240                 }
 2241             }
 2242         }
 2243 
 2244         // Multiple files
 2245         else
 2246         {
 2247             // Open pipes to communicate with child process
 2248             if (pipe(pipes) == -1)
 2249             {
 2250                 perror("pipe");
 2251                 exit(EXIT_FAILURE);
 2252             }
 2253 
 2254             // Create child process
 2255             pid = fork();
 2256                         
 2257             if (pid == -1)
 2258             {
 2259                 perror("fork");
 2260                 exit(EXIT_FAILURE);
 2261             }
 2262             if (pid == 0) // Child
 2263             {
 2264                 struct stat info;
 2265 
 2266                 // Total size and files type
 2267                 for (int i = 0; i < num; i++)
 2268                 {
 2269                     FXString pathname;
 2270 
 2271                     if (paths == NULL)
 2272                     {
 2273                         pathname = FXPath::absolute(parentdir, files[i]);
 2274                     }
 2275                     else
 2276                     {
 2277                         pathname = FXPath::absolute(paths[i], files[i]);
 2278                     }
 2279 
 2280                     if (lstatrep(pathname.text(), &info) != 0)
 2281                     {
 2282                         continue;
 2283                     }
 2284 
 2285                     // Special case of the ".." directory
 2286                     if (files[i] == "..")
 2287                     {
 2288                         continue;
 2289                     }
 2290 
 2291                     // Is it a directory?
 2292                     isDirectory = S_ISDIR(info.st_mode);
 2293                     if (isDirectory)
 2294                     {
 2295                         strlcpy(buf, pathname.text(), pathname.length()+1);
 2296                         
 2297                         if (totalnbsubdirs > 0)
 2298                         {
 2299                             totalnbsubdirs--;
 2300                         }
 2301                         
 2302                         pathsize(buf, &totalnbfiles, &totalnbsubdirs, &totaldirsize, pipes);
 2303                     }
 2304                     else // Regular file
 2305                     {
 2306                         strlcpy(buf, pathname.text(), pathname.length()+1);
 2307                         pathsize(buf, &totalnbfiles, &totalnbsubdirs, &totaldirsize, pipes);
 2308                     }
 2309                 }
 2310 
 2311                 _exit(EXIT_SUCCESS);
 2312             }
 2313             else // Parent
 2314             {
 2315                 // Make sure we get called so we can check when child has finished
 2316                 getApp()->addChore(this, ID_WATCHPROCESS);
 2317             }
 2318         }
 2319     }
 2320 
 2321     recsize = false;
 2322 
 2323     // Update permissions
 2324     if (perm->rec->getCheck())
 2325     {
 2326         perm->dironly->enable();
 2327         perm->fileonly->enable();
 2328         perm->all->enable();
 2329     }
 2330     else
 2331     {
 2332         perm->all->disable();
 2333         perm->dironly->disable();
 2334         perm->fileonly->disable();
 2335     }
 2336 
 2337     if (perm->own->getCheck())
 2338     {
 2339         perm->set->disable();
 2340         perm->clear->disable();
 2341         perm->add->disable();
 2342         perm->ur->disable();
 2343         perm->uw->disable();
 2344         perm->ux->disable();
 2345         perm->gr->disable();
 2346         perm->gw->disable();
 2347         perm->gx->disable();
 2348         perm->or_->disable();
 2349         perm->ow->disable();
 2350         perm->ox->disable();
 2351         perm->suid->disable();
 2352         perm->sgid->disable();
 2353         perm->svtx->disable();
 2354     }
 2355     else
 2356     {
 2357         perm->set->enable();
 2358         perm->clear->enable();
 2359         perm->add->enable();
 2360         perm->ur->enable();
 2361         perm->uw->enable();
 2362         perm->ux->enable();
 2363         perm->gr->enable();
 2364         perm->gw->enable();
 2365         perm->gx->enable();
 2366         perm->or_->enable();
 2367         perm->ow->enable();
 2368         perm->ox->enable();
 2369         perm->suid->enable();
 2370         perm->sgid->enable();
 2371         perm->svtx->enable();
 2372     }
 2373 
 2374     return(1);
 2375 }
 2376 
 2377 
 2378 long PropertiesBox::onCmdKeyPress(FXObject* sender, FXSelector sel, void* ptr)
 2379 {
 2380     FXEvent* event = (FXEvent*)ptr;
 2381 
 2382     switch (event->code)
 2383     {
 2384     case KEY_Escape:
 2385         handle(this, FXSEL(SEL_COMMAND, ID_CANCEL), NULL);
 2386         return(1);
 2387 
 2388     case KEY_KP_Enter:
 2389     case KEY_Return:
 2390         handle(this, FXSEL(SEL_COMMAND, ID_ACCEPT_SINGLE), NULL);
 2391         return(1);
 2392 
 2393     default:
 2394         FXTopWindow::onKeyPress(sender, sel, ptr);
 2395         return(1);
 2396     }
 2397     return(0);
 2398 }
 2399 
 2400 
 2401 #ifdef STARTUP_NOTIFICATION
 2402 // Update the startup notification button depending on the file exec status
 2403 long PropertiesBox::onUpdSnDisable(FXObject*, FXSelector, void*)
 2404 {
 2405     FXbool usesn = getApp()->reg().readUnsignedEntry("OPTIONS", "use_startup_notification", true);
 2406 
 2407     if (usesn && executable)
 2408     {
 2409         sngroup->enable();
 2410         snbutton->enable();
 2411     }
 2412     else
 2413     {
 2414         sngroup->disable();
 2415         snbutton->disable();
 2416     }
 2417     return(1);
 2418 }
 2419 
 2420 
 2421 #endif