KUNCUserNotifications.c [plain text]
#include <mach/port.h>
#include <mach/message.h>
#include <mach/kern_return.h>
#include <mach/host_priv.h>
#include <kern/kern_types.h>
#include <kern/kalloc.h>
#include <kern/host.h>
#include <kern/ipc_kobject.h>
#include <ipc/ipc_port.h>
#include <UserNotification/UNDTypes.h>
#include <UserNotification/UNDRequest.h>
#include <UserNotification/UNDReplyServer.h>
#include <UserNotification/KUNCUserNotifications.h>
#ifdef KERNEL_CF
#include <IOKit/IOCFSerialize.h>
#include <IOKit/IOCFUnserialize.h>
#endif
struct UNDReply {
decl_lck_mtx_data(, lock);
int userLandNotificationKey;
KUNCUserNotificationCallBack callback;
boolean_t inprogress;
ipc_port_t self_port;
};
#define UNDReply_lock(reply) lck_mtx_lock(&reply->lock)
#define UNDReply_unlock(reply) lck_mtx_unlock(&reply->lock)
extern lck_grp_t LockCompatGroup;
void UNDReply_deallocate(
UNDReplyRef reply);
void
UNDReply_deallocate(
UNDReplyRef reply)
{
ipc_port_t port;
UNDReply_lock(reply);
port = reply->self_port;
assert(IP_VALID(port));
ipc_kobject_set(port, IKO_NULL, IKOT_NONE);
reply->self_port = IP_NULL;
UNDReply_unlock(reply);
ipc_port_dealloc_kernel(port);
lck_mtx_destroy(&reply->lock, &LockCompatGroup);
kfree(reply, sizeof(struct UNDReply));
return;
}
static UNDServerRef
UNDServer_reference(void)
{
UNDServerRef UNDServer;
kern_return_t kr;
kr = host_get_user_notification_port(host_priv_self(), &UNDServer);
assert(kr == KERN_SUCCESS);
return UNDServer;
}
static void
UNDServer_deallocate(
UNDServerRef UNDServer)
{
if (IP_VALID(UNDServer)) {
ipc_port_release_send(UNDServer);
}
}
kern_return_t
UNDAlertCompletedWithResult_rpc(
UNDReplyRef reply,
int result,
xmlData_t keyRef,
#ifdef KERNEL_CF
mach_msg_type_number_t keyLen)
#else
__unused mach_msg_type_number_t keyLen)
#endif
{
#ifdef KERNEL_CF
CFStringRef xmlError = NULL;
CFDictionaryRef dict = NULL;
#else
const void *dict = (const void *)keyRef;
#endif
if (reply == UND_REPLY_NULL || !reply->inprogress) {
return KERN_INVALID_ARGUMENT;
}
#ifdef KERNEL_CF
if (keyRef && keyLen) {
dict = IOCFUnserialize(keyRef, NULL, NULL, &xmlError);
}
if (xmlError) {
CFShow(xmlError);
CFRelease(xmlError);
}
#endif
if (reply->callback) {
(reply->callback)((int)(KUNCUserNotificationID)reply, result, dict);
}
UNDReply_lock(reply);
reply->inprogress = FALSE;
reply->userLandNotificationKey = -1;
UNDReply_unlock(reply);
UNDReply_deallocate(reply);
return KERN_SUCCESS;
}
kern_return_t
UNDNotificationCreated_rpc(
UNDReplyRef reply,
int userLandNotificationKey)
{
if (reply == UND_REPLY_NULL) {
return KERN_INVALID_ARGUMENT;
}
UNDReply_lock(reply);
if (reply->inprogress || reply->userLandNotificationKey != -1) {
UNDReply_unlock(reply);
return KERN_INVALID_ARGUMENT;
}
reply->userLandNotificationKey = userLandNotificationKey;
UNDReply_unlock(reply);
return KERN_SUCCESS;
}
KUNCUserNotificationID
KUNCGetNotificationID(void)
{
UNDReplyRef reply;
reply = (UNDReplyRef) kalloc(sizeof(struct UNDReply));
if (reply != UND_REPLY_NULL) {
reply->self_port = ipc_kobject_alloc_port((ipc_kobject_t)reply,
IKOT_UND_REPLY, IPC_KOBJECT_ALLOC_NONE);
lck_mtx_init(&reply->lock, &LockCompatGroup, LCK_ATTR_NULL);
reply->userLandNotificationKey = -1;
reply->inprogress = FALSE;
}
return (KUNCUserNotificationID) reply;
}
kern_return_t
KUNCExecute(char executionPath[1024], int uid, int gid)
{
UNDServerRef UNDServer;
UNDServer = UNDServer_reference();
if (IP_VALID(UNDServer)) {
kern_return_t kr;
kr = UNDExecute_rpc(UNDServer, executionPath, uid, gid);
UNDServer_deallocate(UNDServer);
return kr;
}
return MACH_SEND_INVALID_DEST;
}
kern_return_t
KUNCUserNotificationCancel(
KUNCUserNotificationID id)
{
UNDReplyRef reply = (UNDReplyRef)id;
kern_return_t kr;
int ulkey;
if (reply == UND_REPLY_NULL) {
return KERN_INVALID_ARGUMENT;
}
UNDReply_lock(reply);
if (!reply->inprogress) {
UNDReply_unlock(reply);
return KERN_INVALID_ARGUMENT;
}
reply->inprogress = FALSE;
if ((ulkey = reply->userLandNotificationKey) != 0) {
UNDServerRef UNDServer;
reply->userLandNotificationKey = 0;
UNDReply_unlock(reply);
UNDServer = UNDServer_reference();
if (IP_VALID(UNDServer)) {
kr = UNDCancelNotification_rpc(UNDServer, ulkey);
UNDServer_deallocate(UNDServer);
} else {
kr = MACH_SEND_INVALID_DEST;
}
} else {
UNDReply_unlock(reply);
kr = KERN_SUCCESS;
}
UNDReply_deallocate(reply);
return kr;
}
kern_return_t
KUNCUserNotificationDisplayNotice(
int noticeTimeout,
unsigned flags,
char *iconPath,
char *soundPath,
char *localizationPath,
char *alertHeader,
char *alertMessage,
char *defaultButtonTitle)
{
UNDServerRef UNDServer;
UNDServer = UNDServer_reference();
if (IP_VALID(UNDServer)) {
kern_return_t kr;
kr = UNDDisplayNoticeSimple_rpc(UNDServer,
noticeTimeout,
flags,
iconPath,
soundPath,
localizationPath,
alertHeader,
alertMessage,
defaultButtonTitle);
UNDServer_deallocate(UNDServer);
return kr;
}
return MACH_SEND_INVALID_DEST;
}
kern_return_t
KUNCUserNotificationDisplayAlert(
int alertTimeout,
unsigned flags,
char *iconPath,
char *soundPath,
char *localizationPath,
char *alertHeader,
char *alertMessage,
char *defaultButtonTitle,
char *alternateButtonTitle,
char *otherButtonTitle,
unsigned *responseFlags)
{
UNDServerRef UNDServer;
UNDServer = UNDServer_reference();
if (IP_VALID(UNDServer)) {
kern_return_t kr;
kr = UNDDisplayAlertSimple_rpc(UNDServer,
alertTimeout,
flags,
iconPath,
soundPath,
localizationPath,
alertHeader,
alertMessage,
defaultButtonTitle,
alternateButtonTitle,
otherButtonTitle,
responseFlags);
UNDServer_deallocate(UNDServer);
return kr;
}
return MACH_SEND_INVALID_DEST;
}
kern_return_t
KUNCUserNotificationDisplayFromBundle(
KUNCUserNotificationID id,
char *bundlePath,
char *fileName,
char *fileExtension,
char *messageKey,
char *tokenString,
KUNCUserNotificationCallBack callback,
__unused int contextKey)
{
UNDReplyRef reply = (UNDReplyRef)id;
UNDServerRef UNDServer;
ipc_port_t reply_port;
if (reply == UND_REPLY_NULL) {
return KERN_INVALID_ARGUMENT;
}
UNDReply_lock(reply);
if (reply->inprogress == TRUE || reply->userLandNotificationKey != -1) {
UNDReply_unlock(reply);
return KERN_INVALID_ARGUMENT;
}
reply->inprogress = TRUE;
reply->callback = callback;
reply_port = ipc_port_make_send(reply->self_port);
UNDReply_unlock(reply);
UNDServer = UNDServer_reference();
if (IP_VALID(UNDServer)) {
kern_return_t kr;
kr = UNDDisplayCustomFromBundle_rpc(UNDServer,
reply_port,
bundlePath,
fileName,
fileExtension,
messageKey,
tokenString);
UNDServer_deallocate(UNDServer);
return kr;
}
return MACH_SEND_INVALID_DEST;
}
UNDReplyRef
convert_port_to_UNDReply(
ipc_port_t port)
{
if (IP_VALID(port)) {
UNDReplyRef reply;
ip_lock(port);
if (!ip_active(port) || (ip_kotype(port) != IKOT_UND_REPLY)) {
ip_unlock(port);
return UND_REPLY_NULL;
}
reply = (UNDReplyRef) ip_get_kobject(port);
assert(reply != UND_REPLY_NULL);
ip_unlock(port);
return reply;
}
return UND_REPLY_NULL;
}
kern_return_t
host_set_UNDServer(
host_priv_t host_priv,
UNDServerRef server)
{
return host_set_user_notification_port(host_priv, server);
}
kern_return_t
host_get_UNDServer(
host_priv_t host_priv,
UNDServerRef *serverp)
{
return host_get_user_notification_port(host_priv, serverp);
}