1/*
2 * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6// Small app for testing the registrar's MessageDeliverer.
7
8#include <errno.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <unistd.h>
13
14#include <Application.h>
15#include <Clipboard.h>
16#include <Locker.h>
17#include <Message.h>
18#include <MessageRunner.h>
19#include <OS.h>
20#include <Path.h>
21#include <Roster.h>
22#include <String.h>
23
24// message what codes
25enum {
26	MSG_FILL_PORT	= 'fill',
27	MSG_RUNNER		= 'runn',
28	MSG_BROADCAST	= 'brod',
29};
30
31static const uint32 sExpectedMessages[3] = {
32	B_CLIPBOARD_CHANGED,
33	MSG_RUNNER,
34	MSG_BROADCAST,
35};
36static const int32 sExpectedMessageCount = 3;
37static int32 sExpectedMessageIndex = 0;
38
39// check_expected_message
40static
41bool
42check_expected_message(uint32 what)
43{
44	if (sExpectedMessageIndex >= sExpectedMessageCount) {
45		printf("Unexpected message '%.4s'\n", (char*)&what);
46		exit(1);
47	}
48
49	uint32 expected = sExpectedMessages[sExpectedMessageIndex++];
50	if (what != expected) {
51		printf("Unexpected message '%.4s', expected was: '%.4s'\n",
52			(char*)&what, (char*)&expected);
53		exit(1);
54	}
55
56	return (sExpectedMessageIndex == sExpectedMessageCount);
57}
58
59
60// TestApp
61class TestApp : public BApplication {
62public:
63	TestApp()
64		: BApplication("application/x-vnd.haiku.message-deliverer-test")
65	{
66	}
67
68	virtual void MessageReceived(BMessage *message)
69	{
70		switch (message->what) {
71			case MSG_FILL_PORT:
72				return;
73			case MSG_RUNNER:
74				printf("MSG_RUNNER\n");
75				break;
76			case B_CLIPBOARD_CHANGED:
77				printf("B_CLIPBOARD_CHANGED\n");
78				break;
79			case MSG_BROADCAST:
80				printf("MSG_BROADCAST\n");
81				break;
82			default:
83				BApplication::MessageReceived(message);
84				return;
85		}
86
87		if (check_expected_message(message->what))
88			PostMessage(B_QUIT_REQUESTED);
89	}
90};
91
92// main
93int
94main(int argc, const char *const *argv)
95{
96	// if started with parameter "broadcast", we broadcast a message and exit
97	if (argc > 1 && strcmp(argv[1], "broadcast") == 0) {
98		BMessage message(MSG_BROADCAST);
99		status_t error = be_roster->Broadcast(&message);
100		if (error != B_OK) {
101			printf("Broadcast failed: %s\n", strerror(error));
102			exit(1);
103		}
104		exit(0);
105	}
106
107	TestApp app;
108
109	// fill the looper port
110	status_t error;
111	do {
112		BMessage message(MSG_FILL_PORT);
113		error = be_app_messenger.SendMessage(&message, (BHandler*)NULL, 0LL);
114	} while (error == B_OK);
115
116	if (error != B_WOULD_BLOCK) {
117		printf("sending fill message didn't fail with B_WOULD_BLOCK: %s\n",
118			strerror(error));
119		exit(1);
120	}
121
122	// register looper for clipboard events
123	BClipboard clipboard("message deliverer test");
124	error = clipboard.StartWatching(be_app_messenger);
125	if (error != B_OK) {
126		printf("Failed to start clipboard watching: %s\n", strerror(error));
127		exit(1);
128	}
129
130	// generate a clipboard changed modification
131	if (!clipboard.Lock()) {
132		printf("Failed to lock clipboard.\n");
133		exit(1);
134	}
135	clipboard.Clear();
136	clipboard.Data()->AddString("test", "test data");
137	error = clipboard.Commit();
138	if (error != B_OK) {
139		printf("Failed to commit clipboard data: %s\n", strerror(error));
140		exit(1);
141	}
142	clipboard.Unlock();
143
144	// create a message runner
145	BMessage message(MSG_RUNNER);
146	bigtime_t interval = 100000LL;
147	BMessageRunner runner(be_app_messenger, &message, interval, 3);
148	error = runner.InitCheck();
149	if (error != B_OK) {
150		printf("Message runner initialization failed: %s\n", strerror(error));
151		exit(1);
152	}
153	snooze(5 * interval);
154
155	// broadcast a message: We do that be starting another instance of this
156	// app with parameter "broadcast". We can't do the broadcast ourselves,
157	// since the message is sent only to the other applications.
158
159	// get our app info
160	app_info appInfo;
161	error = app.GetAppInfo(&appInfo);
162	if (error != B_OK) {
163		printf("GetAppInfo() failed: %s\n", strerror(error));
164		exit(1);
165	}
166
167	// get the app path
168	BPath path;
169	error = path.SetTo(&appInfo.ref);
170	if (error != B_OK) {
171		printf("Failed to get app path: %s\n", strerror(error));
172		exit(1);
173	}
174
175	// launch...
176	BString commandLine(path.Path());
177	commandLine << " broadcast";
178	if (system(commandLine.String()) < 0) {
179		printf("Failed re-launch app for broadcasting: %s\n", strerror(errno));
180		exit(1);
181	}
182
183	// wait a bit...
184	snooze(100000);
185
186	// now start the message processing loop
187	app.Run();
188
189	return 0;
190}
191