2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 //%% (c) Copyright 1993, 1994 Hewlett-Packard Company
24 //%% (c) Copyright 1993, 1994 International Business Machines Corp.
25 //%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
26 //%% (c) Copyright 1993, 1994 Novell, Inc.
27 //%% $XConsortium: ttdtfile.C /main/3 1995/10/23 10:32:19 rswiston $
29 * @(#)ttdtfile.C 1.3 93/09/07
31 * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
34 #include "api/c/tt_c.h"
35 #include "api/c/api_api.h"
36 #include "tttk/tttk.h"
37 #include "tttk/tttkpattern.h"
38 #include "tttk/tttkmessage.h"
39 #include "tttk/tttk2free.h"
40 #include "tttk/tttkutils.h"
50 // Parse file message and pass it to user callback
55 Tt_pattern , // Not needed
63 _TttkItem2Free fuse = msg;
64 char *file = tt_message_file( msg );
65 Tt_status status = tt_ptr_error( file );
66 if (status != TT_OK) {
67 return (Tt_message)tt_error_pointer( status );
69 char *opname = tt_message_op( msg );
70 status = tt_ptr_error( opname );
71 if (status != TT_OK) {
72 return (Tt_message)tt_error_pointer( status );
74 Tttk_op op = tttk_string_op( opname );
76 int trust = ( ( geteuid() == tt_message_uid( msg ))
77 && ( getegid() == tt_message_gid( msg )));
79 char *sender = tt_message_sender( msg );
80 char *me = tt_default_procid();
81 if ((tt_ptr_error( sender ) == TT_OK) && (tt_ptr_error(me) == TT_OK)) {
82 from_me = (strcmp( sender, me ) == 0);
86 if ((op == TTDT_GET_MODIFIED) && (_tttk_message_am_handling(msg))) {
88 // If our pattern even matches Get_Modified, it is because
89 // the client called ttdt_file_event(,TTDT_MODIFIED,,).
90 // Reverting or saving unregisters this pattern, so if
91 // we even see the question we know the answer is yes.
93 tt_message_arg_ival_set( msg, 1, 1 );
94 tt_message_reply( msg );
95 // message destroyed by fuse
98 Ttdt_file_cb _cb = (Ttdt_file_cb)clientCB;
99 msg = (*_cb)( msg, op, file, clientData, trust, from_me );
100 fuse = (caddr_t)0; // prevent message destruction
105 // Create the pattern registered at file-join-time
109 const char *pathname,
115 Tt_pattern pat = _ttDtPatternCreate( TT_OBSERVE, theScope,
116 theScope != TT_FILE, pathname,
117 TTDT_DELETED, _ttDtFileCB,
119 Tt_status status = tt_ptr_error( pat );
120 if (status != TT_OK) {
123 _TttkItem2Free fuse = pat;
124 tt_pattern_op_add( pat, _ttDtOp( TTDT_MODIFIED ) );
125 tt_pattern_op_add( pat, _ttDtOp( TTDT_REVERTED ) );
126 tt_pattern_op_add( pat, _ttDtOp( TTDT_MOVED ) );
127 tt_pattern_op_add( pat, _ttDtOp( TTDT_SAVED ) );
128 status = tt_pattern_class_add( pat, TT_NOTICE );
129 if (status != TT_OK) {
130 return (Tt_pattern)tt_error_pointer( status );
132 status = tt_pattern_arg_add( pat, TT_IN, Tttk_file, 0 );
133 if (status != TT_OK) {
134 return (Tt_pattern)tt_error_pointer( status );
136 status = tt_pattern_register( pat );
137 if (status != TT_OK) {
138 return (Tt_pattern)tt_error_pointer( status );
146 const char *pathname,
154 // One pattern to observe notices, one to handle requests, and
155 // a null terminator.
157 Tt_pattern *pPats = (Tt_pattern *)malloc( 3 * sizeof(Tt_pattern) );
159 return (Tt_pattern *)tt_error_pointer( TT_ERR_NOMEM );
161 _TttkList2Free fuses( 3 );
162 fuses += (caddr_t)pPats;
165 Tt_scope toTry = theScope;
166 if (theScope == TT_SCOPE_NONE) {
169 pPats[0] = _ttDtFileJoinPat( pathname, toTry, cb, clientData );
170 Tt_status status = tt_ptr_error( pPats[0] );
171 if ((status != TT_OK) && (theScope == TT_SCOPE_NONE)) {
172 toTry = TT_FILE_IN_SESSION;
173 pPats[0] = _ttDtFileJoinPat( pathname, toTry, cb, clientData );
174 status = tt_ptr_error( pPats[0] );
176 if (status != TT_OK) {
177 return (Tt_pattern *)tt_error_pointer( status );
180 TtDtFileJoinInfo *info = (TtDtFileJoinInfo *)
181 malloc( sizeof( TtDtFileJoinInfo ));
183 return (Tt_pattern *)tt_error_pointer( TT_DESKTOP_ENOMEM );
185 fuses += (caddr_t)info;
186 info->pathname = _tt_strdup( pathname );
187 info->theScope = toTry;
189 info->clientData = clientData;
190 status = tt_pattern_user_set( pPats[0], _TttkJoinInfoKey, info );
191 if (status != TT_OK) {
192 return (Tt_pattern *)tt_error_pointer( status );
195 status = tt_file_join( pathname );
196 if (status != TT_OK) {
197 return (Tt_pattern *)tt_error_pointer( status );
213 if ((op == TTDT_MOVED) && sendAndDestroy) {
214 return (Tt_message)tt_error_pointer( TT_DESKTOP_EINVAL );
216 Tt_message msg = tttk_message_create( context, TT_NOTICE, theScope, 0,
218 Tt_status status = tt_ptr_error( msg );
219 if (status != TT_OK) {
223 // Guarantees that msg will be destroyed when this function returns
225 _TttkItem2Free fuse = msg;
226 status = tt_message_file_set( msg, file );
227 if (status != TT_OK) {
228 return (Tt_message)tt_error_pointer( status );
230 status = tt_message_arg_add( msg, TT_IN, Tttk_file, 0 );
231 if (status != TT_OK) {
232 return (Tt_message)tt_error_pointer( status );
234 if (sendAndDestroy) {
235 status = tt_message_send( msg );
236 if (status != TT_OK) {
237 return (Tt_message)tt_error_pointer( status );
256 Tt_message msg = _ttDtPMessageCreate( context, TT_REQUEST, theScope, 0,
257 op, _ttDtFileCB, cb, clientData);
258 Tt_status status = tt_ptr_error( msg );
259 if (status != TT_OK) {
262 _TttkItem2Free fuse = msg;
263 status = tt_message_file_set( msg, file );
264 if (status != TT_OK) {
265 return (Tt_message)tt_error_pointer( status );
267 status = tt_message_arg_add( msg, TT_IN, Tttk_file, 0 );
268 if (status != TT_OK) {
269 return (Tt_message)tt_error_pointer( status );
271 if (op == TTDT_GET_MODIFIED) {
272 status = tt_message_arg_add( msg, TT_OUT, Tttk_boolean, 0 );
273 if (status != TT_OK) {
274 return (Tt_message)tt_error_pointer( status );
278 status = tt_message_send( msg );
279 if (status != TT_OK) {
280 return (Tt_message)tt_error_pointer( status );
288 // Create the pattern registered at file-event-time
292 const char *pathname,
298 Tt_pattern pat = _ttDtPatternCreate( TT_HANDLE, theScope,
299 theScope != TT_FILE, pathname,
300 TTDT_SAVE, _ttDtFileCB,
302 Tt_status status = tt_ptr_error( pat );
303 if (status != TT_OK) {
306 _TttkItem2Free fuse = pat;
307 tt_pattern_op_add( pat, _ttDtOp( TTDT_GET_MODIFIED ) );
308 tt_pattern_op_add( pat, _ttDtOp( TTDT_REVERT ) );
309 status = tt_pattern_class_add( pat, TT_REQUEST );
310 if (status != TT_OK) {
311 return (Tt_pattern)tt_error_pointer( status );
313 status = tt_pattern_arg_add( pat, TT_IN, Tttk_file, 0 );
314 if (status != TT_OK) {
315 return (Tt_pattern)tt_error_pointer( status );
317 status = tt_pattern_register( pat );
318 if (status != TT_OK) {
319 return (Tt_pattern)tt_error_pointer( status );
333 if ((pats == 0) || (tt_ptr_error( pats ) != TT_OK)) {
334 return TT_ERR_POINTER;
336 TtDtFileJoinInfo *info = (TtDtFileJoinInfo *)
337 tt_pattern_user( pats[0], _TttkJoinInfoKey );
338 Tt_status status = tt_ptr_error( info );
339 if ((status != TT_OK) || (info == 0)) {
342 if (event == TTDT_MODIFIED) {
343 pats[1] = _ttDtFileEventPat( info->pathname, info->theScope,
344 info->cb, info->clientData );
345 Tt_status status = tt_ptr_error( pats[1] );
346 if (status != TT_OK) {
347 // Leave pats[1] as an error pointer
352 Tt_message msg = ttdt_file_notice( context, event,
353 info->theScope, info->pathname, 1 );
354 status = tt_ptr_error( msg );
355 if (status != TT_OK) {
359 if ((event == TTDT_SAVED) || (event == TTDT_REVERTED)) {
360 status = tt_pattern_unregister( pats[1] );
361 if (status != TT_OK) {
374 if ((pats == 0) || (tt_ptr_error( pats ) != TT_OK)) {
375 return TT_ERR_POINTER;
377 TtDtFileJoinInfo *info = (TtDtFileJoinInfo *)
378 tt_pattern_user( pats[0], _TttkJoinInfoKey );
379 Tt_status status = tt_ptr_error( info );
380 if ((status != TT_OK) || (info == 0)) {
383 status = _tttk_patterns_destroy( pats );
385 if (info->pathname != 0) {
386 status = tt_file_quit( info->pathname );
387 tt_free( (char *)info->pathname );
395 // Parse Get_Modified reply and set *(int *)clientData
408 if (! _tttk_message_in_final_state( msg )) {
409 // Not in final state; our address space is probably handler
412 *(int *)clientData = 0; // assume not modified
413 if (tt_message_state(msg) == TT_HANDLED) {
415 Tt_status status = tt_message_arg_ival( msg, 1, &modified );
416 if (status != TT_OK) {
417 tttk_message_destroy( msg );
421 *(int *)clientData = -1;
424 tttk_message_destroy( msg );
431 const char *pathname,
433 XtAppContext app2run,
438 Tt_message msg = ttdt_file_request( context, TTDT_GET_MODIFIED,
440 _ttDtGetModifiedCB, &waiting, 1 );
441 Tt_status status = tt_ptr_error( msg );
442 if (status != TT_OK) {
445 status = tttk_block_while( app2run, &waiting, msTimeOut );
446 if (status == TT_DESKTOP_ETIMEDOUT) {
448 // _ttDtGetModifiedCB() would have destroyed msg,
449 // but this removes the callback. Now, any
450 // late-breaking reply will pop out of
451 // tt_message_receive(). Well-behaved applications
452 // should do [what is done by] tttk_message_abandon(),
453 // but poorly-written apps might panic. XXX
455 tttk_message_destroy( msg );
457 return (waiting < 0);
461 // Private Ttdt_file_cb hung on requests (Get_Modified, Save, Revert)
462 // that we send synchronously.
475 return _ttTkNoteReplyStatus( msg, 0, 0, clientData );
482 const char *pathname,
484 XtAppContext app2run,
489 Tt_message msg = ttdt_file_request( context, op,
491 _ttDtFileRequestCB, &result, 1 );
492 Tt_status status = tt_ptr_error( msg );
493 if (status != TT_OK) {
497 status = tttk_block_while( app2run, &result, msTimeOut );
498 if (status == TT_DESKTOP_ETIMEDOUT) {
499 tttk_message_destroy( msg );
502 return (Tt_status)-result;
508 const char *pathname,
510 XtAppContext app2run,
514 return _ttdt_file_request( TTDT_SAVE, context, pathname, theScope,
515 app2run, msTimeOut );
521 const char *pathname,
523 XtAppContext app2run,
527 return _ttdt_file_request( TTDT_REVERT, context, pathname, theScope,
528 app2run, msTimeOut );