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