xref: /haiku/src/kits/app/Message.cpp (revision 2ae568931fcac7deb9f1e6ff4e47213fbfe4029b)
1 /*
2  * Copyright 2001-2005, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Erik Jaesler (erik@cgsoftware.com)
7  *		DarkWyrm <bpmagic@columbus.rr.com>
8  *		Ingo Weinhold <bonefish@users.sf.net>
9  */
10 
11 #ifdef USING_MESSAGE4
12 #	include "Message4.cpp"
13 #else
14 
15 /**	BMessage class creates objects that store data and that
16  *	can be processed in a message loop.  BMessage objects
17  *	are also used as data containers by the archiving and
18  *	the scripting mechanisms.
19  */
20 
21 // debugging
22 //#define DBG(x) x
23 #define DBG(x)	;
24 #define PRINT(x)	DBG({ printf("[%6ld] ", find_thread(NULL)); printf x; })
25 
26 #include <stdio.h>
27 
28 #include <Application.h>
29 #include <BlockCache.h>
30 #include <ByteOrder.h>
31 #include <Errors.h>
32 #include <Message.h>
33 #include <Messenger.h>
34 #include <MessengerPrivate.h>
35 #include <String.h>
36 
37 #include <AppMisc.h>
38 #include <DataBuffer.h>
39 #include <KMessage.h>
40 #include <MessageBody.h>
41 #include <MessageUtils.h>
42 #include <TokenSpace.h>
43 
44 #include "dano_message.h"
45 
46 
47 static const uint32 kMessageMagic = 'FOB1';
48 static const uint32 kMessageMagicSwapped = '1BOF';
49 
50 static const uint32 kMessageMagicDano = 'FOB2';
51 static const uint32 kMessageMagicDanoSwapped = '2BOF';
52 
53 // flags for the overall message (the bitfield is 1 byte)
54 #define MSG_FLAG_BIG_ENDIAN		0x01
55 #define MSG_FLAG_INCL_TARGET	0x02
56 #define MSG_FLAG_INCL_REPLY		0x04
57 #define MSG_FLAG_SCRIPT_MSG		0x08
58 // These are for future improvement
59 #if 0
60 #define MSG_FLAG_USE_PREFERRED	0x10
61 #define MSG_FLAG_REPLY_WANTED	0x20
62 #define MSG_FLAG_REPLY_DONE		0x40
63 #define MSG_FLAG_IS_REPLY		0x80
64 
65 #define MSG_FLAG_HDR_MASK		0xF0
66 #endif
67 
68 #define MSG_HEADER_MAX_SIZE		38
69 #define MSG_NAME_MAX_SIZE		256
70 
71 // Globals ---------------------------------------------------------------------
72 
73 using namespace BPrivate;
74 
75 const char* B_SPECIFIER_ENTRY = "specifiers";
76 const char* B_PROPERTY_ENTRY = "property";
77 const char* B_PROPERTY_NAME_ENTRY = "name";
78 
79 BBlockCache* BMessage::sMsgCache = NULL;
80 port_id BMessage::sReplyPorts[sNumReplyPorts];
81 long BMessage::sReplyPortInUse[sNumReplyPorts];
82 
83 
84 static status_t handle_reply(port_id   reply_port,
85                              int32*    pCode,
86                              bigtime_t timeout,
87                              BMessage* reply);
88 
89 static status_t convert_message(const KMessage *fromMessage,
90 	BMessage *toMessage);
91 
92 static ssize_t min_hdr_size();
93 
94 
95 // #pragma mark -
96 
97 class BMessage::Header {
98 public:
99 	Header() {}
100 	Header(const BMessage &message) { ReadFrom(message); }
101 
102 	status_t SetMagic(uint32 magic);
103 
104 	status_t ReadFrom(BDataIO &stream);
105 	void ReadFrom(const BMessage &message);
106 	status_t WriteTo(BDataIO &stream, bool calculateCheckSum = true) const;
107 	void WriteTo(BMessage &message) const;
108 
109 	uint32	CalculateCheckSum() const;
110 	uint32	CalculateHeaderSize() const;
111 
112 	bool IsSwapped() const { return fSwapped; }
113 
114 	bool HasTarget() const { return (fFlags & MSG_FLAG_INCL_TARGET); }
115 	void SetTarget(int32 token);
116 
117 	void Dump() const;
118 
119 private:
120 	uint32	fMagic;
121 	int32	fBodySize;
122 	uint32	fWhat;
123 	uint8	fFlags;
124 	int32	fTargetToken;
125 	port_id	fReplyPort;
126 	int32	fReplyToken;
127 	team_id	fReplyTeam;
128 	bool	fReplyRequired;
129 	bool	fReplyDone;
130 	bool	fIsReply;
131 	bool	fSwapped;
132 };
133 
134 
135 status_t
136 BMessage::Header::SetMagic(uint32 magic)
137 {
138 	if (magic == kMessageMagicSwapped) {
139 		fSwapped = true;
140 	} else if (magic == kMessageMagic) {
141 		fSwapped = false;
142 	} else {
143 		// This is *not* a message
144 		return B_NOT_A_MESSAGE;
145 	}
146 
147 	fMagic = magic;
148 	return B_OK;
149 }
150 
151 
152 // ReadFrom
153 status_t
154 BMessage::Header::ReadFrom(BDataIO &stream)
155 {
156 	int32 checkSum;
157 	uchar csBuffer[MSG_HEADER_MAX_SIZE];
158 
159 	TReadHelper read_helper(&stream);
160 	TChecksumHelper checksum_helper(csBuffer);
161 	int32 flattenedSize;
162 
163 	try {
164 		read_helper.SetSwap(fSwapped);
165 
166 		// get the checksum
167 		read_helper(checkSum);
168 		// get the size
169 		read_helper(flattenedSize);
170 		checksum_helper.Cache(flattenedSize);
171 		// Get the what
172 		read_helper(fWhat);
173 		checksum_helper.Cache(fWhat);
174 		// Get the flags
175 		read_helper(fFlags);
176 		checksum_helper.Cache(fFlags);
177 
178 		if (fFlags & MSG_FLAG_BIG_ENDIAN) {
179 			// TODO: ???
180 			// Isn't this already indicated by the byte order of the message version?
181 		}
182 		if (fFlags & MSG_FLAG_INCL_TARGET) {
183 			// Get the target data
184 			read_helper(fTargetToken);
185 			checksum_helper.Cache(fTargetToken);
186 		}
187 		if (fFlags & MSG_FLAG_INCL_REPLY) {
188 			// Get the reply port
189 			read_helper(fReplyPort);
190 			read_helper(fReplyToken);
191 			read_helper(fReplyTeam);
192 			checksum_helper.Cache(fReplyPort);
193 			checksum_helper.Cache(fReplyToken);
194 			checksum_helper.Cache(fReplyTeam);
195 
196 			// Get the "big flags"
197 			uint8 bigFlags;
198 			// Get the preferred flag
199 			read_helper(bigFlags);
200 			checksum_helper.Cache(bigFlags);
201 			if (bigFlags)
202 				fTargetToken = B_PREFERRED_TOKEN;
203 
204 			// Get the reply requirement flag
205 			read_helper(bigFlags);
206 			checksum_helper.Cache(bigFlags);
207 			fReplyRequired = bigFlags;
208 
209 			// Get the reply done flag
210 			read_helper(bigFlags);
211 			checksum_helper.Cache(bigFlags);
212 			fReplyDone = bigFlags;
213 
214 			// Get the "is reply" flag
215 			read_helper(bigFlags);
216 			checksum_helper.Cache(bigFlags);
217 			fIsReply = bigFlags;
218 		}
219 	} catch (status_t& e) {
220 		return e;
221 	}
222 
223 	fBodySize = flattenedSize - CalculateHeaderSize();
224 
225 	if (checkSum != checksum_helper.CheckSum())
226 		return B_NOT_A_MESSAGE;
227 
228 	return B_OK;
229 }
230 
231 // ReadFrom
232 void
233 BMessage::Header::ReadFrom(const BMessage &message)
234 {
235 	fMagic = kMessageMagic;
236 
237 	fBodySize = message.fBody->FlattenedSize();
238 	fWhat = message.what;
239 	fFlags = 0;
240 #ifdef B_HOST_IS_BENDIAN
241 	fFlags |= MSG_FLAG_BIG_ENDIAN;
242 #endif
243 	if (message.HasSpecifiers())
244 		fFlags |= MSG_FLAG_SCRIPT_MSG;
245 	if (message.fTarget != B_NULL_TOKEN)
246 		fFlags |= MSG_FLAG_INCL_TARGET;
247 	if (message.fReplyTo.port >= 0 &&
248 		message.fReplyTo.target != B_NULL_TOKEN &&
249 		message.fReplyTo.team >= 0) {
250 		fFlags |= MSG_FLAG_INCL_REPLY;
251 	}
252 	fTargetToken = message.fTarget;
253 	fReplyPort = message.fReplyTo.port;
254 	fReplyToken = message.fReplyTo.target;
255 	fReplyTeam = message.fReplyTo.team;
256 	fReplyRequired = message.fReplyRequired;
257 	fReplyDone = message.fReplyDone;
258 	fIsReply = message.fIsReply;
259 }
260 
261 // WriteTo
262 status_t
263 BMessage::Header::WriteTo(BDataIO &stream, bool calculateCheckSum) const
264 {
265 	status_t err = B_OK;
266 	int32 data;
267 
268 	// Write the version of the binary data format
269 	data = fMagic;
270 	write_helper(&stream, (const void*)&data, sizeof (data), err);
271 	if (!err) {
272 		// compute checksum
273 		data = (calculateCheckSum ? CalculateCheckSum() : 0);
274 		write_helper(&stream, (const void*)&data, sizeof (data), err);
275 	}
276 	if (!err) {
277 		// Write the flattened size of the entire message
278 		data = CalculateHeaderSize() + fBodySize;
279 		write_helper(&stream, (const void*)&data, sizeof (data), err);
280 	}
281 	if (!err) {
282 		// Write the 'what' member
283 		write_helper(&stream, (const void*)&fWhat, sizeof (fWhat), err);
284 	}
285 	if (!err) {
286 		// Write the header flags
287 		write_helper(&stream, (const void*)&fFlags, sizeof (fFlags), err);
288 	}
289 
290 	// Write targeting info if necessary
291 	if (!err && (fFlags & MSG_FLAG_INCL_TARGET)) {
292 		data = fTargetToken;
293 		write_helper(&stream, (const void*)&data, sizeof (data), err);
294 	}
295 
296 	// Write reply info if necessary
297 	if (!err && (fFlags & MSG_FLAG_INCL_REPLY)) {
298 		write_helper(&stream, (const void*)&fReplyPort, sizeof(fReplyPort),
299 			err);
300 		if (!err) {
301 			write_helper(&stream, (const void*)&fReplyToken,
302 						 sizeof(fReplyToken), err);
303 		}
304 		if (!err) {
305 			write_helper(&stream, (const void*)&fReplyTeam,
306 						 sizeof(fReplyTeam), err);
307 		}
308 
309 		uint8 bigFlags;
310 		if (!err) {
311 			bigFlags = fTargetToken == B_PREFERRED_TOKEN ? 1 : 0;
312 			write_helper(&stream, (const void*)&bigFlags, sizeof(bigFlags),
313 				err);
314 		}
315 		if (!err)
316 		{
317 			bigFlags = fReplyRequired ? 1 : 0;
318 			write_helper(&stream, (const void*)&bigFlags, sizeof(bigFlags),
319 				err);
320 		}
321 		if (!err)
322 		{
323 			bigFlags = fReplyDone ? 1 : 0;
324 			write_helper(&stream, (const void*)&bigFlags, sizeof(bigFlags),
325 				err);
326 		}
327 		if (!err)
328 		{
329 			bigFlags = fIsReply ? 1 : 0;
330 			write_helper(&stream, (const void*)&bigFlags, sizeof(bigFlags),
331 				err);
332 		}
333 	}
334 
335 	return err;
336 }
337 
338 // WriteTo
339 void
340 BMessage::Header::WriteTo(BMessage &message) const
341 {
342 	// Make way for the new data
343 	message.MakeEmpty();
344 
345 	message.what = fWhat;
346 	message.fHasSpecifiers = fFlags & MSG_FLAG_SCRIPT_MSG;
347 
348 	message.fPreferred = fTargetToken == B_PREFERRED_TOKEN;
349 	message.fTarget = fTargetToken;
350 
351 	if (fFlags & MSG_FLAG_INCL_REPLY) {
352 		// Get the reply port
353 		message.fReplyTo.port = fReplyPort;
354 		message.fReplyTo.target = fReplyToken;
355 		message.fReplyTo.team = fReplyTeam;
356 
357 		message.fWasDelivered = true;
358 
359 		message.fReplyRequired = fReplyRequired;
360 		message.fReplyDone = fReplyDone;
361 		message.fIsReply = fIsReply;
362 	}
363 }
364 
365 // CalculateCheckSum
366 uint32
367 BMessage::Header::CalculateCheckSum() const
368 {
369 	uchar buffer[MSG_HEADER_MAX_SIZE];
370 	BMemoryIO stream(buffer, sizeof(buffer));
371 	WriteTo(stream, false);
372 	int32 size = stream.Position();
373 	return _checksum_(buffer + 8, size - 8);
374 }
375 
376 // CalculateHeaderSize
377 uint32
378 BMessage::Header::CalculateHeaderSize() const
379 {
380 	ssize_t size = min_hdr_size();
381 
382 	if (fTargetToken != B_NULL_TOKEN)
383 		size += sizeof (fTargetToken);
384 
385 	if (fReplyPort >= 0 && fReplyToken != B_NULL_TOKEN && fReplyTeam >= 0) {
386 		size += sizeof (fReplyPort);
387 		size += sizeof (fReplyToken);
388 		size += sizeof (fReplyTeam);
389 
390 		size += 4;	// For the "big" flags
391 	}
392 
393 	return size;
394 }
395 
396 // SetTarget
397 void
398 BMessage::Header::SetTarget(int32 token)
399 {
400 	fTargetToken = token;
401 	if (fTargetToken == B_NULL_TOKEN)
402 		fFlags &= ~MSG_FLAG_INCL_TARGET;
403 	else
404 		fFlags |= MSG_FLAG_INCL_TARGET;
405 }
406 
407 // Dump
408 void
409 BMessage::Header::Dump() const
410 {
411 	printf("BMessage::Header:\n");
412 	printf("  magic:            %lx\n", fMagic);
413 	printf("  body size:        %ld\n", fBodySize);
414 	printf("  what:             %lx\n", fWhat);
415 	printf("  flags:            %x\n", fFlags);
416 	printf("  target token:     %ld\n", fTargetToken);
417 	printf("  reply port:       %ld\n", fReplyPort);
418 	printf("  reply token:      %ld\n", fReplyToken);
419 	printf("  reply team:       %ld\n", fReplyTeam);
420 	printf("  reply required:   %d\n", fReplyRequired);
421 	printf("  reply done:       %d\n", fReplyDone);
422 	printf("  is reply:         %d\n", fIsReply);
423 	printf("  swapped:          %d\n", fSwapped);
424 }
425 
426 // #pragma mark -
427 
428 void BMessage::_ReservedMessage1() {}
429 void BMessage::_ReservedMessage2() {}
430 void BMessage::_ReservedMessage3() {}
431 
432 //------------------------------------------------------------------------------
433 BMessage::BMessage()
434 	:	what(0), fBody(NULL)
435 {
436 	init_data();
437 }
438 //------------------------------------------------------------------------------
439 BMessage::BMessage(uint32 w)
440 	:	fBody(NULL)
441 {
442 	init_data();
443 	what = w;
444 }
445 //------------------------------------------------------------------------------
446 BMessage::BMessage(const BMessage& a_message)
447 	:	fBody(NULL)
448 {
449 	init_data();
450 	*this = a_message;
451 }
452 //------------------------------------------------------------------------------
453 BMessage::BMessage(BMessage *a_message)
454 	:	fBody(NULL)
455 {
456 	init_data();
457 	*this = *a_message;
458 }
459 //------------------------------------------------------------------------------
460 BMessage::~BMessage()
461 {
462 	if (IsSourceWaiting())
463 	{
464 		SendReply(B_NO_REPLY);
465 	}
466 	delete fBody;
467 }
468 //------------------------------------------------------------------------------
469 BMessage& BMessage::operator=(const BMessage& msg)
470 {
471 	what = msg.what;
472 
473 	fQueueLink = msg.fQueueLink;
474 	fTarget = msg.fTarget;
475 	fOriginal = msg.fOriginal;
476 	fChangeCount = msg.fChangeCount;
477 	fCurSpecifier = msg.fCurSpecifier;
478 	fPtrOffset = msg.fPtrOffset;
479 
480 	fEntries = msg.fEntries;
481 
482 	fReplyTo.port = msg.fReplyTo.port;
483 	fReplyTo.target = msg.fReplyTo.target;
484 	fReplyTo.team = msg.fReplyTo.team;
485 	fReplyTo.preferred = msg.fReplyTo.preferred;
486 
487 	fPreferred = msg.fPreferred;
488 	fReplyRequired = msg.fReplyRequired;
489 	fReplyDone = msg.fReplyDone;
490 	fIsReply = msg.fIsReply;
491 	fWasDelivered = msg.fWasDelivered;
492 	fReadOnly = msg.fReadOnly;
493 	fHasSpecifiers = msg.fHasSpecifiers;
494 
495 	*fBody = *(msg.fBody);
496 	return *this;
497 }
498 //------------------------------------------------------------------------------
499 void BMessage::init_data()
500 {
501 	what = 0;
502 
503 	fQueueLink = NULL;
504 	fTarget = B_NULL_TOKEN;
505 	fOriginal = NULL;
506 	fChangeCount = 0;
507 	fCurSpecifier = -1;
508 	fPtrOffset = 0;
509 
510 	fEntries = NULL;
511 
512 	fReplyTo.port = -1;
513 	fReplyTo.target = B_NULL_TOKEN;
514 	fReplyTo.team = -1;
515 	fReplyTo.preferred = false;
516 
517 	fPreferred = false;
518 	fReplyRequired = false;
519 	fReplyDone = false;
520 	fIsReply = false;
521 	fWasDelivered = false;
522 	fReadOnly = false;
523 	fHasSpecifiers = false;
524 
525 	if (fBody)
526 	{
527 		fBody->MakeEmpty();
528 	}
529 	else
530 	{
531 		fBody = new BPrivate::BMessageBody;
532 	}
533 }
534 //------------------------------------------------------------------------------
535 status_t BMessage::GetInfo(type_code typeRequested, int32 which, char** name,
536 						   type_code* typeReturned, int32* count) const
537 {
538 	return fBody->GetInfo(typeRequested, which, name, typeReturned, count);
539 }
540 //------------------------------------------------------------------------------
541 status_t BMessage::GetInfo(const char* name, type_code* type, int32* c) const
542 {
543 	return fBody->GetInfo(name, type, c);
544 }
545 //------------------------------------------------------------------------------
546 status_t BMessage::GetInfo(const char* name, type_code* type,
547 						   bool* fixed_size) const
548 {
549 	return fBody->GetInfo(name, type, fixed_size);
550 }
551 //------------------------------------------------------------------------------
552 int32 BMessage::CountNames(type_code type) const
553 {
554 	return fBody->CountNames(type);
555 }
556 //------------------------------------------------------------------------------
557 bool BMessage::IsEmpty() const
558 {
559 	return fBody->IsEmpty();
560 }
561 //------------------------------------------------------------------------------
562 bool BMessage::IsSystem() const
563 {
564 	char a = char(what >> 24);
565 	char b = char(what >> 16);
566 	char c = char(what >> 8);
567 	char d = char(what);
568 
569 	// The BeBook says:
570 	//		... we've adopted a strict convention for assigning values to all
571 	//		Be-defined constants.  The value assigned will always be formed by
572 	//		combining four characters into a multicharacter constant, with the
573 	//		characters limited to uppercase letters and the underbar
574 	// Between that and what's in AppDefs.h, this algo seems like a safe bet:
575 	if (a == '_' && isupper(b) && isupper(c) && isupper(d))
576 	{
577 		return true;
578 	}
579 
580 	return false;
581 }
582 //------------------------------------------------------------------------------
583 bool BMessage::IsReply() const
584 {
585 	return fIsReply;
586 }
587 //------------------------------------------------------------------------------
588 void BMessage::PrintToStream() const
589 {
590 	printf("\nBMessage: what =  (0x%lX or %ld)\n", what, what);
591 	fBody->PrintToStream();
592 }
593 //------------------------------------------------------------------------------
594 status_t BMessage::Rename(const char* old_entry, const char* new_entry)
595 {
596 	return fBody->Rename(old_entry, new_entry);
597 }
598 //------------------------------------------------------------------------------
599 bool BMessage::WasDelivered() const
600 {
601 	return fWasDelivered;
602 }
603 //------------------------------------------------------------------------------
604 bool BMessage::IsSourceWaiting() const
605 {
606 	return fReplyRequired && !fReplyDone;
607 }
608 //------------------------------------------------------------------------------
609 bool BMessage::IsSourceRemote() const
610 {
611 	return WasDelivered() && fReplyTo.team != BPrivate::current_team();
612 }
613 //------------------------------------------------------------------------------
614 BMessenger BMessage::ReturnAddress() const
615 {
616 	if (WasDelivered())
617 	{
618 		BMessenger messenger;
619 		BMessenger::Private(messenger).SetTo(fReplyTo.team, fReplyTo.port,
620 			fReplyTo.target);
621 		return messenger;
622 	}
623 
624 	return BMessenger();
625 }
626 //------------------------------------------------------------------------------
627 const BMessage* BMessage::Previous() const
628 {
629 	// TODO: test
630 	// In particular, look to see if the "_previous_" field is used in R5
631 	if (!fOriginal)
632 	{
633 		BMessage* fOriginal = new BMessage;
634 		if (FindMessage("_previous_", fOriginal) != B_OK)
635 		{
636 			delete fOriginal;
637 			fOriginal = NULL;
638 		}
639 	}
640 
641 	return fOriginal;
642 }
643 //------------------------------------------------------------------------------
644 bool BMessage::WasDropped() const
645 {
646 	return fReadOnly;
647 }
648 //------------------------------------------------------------------------------
649 BPoint BMessage::DropPoint(BPoint* offset) const
650 {
651 	// TODO: Where do we get this stuff???
652 	if (offset)
653 	{
654 		*offset = FindPoint("_drop_offset_");
655 	}
656 	return FindPoint("_drop_point_");
657 }
658 //------------------------------------------------------------------------------
659 status_t BMessage::SendReply(uint32 command, BHandler* reply_to)
660 {
661 	BMessage msg(command);
662 	return SendReply(&msg, reply_to);
663 }
664 //------------------------------------------------------------------------------
665 status_t BMessage::SendReply(BMessage* the_reply, BHandler* reply_to,
666 							 bigtime_t timeout)
667 {
668 	BMessenger messenger(reply_to);
669 	return SendReply(the_reply, messenger, timeout);
670 }
671 //------------------------------------------------------------------------------
672 #if 0
673 template<class Sender>
674 status_t SendReplyHelper(BMessage* the_message, BMessage* the_reply,
675 						 Sender& the_sender)
676 {
677 	BMessenger messenger(the_message->fReplyTo.team, the_message->fReplyTo.port,
678 						 the_message->fReplyTo.target,
679 						 the_message->fReplyTo.preferred);
680 	if (the_message->fReplyRequired)
681 	{
682 		if (the_message->fReplyDone)
683 		{
684 			return B_DUPLICATE_REPLY;
685 		}
686 		the_message->fReplyDone = true;
687 		the_reply->fIsReply = true;
688 		status_t err = the_sender.Send(messenger, the_reply);
689 		the_reply->fIsReply = false;
690 		if (err)
691 		{
692 			if (set_port_owner(messenger.fPort, messenger.fTeam) == B_BAD_TEAM_ID)
693 			{
694 				delete_port(messenger.fPort);
695 			}
696 		}
697 		return err;
698 	}
699 	// no reply required
700 	if (!the_message->fWasDelivered)
701 	{
702 		return B_BAD_REPLY;
703 	}
704 
705 #if 0
706 	char tmp[0x800];
707 	ssize_t size;
708 	char* p = stack_flatten(tmp, sizeof(tmp), true /* include reply */, &size);
709 	the_reply->AddData("_previous_", B_RAW_TYPE, p ? p : tmp, &size);
710 	if (p)
711 	{
712 		free(p);
713 	}
714 #endif
715 	the_reply->AddMessage("_previous_", the_message);
716 	the_reply->fIsReply = true;
717 	status_t err = the_sender.Send(messenger, the_reply);
718 	the_reply->fIsReply = false;
719 	the_reply->RemoveName("_previous_");
720 	return err;
721 };
722 #endif
723 //------------------------------------------------------------------------------
724 #if 0
725 struct Sender1
726 {
727 	BMessenger& reply_to;
728 	bigtime_t timeout;
729 
730 	Sender1(BMessenger& m, bigtime_t t) : reply_to(m), timeout(t) {;}
731 
732 	status_t Send(BMessenger& messenger, BMessage* the_reply)
733 	{
734 		return messenger.SendMessage(the_reply, reply_to, timeout);
735 	}
736 };
737 status_t BMessage::SendReply(BMessage* the_reply, BMessenger reply_to,
738 							 bigtime_t timeout)
739 {
740 	Sender1 mySender(reply_to, timeout);
741 	return SendReplyHelper(this, the_reply, mySender);
742 }
743 #endif
744 status_t BMessage::SendReply(BMessage* the_reply, BMessenger reply_to,
745 							 bigtime_t timeout)
746 {
747 	// TODO: test
748 	BMessenger messenger;
749 
750 	BMessenger::Private messengerPrivate(messenger);
751 	messengerPrivate.SetTo(fReplyTo.team, fReplyTo.port, fReplyTo.target);
752 	if (fReplyRequired)
753 	{
754 		if (fReplyDone)
755 		{
756 			return B_DUPLICATE_REPLY;
757 		}
758 		fReplyDone = true;
759 		the_reply->fIsReply = true;
760 		status_t err = messenger.SendMessage(the_reply, reply_to, timeout);
761 		the_reply->fIsReply = false;
762 		if (err)
763 		{
764 			if (set_port_owner(messengerPrivate.Port(),
765 				messengerPrivate.Team()) == B_BAD_TEAM_ID) {
766 				delete_port(messengerPrivate.Port());
767 			}
768 		}
769 		return err;
770 	}
771 	// no reply required
772 	if (!fWasDelivered)
773 	{
774 		return B_BAD_REPLY;
775 	}
776 
777 	the_reply->AddMessage("_previous_", this);
778 	the_reply->fIsReply = true;
779 	status_t err = messenger.SendMessage(the_reply, reply_to, timeout);
780 	the_reply->fIsReply = false;
781 	the_reply->RemoveName("_previous_");
782 	return err;
783 }
784 //------------------------------------------------------------------------------
785 status_t BMessage::SendReply(uint32 command, BMessage* reply_to_reply)
786 {
787 	BMessage msg(command);
788 	return SendReply(&msg, reply_to_reply);
789 }
790 //------------------------------------------------------------------------------
791 #if 0
792 struct Sender2
793 {
794 	BMessage* reply_to_reply;
795 	bigtime_t send_timeout;
796 	bigtime_t reply_timeout;
797 
798 	Sender2(BMessage* m, bigtime_t t1, bigtime_t t2)
799 		:	reply_to_reply(m), send_timeout(t1), reply_timeout(t2) {;}
800 
801 	status_t Send(BMessenger& messenger, BMessage* the_reply)
802 	{
803 		return messenger.SendMessage(the_reply, reply_to_reply,
804 									 send_timeout, reply_timeout);
805 	}
806 };
807 status_t BMessage::SendReply(BMessage* the_reply, BMessage* reply_to_reply,
808 							 bigtime_t send_timeout, bigtime_t reply_timeout)
809 {
810 	Sender2 mySender(reply_to_reply, send_timeout, reply_timeout);
811 	return SendReplyHelper(this, the_reply, mySender);
812 }
813 #endif
814 status_t BMessage::SendReply(BMessage* the_reply, BMessage* reply_to_reply,
815 							 bigtime_t send_timeout, bigtime_t reply_timeout)
816 {
817 	// TODO: test
818 	BMessenger messenger;
819 	BMessenger::Private messengerPrivate(messenger);
820 	messengerPrivate.SetTo(fReplyTo.team, fReplyTo.port, fReplyTo.target);
821 	if (fReplyRequired)
822 	{
823 		if (fReplyDone)
824 		{
825 			return B_DUPLICATE_REPLY;
826 		}
827 		fReplyDone = true;
828 		the_reply->fIsReply = true;
829 		status_t err = messenger.SendMessage(the_reply, reply_to_reply,
830 											 send_timeout, reply_timeout);
831 		the_reply->fIsReply = false;
832 		if (err)
833 		{
834 			if (set_port_owner(messengerPrivate.Port(),
835 				messengerPrivate.Team()) == B_BAD_TEAM_ID) {
836 				delete_port(messengerPrivate.Port());
837 			}
838 		}
839 		return err;
840 	}
841 	// no reply required
842 	if (!fWasDelivered)
843 	{
844 		return B_BAD_REPLY;
845 	}
846 
847 	the_reply->AddMessage("_previous_", this);
848 	the_reply->fIsReply = true;
849 	status_t err = messenger.SendMessage(the_reply, reply_to_reply,
850 										 send_timeout, reply_timeout);
851 	the_reply->fIsReply = false;
852 	the_reply->RemoveName("_previous_");
853 	return err;
854 }
855 //------------------------------------------------------------------------------
856 ssize_t BMessage::FlattenedSize() const
857 {
858 	return calc_hdr_size(0) + fBody->FlattenedSize();
859 }
860 //------------------------------------------------------------------------------
861 status_t BMessage::Flatten(char* buffer, ssize_t size) const
862 {
863 	return real_flatten(buffer, size);
864 }
865 //------------------------------------------------------------------------------
866 status_t BMessage::Flatten(BDataIO* stream, ssize_t* size) const
867 {
868 	status_t err = B_OK;
869 	ssize_t len = FlattenedSize();
870 	char* buffer = new(nothrow) char[len];
871 	if (buffer)
872 	{
873 		err = Flatten(buffer, len);
874 		if (!err)
875 		{
876 			// size is an optional parameter, don't crash on NULL
877 			if (size != NULL)
878 			{
879 				*size = len;
880 			}
881 			err = stream->Write(buffer, len);
882 			if (err > B_OK)
883 				err = B_OK;
884 		}
885 
886 		delete[] buffer;
887 	}
888 	else
889 	{
890 		err = B_NO_MEMORY;
891 	}
892 
893 	return err;
894 }
895 
896 
897 status_t
898 BMessage::Unflatten(const char* buffer)
899 {
900 	if (!buffer)
901 		return B_BAD_VALUE;
902 
903 	uint32 magic = *(uint32*)buffer;
904 
905 	// we support several message formats - this list is ordered
906 	// by importance and frequency
907 
908 	if (magic == kMessageMagic) {
909 		// it appears to be a normal flattened BMessage
910 		BMemoryIO memoryStream(buffer, ((uint32*)buffer)[2]);
911 		return Unflatten(&memoryStream);
912 	}
913 
914 	// check whether this is a KMessage
915 	if (((KMessage::Header*)buffer)->magic
916 		== KMessage::kMessageHeaderMagic)
917 		return _UnflattenKMessage(buffer);
918 
919 	if (magic == kMessageMagicSwapped) {
920 		// it appears to be a swapped flattened BMessage
921 		uint32 size = ((uint32*)buffer)[2];
922 
923 		BMemoryIO memoryStream(buffer, __swap_int32(size));
924 		return Unflatten(&memoryStream);
925 	}
926 
927 	if (magic == kMessageMagicDano || magic == kMessageMagicDanoSwapped) {
928 		// dano style message
929 		BMemoryIO memoryStream(buffer,
930 			BPrivate::dano_message_flattened_size(buffer));
931 		return Unflatten(&memoryStream);
932 	}
933 
934 	return B_NOT_A_MESSAGE;
935 }
936 
937 
938 status_t
939 BMessage::Unflatten(BDataIO* stream)
940 {
941 	TReadHelper reader(stream);
942 	Header header;
943 	status_t status = B_OK;
944 
945 	// ToDo: while reading from a stream is certainly more convenient than
946 	//	from a buffer, it causes a lot of unnecessary copies, and therefore
947 	//	probably shouldn't be the preferred (or only) route.
948 
949 	try {
950 		uint32 magic;
951 		reader(magic);
952 
953 		status = header.SetMagic(magic);
954 		if (status < B_OK) {
955 			// we support reading Dano messages from disk as well
956 			if (magic == kMessageMagicDano)
957 				return BPrivate::unflatten_dano_message(magic, *stream, *this);
958 
959 			return status;
960 		}
961 
962 		status = header.ReadFrom(*stream);
963 		if (status < B_OK) {
964 			printf("BMessage::Unflatten(): Reading the header failed: %lx\n", status);
965 			return status;
966 		}
967 
968 		header.WriteTo(*this);
969 		bool swap = header.IsSwapped();
970 
971 		uint32 count;
972 		uint32 dataLen;
973 		uint8 nameLen;
974 		char name[MSG_NAME_MAX_SIZE];
975 		unsigned char* databuffer = NULL;
976 
977 		int8 flags;
978 		reader(flags);
979 
980 		while (flags != MSG_LAST_ENTRY) {
981 			type_code type;
982 			reader(type);
983 
984 			// Is there more than one data item?
985 			if (flags & MSG_FLAG_SINGLE_ITEM) {
986 				count = 1;
987 				if (flags & MSG_FLAG_MINI_DATA) {
988 					uint8 littleLen;
989 					reader(littleLen);
990 					dataLen = littleLen;
991 				} else
992 					reader(dataLen);
993 			} else {
994 				// Is there a little data?
995 				if (flags & MSG_FLAG_MINI_DATA) {
996 					// Get item count (1 byte)
997 					uint8 littleCount;
998 					reader(littleCount);
999 					count = littleCount;
1000 
1001 					// Get data length (1 byte)
1002 					uint8 littleLen;
1003 					reader(littleLen);
1004 					dataLen = littleLen;
1005 				} else {
1006 					// Is there a lot of data?
1007 					// Get item count (4 bytes)
1008 					reader(count);
1009 					// Get data length (4 bytes)
1010 					reader(dataLen);
1011 				}
1012 			}
1013 
1014 			// Get the name length (1 byte)
1015 			reader(nameLen);
1016 			// Get the name (name length bytes)
1017 			reader(name, nameLen);
1018 			name[nameLen] = '\0';
1019 
1020 			// Copy the data into a new buffer to byte align it
1021 			databuffer = (unsigned char*)realloc(databuffer, dataLen);
1022 			if (!databuffer)
1023 				throw B_NO_MEMORY;
1024 			// Get the data
1025 			reader(databuffer, dataLen);
1026 
1027 			if (swap) {
1028 				// Is the data fixed size?
1029 				if ((flags & MSG_FLAG_FIXED_SIZE) != 0) {
1030 					// Make sure to swap the data
1031 					status = swap_data(type, (void*)databuffer, dataLen,
1032 									B_SWAP_ALWAYS);
1033 					if (status < B_OK)
1034 						throw status;
1035 				} else if (type == B_REF_TYPE) {
1036 					// Is the data variable size?
1037 					// Apparently, entry_refs are the only variable-length data
1038 					// 	  explicitely swapped -- the dev_t and ino_t
1039 					//    specifically
1040 					byte_swap(*(entry_ref*)databuffer);
1041 				}
1042 			}
1043 
1044 			// Add each data field to the message
1045 			uint32 itemSize = 0;
1046 			if (flags & MSG_FLAG_FIXED_SIZE)
1047 				itemSize = dataLen / count;
1048 
1049 			unsigned char* dataPtr = databuffer;
1050 
1051 			for (uint32 i = 0; i < count; ++i) {
1052 				// Line up for the next item
1053 				if (i) {
1054 					if (flags & MSG_FLAG_FIXED_SIZE) {
1055 						dataPtr += itemSize;
1056 					} else {
1057 						// Have to account for 8-byte boundary padding
1058 						// We add 4 because padding as calculated during
1059 						// flattening includes the four-byte size header
1060 						dataPtr += itemSize + calc_padding(itemSize + 4, 8);
1061 					}
1062 				}
1063 
1064 				if ((flags & MSG_FLAG_FIXED_SIZE) == 0) {
1065 					itemSize = *(uint32*)dataPtr;
1066 					dataPtr += sizeof (uint32);
1067 				}
1068 
1069 				status = AddData(name, type, dataPtr, itemSize,
1070 							  flags & MSG_FLAG_FIXED_SIZE);
1071 				if (status < B_OK)
1072 					throw status;
1073 			}
1074 
1075 			reader(flags);
1076 		}
1077 	} catch (status_t& e) {
1078 		status = e;
1079 	}
1080 
1081 	return status;
1082 }
1083 //------------------------------------------------------------------------------
1084 status_t BMessage::AddSpecifier(const char* property)
1085 {
1086 	BMessage message(B_DIRECT_SPECIFIER);
1087 	status_t err = message.AddString(B_PROPERTY_ENTRY, property);
1088 	if (err)
1089 		return err;
1090 
1091 	return AddSpecifier(&message);
1092 }
1093 //------------------------------------------------------------------------------
1094 status_t BMessage::AddSpecifier(const char* property, int32 index)
1095 {
1096 	BMessage message(B_INDEX_SPECIFIER);
1097 	status_t err = message.AddString(B_PROPERTY_ENTRY, property);
1098 	if (err)
1099 		return err;
1100 
1101 	err = message.AddInt32("index", index);
1102 	if (err)
1103 		return err;
1104 
1105 	return AddSpecifier(&message);
1106 }
1107 //------------------------------------------------------------------------------
1108 status_t BMessage::AddSpecifier(const char* property, int32 index, int32 range)
1109 {
1110 	if (range < 0)
1111 		return B_BAD_VALUE;
1112 
1113 	BMessage message(B_RANGE_SPECIFIER);
1114 	status_t err = message.AddString(B_PROPERTY_ENTRY, property);
1115 	if (err)
1116 		return err;
1117 
1118 	err = message.AddInt32("index", index);
1119 	if (err)
1120 		return err;
1121 
1122 	err = message.AddInt32("range", range);
1123 	if (err)
1124 		return err;
1125 
1126 	return AddSpecifier(&message);
1127 }
1128 //------------------------------------------------------------------------------
1129 status_t BMessage::AddSpecifier(const char* property, const char* name)
1130 {
1131 	BMessage message(B_NAME_SPECIFIER);
1132 	status_t err = message.AddString(B_PROPERTY_ENTRY, property);
1133 	if (err)
1134 		return err;
1135 
1136 	err = message.AddString(B_PROPERTY_NAME_ENTRY, name);
1137 	if (err)
1138 		return err;
1139 
1140 	return AddSpecifier(&message);
1141 }
1142 //------------------------------------------------------------------------------
1143 status_t BMessage::AddSpecifier(const BMessage* specifier)
1144 {
1145 	status_t err = AddMessage(B_SPECIFIER_ENTRY, specifier);
1146 	if (!err)
1147 	{
1148 		++fCurSpecifier;
1149 		fHasSpecifiers = true;
1150 	}
1151 	return err;
1152 }
1153 //------------------------------------------------------------------------------
1154 status_t BMessage::SetCurrentSpecifier(int32 index)
1155 {
1156 	type_code	type;
1157 	int32		count;
1158 	status_t	err = GetInfo(B_SPECIFIER_ENTRY, &type, &count);
1159 	if (err)
1160 		return err;
1161 
1162 	if (index < 0 || index >= count)
1163 		return B_BAD_INDEX;
1164 
1165 	fCurSpecifier = index;
1166 
1167 	return B_OK;
1168 }
1169 //------------------------------------------------------------------------------
1170 status_t BMessage::GetCurrentSpecifier(int32* index, BMessage* specifier,
1171 									   int32* what, const char** property) const
1172 {
1173 	if (fCurSpecifier == -1 || !WasDelivered())
1174 		return B_BAD_SCRIPT_SYNTAX;
1175 
1176 	if (index)
1177 		*index = fCurSpecifier;
1178 
1179 	if (specifier)
1180 	{
1181 		if (FindMessage(B_SPECIFIER_ENTRY, fCurSpecifier, specifier))
1182 			return B_BAD_SCRIPT_SYNTAX;
1183 
1184 		if (what)
1185 			*what = specifier->what;
1186 
1187 		if (property)
1188 		{
1189 			if (specifier->FindString(B_PROPERTY_ENTRY, property))
1190 				return B_BAD_SCRIPT_SYNTAX;
1191 		}
1192 	}
1193 
1194 	return B_OK;
1195 }
1196 //------------------------------------------------------------------------------
1197 bool BMessage::HasSpecifiers() const
1198 {
1199 	return fHasSpecifiers;
1200 }
1201 //------------------------------------------------------------------------------
1202 status_t BMessage::PopSpecifier()
1203 {
1204 	if (fCurSpecifier < 0 || !WasDelivered())
1205 	{
1206 		return B_BAD_VALUE;
1207 	}
1208 
1209 	--fCurSpecifier;
1210 	return B_OK;
1211 }
1212 //------------------------------------------------------------------------------
1213 //	return fBody->AddData<TYPE>(name, val, TYPESPEC);
1214 //	return fBody->FindData<TYPE>(name, index, val, TYPESPEC);
1215 //	return fBody->ReplaceData<TYPE>(name, index, val, TYPESPEC);
1216 //	return fBody->HasData(name, TYPESPEC, n);
1217 
1218 #define DEFINE_FUNCTIONS(TYPE, fnName, TYPESPEC)									\
1219 	status_t BMessage::Add ## fnName(const char* name, TYPE val)					\
1220 	{ return AddData(name, TYPESPEC, &val, sizeof(TYPE)); }							\
1221 	status_t BMessage::Find ## fnName(const char* name, TYPE* p) const				\
1222 	{ return Find ## fnName(name, 0, p); }											\
1223 	status_t BMessage::Find ## fnName(const char* name, int32 index, TYPE* p) const	\
1224 	{															\
1225 		void* ptr = NULL; ssize_t bytes = 0; status_t err = B_OK;\
1226 		*p = TYPE(); 	\
1227 		err = FindData(name, TYPESPEC, index, (const void**)&ptr, &bytes); \
1228 		if (err == B_OK) \
1229 			memcpy(p, ptr, sizeof(TYPE)); \
1230 		return err; \
1231 	}														\
1232 	status_t BMessage::Replace ## fnName(const char* name, TYPE val)				\
1233 	{ return Replace ## fnName(name, 0, val); }										\
1234 	status_t BMessage::Replace ## fnName(const char *name, int32 index, TYPE val)	\
1235 	{ return ReplaceData(name, TYPESPEC, index, &val, sizeof(TYPE)); }				\
1236 	bool BMessage::Has ## fnName(const char* name, int32 n) const					\
1237 	{ return fBody->HasData(name, TYPESPEC, n); }
1238 
1239 DEFINE_FUNCTIONS(int8  , Int8  , B_INT8_TYPE)
1240 DEFINE_FUNCTIONS(int16 , Int16 , B_INT16_TYPE)
1241 DEFINE_FUNCTIONS(int32 , Int32 , B_INT32_TYPE)
1242 DEFINE_FUNCTIONS(int64 , Int64 , B_INT64_TYPE)
1243 DEFINE_FUNCTIONS(BPoint, Point , B_POINT_TYPE)
1244 DEFINE_FUNCTIONS(BRect , Rect  , B_RECT_TYPE)
1245 DEFINE_FUNCTIONS(float , Float , B_FLOAT_TYPE)
1246 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE)
1247 DEFINE_FUNCTIONS(bool  , Bool  , B_BOOL_TYPE)
1248 
1249 #undef DEFINE_FUNCTIONS
1250 
1251 
1252 #define DEFINE_HAS_FUNCTION(fnName, TYPESPEC)						\
1253 	bool BMessage::Has ## fnName(const char* name, int32 n) const	\
1254 	{ return HasData(name, TYPESPEC, n); }
1255 
1256 DEFINE_HAS_FUNCTION(Message  , B_MESSAGE_TYPE)
1257 DEFINE_HAS_FUNCTION(String   , B_STRING_TYPE)
1258 DEFINE_HAS_FUNCTION(Pointer  , B_POINTER_TYPE)
1259 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE)
1260 DEFINE_HAS_FUNCTION(Ref      , B_REF_TYPE)
1261 
1262 #undef DEFINE_HAS_FUNCTION
1263 
1264 #define DEFINE_LAZY_FIND_FUNCTION(TYPE, fnName)						\
1265 	TYPE BMessage::Find ## fnName(const char* name, int32 n) const	\
1266 	{																\
1267 		TYPE i = 0;													\
1268 		Find ## fnName(name, n, &i);								\
1269 		return i;													\
1270 	}
1271 
1272 DEFINE_LAZY_FIND_FUNCTION(int8			, Int8)
1273 DEFINE_LAZY_FIND_FUNCTION(int16			, Int16)
1274 DEFINE_LAZY_FIND_FUNCTION(int32			, Int32)
1275 DEFINE_LAZY_FIND_FUNCTION(int64			, Int64)
1276 DEFINE_LAZY_FIND_FUNCTION(float			, Float)
1277 DEFINE_LAZY_FIND_FUNCTION(double		, Double)
1278 DEFINE_LAZY_FIND_FUNCTION(bool			, Bool)
1279 DEFINE_LAZY_FIND_FUNCTION(const char*	, String)
1280 
1281 #undef DEFINE_LAZY_FIND_FUNCTION
1282 
1283 //------------------------------------------------------------------------------
1284 
1285 
1286 status_t
1287 BMessage::AddString(const char* name, const char* string)
1288 {
1289 	return AddData(name, B_STRING_TYPE, string, strlen(string) + 1);
1290 }
1291 
1292 
1293 status_t
1294 BMessage::AddString(const char* name, const BString& string)
1295 {
1296 	return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1);
1297 }
1298 
1299 
1300 status_t
1301 BMessage::AddPointer(const char* name, const void* pointer)
1302 {
1303 	return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer));
1304 }
1305 
1306 
1307 status_t
1308 BMessage::AddMessenger(const char* name, BMessenger messenger)
1309 {
1310 	return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger));
1311 }
1312 
1313 
1314 status_t
1315 BMessage::AddRef(const char* name, const entry_ref* ref)
1316 {
1317 	char* buffer = new(nothrow) char[sizeof(entry_ref) + B_PATH_NAME_LENGTH];
1318 	if (buffer == NULL)
1319 		return B_NO_MEMORY;
1320 
1321 	size_t size;
1322 	status_t err = entry_ref_flatten(buffer, &size, ref);
1323 	if (err >= B_OK) {
1324 		BDataBuffer databuffer((void*)buffer, size);
1325 		err = fBody->AddData<BDataBuffer>(name, databuffer, B_REF_TYPE);
1326 			// ToDo: even if the code looks like it, test this for real
1327 			// if AddData() fails here, the buffer is freed automatically
1328 			// as part of the BDataBuffer destruction
1329 	} else
1330 		delete[] buffer;
1331 
1332 	return err;
1333 }
1334 
1335 
1336 status_t
1337 BMessage::AddMessage(const char* name, const BMessage* msg)
1338 {
1339 	ssize_t size = msg->FlattenedSize();
1340 	char* buffer = new(nothrow) char[size];
1341 	if (buffer == NULL)
1342 		return B_NO_MEMORY;
1343 
1344 	status_t err = msg->Flatten(buffer, size);
1345 	if (err >= B_OK) {
1346 		BDataBuffer dataBuffer((void*)buffer, size);
1347 		err = fBody->AddData<BDataBuffer>(name, dataBuffer, B_MESSAGE_TYPE);
1348 			// if AddData() fails here, the buffer is freed automatically
1349 			// as part of the BDataBuffer destruction
1350 	} else
1351 		delete[] buffer;
1352 
1353 	return err;
1354 }
1355 
1356 
1357 status_t
1358 BMessage::AddFlat(const char* name, BFlattenable* object, int32 count)
1359 {
1360 	ssize_t size = object->FlattenedSize();
1361 	char* buffer = new(nothrow) char[size];
1362 	if (buffer == NULL)
1363 		return B_NO_MEMORY;
1364 
1365 	status_t err = object->Flatten((void*)buffer, size);
1366 	if (err >= B_OK) {
1367 		BDataBuffer dataBuffer((void*)buffer, size);
1368 		err = fBody->AddData<BDataBuffer>(name, dataBuffer, object->TypeCode());
1369 			// if AddData() fails here, the buffer is freed automatically
1370 			// as part of the BDataBuffer destruction
1371 	} else
1372 		delete[] buffer;
1373 
1374 	return err;
1375 }
1376 
1377 
1378 status_t
1379 BMessage::AddData(const char* name, type_code type, const void* data,
1380 				   ssize_t numBytes, bool is_fixed_size, int32 /*count*/)
1381 {
1382 	/** @note
1383 			Because we're using vectors for our item storage, the count param
1384 			is no longer useful to us:  dynamically adding more items is not
1385 			really a performance issue, so pre-allocating space for objects
1386 			gives us no real advantage.
1387 	 */
1388 
1389 	// TODO: test
1390 	// In particular, we want to see what happens if is_fixed_size == true and
1391 	// the user attempts to add something bigger or smaller.  We may need to
1392 	// enforce the size thing.
1393 
1394 	BDataBuffer buffer((void*)data, numBytes, true);
1395 	return fBody->AddData<BDataBuffer>(name, buffer, type);
1396 }
1397 
1398 
1399 status_t
1400 BMessage::RemoveData(const char* name, int32 index)
1401 {
1402 	return fReadOnly ? B_ERROR : fBody->RemoveData(name, index);
1403 }
1404 
1405 
1406 status_t
1407 BMessage::RemoveName(const char* name)
1408 {
1409 	return fReadOnly ? B_ERROR : fBody->RemoveName(name);
1410 }
1411 
1412 
1413 status_t
1414 BMessage::MakeEmpty()
1415 {
1416 	return fReadOnly ? B_ERROR : fBody->MakeEmpty();
1417 }
1418 
1419 
1420 status_t
1421 BMessage::FindString(const char* name, const char** string) const
1422 {
1423 	return FindString(name, 0, string);
1424 }
1425 
1426 
1427 status_t
1428 BMessage::FindString(const char* name, int32 index,
1429 	const char** string) const
1430 {
1431 	ssize_t bytes;
1432 	return FindData(name, B_STRING_TYPE, index,
1433 		(const void**)string, &bytes);
1434 }
1435 
1436 
1437 status_t
1438 BMessage::FindString(const char* name, BString* string) const
1439 {
1440 	return FindString(name, 0, string);
1441 }
1442 
1443 
1444 status_t
1445 BMessage::FindString(const char* name, int32 index, BString* string) const
1446 {
1447 	const char* cstr;
1448 	status_t err = FindString(name, index, &cstr);
1449 	if (err < B_OK)
1450 		return err;
1451 
1452 	*string = cstr;
1453 	return B_OK;
1454 }
1455 
1456 
1457 status_t
1458 BMessage::FindPointer(const char* name, void** ptr) const
1459 {
1460 	return FindPointer(name, 0, ptr);
1461 }
1462 
1463 
1464 status_t
1465 BMessage::FindPointer(const char* name, int32 index, void** ptr) const
1466 {
1467 	void** data = NULL;
1468 	ssize_t size = 0;
1469 	status_t err = FindData(name, B_POINTER_TYPE, index, (const void**)&data, &size);
1470 	if (err == B_OK)
1471 		*ptr = *data;
1472 	else
1473 		*ptr = NULL;
1474 	return err;
1475 }
1476 
1477 
1478 status_t
1479 BMessage::FindMessenger(const char* name, BMessenger* m) const
1480 {
1481 	return FindMessenger(name, 0, m);
1482 }
1483 
1484 
1485 status_t
1486 BMessage::FindMessenger(const char* name, int32 index, BMessenger* m) const
1487 {
1488 	void* data = NULL;
1489 	ssize_t size = 0;
1490 	status_t err = FindData(name, B_MESSENGER_TYPE, index, (const void **)&data, &size);
1491 	if (err == B_OK)
1492 		memcpy(m, data, sizeof(BMessenger));
1493 	else
1494 		*m = BMessenger();
1495 	return err;
1496 }
1497 
1498 
1499 status_t
1500 BMessage::FindRef(const char* name, entry_ref* ref) const
1501 {
1502 	return FindRef(name, 0, ref);
1503 }
1504 
1505 
1506 status_t
1507 BMessage::FindRef(const char* name, int32 index, entry_ref* ref) const
1508 {
1509 	void* data = NULL;
1510 	ssize_t size = 0;
1511 	status_t err = FindData(name, B_REF_TYPE, index, (const void**)&data, &size);
1512 	if (err == B_OK)
1513 		err = entry_ref_unflatten(ref, (char*)data, size);
1514 	else
1515 		*ref = entry_ref();
1516 	return err;
1517 }
1518 
1519 
1520 status_t
1521 BMessage::FindMessage(const char* name, BMessage* msg) const
1522 {
1523 	return FindMessage(name, 0, msg);
1524 }
1525 
1526 
1527 status_t
1528 BMessage::FindMessage(const char* name, int32 index, BMessage* msg) const
1529 {
1530 	void* data = NULL;
1531 	ssize_t size = 0;
1532 	status_t err = FindData(name, B_MESSAGE_TYPE, index, (const void**)&data, &size);
1533 	if (!err)
1534 		err = msg->Unflatten((const char*)data);
1535 	else
1536 		*msg = BMessage();
1537 	return err;
1538 }
1539 
1540 
1541 status_t
1542 BMessage::FindFlat(const char* name, BFlattenable* obj) const
1543 {
1544 	return FindFlat(name, 0, obj);
1545 }
1546 
1547 
1548 status_t
1549 BMessage::FindFlat(const char* name, int32 index, BFlattenable* obj) const
1550 {
1551 	void* data = NULL;
1552 	ssize_t numBytes = 0;
1553 	status_t err = FindData(name, obj->TypeCode(), index, (const void**)&data, &numBytes);
1554 	if (!err)
1555 		err = obj->Unflatten(obj->TypeCode(), data, numBytes);
1556 	return err;
1557 }
1558 
1559 
1560 status_t
1561 BMessage::FindData(const char* name, type_code type, const void** data,
1562 			ssize_t* numBytes) const
1563 {
1564 	return FindData(name, type, 0, data, numBytes);
1565 }
1566 
1567 
1568 status_t
1569 BMessage::FindData(const char* name, type_code type, int32 index,
1570 			const void** data, ssize_t* numBytes) const
1571 {
1572 	return fBody->FindData(name, type, index, data, numBytes);
1573 }
1574 
1575 
1576 status_t
1577 BMessage::ReplaceString(const char* name, const char* string)
1578 {
1579 	return ReplaceString(name, 0, string);
1580 }
1581 
1582 
1583 status_t
1584 BMessage::ReplaceString(const char* name, int32 index, const char* string)
1585 {
1586 	return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string)+1);
1587 }
1588 
1589 
1590 status_t
1591 BMessage::ReplaceString(const char* name, const BString& string)
1592 {
1593 	return ReplaceString(name, 0, string);
1594 }
1595 
1596 
1597 status_t
1598 BMessage::ReplaceString(const char* name, int32 index, const BString& string)
1599 {
1600 	return ReplaceData(name, B_STRING_TYPE, index, string.String(), string.Length()+1);
1601 }
1602 
1603 
1604 status_t
1605 BMessage::ReplacePointer(const char* name, const void* ptr)
1606 {
1607 	return ReplacePointer(name, 0, ptr);
1608 }
1609 
1610 
1611 status_t
1612 BMessage::ReplacePointer(const char* name, int32 index, const void* ptr)
1613 {
1614 	return ReplaceData(name, B_POINTER_TYPE, index, &ptr, sizeof(ptr));
1615 }
1616 
1617 
1618 status_t
1619 BMessage::ReplaceMessenger(const char* name, BMessenger messenger)
1620 {
1621 	return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger, sizeof(BMessenger));
1622 }
1623 
1624 
1625 status_t
1626 BMessage::ReplaceMessenger(const char* name, int32 index, BMessenger messenger)
1627 {
1628 	return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger, sizeof(BMessenger));
1629 }
1630 
1631 
1632 status_t
1633 BMessage::ReplaceRef(const char* name, const entry_ref* ref)
1634 {
1635 	return ReplaceRef(name, 0, ref);
1636 }
1637 
1638 
1639 status_t
1640 BMessage::ReplaceRef(const char* name, int32 index, const entry_ref* ref)
1641 {
1642 	char* buffer = new(nothrow) char[sizeof (entry_ref) + B_PATH_NAME_LENGTH];
1643 	if (buffer == NULL)
1644 		return B_NO_MEMORY;
1645 
1646 	size_t size;
1647 	status_t err = entry_ref_flatten(buffer, &size, ref);
1648 	if (err >= B_OK) {
1649 		BDataBuffer dataBuffer((void*)buffer, size);
1650 		err = fBody->ReplaceData<BDataBuffer>(name, index, dataBuffer, B_REF_TYPE);
1651 	} else
1652 		delete[] buffer;
1653 
1654 	return err;
1655 }
1656 
1657 
1658 status_t
1659 BMessage::ReplaceMessage(const char* name, const BMessage* msg)
1660 {
1661 	return ReplaceMessage(name, 0, msg);
1662 }
1663 
1664 
1665 status_t
1666 BMessage::ReplaceMessage(const char* name, int32 index, const BMessage* msg)
1667 {
1668 	ssize_t size = msg->FlattenedSize();
1669 	char* buffer = new(nothrow) char[size];
1670 	if (buffer == NULL)
1671 		return B_NO_MEMORY;
1672 
1673 	status_t err = msg->Flatten(buffer, size);
1674 	if (err >= B_OK) {
1675 		BDataBuffer dataBuffer((void*)buffer, size);
1676 		err = fBody->ReplaceData<BDataBuffer>(name, index, dataBuffer, B_MESSAGE_TYPE);
1677 	} else
1678 		delete[] buffer;
1679 
1680 	return err;
1681 }
1682 
1683 
1684 status_t
1685 BMessage::ReplaceFlat(const char* name, BFlattenable* object)
1686 {
1687 	return ReplaceFlat(name, 0, object);
1688 }
1689 
1690 
1691 status_t
1692 BMessage::ReplaceFlat(const char* name, int32 index, BFlattenable* object)
1693 {
1694 	ssize_t size = object->FlattenedSize();
1695 	char* buffer = new(nothrow) char[size];
1696 	if (buffer == NULL)
1697 		return B_NO_MEMORY;
1698 
1699 	status_t err = object->Flatten(buffer, size);
1700 	if (err >= B_OK) {
1701 		BDataBuffer dataBuffer((void*)buffer, size);
1702 		err = fBody->ReplaceData<BDataBuffer>(name, index, dataBuffer, object->TypeCode());
1703 	} else
1704 		delete[] buffer;
1705 
1706 	return err;
1707 }
1708 
1709 
1710 status_t
1711 BMessage::ReplaceData(const char* name, type_code type,
1712 	const void* data, ssize_t data_size)
1713 {
1714 	return ReplaceData(name, type, 0, data, data_size);
1715 }
1716 
1717 
1718 status_t
1719 BMessage::ReplaceData(const char* name, type_code type, int32 index,
1720 	const void* data, ssize_t data_size)
1721 {
1722 	BDataBuffer databuffer((void*)data, data_size, true);
1723 	return fBody->ReplaceData<BDataBuffer>(name, index, databuffer, type);
1724 }
1725 
1726 
1727 void*
1728 BMessage::operator new(size_t size)
1729 {
1730 	if (!sMsgCache)
1731 		sMsgCache = new BBlockCache(10, size, B_OBJECT_CACHE);
1732 
1733 	return sMsgCache->Get(size);
1734 }
1735 
1736 
1737 void*
1738 BMessage::operator new(size_t, void* p)
1739 {
1740 	return p;
1741 }
1742 
1743 
1744 void
1745 BMessage::operator delete(void* ptr, size_t size)
1746 {
1747 	sMsgCache->Save(ptr, size);
1748 }
1749 
1750 
1751 bool
1752 BMessage::HasFlat(const char* name, const BFlattenable* flat) const
1753 {
1754 	return HasFlat(name, 0, flat);
1755 }
1756 
1757 
1758 bool
1759 BMessage::HasFlat(const char* name, int32 n, const BFlattenable* flat) const
1760 {
1761 	return fBody->HasData(name, flat->TypeCode(), n);
1762 }
1763 
1764 
1765 bool
1766 BMessage::HasData(const char* name, type_code t, int32 n) const
1767 {
1768 	return fBody->HasData(name, t, n);
1769 }
1770 
1771 
1772 BRect
1773 BMessage::FindRect(const char* name, int32 n) const
1774 {
1775 	BRect r(0, 0, -1, -1);
1776 	FindRect(name, n, &r);
1777 	return r;
1778 }
1779 
1780 
1781 BPoint
1782 BMessage::FindPoint(const char* name, int32 n) const
1783 {
1784 	BPoint p(0, 0);
1785 	FindPoint(name, n, &p);
1786 	return p;
1787 }
1788 
1789 
1790 status_t
1791 BMessage::real_flatten(char* result, ssize_t size) const
1792 {
1793 	BMemoryIO stream((void*)result, size);
1794 	return real_flatten(&stream);
1795 }
1796 
1797 
1798 status_t
1799 BMessage::real_flatten(BDataIO* stream) const
1800 {
1801 	Header header(*this);
1802 
1803 	status_t err = header.WriteTo(*stream);
1804 
1805 	if (!err)
1806 		err = fBody->Flatten(stream);
1807 
1808 	return err;
1809 }
1810 
1811 
1812 char*
1813 BMessage::stack_flatten(char* stack_ptr, ssize_t stack_size,
1814 	bool /*incl_reply*/, ssize_t* size) const
1815 {
1816 	const ssize_t calcd_size = calc_hdr_size(0) + fBody->FlattenedSize();
1817 	char* new_ptr = NULL;
1818 	if (calcd_size > stack_size) {
1819 		stack_ptr = new char[calcd_size];
1820 		new_ptr = stack_ptr;
1821 	}
1822 
1823 	real_flatten(stack_ptr, calcd_size);
1824 	if (size)
1825 		*size = calcd_size;
1826 
1827 	return new_ptr;
1828 }
1829 
1830 
1831 status_t
1832 BMessage::_UnflattenKMessage(const char *buffer)
1833 {
1834 	// init a real KMessage
1835 	KMessage message;
1836 	status_t error = message.SetTo(buffer, ((KMessage::Header*)buffer)->size);
1837 	if (error != B_OK)
1838 		return error;
1839 
1840 	// let convert_message() do the real job
1841 	return convert_message(&message, this);
1842 }
1843 
1844 
1845 ssize_t
1846 BMessage::calc_hdr_size(uchar flags) const
1847 {
1848 	ssize_t size = min_hdr_size();
1849 
1850 	if (fTarget != B_NULL_TOKEN)
1851 		size += sizeof (fTarget);
1852 
1853 	if (fReplyTo.port >= 0
1854 		&& fReplyTo.target != B_NULL_TOKEN
1855 		&& fReplyTo.team >= 0) {
1856 		size += sizeof (fReplyTo.port);
1857 		size += sizeof (fReplyTo.target);
1858 		size += sizeof (fReplyTo.team);
1859 
1860 		size += 4;	// For the "big" flags
1861 	}
1862 
1863 	return size;
1864 }
1865 
1866 
1867 status_t
1868 BMessage::_send_(port_id port, int32 token, bigtime_t timeout,
1869 	bool reply_required, BMessenger& reply_to) const
1870 {
1871 	PRINT(("BMessage::_send_(port: %ld, token: %ld): "
1872 		"what: %lx (%.4s)\n", port, token, what, (char*)&what));
1873 
1874 	bool oldPreferred = fPreferred;
1875 	int32 oldTarget = fTarget;
1876 	reply_to_info oldReplyTo = fReplyTo;
1877 
1878 	if (!reply_to.IsValid()) {
1879 		BMessenger::Private(reply_to).SetTo(fReplyTo.team,
1880 			fReplyTo.port, fReplyTo.target);
1881 		if (!reply_to.IsValid())
1882 			reply_to = be_app_messenger;
1883 	}
1884 
1885 	BMessage* self = const_cast<BMessage*>(this);
1886 	BMessenger::Private replyToPrivate(reply_to);
1887 	self->fPreferred         = token == B_PREFERRED_TOKEN;
1888 	self->fTarget            = token;
1889 	self->fReplyRequired     = reply_required;
1890 	self->fReplyTo.team      = replyToPrivate.Team();
1891 	self->fReplyTo.port      = replyToPrivate.Port();
1892 	self->fReplyTo.target    = (replyToPrivate.IsPreferredTarget()
1893 								? B_PREFERRED_TOKEN : replyToPrivate.Token());
1894 	self->fReplyTo.preferred = replyToPrivate.IsPreferredTarget();
1895 
1896 	char tmp[0x800];
1897 	ssize_t size;
1898 	char* p = stack_flatten(tmp, sizeof(tmp), true /* include reply */, &size);
1899 	char* pMem = p ? p : tmp;
1900 	status_t err;
1901 	do {
1902 		err = write_port_etc(port, 'pjpp', pMem, size, B_RELATIVE_TIMEOUT, timeout);
1903 	} while (err == B_INTERRUPTED);
1904 	if (p)
1905 		delete[] p;
1906 
1907 	self->fPreferred     = oldPreferred;
1908 	self->fTarget        = oldTarget;
1909 	self->fReplyRequired = false;	// To this copy, no reply is required.
1910 									// Only relevant when forwarding anyway.
1911 	self->fReplyTo       = oldReplyTo;
1912 
1913 	PRINT(("BMessage::_send_() done: %lx\n", err));
1914 	return err;
1915 }
1916 
1917 
1918 status_t
1919 BMessage::send_message(port_id port, team_id port_owner, int32 token,
1920 	BMessage* reply, bigtime_t send_timeout,
1921 	bigtime_t reply_timeout) const
1922 {
1923 	const int32 cached_reply_port = sGetCachedReplyPort();
1924 	port_id reply_port;
1925 	status_t err;
1926 	if (cached_reply_port == -1) {
1927 		// All the cached reply ports are in use; create a new one
1928 		reply_port = create_port(1 /* for one message */, "tmp_reply_port");
1929 		if (reply_port < 0)
1930 			return reply_port;
1931 	} else {
1932 		assert(cached_reply_port < sNumReplyPorts);
1933 		reply_port = sReplyPorts[cached_reply_port];
1934 	}
1935 
1936 	team_id team = B_BAD_TEAM_ID;
1937 	if (be_app != NULL)
1938 		team = be_app->Team();
1939 	else {
1940 		port_info pi;
1941 		err = get_port_info(reply_port, &pi);
1942 		if (err)
1943 			goto error;
1944 
1945 		team = pi.team;
1946 	}
1947 
1948 	err = set_port_owner(reply_port, port_owner);
1949 	if (err)
1950 		goto error;
1951 
1952 	{
1953 		BMessenger messenger;
1954 		BMessenger::Private(messenger).SetTo(team, reply_port,
1955 			B_PREFERRED_TOKEN);
1956 		err = _send_(port, token, send_timeout, true, messenger);
1957 	}
1958 	if (err)
1959 		goto error;
1960 
1961 	int32 code;
1962 	err = handle_reply(reply_port, &code, reply_timeout, reply);
1963 	if (err && cached_reply_port >= 0) {
1964 		delete_port(reply_port);
1965 		sReplyPorts[cached_reply_port] = create_port(1, "tmp_rport");
1966 	}
1967 
1968 error:
1969 	if (cached_reply_port >= 0) {
1970 		// Reclaim ownership of cached port
1971 		set_port_owner(reply_port, team);
1972 		// Flag as available
1973 		atomic_add(&sReplyPortInUse[cached_reply_port], -1);
1974 		return err;
1975 	}
1976 	delete_port(reply_port);
1977 	return err;
1978 }
1979 
1980 
1981 // Note, that in case of a flattened BMessage setting the target token will
1982 // change the header size, if no token was set when the message was flattened.
1983 // Hence the message would need to unflattened and flattened again before it
1984 // can be sent.
1985 status_t
1986 BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port,
1987 	int32 token, bigtime_t timeout)
1988 {
1989 	if (!data)
1990 		return B_BAD_VALUE;
1991 
1992 	uint32 magic = *(uint32*)data;
1993 
1994 	// prepare flattened fields
1995 	if (((KMessage::Header*)data)->magic == KMessage::kMessageHeaderMagic) {
1996 		// a KMessage
1997 		KMessage::Header *header = (KMessage::Header*)data;
1998 		header->targetToken = token;
1999 	} else if (magic == kMessageMagic || magic == kMessageMagicSwapped) {
2000 		// get the header
2001 		BMemoryIO stream(data, size);
2002 
2003 		stream.Read(&magic, sizeof(uint32));
2004 			// "discard" the magic (we already know it anyway)
2005 
2006 		Header header;
2007 		status_t error = header.SetMagic(magic);
2008 		if (error != B_OK)
2009 			return error;
2010 
2011 		error = header.ReadFrom(stream);
2012 		if (error != B_OK)
2013 			return error;
2014 
2015 		if (!header.HasTarget()) {
2016 			// fallback implementation -- the header size would change by
2017 			// setting the token
2018 
2019 			// unflatten the message
2020 			BMessage message;
2021 			error = message.Unflatten((const char*)data);
2022 			if (error != B_OK)
2023 				return error;
2024 
2025 			// send the message
2026 			BMessenger messenger;
2027 			return message._send_(port, token, timeout, false,
2028 				messenger);
2029 		}
2030 
2031 		// set the target token and replace the header
2032 		header.SetTarget(token);
2033 		stream.Seek(0LL, SEEK_SET);
2034 		error = header.WriteTo(stream);
2035 		if (error != B_OK)
2036 			return error;
2037 	} else {
2038 		return B_NOT_A_MESSAGE;
2039 	}
2040 
2041 	// send the message
2042 	status_t error;
2043 	do {
2044 		error = write_port_etc(port, 'pjpp', data, size, B_RELATIVE_TIMEOUT,
2045 			timeout);
2046 	} while (error == B_INTERRUPTED);
2047 
2048 	return error;
2049 }
2050 
2051 
2052 void
2053 BMessage::_StaticCacheCleanup()
2054 {
2055 	delete sMsgCache;
2056 	sMsgCache = NULL;
2057 }
2058 
2059 
2060 void
2061 BMessage::_StaticInit()
2062 {
2063 	sReplyPorts[0] = create_port(1, "tmp_rport0");
2064 	sReplyPorts[1] = create_port(1, "tmp_rport1");
2065 	sReplyPorts[2] = create_port(1, "tmp_rport2");
2066 
2067 	sReplyPortInUse[0] = 0;
2068 	sReplyPortInUse[1] = 0;
2069 	sReplyPortInUse[2] = 0;
2070 }
2071 
2072 
2073 void
2074 BMessage::_StaticCleanup()
2075 {
2076 	delete_port(sReplyPorts[0]);
2077 	sReplyPorts[0] = -1;
2078 	delete_port(sReplyPorts[1]);
2079 	sReplyPorts[1] = -1;
2080 	delete_port(sReplyPorts[2]);
2081 	sReplyPorts[2] = -1;
2082 }
2083 
2084 
2085 int32
2086 BMessage::sGetCachedReplyPort()
2087 {
2088 	int index = -1;
2089 	for (int32 i = 0; i < sNumReplyPorts; i++)
2090 	{
2091 		int32 old = atomic_add(&(sReplyPortInUse[i]), 1);
2092 		if (old == 0)
2093 		{
2094 			// This entry is free
2095 			index = i;
2096 			break;
2097 		}
2098 		else
2099 		{
2100 			// This entry is being used.
2101 			atomic_add(&(sReplyPortInUse[i]), -1);
2102 		}
2103 	}
2104 
2105 	return index;
2106 }
2107 
2108 
2109 static status_t
2110 handle_reply(port_id reply_port, int32* pCode,
2111 	bigtime_t timeout, BMessage* reply)
2112 {
2113 	PRINT(("handle_reply(port: %ld)\n", reply_port));
2114 
2115 	status_t err;
2116 	do {
2117 		err = port_buffer_size_etc(reply_port, 8, timeout);
2118 	} while (err == B_INTERRUPTED);
2119 
2120 	if (err < 0) {
2121 		PRINT(("handle_reply() error 1: %lx\n", err));
2122 		return err;
2123 	}
2124 
2125 	// The API lied. It really isn't an error code, but the message size...
2126 	char* pAllocd = NULL;
2127 	char* pMem    = NULL;
2128 	char tmp[0x800];
2129 	if (err < 0x800)
2130 		pMem = tmp;
2131 	else {
2132 		pAllocd = new char[err];
2133 		pMem = pAllocd;
2134 	}
2135 
2136 	do {
2137 		err = read_port(reply_port, pCode, pMem, err);
2138 	} while (err == B_INTERRUPTED);
2139 
2140 	if (err < 0) {
2141 		PRINT(("handle_reply() error 2: %lx\n", err));
2142 		return err;
2143 	}
2144 
2145 	if (*pCode == 'PUSH') {
2146 		PRINT(("handle_reply() error 3: %x\n", B_ERROR));
2147 		return B_ERROR;
2148 	}
2149 	if (*pCode != 'pjpp') {
2150 		PRINT(("handle_reply() error 4: port message code not 'pjpp' but "
2151 			"'%lx'\n", *pCode));
2152 		return B_ERROR;
2153 	}
2154 
2155 	err = reply->Unflatten(pMem);
2156 
2157 	// There seems to be a bug in the original Be implementation.
2158 	// It never free'd pAllocd !
2159 	if (pAllocd)
2160 		delete[] pAllocd;
2161 
2162 	PRINT(("handle_reply() done: %lx\n", err));
2163 	return err;
2164 }
2165 
2166 
2167 // convert_message
2168 static status_t
2169 convert_message(const KMessage *fromMessage, BMessage *toMessage)
2170 {
2171 	if (!fromMessage || !toMessage)
2172 		return B_BAD_VALUE;
2173 
2174 	// make empty and init what of the target message
2175 	toMessage->MakeEmpty();
2176 	toMessage->what = fromMessage->What();
2177 
2178 	// iterate through the fields and import them in the target message
2179 	KMessageField field;
2180 	while (fromMessage->GetNextField(&field) == B_OK) {
2181 		int32 elementCount = field.CountElements();
2182 		if (elementCount > 0) {
2183 			for (int32 i = 0; i < elementCount; i++) {
2184 				int32 size;
2185 				const void *data = field.ElementAt(i, &size);
2186 				status_t error;
2187 				if (field.TypeCode() == B_MESSAGE_TYPE) {
2188 					// message type: if it's a KMessage, convert it
2189 					KMessage message;
2190 					if (message.SetTo(data, size) == B_OK) {
2191 						BMessage bMessage;
2192 						error = convert_message(&message, &bMessage);
2193 						if (error != B_OK)
2194 							return error;
2195 						error = toMessage->AddMessage(field.Name(), &bMessage);
2196 					} else {
2197 						// just add it
2198 						error = toMessage->AddData(field.Name(),
2199 							field.TypeCode(), data, size,
2200 							field.HasFixedElementSize(), 1);
2201 					}
2202 				} else {
2203 					error = toMessage->AddData(field.Name(), field.TypeCode(),
2204 						data, size, field.HasFixedElementSize(), 1);
2205 				}
2206 
2207 				if (error != B_OK)
2208 					return error;
2209 			}
2210 		}
2211 	}
2212 	return B_OK;
2213 }
2214 
2215 
2216 static ssize_t
2217 min_hdr_size()
2218 {
2219 	ssize_t size = 0;
2220 
2221 	size += 4;	// version
2222 	size += 4;	// checksum
2223 	size += 4;	// flattened size
2224 	size += 4;	// 'what'
2225 	size += 1;	// flags
2226 
2227 	return size;
2228 }
2229 
2230 #endif	// USING_MESSAGE4
2231