Tooltalk fixes for OpenBSD. This consists mainly of #ifdefs, casts and some small...
[oweals/cde.git] / cde / lib / tt / lib / tttk / tttkmessage.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 //%%  (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 //%%  $TOG: tttkmessage.C /main/5 1998/03/19 18:34:28 mgreess $                                                         
28 /*
29  * @(#)tttkmessage.C    1.3 93/09/07
30  *
31  * Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
32  */
33 #include "api/c/tt_c.h"
34 #include "api/c/api_mp.h"
35 #include "tttk/tttk.h"
36 #include "tttk/tttkpattern.h"
37 #include "tttk/tttkmessage.h"
38 #include "tttk/tttk2free.h"
39 #include "tttk/tttkutils.h"
40  
41 Tt_message
42 tttk_message_create( // XXX propagate contexts
43         Tt_message              ,
44         Tt_class                theClass,
45         Tt_scope                theScope,
46         const char             *handler,
47         const char             *op,
48         Tt_message_callback     callback
49 )
50 {
51         Tt_message msg = tt_message_create();
52         Tt_status status = tt_ptr_error( msg );
53         if (status != TT_OK) {
54                 return msg;
55         }
56         // fuse msg for automatic destruction if we return before defusing
57         _TttkItem2Free temp = msg;
58         status = tt_message_class_set( msg, theClass );
59         if (status != TT_OK) {
60                 return (Tt_message)tt_error_pointer( status );
61         }
62         status = tt_message_scope_set( msg, theScope );
63         if (status != TT_OK) {
64                 return (Tt_message)tt_error_pointer( status );
65         }
66         Tt_address address = TT_PROCEDURE;
67         if (handler != 0) {
68                 status = tt_message_handler_set( msg, handler );
69                 if (status != TT_OK) {
70                         return (Tt_message)tt_error_pointer( status );
71                 }
72                 address = TT_HANDLER;
73         }
74         status = tt_message_address_set( msg, address );
75         if (status != TT_OK) {
76                 return (Tt_message)tt_error_pointer( status );
77         }
78         if (op != 0) {
79                 status = tt_message_op_set( msg, op );
80                 if (status != TT_OK) {
81                         return (Tt_message)tt_error_pointer( status );
82                 }
83         }
84         if (callback != 0) {
85                 status = tt_message_callback_add( msg, callback );
86                 if (status != TT_OK) {
87                         return (Tt_message)tt_error_pointer( status );
88                 }
89         }
90         temp = (caddr_t)0;  // defuse
91         return msg;
92 }
93
94 // extern "C" { extern Tt_status _tt_message_destroy( Tt_message ); }
95
96 Tt_status
97 tttk_message_destroy(
98         Tt_message msg
99 )
100 {
101         Tt_pattern *pats1;
102         Tt_pattern *pats2;
103         pats1 = (Tt_pattern *)tt_message_user( msg, _TttkContractKey );
104         pats2 = (Tt_pattern *)tt_message_user( msg, _TttkSubContractKey );
105         Tt_status status = _tt_message_destroy( msg );
106         if (status != TT_WRN_STOPPED) {
107                 _tttk_patterns_destroy( pats1 );
108                 _tttk_patterns_destroy( pats2 );
109         }
110         return status;
111 }
112
113 //
114 // This is the only message callback we ever use.  It retrieves
115 // the clientdata, client callback, and a tttk internal callback.
116 // That internal callback will parse the message and pass the
117 // info (along with the clientdata) to the client callback.
118 //
119 Tt_callback_action
120 _ttDtMessageCB(
121         Tt_message msg,
122         Tt_pattern pat
123 )
124 {
125         _TtDtMessageCB cb = (_TtDtMessageCB)
126                 tt_message_user( msg, _TttkCBKey );
127         Tt_status status = tt_ptr_error( cb );
128         if (status != TT_OK) {
129                 return TT_CALLBACK_PROCESSED;
130         }
131         if (cb == 0) {
132                 return TT_CALLBACK_CONTINUE;
133         }
134         void *clientCB = tt_message_user( msg, _TttkClientCBKey );
135         status = tt_ptr_error( clientCB );
136         if (status != TT_OK) {
137                 return TT_CALLBACK_PROCESSED;
138         }
139         // clientCB is allowed to be 0.  cf. ttmedia_Deposit()
140         void *clientData = tt_message_user( msg, _TttkClientDataKey );
141         status = tt_ptr_error( clientData );
142         if (status != TT_OK) {
143                 return TT_CALLBACK_PROCESSED;
144         }
145         msg = (*cb)( msg, pat, clientCB, clientData );
146         return _ttDtCallbackAction( msg );
147 }
148
149 //
150 // Create a message and and store on it an internal callback, a
151 // client callback, and a client datum.
152 //
153 Tt_message
154 _ttDtPMessageCreate(
155         Tt_message              context,
156         Tt_class                theClass,
157         Tt_scope                theScope,
158         const char             *handler,
159         Tttk_op                 op,
160         _TtDtMessageCB          cb,
161         void                   *clientCB,
162         void                   *clientData
163 )
164 {
165         Tt_message msg = tttk_message_create( context, theClass, theScope,
166                                 handler, _ttDtOp( op ), _ttDtMessageCB );
167         Tt_status status = tt_ptr_error( msg );
168         if (status != TT_OK) {
169                 return msg;
170         }
171         _TttkItem2Free fuse( msg );
172         status = tt_message_user_set( msg, _TttkCBKey, (void *)cb );
173         if (status != TT_OK) {
174                 return (Tt_message)tt_error_pointer( status );
175         }
176         status = tt_message_user_set( msg, _TttkClientCBKey, clientCB );
177         if (status != TT_OK) {
178                 return (Tt_message)tt_error_pointer( status );
179         }
180         status = tt_message_user_set( msg, _TttkClientDataKey, clientData );
181         if (status != TT_OK) {
182                 return (Tt_message)tt_error_pointer( status );
183         }
184         fuse = (caddr_t)0;
185         return msg;
186 }
187
188 //
189 // Set the status info on a message, fail or reject it, and optionally
190 // destroy it.
191 //
192 Tt_status
193 _ttDtMessageGong(
194         Tt_message  msg,
195         Tt_status   status,
196         const char *statusString,
197         int         reject,
198         int         destroy
199 )
200 {
201         tt_message_status_set( msg, status );
202         if (statusString != 0) {
203                 tt_message_status_string_set( msg, statusString );
204         }
205         Tt_status ttStatus;
206         if (reject) {
207                 ttStatus = tt_message_reject( msg );
208         } else {
209                 ttStatus = tt_message_fail( msg );
210         }
211         if (destroy) {
212                 tttk_message_destroy( msg );
213         }
214         return ttStatus;
215 }
216
217 Tt_status
218 tttk_message_reject(
219         Tt_message  msg,
220         Tt_status   status,
221         const char *statusString,
222         int         destroy
223 )
224 {
225         return _ttDtMessageGong( msg, status, statusString, 1, destroy );
226 }
227
228 Tt_status
229 tttk_message_fail(
230         Tt_message  msg,
231         Tt_status   status,
232         const char *statusString,
233         int         destroy
234 )
235 {
236         if (tt_message_class( msg ) == TT_REQUEST) {
237                 return _ttDtMessageGong( msg, status, statusString, 0,
238                                          destroy );
239         } else if (destroy) {
240                 return tttk_message_destroy( msg );
241         }
242         return TT_OK;
243 }
244
245 //
246 // Set the default procid and call tt_message_receive()
247 //
248 Tt_message
249 _tttk_message_receive(
250         const char *procid
251 )
252 {
253         Tt_status          status;
254         if (procid != 0) {
255                 status = tt_default_procid_set( procid );
256                 if (status != TT_OK) {
257                         return (Tt_message)tt_error_pointer( status );
258                 }
259         }
260         return tt_message_receive();
261 }
262
263 //
264 // Used internally to reply to messages that might be edicts (i.e. notices)
265 //
266 Tt_status
267 _tttk_message_reply(
268         Tt_message  msg
269 )
270 {
271         if (tt_message_class( msg ) == TT_REQUEST) {
272                 return tt_message_reply( msg );
273         }
274         return TT_OK;
275 }
276
277 Tt_status
278 tttk_message_abandon(
279         Tt_message msg
280 )
281 {
282         if (_tttk_message_am_handling( msg )) {
283                 int fail = 0;
284                 if (tt_message_address( msg ) == TT_HANDLER) {
285                         fail = 1;
286                 } else if (tt_message_status( msg ) == TT_WRN_START_MESSAGE) {
287                         fail = 1;
288                 }
289                 if (fail) {
290                         return tttk_message_fail(  msg, TT_DESKTOP_ENOTSUP,0,1);
291                 } else {
292                         return tttk_message_reject(msg, TT_DESKTOP_ENOTSUP,0,1);
293                 }
294         } else {
295                 return tttk_message_destroy( msg );
296         }
297 }
298
299 //
300 // Returns the sender-set message id if any, otherwise the tt_message_id()
301 //
302 char *
303 _tttk_message_id(
304         Tt_message msg,
305         int        arg
306 )
307 {
308         int numArgs = tt_message_args_count( msg );
309         Tt_status status = tt_int_error( numArgs );
310         if (status != TT_OK) {
311                 return 0;
312         }
313         for (int i = arg; i < numArgs; i++) {
314                 char *type = tt_message_arg_type( msg, i );
315                 status = tt_ptr_error( type );
316                 if (status != TT_OK) {
317                         return 0;
318                 }
319                 if (type == 0) {
320                         continue;
321                 }
322                 int miss = strcmp( type, Tttk_message_id );
323                 tt_free( type );
324                 if (miss) {
325                         continue;
326                 }
327                 char *msgID = tt_message_arg_val( msg, i );
328                 status = tt_ptr_error( type );
329                 if (status != TT_OK) {
330                         return 0;
331                 }
332                 return msgID;
333         }
334         return tt_message_id( msg );
335 }
336
337 int
338 _tttk_message_in_final_state(
339         Tt_message msg
340 )
341 {
342         Tt_state theState = tt_message_state( msg );
343         switch (tt_message_class( msg )) {
344             case TT_NOTICE:
345                 return theState == TT_SENT;
346             case TT_REQUEST:
347                 return (theState == TT_HANDLED) || (theState == TT_FAILED);
348             case TT_OFFER:
349                 return theState == TT_RETURNED;
350         }
351         return 0;
352 }
353
354 //
355 // Can I reply to this message?
356 //
357 int
358 _tttk_message_am_handling(
359         Tt_message msg
360 )
361 {
362         if (tt_message_class( msg ) != TT_REQUEST) {
363                 return 0;
364         }
365         if (tt_message_state( msg ) != TT_SENT) {
366                 return 0;
367         }
368         char *handler = tt_message_handler( msg );
369         int am_handling = 0;
370         if ((tt_ptr_error( handler ) == TT_OK) && (handler != 0)) {
371                 am_handling = 1;
372         }
373         tt_free( handler );
374         return am_handling;
375 }
376
377 //
378 // Get arg value and return default_val on error.
379 //
380 int
381 _tttk_message_arg_ival(
382         Tt_message              msg,
383         unsigned int            n,
384         int                     default_val
385 )
386 {
387         if (! _tttk_message_arg_is_set( msg, n )) {
388                 return default_val;
389         }
390         int val;
391         Tt_status status = tt_message_arg_ival( msg, n, &val );
392         if (status != TT_OK) {
393                 return default_val;
394         }
395         return val;
396 }
397
398 char *
399 _tttk_message_arg_val(
400         Tt_message              msg,
401         unsigned int            n,
402         const char             *default_val
403 )
404 {
405         if (! _tttk_message_arg_is_set( msg, n )) {
406                 return (char *)default_val;
407         }
408         char *val = tt_message_arg_val( msg, n );
409         Tt_status status = tt_ptr_error( val );
410         if (status != TT_OK) {
411                 return (char *)default_val;
412         }
413         return val;
414 }
415
416 //
417 // Does arg n have a value?
418 //
419 int
420 _tttk_message_arg_is_set(
421         Tt_message              msg,
422         unsigned int            n
423 )
424 {
425         int val;
426         Tt_status status = tt_message_arg_ival( msg, n, &val );
427         if (status == TT_OK) {
428                 return 1;
429         }
430         if (status != TT_ERR_NUM) {
431                 return 0;
432         }
433         unsigned char *s;
434         int len;
435         status = tt_message_arg_bval( msg, n, &s, &len );
436         if (status != TT_OK) {
437                 return 0;
438         }
439         return (s != 0);
440 }
441
442 //
443 // Generic _TtDtMessageCB that sets *clientData to the negated
444 // tt_message_status() of the reply (or failure) of the message.
445 // Useful when sending synchronous requests and you only care to
446 // know the Tt_status of the reply/failure.
447 //
448 Tt_message
449 _ttTkNoteReplyStatus(
450         Tt_message      msg,
451         Tt_pattern      ,
452         void           *,
453         void           *clientData
454 )
455 {
456         if (! _tttk_message_in_final_state( msg )) {
457                 return msg;
458         }
459         int *result = (int *)clientData;
460         *result = -TT_DESKTOP_ETIMEDOUT;
461         switch (tt_message_state( msg )) {
462             case TT_HANDLED:
463                 *result = -TT_OK;
464                 break;
465             case TT_FAILED:
466                 *result = -tt_message_status( msg );
467                 if (*result == -TT_OK) {
468                         //
469                         // The handler did not say why he failed the
470                         // request, so we have to make up a reason
471                         // to pass back through e.g. ttdt_Save().
472                         //
473                         *result = -TT_DESKTOP_EPROTO;
474                 }
475                 break;
476         }
477         tttk_message_destroy( msg );
478         // Protect against bogus message status causing infinite loop
479         if (*result > 0) {
480                 *result = -(*result);
481         }
482         return 0;
483 }