/* Marmot * Copyright (C) 2003 James Willcox, Corey Bowers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "server_config.h" #include #include #include #include "gam_event.h" #include "gam_listener.h" #include "gam_subscription.h" #include "gam_protocol.h" #include "gam_event.h" #include "gam_error.h" //#define GAM_SUB_VERBOSE struct _GamSubscription { char *path; int events; int reqno; int pathlen; int options; gboolean is_dir; gboolean cancelled; GamListener *listener; }; /** * @defgroup GamSubscription GamSubscription * @ingroup Daemon * @brief GamSubscription API. * * A #GamSubscription represents a single monitoring request (or "subscription"). * * @{ */ /** * Creates a new GamSubscription * * @param path the path to be monitored * @param events the events that are accepted * @param is_dir whether the subscription is for a directory or not * @returns the new GamSubscription */ GamSubscription * gam_subscription_new(const char *path, int events, int reqno, gboolean is_dir, int options) { GamSubscription *sub; sub = g_new0(GamSubscription, 1); sub->path = g_strdup(path); sub->events = events; sub->reqno = reqno; sub->pathlen = strlen(path); /* everyone accepts this */ gam_subscription_set_event(sub, GAMIN_EVENT_EXISTS | GAMIN_EVENT_ENDEXISTS); sub->is_dir = is_dir; sub->options = options; #ifdef GAM_SUB_VERBOSE GAM_DEBUG(DEBUG_INFO, "Created subscription for %s\n", path); #endif return sub; } /** * Frees a GamSubscription * * @param sub the GamSubscription */ void gam_subscription_free(GamSubscription * sub) { if (sub == NULL) return; #ifdef GAM_SUB_VERBOSE GAM_DEBUG(DEBUG_INFO, "Freeing subscription for %s\n", sub->path); #endif g_free(sub->path); g_free(sub); } /** * Tells if a GamSubscription is for a directory or not * * @param sub the GamSubscription * @returns TRUE if the subscription is for a directory, FALSE otherwise */ gboolean gam_subscription_is_dir(GamSubscription * sub) { if (sub == NULL) return(FALSE); return sub->is_dir; } /** * Provide the path len for a GamSubscription * * @param sub the GamSubscription * @returns the path len for the subscription */ int gam_subscription_pathlen(GamSubscription * sub) { if (sub == NULL) return(-1); return sub->pathlen; } /** * Gets the path for a GamSubscription * * @param sub the GamSubscription * @returns The path being monitored. It should not be freed. */ G_CONST_RETURN char * gam_subscription_get_path(GamSubscription * sub) { if (sub == NULL) return(NULL); return sub->path; } /** * Gets the request number for a GamSubscription * * @param sub the GamSubscription * @returns The request number */ int gam_subscription_get_reqno(GamSubscription * sub) { if (sub == NULL) return(-1); return sub->reqno; } /** * Gets the GamListener which owns this GamSubscription * * @param sub the GamSubscription * @returns the GamListener, or NULL */ GamListener * gam_subscription_get_listener(GamSubscription * sub) { if (sub == NULL) return(NULL); return sub->listener; } /** * Sets the GamListener which is owned by this GamSubscription * * @param sub the GamSubscription * @param listener the GamListener */ void gam_subscription_set_listener(GamSubscription * sub, GamListener * listener) { if (sub == NULL) return; GAM_DEBUG(DEBUG_INFO, "%s listening for %s\n", gam_listener_get_pidname (listener), sub->path); sub->listener = listener; } /** * Set the events this GamSubscription is interested in * * @param sub the GamSubscription * @param event an ORed combination of the events desired */ void gam_subscription_set_event(GamSubscription * sub, int event) { if (sub == NULL) return; sub->events |= event; } /** * Removes an event from the set of acceptable events * * @param sub the GamSubscription * @param event the event to remove */ void gam_subscription_unset_event(GamSubscription * sub, int event) { if (sub == NULL) return; sub->events &= ~event; } /** * * @param sub the GamSubscription * @param event the event to test for * @returns Whether or not this subscription accepts a given event */ gboolean gam_subscription_has_event(GamSubscription * sub, int event) { if (sub == NULL) return(FALSE); return((sub->events & event) != 0); } /** * * @param sub the GamSubscription * @option option * @returns Whether or not this subscription has that option. */ gboolean gam_subscription_has_option(GamSubscription * sub, int option) { if (sub == NULL) return(FALSE); return((sub->options & option) != 0); } /** * Mark this GamSubscription as cancelled * * @param sub the GamSubscription */ void gam_subscription_cancel(GamSubscription * sub) { if (sub == NULL) return; GAM_DEBUG(DEBUG_INFO, "%s not listening for %s\n", gam_listener_get_pidname (sub->listener), sub->path); sub->cancelled = TRUE; } /** * Checks if the GamSubscription is cancelled or not * * @param sub the GamSubscription * @returns TRUE if the GamSubscription is cancelled, FALSE otherwise */ gboolean gam_subscription_is_cancelled(GamSubscription * sub) { if (sub == NULL) return(TRUE); return sub->cancelled == TRUE; } /** * gam_subscription_wants_event: * @sub: the GamSubscription * @name: file name (just the base name, not the complete path) * @is_dir_node: is the target a directory * @event: the event * @force: force the event as much as possible * * Checks if a given path/event combination is accepted by this GamSubscription * * Returns TRUE if the combination is accepted, FALSE otherwise */ gboolean gam_subscription_wants_event(GamSubscription * sub, const char *name, int is_dir_node, GaminEventType event, int force) { int same_path = 0; if ((sub == NULL) || (name == NULL) || (event == 0)) return(FALSE); if (sub->cancelled) return FALSE; if ((sub->options & GAM_OPT_NOEXISTS) && ((event == GAMIN_EVENT_EXISTS) || (event == GAMIN_EVENT_ENDEXISTS))) return FALSE; /* only directory listening cares for other files */ same_path = !strcmp(name, sub->path); if ((sub->is_dir == 0) && (!same_path)) return(FALSE); if (!gam_subscription_has_event(sub, event)) { return FALSE; } if (force) return TRUE; if ((sub->is_dir) && (is_dir_node) && (same_path)) { if ((event == GAMIN_EVENT_EXISTS) || (event == GAMIN_EVENT_CHANGED) || (event == GAMIN_EVENT_ENDEXISTS)) return FALSE; } return TRUE; } /** * gam_subscription_debug: * @sub: the subscription * * Provide debug output for that subscription node/state */ void gam_subscription_debug(GamSubscription *sub) { #ifdef GAM_DEBUG_ENABLED if (sub == NULL) { GAM_DEBUG(DEBUG_INFO, " Subscription is NULL\n"); return; } GAM_DEBUG(DEBUG_INFO, " Subscription %d reqno %d events %d dir %d: %s\n", sub->reqno, sub->events, sub->events, sub->is_dir, sub->path); #endif } void gam_subscription_shutdown () { } /** @} */