1/*
2 * Copyright 2010-2017, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
7 *		Stephan A��mus, superstippi@gmx.de
8 *		Brian Hill, supernova@tycho.email
9 */
10
11
12#include <Notification.h>
13
14#include <new>
15
16#include <stdlib.h>
17#include <string.h>
18
19#include <notification/Notifications.h>
20
21#include <Bitmap.h>
22#include <Message.h>
23#include <NodeInfo.h>
24#include <Path.h>
25#include <Roster.h>
26
27
28BNotification::BNotification(notification_type type)
29	:
30	BArchivable(),
31	fInitStatus(B_OK),
32	fType(type),
33	fProgress(0.f),
34	fFile(NULL),
35	fBitmap(NULL)
36{
37	team_info teamInfo;
38	get_team_info(B_CURRENT_TEAM, &teamInfo);
39	app_info appInfo;
40	be_roster->GetRunningAppInfo(teamInfo.team, &appInfo);
41
42	int32 iconSize = B_LARGE_ICON;
43	fBitmap = new BBitmap(BRect(0, 0, iconSize - 1, iconSize - 1), 0, B_RGBA32);
44	if (fBitmap) {
45		if (BNodeInfo::GetTrackerIcon(&appInfo.ref, fBitmap,
46			icon_size(iconSize)) != B_OK) {
47			delete fBitmap;
48			fBitmap = NULL;
49		}
50	}
51	fSourceSignature = appInfo.signature;
52	BPath path(&appInfo.ref);
53	if (path.InitCheck() == B_OK)
54		fSourceName = path.Leaf();
55}
56
57
58BNotification::BNotification(BMessage* archive)
59	:
60	BArchivable(archive),
61	fInitStatus(B_OK),
62	fProgress(0.0f),
63	fFile(NULL),
64	fBitmap(NULL)
65{
66	BString appName;
67	if (archive->FindString("_appname", &appName) == B_OK)
68		fSourceName = appName;
69
70	BString signature;
71	if (archive->FindString("_signature", &signature) == B_OK)
72		fSourceSignature = signature;
73
74	int32 type;
75	if (archive->FindInt32("_type", &type) == B_OK)
76		fType = (notification_type)type;
77	else
78		fInitStatus = B_ERROR;
79
80	BString group;
81	if (archive->FindString("_group", &group) == B_OK)
82		SetGroup(group);
83
84	BString title;
85	if (archive->FindString("_title", &title) == B_OK)
86		SetTitle(title);
87
88	BString content;
89	if (archive->FindString("_content", &content) == B_OK)
90		SetContent(content);
91
92	BString messageID;
93	if (archive->FindString("_messageID", &messageID) == B_OK)
94		SetMessageID(messageID);
95
96	float progress;
97	if (type == B_PROGRESS_NOTIFICATION
98		&& archive->FindFloat("_progress", &progress) == B_OK)
99		SetProgress(progress);
100
101	BString onClickApp;
102	if (archive->FindString("_onClickApp", &onClickApp) == B_OK)
103		SetOnClickApp(onClickApp);
104
105	entry_ref onClickFile;
106	if (archive->FindRef("_onClickFile", &onClickFile) == B_OK)
107		SetOnClickFile(&onClickFile);
108
109	entry_ref onClickRef;
110	int32 index = 0;
111	while (archive->FindRef("_onClickRef", index++, &onClickRef) == B_OK)
112		AddOnClickRef(&onClickRef);
113
114	BString onClickArgv;
115	index = 0;
116	while (archive->FindString("_onClickArgv", index++, &onClickArgv) == B_OK)
117		AddOnClickArg(onClickArgv);
118
119	status_t ret = B_OK;
120	BMessage icon;
121	if ((ret = archive->FindMessage("_icon", &icon)) == B_OK) {
122		BBitmap bitmap(&icon);
123		ret = bitmap.InitCheck();
124		if (ret == B_OK)
125			ret = SetIcon(&bitmap);
126	}
127}
128
129
130BNotification::~BNotification()
131{
132	delete fFile;
133	delete fBitmap;
134
135	for (int32 i = fRefs.CountItems() - 1; i >= 0; i--)
136		delete (entry_ref*)fRefs.ItemAtFast(i);
137
138	for (int32 i = fArgv.CountItems() - 1; i >= 0; i--)
139		free(fArgv.ItemAtFast(i));
140}
141
142
143status_t
144BNotification::InitCheck() const
145{
146	return fInitStatus;
147}
148
149
150BArchivable*
151BNotification::Instantiate(BMessage* archive)
152{
153	if (validate_instantiation(archive, "BNotification"))
154		return new(std::nothrow) BNotification(archive);
155
156	return NULL;
157}
158
159
160status_t
161BNotification::Archive(BMessage* archive, bool deep) const
162{
163	status_t status = BArchivable::Archive(archive, deep);
164
165	if (status == B_OK)
166		status = archive->AddString("_appname", fSourceName);
167
168	if (status == B_OK)
169		status = archive->AddString("_signature", fSourceSignature);
170
171	if (status == B_OK)
172		status = archive->AddInt32("_type", (int32)fType);
173
174	if (status == B_OK && Group() != NULL)
175		status = archive->AddString("_group", Group());
176
177	if (status == B_OK && Title() != NULL)
178		status = archive->AddString("_title", Title());
179
180	if (status == B_OK && Content() != NULL)
181		status = archive->AddString("_content", Content());
182
183	if (status == B_OK && MessageID() != NULL)
184		status = archive->AddString("_messageID", MessageID());
185
186	if (status == B_OK && Type() == B_PROGRESS_NOTIFICATION)
187		status = archive->AddFloat("_progress", Progress());
188
189	if (status == B_OK && OnClickApp() != NULL)
190		status = archive->AddString("_onClickApp", OnClickApp());
191
192	if (status == B_OK && OnClickFile() != NULL)
193		status = archive->AddRef("_onClickFile", OnClickFile());
194
195	if (status == B_OK) {
196		for (int32 i = 0; i < CountOnClickRefs(); i++) {
197			status = archive->AddRef("_onClickRef", OnClickRefAt(i));
198			if (status != B_OK)
199				break;
200		}
201	}
202
203	if (status == B_OK) {
204		for (int32 i = 0; i < CountOnClickArgs(); i++) {
205			status = archive->AddString("_onClickArgv", OnClickArgAt(i));
206			if (status != B_OK)
207				break;
208		}
209	}
210
211	if (status == B_OK) {
212		const BBitmap* icon = Icon();
213		if (icon != NULL) {
214			BMessage iconArchive;
215			status = icon->Archive(&iconArchive);
216			if (status == B_OK)
217				archive->AddMessage("_icon", &iconArchive);
218		}
219	}
220
221	return status;
222}
223
224
225const char*
226BNotification::SourceSignature() const
227{
228	return fSourceSignature;
229}
230
231
232const char*
233BNotification::SourceName() const
234{
235	return fSourceName;
236}
237
238
239notification_type
240BNotification::Type() const
241{
242	return fType;
243}
244
245
246const char*
247BNotification::Group() const
248{
249	if (fGroup == "")
250		return NULL;
251	return fGroup;
252}
253
254
255void
256BNotification::SetGroup(const BString& group)
257{
258	fGroup = group;
259}
260
261
262const char*
263BNotification::Title() const
264{
265	if (fTitle == "")
266		return NULL;
267	return fTitle;
268}
269
270
271void
272BNotification::SetTitle(const BString& title)
273{
274	fTitle = title;
275}
276
277
278const char*
279BNotification::Content() const
280{
281	if (fContent == "")
282		return NULL;
283	return fContent;
284}
285
286
287void
288BNotification::SetContent(const BString& content)
289{
290	fContent = content;
291}
292
293
294const char*
295BNotification::MessageID() const
296{
297	if (fID == "")
298		return NULL;
299	return fID;
300}
301
302
303void
304BNotification::SetMessageID(const BString& id)
305{
306	fID = id;
307}
308
309
310float
311BNotification::Progress() const
312{
313	if (fType != B_PROGRESS_NOTIFICATION)
314		return -1;
315	return fProgress;
316}
317
318
319void
320BNotification::SetProgress(float progress)
321{
322	if (progress < 0)
323		fProgress = 0;
324	else if (progress > 1)
325		fProgress = 1;
326	else
327		fProgress = progress;
328}
329
330
331const char*
332BNotification::OnClickApp() const
333{
334	if (fApp == "")
335		return NULL;
336	return fApp;
337}
338
339
340void
341BNotification::SetOnClickApp(const BString& app)
342{
343	fApp = app;
344}
345
346
347const entry_ref*
348BNotification::OnClickFile() const
349{
350	return fFile;
351}
352
353
354status_t
355BNotification::SetOnClickFile(const entry_ref* file)
356{
357	delete fFile;
358
359	if (file != NULL) {
360		fFile = new(std::nothrow) entry_ref(*file);
361		if (fFile == NULL)
362			return B_NO_MEMORY;
363	} else
364		fFile = NULL;
365
366	return B_OK;
367}
368
369
370status_t
371BNotification::AddOnClickRef(const entry_ref* ref)
372{
373	if (ref == NULL)
374		return B_BAD_VALUE;
375
376	entry_ref* clonedRef = new(std::nothrow) entry_ref(*ref);
377	if (clonedRef == NULL || !fRefs.AddItem(clonedRef))
378		return B_NO_MEMORY;
379
380	return B_OK;
381}
382
383
384int32
385BNotification::CountOnClickRefs() const
386{
387	return fRefs.CountItems();
388}
389
390
391const entry_ref*
392BNotification::OnClickRefAt(int32 index) const
393{
394	return (entry_ref*)fRefs.ItemAt(index);
395}
396
397
398status_t
399BNotification::AddOnClickArg(const BString& arg)
400{
401	char* clonedArg = strdup(arg.String());
402	if (clonedArg == NULL || !fArgv.AddItem(clonedArg))
403		return B_NO_MEMORY;
404
405	return B_OK;
406}
407
408
409int32
410BNotification::CountOnClickArgs() const
411{
412	return fArgv.CountItems();
413}
414
415
416const char*
417BNotification::OnClickArgAt(int32 index) const
418{
419	return (char*)fArgv.ItemAt(index);
420}
421
422
423const BBitmap*
424BNotification::Icon() const
425{
426	return fBitmap;
427}
428
429
430status_t
431BNotification::SetIcon(const BBitmap* icon)
432{
433	delete fBitmap;
434
435	if (icon != NULL) {
436		fBitmap = new(std::nothrow) BBitmap(icon);
437		if (fBitmap == NULL)
438			return B_NO_MEMORY;
439		return fBitmap->InitCheck();
440	}
441
442	fBitmap = NULL;
443	return B_OK;
444}
445
446
447status_t
448BNotification::Send(bigtime_t timeout)
449{
450	BMessage msg(kNotificationMessage);
451
452	// Archive notification
453	status_t ret = Archive(&msg);
454
455	// Custom time out
456	if (ret == B_OK && timeout > 0)
457		ret = msg.AddInt64("timeout", timeout);
458
459	// Send message
460	if (ret == B_OK) {
461		BMessenger server(kNotificationServerSignature);
462		ret = server.SendMessage(&msg);
463	}
464
465	return ret;
466}
467
468
469void BNotification::_ReservedNotification1() {}
470void BNotification::_ReservedNotification2() {}
471void BNotification::_ReservedNotification3() {}
472void BNotification::_ReservedNotification4() {}
473void BNotification::_ReservedNotification5() {}
474void BNotification::_ReservedNotification6() {}
475void BNotification::_ReservedNotification7() {}
476void BNotification::_ReservedNotification8() {}
477