2 * Copyright 2010, Haiku, Inc. All rights reserved.
3 * Copyright 2008, Pier Luigi Fiorini.
4 * Distributed under the terms of the MIT License.
7 * Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
8 * Stephan Aßmus <superstippi@gmx.de>
14 #include <Application.h>
16 #include <IconUtils.h>
19 #include <Notification.h>
21 #include <TranslationUtils.h>
23 const char* kSignature
= "application/x-vnd.Haiku-notify";
24 const char* kSmallIconAttribute
= "BEOS:M:STD_ICON";
25 const char* kLargeIconAttribute
= "BEOS:L:STD_ICON";
26 const char* kIconAttribute
= "BEOS:ICON";
28 const char *kTypeNames
[] = {
36 const int32 kErrorInitFail
= 127;
37 const int32 kErrorArgumentsFail
= 126;
39 class NotifyApp
: public BApplication
{
44 virtual void ReadyToRun();
45 virtual void ArgvReceived(int32 argc
, char** argv
);
47 bool HasGoodArguments() const
48 { return fHasGoodArguments
; }
51 bool fHasGoodArguments
;
52 notification_type fType
;
68 BBitmap
* _GetBitmap(const entry_ref
* ref
) const;
72 NotifyApp::NotifyApp()
74 BApplication(kSignature
),
75 fHasGoodArguments(false),
76 fType(B_INFORMATION_NOTIFICATION
),
86 NotifyApp::~NotifyApp()
88 for (int32 i
= 0; void* item
= fRefs
->ItemAt(i
); i
++)
92 for (int32 i
= 0; void* item
= fArgv
->ItemAt(i
); i
++)
93 delete (BString
*)item
;
99 NotifyApp::ArgvReceived(int32 argc
, char** argv
)
101 const uint32 kArgCount
= argc
- 1;
104 // Look for valid options
105 for (; index
<= kArgCount
; ++index
) {
106 if (argv
[index
][0] == '-' && argv
[index
][1] == '-') {
107 const char* option
= argv
[index
] + 2;
109 if (++index
> kArgCount
) {
110 // No argument to option
111 fprintf(stderr
, "Missing argument to option --%s\n\n", option
);
115 const char* argument
= argv
[index
];
117 if (strcmp(option
, "type") == 0) {
118 for (int32 i
= 0; kTypeNames
[i
]; i
++) {
119 if (strncmp(kTypeNames
[i
], argument
, strlen(argument
)) == 0)
120 fType
= (notification_type
)i
;
122 } else if (strcmp(option
, "group") == 0)
124 else if (strcmp(option
, "title") == 0)
126 else if (strcmp(option
, "messageID") == 0)
128 else if (strcmp(option
, "progress") == 0)
129 fProgress
= atof(argument
);
130 else if (strcmp(option
, "timeout") == 0)
131 fTimeout
= atol(argument
) * 1000000;
132 else if (strcmp(option
, "icon") == 0) {
133 fIconFile
= argument
;
135 if (get_ref_for_path(fIconFile
.String(), &fFileRef
) < B_OK
) {
136 fprintf(stderr
, "Bad icon path!\n\n");
139 } else if (strcmp(option
, "onClickApp") == 0)
140 fOnClickApp
= argument
;
141 else if (strcmp(option
, "onClickFile") == 0) {
142 if (get_ref_for_path(argument
, &fFile
) != B_OK
) {
143 fprintf(stderr
, "Bad path for --onClickFile!\n\n");
148 } else if (strcmp(option
, "onClickRef") == 0) {
151 if (get_ref_for_path(argument
, &ref
) != B_OK
) {
152 fprintf(stderr
, "Bad path for --onClickRef!\n\n");
156 fRefs
->AddItem(new BEntry(&ref
));
157 } else if (strcmp(option
, "onClickArgv") == 0)
158 fArgv
->AddItem(new BString(argument
));
160 // Unrecognized option
161 fprintf(stderr
, "Unrecognized option --%s\n\n", option
);
165 // Option doesn't start with '--'
169 if (index
== kArgCount
) {
170 // No text argument provided, only '--' arguments
171 fprintf(stderr
, "Missing message argument!\n\n");
176 fContent
= argv
[index
];
177 fHasGoodArguments
= true;
181 NotifyApp::_Usage() const
183 fprintf(stderr
, "Usage: notify [OPTION]... [MESSAGE]\n"
184 "Send notifications to notification_server.\n"
185 " --type <type>\tNotification type,\n"
186 " \t <type> - \"information\" is assumed by default: ");
188 for (int32 i
= 0; kTypeNames
[i
]; i
++)
189 fprintf(stderr
, kTypeNames
[i
+ 1] ? "%s|" : "%s\n", kTypeNames
[i
]);
192 " --group <group>\tGroup\n"
193 " --title <title>\tMessage title\n"
194 " --messageID <msg id>\tMessage ID\n"
195 " --progress <float>\tProgress, value between 0.0 and 1.0 - if type is set to progress\n"
196 " --timeout <secs>\tSpecify timeout\n"
197 " --onClickApp <signature>\tApplication to open when notification is clicked\n"
198 " --onClickFile <fullpath>\tFile to open when notification is clicked\n"
199 " --onClickRef <fullpath>\tFile to open with the application when notification is clicked\n"
200 " --onClickArgv <arg>\tArgument to the application when notification is clicked\n"
201 " --icon <icon file> Icon\n");
206 NotifyApp::_GetBitmap(const entry_ref
* ref
) const
208 BBitmap
* bitmap
= NULL
;
210 // First try by contents
211 bitmap
= BTranslationUtils::GetBitmap(ref
);
215 // Then, try reading its attribute
216 BNode
node(BPath(ref
).Path());
217 bitmap
= new BBitmap(BRect(0, 0, (float)B_LARGE_ICON
- 1,
218 (float)B_LARGE_ICON
- 1), B_RGBA32
);
219 if (BIconUtils::GetIcon(&node
, kIconAttribute
, kSmallIconAttribute
,
220 kLargeIconAttribute
, B_LARGE_ICON
, bitmap
) != B_OK
) {
230 NotifyApp::ReadyToRun()
232 if (HasGoodArguments()) {
233 BNotification
notification(fType
);
235 notification
.SetGroup(fGroup
);
237 notification
.SetTitle(fTitle
);
239 notification
.SetContent(fContent
);
242 notification
.SetMessageID(fMsgId
);
244 if (fType
== B_PROGRESS_NOTIFICATION
)
245 notification
.SetProgress(fProgress
);
247 if (fIconFile
!= "") {
248 BBitmap
* bitmap
= _GetBitmap(&fFileRef
);
250 notification
.SetIcon(bitmap
);
255 if (fOnClickApp
!= "")
256 notification
.SetOnClickApp(fOnClickApp
);
259 notification
.SetOnClickFile(&fFile
);
261 for (int32 i
= 0; void* item
= fRefs
->ItemAt(i
); i
++) {
262 BEntry
* entry
= (BEntry
*)item
;
265 if (entry
->GetRef(&ref
) == B_OK
)
266 notification
.AddOnClickRef(&ref
);
269 for (int32 i
= 0; void* item
= fArgv
->ItemAt(i
); i
++) {
270 BString
* arg
= (BString
*)item
;
271 notification
.AddOnClickArg(arg
->String());
274 status_t ret
= notification
.Send(fTimeout
);
276 fprintf(stderr
, "Failed to deliver notification: %s\n",
287 main(int argc
, char** argv
)
290 if (app
.InitCheck() != B_OK
)
291 return kErrorInitFail
;
294 if (!app
.HasGoodArguments())
295 return kErrorArgumentsFail
;