Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / tt / lib / mp / mp_message.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: mp_message.C /main/4 1998/04/09 17:52:22 mgreess $                                                  
28 /*
29  *
30  * @(#)mp_message.C     1.52 93/09/07
31  *
32  * Tool Talk Message Passer (MP) - mp_message.cc
33  * 
34  * Copyright (c) 1990,1992 by Sun Microsystems, Inc.
35  */
36 #include <util/tt_global_env.h>
37 // Strictly, mp_message should not include the client-only mp structure.
38 // But we have just one client-only call buried in the xdr method,
39 // and splitting that out would be too hard (having different xdr
40 // methods for the server and the client would be madness!)
41 #include <mp/mp_c_global.h>
42 #include <mp/mp_c_mp.h>
43 #include <mp/mp_arg.h>
44 #include <mp/mp_msg_context.h>
45 #include <mp/mp_message.h>
46 #include <mp/mp_pattern.h>
47 #include <mp/mp_procid.h>
48 #include <mp/mp_session.h>
49 #include <util/tt_enumname.h>
50
51         
52 //
53 // Base constructor for a message.  ::xdr() relies on this
54 // to reset everything because _Tt_s_mp keeps a global
55 // _Tt_message as a buffer for reading messages off the wire,
56 // instead of constructing a new one each time.  XXX I refuse
57 // to believe that constructing a new one cannot be made cheap.
58 //
59 void _Tt_message::
60 base_constructor()
61 {
62         _pattern_id = 0;
63         _state = TT_CREATED;
64         _status = (int)TT_OK;
65         _paradigm = TT_ADDRESS_LAST;
66         _scope = TT_SCOPE_NONE;
67         _reliability = TT_DISCARD;
68         _opnum = -1;
69         _object = 0;
70         _file = 0;
71         _op = 0;
72         _otype = 0;
73         _session = 0;
74         _sender = 0;
75         _handler = 0;
76         _abstainers = 0;
77         _accepters = 0;
78         _rejecters = 0;
79         _sender_ptype = 0;
80         _handler_ptype = 0;
81         _rsessions = 0;
82         _id = 0;
83         _api_id = 0;
84         _args = new _Tt_arg_list;
85         _out_args = 0;
86         _contexts = new _Tt_msg_context_list;
87         _flags = 0;
88         _ptr_guards = 0;
89         _gid = _tt_global->gid;
90         _uid = _tt_global->uid;
91         // Set the default set of fields to be sent by
92         // _Tt_message::xdr. Note that it is important for
93         // _TT_MSK_PARADIGM and _TT_MSK_STATE to be part of this set
94         // (see relevant comments in _Tt_message::xdr).
95         _full_msg_guards = (_TT_MSK_ID |
96                             _TT_MSK_MESSAGE_CLASS |
97                             _TT_MSK_STATE |
98                             _TT_MSK_PARADIGM |
99                             _TT_MSK_SCOPE |
100                             _TT_MSK_UID |
101                             _TT_MSK_GID |
102                             _TT_MSK_STATUS |
103                             _TT_MSK_FLAGS);
104         _message_class = TT_CLASS_UNDEFINED;
105         _status_string = 0;
106 }
107
108
109
110 //
111 // Default constructor.
112 //
113
114 // XXX: Make sure all _Tt_strings do *not* point to
115 // _tt_global->universal_null_string for messages,
116 // because otherwise svc_getargs will clobber the
117 // global data
118
119 _Tt_message::
120 _Tt_message()
121 : _pattern_id(NULL), _object(NULL), _file(NULL), _op(NULL),
122   _otype(NULL), _sender_ptype(NULL), _handler_ptype(NULL),
123   _api_id(NULL), _status_string(NULL)
124 {
125         base_constructor();
126 }
127
128
129
130 //
131 // Destroys a message object.
132 //
133 _Tt_message::
134 ~_Tt_message()
135 {
136         // note _sender and _handler may be circular references
137         // so we explicitly set them to 0 to produce any garbage
138         // collection.
139         _sender = (_Tt_procid *)0;
140         _handler = (_Tt_procid *)0;
141         _session = (_Tt_session *)0;
142 }
143
144
145
146 // 
147 // Returns 1 if m is equal to this message. Message equality can be
148 // determined by logically concatenating the message sender with the
149 // message id. 
150 // 
151 int _Tt_message::
152 is_equal(const _Tt_message_ptr &m)
153 {
154         if (m->_id != _id) {
155                 return(0);
156         }
157         if (m->_sender.is_null() && _sender.is_null()) {
158                 return(1);
159         } else if (m->_sender.is_null() || _sender.is_null()) {
160                 return(0);
161         } else {
162                 return(m->_sender->id() == _sender->id());
163         }
164 }
165
166
167
168 // 
169 // XDR encodes/decodes a message.
170 // 
171 // Because xdr'ing a message is crucial to the message-passing
172 // performance the way messages are xdr'ed is a little more complicated
173 // than other xdr methods.
174 // 
175 // The main optimization that is done is to have an integer field,
176 // _ptr_guards,  is a collection of bit fields. If a particular bit is
177 // turned on then this means that the corresponding message field is
178 // being sent/received from the xdr stream. These bit fields obey the
179 // following naming convention, if _ptr_guards&_TT_MSK_<field> is true
180 // then <field> is being sent/received from the xdr stream. Note that
181 // this means that this optimization can only apply to at most 32
182 // fields.
183 // 
184 // This scheme is an optimization if it allows us to send less
185 // information for a given message. The way it does this is by allowing
186 // "default" values to not be sent. For example, if a typical value of
187 // the _scope field is TT_SESSION then rather than send this value every
188 // time, we just leave the bit turned off and have the other end just use
189 // the default value if it notices the bit is turned off.  Another way
190 // we can avoid sending the entire message is if it is known that
191 // certain fields won't be required. For example, when a handler
192 // replies to a message, it is unnecessary to send back the entire
193 // list of arguments since, by definition,  only the TT_OUT and
194 // TT_INOUT arguments can change. 
195 // 
196 // There are certain methods that are called just before a message is
197 // going to be xdr'ed that set up the _ptr_guards field to turn on the
198 // proper set of flags. These methods are:
199 // 
200 // _Tt_c_message::set_return_handler_flags
201 // 
202 //      Optimizes message xdr for the case of a handler replying to a
203 //      message. 
204 // 
205 // _Tt_s_message::set_return_sender_flags
206 //
207 //      Optimizes message xdr for the case of a message being returned
208 //      to its original sender. 
209 // 
210 // _Tt_s_message::set_send_handler_flags
211 //
212 //      Optimizes message xdr for the case of sending a message to a
213 //      handler. 
214 // 
215 // The way these methods work is by setting the _ptr_guards field to some
216 // value other than 0 that has the proper flag bits turned on. Then this
217 // method checks for _ptr_guards being 0. If it is then it just uses the
218 // value of _full_msg_guards which is an always up-to-date set of flags
219 // of message fields that need to get xdr'ed in the default case. If
220 // _ptr_guards is not 0 then that value gets used instead of the default.
221 // Another detail of this mechanism is that the _flags field may
222 // sometimes have the _TT_MSG_UPDATE_XDR_MODE flag turned on. If this is
223 // the case then this indicates that when encoding the message only the
224 // arguments contained in the _out_args list are to be used rather than
225 // the ones in the _args list. This is because the args in _out_args are
226 // only the TT_OUT and TT_INOUT arguments.
227 //
228 bool_t _Tt_message::
229 xdr(XDR *xdrs)
230 {
231         if (xdrs->x_op == XDR_DECODE) {
232                 base_constructor();
233         }
234         if (xdrs->x_op == XDR_ENCODE && _ptr_guards==0) {
235                 _flags &= ~(1<<_TT_MSG_UPDATE_XDR_MODE);        
236                 _ptr_guards = _full_msg_guards;
237         }
238
239         
240         if (! xdr_int(xdrs, &_ptr_guards)) {
241                 return(0);
242         }
243         int id_2_set;
244         int need_2_set_id = 0;
245         if (_ptr_guards&_TT_MSK_ID) {
246                 if (xdrs->x_op == XDR_DECODE) {
247                         need_2_set_id = 1;
248                         if (! xdr_int(xdrs, &id_2_set)) {
249                                 return(0);
250                         }
251                 } else {
252                         if (! xdr_int(xdrs, &_id)) {
253                                 return(0);
254                         }
255                 }
256         }
257         if (_ptr_guards&_TT_MSK_MESSAGE_CLASS) {
258                 if (! xdr_int(xdrs, (int *)&_message_class)) {
259                         return(0);
260                 }
261         }
262         if (_ptr_guards&_TT_MSK_STATE) {
263                 if (! xdr_int(xdrs, (int *)&_state)) {
264                         return(0);
265                 }
266         } else { // XXXX only if XDR_DECODE, right?  et al!
267                 _state = TT_SENT;
268         }
269         if (_ptr_guards&_TT_MSK_PARADIGM) {
270                 if (! xdr_int(xdrs, (int *)&_paradigm)) {
271                         return(0);
272                 }
273         }
274         if (_ptr_guards&_TT_MSK_SCOPE) {
275                 if (! xdr_int(xdrs, (int *)&_scope)) {
276                         return(0);
277                 }
278         } else if (_tt_global->xdr_version() > 1) {
279                 _scope = TT_SESSION;
280         }
281         if (_ptr_guards&_TT_MSK_RELIABILITY) {
282                 if (! xdr_int(xdrs, (int *)&_reliability)) {
283                         return(0);
284                 }
285         }
286         if (_ptr_guards&_TT_MSK_OPNUM) {
287                 if (! xdr_int(xdrs, &_opnum)) {
288                         return(0);
289                 }
290         }
291         if (_ptr_guards&_TT_MSK_STATUS) {
292                 if (! xdr_int(xdrs,&_status)) {
293                         return(0);
294                 }
295         }
296         // Even though in Solaris 2.x uid_t and gid_t are typedef'd as
297         // u_long, the compiler complains if they are not explicitly
298         // coerced.
299         if (_ptr_guards&_TT_MSK_UID) {
300                 if (xdrs->x_op == XDR_DECODE) {
301                         _uid = 0;
302                 }
303 #ifdef __osf__
304                 if (! xdr_u_int(xdrs, &_uid)) {
305                         return(0);
306                 }
307 #else
308                 if (! xdr_u_long(xdrs,(u_long *) &_uid)) {
309                         return(0);
310                 }
311 #endif
312         }
313         if (_ptr_guards&_TT_MSK_GID) {
314                 if (xdrs->x_op == XDR_DECODE) {
315                         _gid = 0;
316                 }
317 #ifdef __osf__
318                 if (! xdr_u_int(xdrs, &_gid)) {
319                         return(0);
320                 }
321 #else
322                 if (! xdr_u_long(xdrs,(u_long *) &_gid)) {
323                         return(0);
324                 }
325 #endif
326         }
327
328         if (_ptr_guards&_TT_MSK_SESSION) {
329                 if (xdrs->x_op == XDR_DECODE) {
330                         _session = new _Tt_session();
331                 }
332                 if (! _session->xdr(xdrs)) {
333                         return(0);
334                 }
335         } else if (xdrs->x_op == XDR_DECODE) {
336                 _session = _tt_mp->initial_session;
337         }
338
339         if (_ptr_guards&_TT_MSK_SENDER) {
340                 if (xdrs->x_op == XDR_DECODE) {
341                         _sender = new _Tt_procid();
342                 }
343                 if (! _sender->xdr(xdrs)) {
344                         return(0);
345                 }
346         } else if (! _tt_mp->in_server()) {
347                 // Since we know we're not in the server, we know that
348                 // _tt_c_mp is valid.
349                 _sender = _tt_c_mp->default_procid();
350         }
351         // _set_id() only works if _handler is set
352         if (need_2_set_id) {
353                 _set_id(id_2_set);
354         }
355         
356         
357         switch (_tt_global->xdr_version()) {
358               case 1:
359                 // version 1 tooltalk always xdr's a _Tt_procid_ptr
360                 if (! _handler.xdr(xdrs)) {
361                         return(0);
362                 }
363                 break;
364               case 2:
365               default:
366                 if (xdrs->x_op == XDR_DECODE) {
367                         //
368                         // XXX holtz: Also do this for other fields?
369                         // If not, *this is a hybrid message that
370                         // is dangerous to look at until you use it
371                         // to update_message().
372                         //
373                         _handler = 0;
374                 }
375                 if (_ptr_guards&_TT_MSK_HANDLER) {
376                         if (xdrs->x_op == XDR_DECODE) {
377                                 _handler = new _Tt_procid();
378                         }
379                         if (! _handler->xdr(xdrs)) {
380                                 return(0);
381                         }
382                 }
383                 break;
384         }
385         if (_ptr_guards&_TT_MSK_FILE) {
386                 if (! _file->xdr(xdrs)) {
387                         return(0);
388                 }
389         }
390
391         if (_ptr_guards&_TT_MSK_OBJECT) {
392                 if (! _object->xdr(xdrs)) {
393                         return(0);
394                 }
395         }
396
397         if (_ptr_guards&_TT_MSK_OP) {
398                 if (! _op->xdr(xdrs)) {
399                         return(0);
400                 }
401         }
402
403         if (_ptr_guards&_TT_MSK_ARGS) {
404                 if (xdrs->x_op == XDR_ENCODE) {
405                         if (_flags&(1<<_TT_MSG_UPDATE_XDR_MODE)) {
406
407                                 // if this flag is turned on then only
408                                 // send arguments from the _out_args
409                                 // field rather than the _args field.
410
411                                 if (_out_args.is_null()) {
412                                         _out_args = new _Tt_arg_list();
413                                 }
414                                 if (! _out_args->xdr(xdrs)) {
415                                         return(0);
416                                 }
417                         } else {
418                                 if (! _args->xdr(xdrs)) {
419                                         return(0);
420                                 }
421                         }
422                 } else {
423                         _args->flush();
424                         SET_GUARD(_full_msg_guards, 0, _TT_MSK_ARGS);
425
426                         if (! _args->xdr(xdrs)) {
427                                 return(0);
428                         }
429                 }
430         }
431         if (_ptr_guards&_TT_MSK_FLAGS) {
432                 if (! xdr_int(xdrs, &_flags)) {
433                         return(0);
434                 }
435                 if (xdrs->x_op == XDR_DECODE) {
436                         // Assume non-remote, until we learn otherwise
437                         _flags &= ~(1<<_TT_MSG_IS_REMOTE);
438                 }
439         }
440         if (_ptr_guards&_TT_MSK_OTYPE) {
441                 if (! _otype->xdr(xdrs)) {
442                         return(0);
443                 }
444         }
445
446         if (_ptr_guards&_TT_MSK_SENDER_PTYPE) {
447                 if (! _sender_ptype->xdr(xdrs)) {
448                         return(0);
449                 }
450         }
451         if (_ptr_guards&_TT_MSK_HANDLER_PTYPE) {
452                 if (! _handler_ptype->xdr(xdrs)) {
453                         return(0);
454                 }
455         }
456         if (_ptr_guards&_TT_MSK_PATTERN_ID) {
457                 if (! _pattern_id->xdr(xdrs)) {
458                         return(0);
459                 }
460         }
461         if (_ptr_guards&_TT_MSK_RSESSIONS) {
462                 if (xdrs->x_op == XDR_DECODE) {
463                         _rsessions = new _Tt_string_list();
464                 }
465                 if (! _rsessions->xdr(xdrs)) {
466                         return(0);
467                 }
468         }
469         if (_ptr_guards&_TT_MSK_STATUS_STRING) {
470                 if (! _status_string->xdr(xdrs)) {
471                         return(0);
472                 }
473         }
474         //
475         // Because of the bitmask, we don't worry about
476         // xdr versioning here, and in effect pretend that
477         // _TT_MSK_CONTEXTS has been defined from day 1.
478         //
479         if (_ptr_guards&_TT_MSK_CONTEXTS) {
480                 if (! _contexts->xdr(xdrs)) {
481                         return(0);
482                 }
483         }
484         //
485         // Ditto.
486         //
487         if (_ptr_guards&_TT_MSK_OFFEREES) {
488                 //
489                 // TT_OFFERS are more rare than contexts, so
490                 // we allocate the lists lazily to save memory.
491                 //
492                 if (_abstainers.is_null()) {
493                         _abstainers = new _Tt_procid_list;
494                 }
495                 if (! _abstainers->xdr(xdrs)) {
496                         return(0);
497                 }
498                 if (_accepters.is_null()) {
499                         _accepters = new _Tt_procid_list;
500                 }
501                 if (! _accepters->xdr(xdrs)) {
502                         return(0);
503                 }
504                 if (_rejecters.is_null()) {
505                         _rejecters = new _Tt_procid_list;
506                 }
507                 if (! _rejecters->xdr(xdrs)) {
508                         return(0);
509                 }
510         }
511
512         if (xdrs->x_op == XDR_DECODE) {
513                 // Now we want to update _full_msg_guards from
514                 // _ptr_guards appropiately. We must choose to do this
515                 // either by assignment or by or'ing the fields.
516                 // Assignment is required if this is a new message
517                 // because _full_msg_guards may contain fields that
518                 // are 1 when they need to be 0 (see
519                 // _Tt_message::_Tt_message). (and or'ing won't
520                 // help). We can tell that the message coming in is a
521                 // new message by checking whether the paradigm and
522                 // state field is being sent. This is a gross hack but
523                 // unfortunately when the need for it was discovered
524                 // there was no other way to test for this in a
525                 // binary-compatible way with previous versions. Note
526                 // that the paradigm (known as "address" in the
527                 // documentation) doesn't ever change once its been
528                 // created so it should never be the case that sending
529                 // the message to a recipient in other than the
530                 // defualt xdr mode should require sending the
531                 // paradigm field.
532
533                 if (_ptr_guards&(_TT_MSK_PARADIGM|_TT_MSK_STATE)) {
534                         _full_msg_guards = _ptr_guards;
535                 } else {
536                         _full_msg_guards |= _ptr_guards;
537                 }
538         }
539         
540         _ptr_guards = 0;
541         return(1);
542 }
543
544
545 // 
546 // m represents the same message as this but perhaps with updated
547 // information. This method handles updating this message with the
548 // appropiate values in m. 
549 // 
550 void _Tt_message::
551 update_message(const _Tt_message_ptr &m)
552 {
553         int     margc;
554         int     mguards = m->_full_msg_guards;
555
556         _full_msg_guards |= mguards;
557         if (!_tt_mp->in_server()) {
558                 if (mguards&_TT_MSK_STATE) {
559                         set_state(m->_state);
560                 }
561                 if (mguards&_TT_MSK_RELIABILITY) {
562                         set_reliability(m->_reliability);
563                 }
564                 switch (_paradigm) {
565                       case TT_OBJECT:
566                       case TT_OTYPE:
567                         if (mguards&_TT_MSK_SCOPE) {
568                                 _scope = m->_scope;
569                         }
570                         break;
571                       default:
572                         break;
573                 }
574                 if (mguards&_TT_MSK_PATTERN_ID) {
575                         if (m->_pattern_id.len()) {
576                                 _pattern_id = m->_pattern_id;
577                         }
578                 }
579                 if (mguards&_TT_MSK_HANDLER) {
580                         _handler = m->_handler;
581                 }
582                 if (mguards&_TT_MSK_HANDLER_PTYPE) {
583                         _handler_ptype = m->_handler_ptype;
584                 }
585                 if (mguards&_TT_MSK_OPNUM) {
586                         set_opnum(m->opnum());
587                 }
588         }
589         if (mguards&_TT_MSK_STATUS) {
590                 _status = m->_status;
591         }
592         if (mguards & _TT_MSK_STATUS_STRING) {
593                 set_status_string(m->_status_string);
594         }
595         if (mguards & _TT_MSK_OFFEREES) {
596                 //
597                 // We could just snare references and share the lists,
598                 // but if the given message is ttsession's static
599                 // wire buffer, then the lists will probably be changing.
600                 //
601                 _abstainers = new _Tt_procid_list( *m->_abstainers );
602                 _accepters  = new _Tt_procid_list( *m->_accepters );
603                 _rejecters  = new _Tt_procid_list( *m->_rejecters );
604         }
605         switch (m->_state) {
606             case TT_HANDLED:
607             case TT_FAILED:
608                 //
609                 // update object and file
610                 //
611
612                 if (mguards&_TT_MSK_OBJECT) {
613                         _object = m->_object;
614                 }
615                 if (mguards&_TT_MSK_FILE) {
616                         _file = m->_file;
617                 }
618                 if (mguards&_TT_MSK_CONTEXTS) {
619                         // All contexts are INOUT, and extra can
620                         // be added by the handler.
621                         _contexts = new _Tt_msg_context_list( *m->_contexts );
622                 }
623                 if (mguards&_TT_MSK_ARGS) {
624                         margc = _args->count();
625                         if (margc && m->_args->count()) { 
626
627                                 //
628                                 // update arguments with new values
629                                 //
630
631                                 _Tt_arg_list_cursor     argc;
632                                 _Tt_arg_list_cursor     nargc;
633
634                                 argc.reset(_args);
635                                 nargc.reset(m->_args);
636                                 while (argc.next()) {
637                                         switch (argc->mode()) {
638                                               case TT_OUT:
639                                               case TT_INOUT:
640                                                 if (nargc.next()) {
641                                                         argc->update_value(*nargc);
642                                                         nargc.remove();
643                                                 }
644                                                 break;
645                                               default:
646                                                 if (!_tt_mp->in_server() &&
647                                                     _message_class==TT_NOTICE &&
648                                                     !nargc.next()) { 
649                                                         m->_full_msg_guards = 0;
650                                                         m->_args->flush();
651                                                         return;
652                                                 }
653                                                 break;
654                                         }
655                                 }
656                         }
657                 }
658                 // fall through
659             case TT_RETURNED:
660                 if (is_awaiting_reply()) {
661                         set_awaiting_reply( 0 );
662                 }
663                 break;
664         }
665         m->_full_msg_guards = 0;
666         // XXX holtz 20 Jul 94  Why change given message?
667         m->_args->flush();
668 }
669
670 _Tt_msg_context_ptr _Tt_message::
671 context(const char *slotname) const
672 {
673         _Tt_msg_context_list_cursor contextC( _contexts );
674         while (contextC.next()) {
675                 if (contextC->slotName() == slotname) {
676                         return *contextC;
677                 }
678         }
679         return 0;
680 }
681
682
683 _Tt_msg_context_ptr _Tt_message::
684 context(int i) const
685 {
686         if ((i >= 0) && (i < _contexts->count())) {
687                 return (*_contexts)[ i ];
688         }
689         return 0;
690 }
691
692
693 int _Tt_message::
694 contextsCount() const
695 {
696         if (_contexts.is_null()) {
697                 return 0;
698         }
699         return _contexts->count();
700 }
701
702
703 // 
704 // Returns the id of the pattern that matched this message (ie. that
705 // caused it to be delivered). This id will be null if the message
706 // matched a ptype pattern rather than a dynamic pattern.
707 // 
708 _Tt_string & _Tt_message::
709 pattern_id()
710 {
711         return(_pattern_id);
712 }
713
714
715 // 
716 // Sets the pattern id of a messsage and turns on the corresponding bit
717 // field in _full_msg_guards if non-empty.
718 // 
719 void _Tt_message::
720 set_pattern_id(_Tt_string id)
721 {
722         _pattern_id = id;
723         SET_GUARD(_full_msg_guards, _pattern_id.len(), _TT_MSK_PATTERN_ID);
724
725 }
726
727
728 // 
729 // Function wrapper used to invoke the xdr method on a message when
730 // interfacing to the C RPC routines.
731 // 
732 bool_t
733 tt_xdr_message(XDR *xdrs, _Tt_message_ptr *msgp)
734 {
735         return((*msgp).xdr(xdrs));
736 }
737
738
739 uid_t _Tt_message::
740 uid() const
741 {
742         return _uid;
743 }
744
745
746 gid_t _Tt_message::
747 gid() const
748 {
749         return _gid;
750 }
751
752
753 int _Tt_message::
754 id() const
755 {
756         return(_id);
757 }
758
759 const _Tt_string & _Tt_message::
760 api_id() const
761 {
762         return _api_id;
763 }
764
765
766 Tt_status _Tt_message::
767 set_message_class(Tt_class mclass)
768 {
769         _message_class = mclass;
770         return(TT_OK);
771 }
772
773
774 Tt_status _Tt_message::
775 set_state(Tt_state state)
776 {
777         _state = state;
778
779         return(TT_OK);
780 }
781
782
783 Tt_status _Tt_message::
784 set_paradigm(Tt_address p)
785 {
786         _paradigm = p;
787         
788         return(TT_OK);
789 }
790
791
792 // 
793 // Sets the scope of a message. Note that if we're a post-version-1
794 // client then we also turn on the corresponding flag in _full_msg_guards
795 // if this is a non-TT_SESSION scope.
796 // 
797 Tt_status _Tt_message::
798 set_scope(Tt_scope s)
799 {
800
801 // XXX: The xdr_version() only shadows to the sessions xdr version when an 
802 //      RPC call is in progress. set_scope() can be called by
803 //      tt_message_scope_set() at which time the xdr version is not setup
804 //      correctly.
805
806         _scope = s;
807         SET_GUARD(_full_msg_guards,1,_TT_MSK_SCOPE);
808         return(TT_OK);
809 }
810
811
812 // 
813 // Sets the file field of a message and turn on the corresponding bit in
814 // _full_msg_guards if non-empty.
815 // 
816 Tt_status _Tt_message::
817 set_file(_Tt_string f)
818 {
819         if (f.len() == 0) {
820                 return(TT_OK);
821         }
822         _file = f;
823         SET_GUARD(_full_msg_guards, 1, _TT_MSK_FILE);
824         return(TT_OK);
825 }
826
827
828 // 
829 // Sets the session field in a message and turns on the corresponding bit
830 // field in _full_msg_guards if non-null.
831 // 
832 Tt_status _Tt_message::
833 set_session(_Tt_session_ptr &s)
834 {
835         _session = s;
836         SET_GUARD(_full_msg_guards,(! _session.is_null()), _TT_MSK_SESSION);
837         
838         return(TT_OK);
839 }
840
841
842 //
843 // Sets the op field in a message and turns on the corresponding bit
844 // field in _full_msg_guards if non-null.
845 //
846 Tt_status _Tt_message::
847 set_op(_Tt_string o)
848 {
849         _op = o;
850         SET_GUARD(_full_msg_guards, _op.len(), _TT_MSK_OP);
851         
852         return(TT_OK);
853 }
854
855
856 //
857 // Sets the opnum field in a message and turns on the corresponding
858 // bit field in _full_msg_guards if not equal to -1 (the default).
859 //
860 Tt_status _Tt_message::
861 set_opnum(int o)
862 {
863         _opnum = o;
864         SET_GUARD(_full_msg_guards, _opnum != -1, _TT_MSK_OPNUM);
865         
866         return(TT_OK);
867 }
868
869
870 // 
871 // Adds an argument to a message. Turns on the bit field for _args in
872 // _full_msg_guards since we know the list is non-empty.
873 // 
874 Tt_status _Tt_message::
875 add_arg(_Tt_arg_ptr &arg)
876 {
877         _args->append(arg);
878         
879         SET_GUARD(_full_msg_guards, 1, _TT_MSK_ARGS);
880         return(TT_OK);
881 }
882
883
884 // 
885 // Adds a TT_OUT or TT_INOUT argument to the _out_args list. This is used
886 // by _Tt_message::xdr when the _TT_MSG_UPDATE_XDR flag is turned on.
887 // 
888 void _Tt_message::
889 add_out_arg(_Tt_arg_ptr &arg)
890 {
891         if (_out_args.is_null()) {
892                 _out_args = new _Tt_arg_list();
893         }
894         switch (arg->mode()) {
895               case TT_OUT:
896               case TT_INOUT:
897                 // a parallel list of just out arguments is kept since
898                 // whenever it is known that the receiver of a message
899                 // is only seeing an update of the message, only the
900                 // out arguments need to be sent.
901                 _out_args->append(arg);
902                 SET_GUARD(_full_msg_guards, 1, _TT_MSK_ARGS);
903                 break;
904               case TT_IN:
905               default:
906                 break;
907         }
908 }
909
910
911 // 
912 // Adds a context to a message. Turns on the bit field for _contexts in
913 // _full_msg_guards since we know the list is non-empty.
914 // 
915 Tt_status _Tt_message::
916 add_context(_Tt_msg_context_ptr &context)
917 {
918         _contexts->append_ordered(context);
919         
920         SET_GUARD(_full_msg_guards, 1, _TT_MSK_CONTEXTS);
921         return(TT_OK);
922 }
923
924
925 // 
926 // Sets the object field in a message and turns on the corresponding bit
927 // field in _full_msg_guards.
928 // 
929 Tt_status _Tt_message::
930 set_object(_Tt_string oid)
931 {
932         _object = oid;
933         SET_GUARD(_full_msg_guards, _object.len(), _TT_MSK_OBJECT);
934         return(TT_OK);
935 }
936
937
938 Tt_status _Tt_message::
939 set_otype(_Tt_string ot)
940 {
941         _otype = ot;
942         SET_GUARD(_full_msg_guards, _otype.len(), _TT_MSK_OTYPE);
943         
944         return(TT_OK);
945 }
946
947
948 Tt_status _Tt_message::
949 set_sender(_Tt_procid_ptr &s)
950 {
951         _sender = s;
952         SET_GUARD(_full_msg_guards, (! _sender.is_null()), _TT_MSK_SENDER);
953         
954         return(TT_OK);
955 }
956
957
958 Tt_status _Tt_message::
959 unset_handler_procid(void)
960 {
961         _handler = (_Tt_procid *) 0;
962         SET_GUARD(_full_msg_guards, 0, _TT_MSK_HANDLER);
963         
964         return(TT_OK);
965 }
966
967 Tt_status _Tt_message::
968 set_handler_procid(const _Tt_procid_ptr &h)
969 {
970         _handler = h;
971         SET_GUARD(_full_msg_guards, (! _handler.is_null()), _TT_MSK_HANDLER);
972         
973         return(TT_OK);
974 }
975
976
977 Tt_status _Tt_message::
978 add_voter(const _Tt_procid_ptr &voter, Tt_state vote)
979 {
980         if (voter.is_null() || (_message_class != TT_OFFER)) {
981                 return TT_OK;
982         }
983         if (_abstainers.is_null()) {
984                 _abstainers = new _Tt_procid_list;
985         }
986         if (_abstainers.is_null()) {
987                 return TT_ERR_NOMEM;
988         }
989         if (_accepters.is_null()) {
990                 _accepters = new _Tt_procid_list;
991         }
992         if (_accepters.is_null()) {
993                 return TT_ERR_NOMEM;
994         }
995         if (_rejecters.is_null()) {
996                 _rejecters = new _Tt_procid_list;
997         }
998         if (_rejecters.is_null()) {
999                 return TT_ERR_NOMEM;
1000         }
1001         switch (vote) {
1002             case TT_ACCEPTED:
1003                 _accepters->append( voter );
1004                 break;
1005             case TT_REJECTED:
1006                 _rejecters->append( voter );
1007                 break;
1008             case TT_ABSTAINED:
1009                 _abstainers->append( voter );
1010                 break;
1011             default:
1012                 // Not a vote; bail out.
1013                 return TT_OK;
1014         }
1015         SET_GUARD(_full_msg_guards, 1, _TT_MSK_OFFEREES);
1016         return TT_OK;
1017 }
1018
1019
1020 Tt_status _Tt_message::
1021 set_sender_ptype(_Tt_string s)
1022 {
1023         _sender_ptype = s;
1024         SET_GUARD(_full_msg_guards,_sender_ptype.len(), _TT_MSK_SENDER_PTYPE);
1025         
1026         return(TT_OK);
1027 }
1028
1029
1030 Tt_status _Tt_message::
1031 set_handler_ptype(_Tt_string h)
1032 {
1033         _handler_ptype = h;
1034         SET_GUARD(_full_msg_guards,_handler_ptype.len(),_TT_MSK_HANDLER_PTYPE);
1035         
1036         return(TT_OK);
1037 }
1038
1039
1040 Tt_status _Tt_message::
1041 set_reliability(Tt_disposition r)
1042 {
1043         _reliability = r;
1044         SET_GUARD(_full_msg_guards, _reliability != TT_DISCARD,
1045                   _TT_MSK_RELIABILITY);         
1046         
1047         return(TT_OK);
1048 }
1049
1050
1051 // 
1052 // Sets the id of a message which is used to uniquely identify the
1053 // message within the sending process. The id is also used when queueing
1054 // the message.  This implies that the message contains enough
1055 // information that is unique so that the queued message will never be
1056 // misinterpreted to be another message. This uniqueness is achieved by
1057 // combining the sender procid with the message id. This works because
1058 // the prefix of the sender procid is unique and the message id then
1059 // distinguishes the message among other messages the process has sent.
1060 // 
1061 Tt_status _Tt_message::
1062 set_id()
1063 {
1064         return _set_id(_tt_mp->generate_message_id());
1065 }
1066
1067 Tt_status _Tt_message::
1068 _set_id(int id)
1069 {
1070         _id = id;
1071         char buf[BUFSIZ];
1072         sprintf( buf, "%d ", _id );
1073         _api_id = buf;
1074         if (sender().is_null()) {       
1075                 abort();
1076         }
1077         _api_id = _api_id.cat( sender()->id() );
1078         return(TT_OK);
1079 }
1080
1081 /* 
1082  * Sets this to be a super message (send to parent type)
1083  */
1084 void _Tt_message::
1085 set_super()
1086 {
1087         _flags |= (1<<_TT_MSG_IS_SUPER);
1088 }
1089
1090 _Tt_string & _Tt_message::
1091 status_string()
1092 {
1093         return(_status_string);
1094 }
1095
1096
1097 Tt_status _Tt_message::
1098 set_status_string(_Tt_string st)
1099 {
1100         _status_string = st;
1101         SET_GUARD(_full_msg_guards,_status_string.len(),_TT_MSK_STATUS_STRING);
1102         
1103         return(TT_OK);
1104 }
1105
1106
1107 // 
1108 // This method will identify this message as a "start" message if flag is
1109 // 1. Otherwise it clears the flag associated with this. When turning the
1110 // flag on we set the status field to TT_WRN_START_MESSAGE because the
1111 // tooltalk client needs to check for this value to know that this is a
1112 // start message. When turning the flag off we have to set the status to
1113 // TT_OK but only if it is still TT_WRN_START_MESSAGE (otherwise we end
1114 // up stomping on a status code set by the client.).
1115 // 
1116 void _Tt_message::
1117 set_start_message(int flag)
1118 {
1119         if (flag) {
1120                 set_status((int)TT_WRN_START_MESSAGE);
1121                 _flags |= (1<<_TT_MSG_IS_START_MSG);
1122         } else {
1123                 if (_status == (int)TT_WRN_START_MESSAGE) {
1124                         SET_GUARD(_full_msg_guards,1,_TT_MSK_STATUS);
1125                         _status = TT_OK;
1126                 }
1127                 _flags &= ~(1<<_TT_MSG_IS_START_MSG);
1128         }
1129 }
1130
1131
1132 // 
1133 // Returns 1 if this is a start message. Version 1 clients didn't
1134 // implement the _TT_MSG_IS_START_MSG flag so the only way to tell with
1135 // them is if the _status field is TT_WRN_START_MESSAGE.
1136 // 
1137 int _Tt_message::
1138 is_start_message() const
1139 {
1140         return(_status == TT_WRN_START_MESSAGE ||
1141                (_flags&(1<<_TT_MSG_IS_START_MSG)));
1142 }
1143
1144 void _Tt_message::
1145 set_awaiting_reply(int flag)
1146 {
1147         if (flag) {
1148                 _flags |= (1<<_TT_MSG_AWAITING_REPLY);
1149         } else {
1150                 _flags &= ~(1<<_TT_MSG_AWAITING_REPLY);
1151         }
1152 }
1153
1154 int _Tt_message::
1155 is_awaiting_reply() const
1156 {
1157         return (_flags&(1<<_TT_MSG_AWAITING_REPLY));
1158 }
1159
1160
1161 Tt_status _Tt_message::
1162 set_status(int st)
1163 {
1164         // _status is used in the special case of a start message
1165         if (st == (int)TT_OK && _status == TT_WRN_START_MESSAGE) {
1166                 return(TT_OK);
1167         }
1168         _status = st;
1169         SET_GUARD(_full_msg_guards,1,_TT_MSK_STATUS);
1170         return(TT_OK);
1171 }
1172
1173
1174 // 
1175 // Sets the _handler field of a message for the special case of an
1176 // observer replying to a start message. This special case is
1177 // distinguished by turning on the _TT_MSG_OBSERVER flag.
1178 // 
1179 void _Tt_message::
1180 set_observer_procid(const _Tt_procid_ptr &p)
1181 {
1182         _flags |= (1<<_TT_MSG_OBSERVER);
1183         _handler = p;
1184 }
1185
1186
1187 // 
1188 // Clears the _TT_MSG_OBSERVER flag and sets the _handler field back to
1189 // null. 
1190 // 
1191 void _Tt_message::
1192 clr_observer_procid()
1193 {
1194         _flags &= ~(1<<_TT_MSG_OBSERVER);
1195         _handler = (_Tt_procid *)0;
1196 }
1197
1198
1199 static void
1200 _tt_procid_list_print(const _Tt_ostream &os,
1201                       const _Tt_procid_list_ptr &procs, const char *label)
1202 {
1203         if ((! procs.is_null()) && (procs->count() > 0)) {
1204                 os << label << ":\n";
1205                 _Tt_string indent = os.indent();
1206                 os.set_indent( indent.cat( "\t" ));
1207                 _Tt_procid_list_cursor procC( procs );
1208                 while (procC.next()) {  
1209                         procC->print( os );
1210                 }
1211                 os.set_indent( indent );
1212         }
1213 }
1214
1215
1216 //
1217 // Prints out a message to os.
1218 //
1219 void _Tt_message::
1220 print(const _Tt_ostream &os) const
1221 {
1222         _Tt_arg_list_cursor             arg_cursor;
1223
1224         os << _tt_enumname(state()) << " ";
1225         os << _tt_enumname(_paradigm) << " ";
1226         os << _tt_enumname(_message_class) << " ";
1227         os << "(" << _tt_enumname(reliability()) << " in ";
1228         os << _tt_enumname(scope()) << "): ";
1229         os << (int)_status << " == " << (Tt_status)_status << "\n";
1230
1231         os << "id:\t\t" << _api_id << "\n";
1232         os << "op:\t\t" << _op << "\n";
1233         if (_args->count() > 0) {
1234                 os << "args:\n";
1235                 _Tt_string indent = os.indent();
1236                 os.set_indent( indent.cat( "\t" ));
1237                 _Tt_arg_list_cursor argC( _args );
1238                 while (argC.next()) {   
1239                         argC->print( os );
1240                 }
1241                 os.set_indent( indent );
1242         }
1243         if (_contexts->count() > 0) {
1244                 os << "contexts:\n";
1245                 _Tt_string indent = os.indent();
1246                 os.set_indent( indent.cat( "\t" ));
1247                 _Tt_msg_context_list_cursor contextC( _contexts );
1248                 while (contextC.next()) {       
1249                         contextC->print( os );
1250                 }
1251                 os.set_indent( indent );
1252         }
1253         if (_status_string.len() > 0) {
1254                 os << "status_string:\t" << _status_string << "\n";
1255         }
1256         if (! _session.is_null()) {
1257                 os << "session:\t" << _session->address_string() << "\n";
1258         }
1259         if (_file.len() > 0) {
1260                 os << "file:\t\t" << _tt_network_path_to_local_path(_file)
1261                    << "\n";
1262         }
1263         if (_object.len() > 0) {
1264                 os << "object:\t\t" << _object << "\n";
1265         }
1266         if (_otype.len() > 0) {
1267                 os << "otype:\t\t" << _otype << "\n";
1268         }
1269         if (! _sender.is_null()) {
1270                 os << "sender:\t\t[" << _uid << "/" << _gid << "] ";
1271                 _sender->print( os );
1272         }
1273         if (_sender_ptype.len() > 0) {
1274                 os << "sender_ptype:\t" << _sender_ptype << "\n";
1275         }
1276         if (_pattern_id.len() > 0) {
1277                 os << "pattern:\t" << _pattern_id << "\n";
1278         }
1279         if (opnum() != -1) {
1280                 os << "opnum:\t\t" << opnum() << "\n";
1281         }
1282         if (! _handler.is_null()) {
1283                 os << "handler:\t";
1284                 _handler->print( os );
1285         }
1286         if (_handler_ptype.len() > 0) {
1287                 os << "handler_ptype:\t" << _handler_ptype << "\n";
1288         }
1289         _tt_procid_list_print( os, _accepters, "accepters" );
1290         _tt_procid_list_print( os, _rejecters, "rejecters" );
1291         _tt_procid_list_print( os, _abstainers, "abstainers" );
1292 }