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