Link with C++ linker
[oweals/cde.git] / cde / programs / dtfile / ModAttrP.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: ModAttrP.c /main/8 1999/12/09 13:07:16 mgreess $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  *
27  *   FILE:           ModAttrP.c
28  *
29  *   COMPONENT_NAME: Desktop File Manager (dtfile)
30  *
31  *   Description:    Processing functions for the modify file attribute dialog.
32  *
33  *   FUNCTIONS: AttrChangePipeCB
34  *              AttrChangeProcess
35  *              ModAttrChange
36  *              ModAttrClose
37  *              ShowModAttrDialog
38  *
39  *   (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
40  *   (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
41  *   (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
42  *   (c) Copyright 1993, 1994, 1995 Novell, Inc.
43  *
44  ****************************************************************************
45  ************************************<+>*************************************/
46
47 #if defined __osf__ || defined _AIX
48 #include <stdio.h>
49 #endif
50   
51 #include <grp.h>
52 #include <pwd.h>
53 #include <errno.h>
54 #include <ctype.h>
55
56 #include <Xm/Xm.h>
57 #include <Xm/XmP.h>
58 #include <Xm/RowColumn.h>
59
60 #include <Dt/Connect.h>
61 #include <Dt/FileM.h>
62
63 #include <Tt/tttk.h>
64
65 #include "Encaps.h"
66 #include "SharedProcs.h"
67 #include "FileMgr.h"
68 #include "Desktop.h"
69 #include "Main.h"
70 #include "Help.h"
71 #include "ModAttr.h"
72
73
74 extern int mod_attr_dialog;
75
76
77 /* types of messages sent through the pipe */
78 #define PIPEMSG_DONE 1
79
80 /* callback data for pipe input handler */
81 typedef struct
82 {
83    char *host;
84    char *directory;
85    char *file;
86    int child;
87 } AttrChangeCBData;
88
89
90 /********    Static Function Declarations    ********/
91
92 void ModAttrChange(
93                         XtPointer client_data,
94                         DialogData *old_dialog_data,
95                         DialogData *new_dialog_data,
96                         XtPointer call_data) ;
97 void ModAttrClose(
98                         XtPointer client_data,
99                         DialogData *old_dialog_data,
100                         DialogData *new_dialog_data) ;
101
102 /********    End Static Function Declarations    ********/
103
104
105 /************************************************************************
106  *
107  *  ShowModAttrDialog
108  *      Callback functions invoked from the Modify Attributes ... menu
109  *      item.  This function displays the file attribute dialog.
110  *
111  ************************************************************************/
112
113 void
114 ShowModAttrDialog(
115         Widget w,
116         XtPointer client_data,
117         XtPointer callback )
118 {
119    FileMgrRec  * file_mgr_rec;
120    DialogData  * dialog_data;
121    FileMgrData * file_mgr_data;
122    DialogData  * attr_dialog;
123    DirectorySet * directory_set;
124    FileViewData * file_view_data;
125    ModAttrRec *modAttr_rec;
126    int count, i;
127    Boolean loadOk=True;
128    char * errorMsg=NULL;
129    char * title=NULL;
130    Arg args[1];
131    Widget mbar;
132    char * tmpStr, *tempStr;
133   
134    XmUpdateDisplay (w);
135
136    if((int)client_data != NULL)
137       mbar = XtParent(w);
138    else
139       mbar = XmGetPostedFromWidget(XtParent(w));
140
141    XtSetArg(args[0], XmNuserData, &file_mgr_rec);
142    XtGetValues(mbar, args, 1);
143
144    /* Ignore accelerators when we're insensitive */
145    if (client_data == NULL)
146       if ((file_mgr_rec->menuStates & MODIFY) == 0)
147          return;
148
149    /* Ignore accelerators received after we're unposted */
150    if ((dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec)) == NULL)
151       return;
152    file_mgr_data = (FileMgrData *) dialog_data->data;
153
154    /* get the file_view_data object from which the menu was invoked */
155    if (client_data == NULL)
156      file_view_data = NULL;
157    else
158    {
159      file_view_data = file_mgr_data->popup_menu_icon;
160      if (file_view_data == NULL)
161        /* the object has gone away (probably deleted) */
162        return;
163
164      file_mgr_data->popup_menu_icon = NULL; /* Reset it, we don't need it */
165    }
166
167
168    attr_dialog = _DtGetDefaultDialogData (mod_attr_dialog);
169
170    file_mgr_rec->menuStates &= ~MODIFY;
171    if (file_view_data == NULL)
172    {
173       directory_set =
174          (DirectorySet *) file_mgr_data->selection_list[0]->directory_set;
175
176       /* Determine which file is selected */
177       loadOk =  LoadFileAttributes(file_mgr_data->host, directory_set->name,
178                       file_mgr_data->selection_list[0]->file_data->file_name,
179                       (ModAttrData *)attr_dialog->data);
180    }
181    else
182    {
183       directory_set =
184          (DirectorySet *)file_view_data->directory_set;
185
186       /* Determine which file is selected */
187       loadOk =  LoadFileAttributes(file_mgr_data->host, directory_set->name,
188                       file_view_data->file_data->file_name,
189                       (ModAttrData *)attr_dialog->data);
190    }
191
192    if (loadOk)
193    {
194      /* Get the initial attribute values for seleceted file */
195      _DtAddOneSubdialog (attr_dialog,
196                       &file_mgr_data->attr_dialog_list,
197                       &file_mgr_data->attr_dialog_count);
198      /* We need the file_mgr_rec inside the create routine so
199       * we attach it here for use later.
200       */
201      ((ModAttrData *) (attr_dialog->data))->main_widget = file_mgr_rec->main;
202
203      _DtShowDialog (file_mgr_rec->shell, NULL,
204                  (XtPointer)file_mgr_rec, attr_dialog,
205                  ModAttrChange, (XtPointer)file_mgr_rec, ModAttrClose,
206                  (XtPointer)file_mgr_rec,NULL, False, False, NULL, NULL);
207
208      for(i = 0; i < file_mgr_data->attr_dialog_count; i++)
209      {
210         modAttr_rec = (ModAttrRec *)_DtGetDialogInstance(
211                                        file_mgr_data->attr_dialog_list[i]);
212
213         if(file_mgr_data->title != NULL &&
214                    strcmp(file_mgr_data->helpVol, DTFILE_HELP_NAME) != 0)
215         {
216            tmpStr = GETMESSAGE(21, 1, "File Permissions");
217            tempStr = (char *)XtMalloc(strlen(tmpStr) +
218                                  strlen(file_mgr_data->title) + 5);
219            sprintf(tempStr, "%s - %s", file_mgr_data->title, tmpStr);
220         }
221         else
222         {
223            tmpStr = (GETMESSAGE(21,34, "File Manager - Permissions"));
224            tempStr = XtNewString(tmpStr);
225         }
226         XtSetArg (args[0], XmNtitle, tempStr);
227         XtSetValues (modAttr_rec->shell, args, 1);
228         XtFree(tempStr);
229       }
230    }
231    else
232    {
233      /* Clean up used structures and put up an error dialog */
234
235      file_mgr_rec->menuStates |= MODIFY;
236      _DtFreeDialogData (attr_dialog);
237  
238      tmpStr = GETMESSAGE(22, 4, "Cannot open object.");
239      errorMsg = XtNewString(tmpStr);
240      tmpStr = GETMESSAGE(22, 5, "Set Permissions Error");
241      title = XtNewString(tmpStr);
242      _DtMessage (file_mgr_rec->shell, title, errorMsg, NULL, HelpRequestCB);
243      XtFree(title);
244      XtFree(errorMsg);
245    }
246 }
247
248
249
250
251 /************************************************************************
252  *
253  *  ModAttrChange
254  *      Callback functions invoked from the file attribute dialog's
255  *      Ok button being pressed.  This function updates the indicated
256  *      file.
257  *
258  ************************************************************************/
259
260 /*--------------------------------------------------------------------
261  * AttrChangeProcess
262  *   Main routine of background process for AttrChange
263  *------------------------------------------------------------------*/
264
265 static int
266 AttrChangeProcess(
267         int pipe_fd,
268         char *host,
269         char *directory,
270         char *file,
271         int uid,
272         int gid,
273         long mode)
274 {
275   char *path;
276   struct stat stat_buf;
277   long modify_time;
278   short pipe_msg;
279   int rc = -1;
280   Tt_status tt_status;
281
282   /* get directory timestamp */
283   path = ResolveLocalPathName(host, directory, NULL,home_host_name, &tt_status);
284   if( TT_OK == tt_status )
285   {
286     if (stat(path, &stat_buf) == 0)
287       modify_time = stat_buf.st_mtime;
288     XtFree(path);
289
290     /* change the file attributes */
291     path = ResolveLocalPathName(host, directory, file, home_host_name, &tt_status);
292     if( TT_OK == tt_status )
293     {
294       if (chmod(path, mode) == 0)
295       {
296         rc = 0;
297         chown(path, uid, gid);
298       }
299       else
300         rc = errno;
301       XtFree (path);
302     }
303   }
304
305   /* send a 'done' msg through the pipe */
306   DPRINTF(("AttrChangeProcess: sending DONE, rc %d\n", rc));
307   pipe_msg = PIPEMSG_DONE;
308   write(pipe_fd, &pipe_msg, sizeof(short));
309   write(pipe_fd, &rc, sizeof(int));
310   write(pipe_fd, &modify_time, sizeof(long));
311
312   return rc;
313 }
314
315
316 /*--------------------------------------------------------------------
317  * AttrChangePipeCB:
318  *   Read and process data sent through the pipe.
319  *------------------------------------------------------------------*/
320
321 static void
322 AttrChangePipeCB(
323    XtPointer client_data,
324    int *fd,
325    XtInputId *id)
326 {
327    AttrChangeCBData *cb_data = (AttrChangeCBData *)client_data;
328    short pipe_msg;
329    char *title, *err_msg, *err_arg;
330    long modify_time;
331    int i, n, rc;
332
333    /* read the msg from the pipe */
334    pipe_msg = -1;
335    n = PipeRead(*fd, &pipe_msg, sizeof(short));
336
337    if (pipe_msg == PIPEMSG_DONE)
338    {
339       PipeRead(*fd, &rc, sizeof(int));
340       PipeRead(*fd, &modify_time, sizeof(long));
341    }
342    else
343    {
344       fprintf(stderr, "Internal error in AttrChangePipeCB: bad pipe_msg %d\n",
345               pipe_msg);
346       rc = 0;
347       modify_time = 0;
348    }
349
350    DPRINTF(("AttrChangePipeCB: n %d, pipe_msg %d, rc %d\n", n, pipe_msg, rc));
351
352    /* if error, post error message */
353    if (rc)
354    {
355       err_msg = XtNewString(GETMESSAGE(22,3,"Cannot change properties for %s"));
356       FileOperationError(toplevel, err_msg, cb_data->file);
357       XtFree(err_msg);
358    }
359
360    /* arrange for modified directory to be updated */
361    if (modify_time != 0)
362       DirectoryModifyTime(cb_data->host, cb_data->directory, modify_time);
363    DirectoryFileModified(cb_data->host, cb_data->directory, cb_data->file);
364    DirectoryEndModify(cb_data->host, cb_data->directory);
365    if(!strcmp(cb_data->file,".") || !strcmp(cb_data->file,".."))
366    {
367        char *dir;
368        char *tmpptr = strrchr(cb_data->directory,'/');
369        if(tmpptr)
370        {
371            if(tmpptr != cb_data->directory)
372                tmpptr = NULL, dir = cb_data->directory;
373            else
374                dir = "/";
375            DirectoryBeginModify(cb_data->host,dir);
376            DirectoryFileModified(cb_data->host,dir, tmpptr+1);
377            DirectoryEndModify(cb_data->host,dir);
378            
379            if(tmpptr)
380                *tmpptr='/';
381        }
382    }
383    else
384    {
385        char subdir_name[MAX_PATH + 1];
386        char *p;
387        
388        strcpy(subdir_name, cb_data->directory);
389        p = subdir_name + strlen(subdir_name);
390        if (p[-1] != '/')
391            *p++ = '/';
392        
393        strcpy(p, cb_data->file);
394        UpdateDirectory(NULL,cb_data->host, subdir_name);
395    }
396
397    /* close the pipe and cancel the callback */
398    close(*fd);
399    XtRemoveInput(*id);
400
401    /* free callback data */
402    XtFree(cb_data->host);
403    XtFree(cb_data->directory);
404    XtFree(cb_data->file);
405    XtFree((char *)cb_data);
406 }
407
408
409 /*--------------------------------------------------------------------
410  * ModAttrChange:
411  *    Start the background process and set up callback for the pipe.
412  *------------------------------------------------------------------*/
413
414 void
415 ModAttrChange(
416         XtPointer client_data,
417         DialogData *old_dialog_data,
418         DialogData *new_dialog_data,
419         XtPointer call_data )
420 {
421    static char *pname = "ModAttrChange";
422    AttrChangeCBData *cb_data;
423    FileMgrRec  * file_mgr_rec = (FileMgrRec *) client_data;
424    ModAttrData * current;
425    ModAttrData * old;
426    struct group * gr;
427    struct passwd * pw;
428    int uid, gid;
429    long mode;
430    int pipe_fd[2];
431    int pid;
432    int rc;
433
434    /* Get current data */
435    current = (ModAttrData *) new_dialog_data->data;
436    old = (ModAttrData *) old_dialog_data->data;
437
438    /* see if anything has changed */
439    if (strcmp(current->owner, old->owner) == 0 &&
440        strcmp(current->group, old->group) == 0 &&
441        current->accessBits == old->accessBits &&
442        current->setuidBits == old->setuidBits)
443    {
444       /* nothing changed: close the dialog and return */
445        ModAttrClose ((XtPointer)file_mgr_rec, old_dialog_data, new_dialog_data);
446        return;
447    }
448
449    /* get new owner uid */
450    pw = getpwnam(current->owner);
451    if (pw)
452       uid = pw->pw_uid;
453    else if (isdigit(current->owner[0]))
454       uid = atoi(current->owner);
455    else
456       uid = -1;
457
458    /* get new group gid */
459    gr = getgrnam(current->group);
460    if (gr)
461       gid = gr->gr_gid;
462    else if (isdigit(current->group[0]))
463       gid = atoi(current->group);
464    else
465       gid = -1;
466
467    /* get new file mode */
468    mode = current->accessBits + current->setuidBits;
469
470    /* set up callback data */
471    cb_data = XtNew(AttrChangeCBData);
472    cb_data->host = XtNewString(current->host);
473    cb_data->directory = XtNewString(current->directory);
474    cb_data->file = XtNewString(current->name);
475
476    /* mark the directory as being modified in the directory cache */
477    DirectoryBeginModify(cb_data->host, cb_data->directory);
478
479    /* create a pipe */
480    pipe(pipe_fd);
481
482    /* fork the process that does the actual work */
483    pid = fork();
484    if (pid == -1)
485    {
486        DirectoryAbortModify(cb_data->host, cb_data->directory);
487        fprintf(stderr,
488                 "%s:  fork failed, ppid %d, pid %d: error %d=%s\n",
489                 pname, getppid(), getpid(), errno, strerror(errno));
490        return;
491    }
492
493    if (pid == 0)
494    {
495       /* child process */
496       DBGFORK(("%s:  child forked, pipe %d\n", pname, pipe_fd[1]));
497
498       close(pipe_fd[0]);  /* child won't read from the pipe */
499
500       rc = AttrChangeProcess(pipe_fd[1], cb_data->host, cb_data->directory,
501                              cb_data->file, uid, gid, mode);
502       close(pipe_fd[1]);
503
504       DBGFORK(("%s:  child exiting (rc %d)\n", pname, rc));
505
506       exit(rc);
507    }
508
509    DBGFORK(("%s:  forked child<%d>, pipe %d\n", pname, pid, pipe_fd[0]));
510
511    /* parent: set up callback to get the pipe data */
512    close(pipe_fd[1]);  /* parent won't write the pipe */
513
514    cb_data->child = pid;
515
516    XtAppAddInput(XtWidgetToApplicationContext(toplevel),
517                  pipe_fd[0], (XtPointer)XtInputReadMask,
518                  AttrChangePipeCB, (XtPointer)cb_data);
519
520    ModAttrClose ((XtPointer)file_mgr_rec, old_dialog_data, new_dialog_data);
521 }
522
523
524
525
526 /************************************************************************
527  *
528  *  ModAttrClose
529  *      Callback function invoked from the file attribute dialog's close
530  *      button.
531  *
532  ************************************************************************/
533
534 void
535 ModAttrClose(
536         XtPointer client_data,
537         DialogData *old_dialog_data,
538         DialogData *new_dialog_data )
539 {
540    FileMgrRec  * file_mgr_rec = (FileMgrRec *) client_data;
541    FileMgrData * file_mgr_data;
542    DialogData  * dialog_data;
543    int count;
544    int i, j;
545
546
547
548    dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
549    file_mgr_data = (FileMgrData *) dialog_data->data;
550
551    if(file_mgr_data->selected_file_count > 0)
552       file_mgr_rec->menuStates |= MODIFY;
553
554
555    /*  Remove the dialog data from the file managers list  */
556    _DtHideOneSubdialog( old_dialog_data,
557                      &file_mgr_data->attr_dialog_list,
558                      &file_mgr_data->attr_dialog_count);
559
560    _DtHideDialog (old_dialog_data, False);
561    _DtFreeDialogData (old_dialog_data);
562    _DtFreeDialogData (new_dialog_data);
563 }