/* Jungle Monkey * Copyright (C) 1999-2001 The Regents of the University of Michigan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "jmmsp_search.h" #include "jmmsp_debug.h" #include #include typedef struct _Search { JMMSPSearch* jsearch; gchar* keyword; guint hop; guint timer; GSList* searchers; } Search; typedef struct _Searcher { Search* search; JMMSPSearchFunc func; gpointer* user_data; } Searcher; static void search_delete (Search* search); static void search_reply (JMMSPHandler* handler, JMMSP* jmmsp, const gchar* keyword, const JMMSPReply* reply); static gboolean timeout_cb (gpointer data); static JMMSPHandlerFuncs search_vtbl = { NULL, search_reply, NULL, NULL}; /* **************************************** */ JMMSPSearch* jmmsp_search_new (void) { JMMSPSearch* search; search = g_new0 (JMMSPSearch, 1); jmmsp_handler_init (&search->handler, &search_vtbl); search->handler.loopback = TRUE; return search; } void jmmsp_search_delete (JMMSPSearch* jsearch) { GSList* i; if (!jsearch) return; /* Delete searches */ for (i = jsearch->searches; i != NULL; i = i->next) search_delete ((Search*) i->data); g_slist_free (jsearch->searches); /* Remove handlers */ jmmsp_handler_uninit (&jsearch->handler); g_free (jsearch); } /* **************************************** */ JMMSPSearchID jmmsp_search_query (JMMSPSearch* jsearch, const gchar* keyword, JMMSPSearchFunc func, gpointer user_data) { Searcher* srcher; Search* srch; GSList* i; g_return_val_if_fail (jsearch, NULL); g_return_val_if_fail (keyword, NULL); g_return_val_if_fail (func, NULL); /* Create a new searcher */ srcher = g_new (Searcher, 1); srcher->func = func; srcher->user_data = user_data; /* Attempt to find existing search */ srch = NULL; for (i = jsearch->searches; i != NULL; i = i->next) { Search* srch2 = (Search*) i->data; if (!strcmp(srch2->keyword, keyword)) { srch = srch2; break; } } /* Create new search if we did not find one */ if (!srch) { srch = g_new0 (Search, 1); srch->jsearch = jsearch; srch->keyword = g_strdup (keyword); jsearch->searches = g_slist_prepend (jsearch->searches, srch); } /* Add searcher to searches list */ srch->searchers = g_slist_prepend (srch->searchers, srcher); srcher->search = srch; /* Send first search query if we haven't already */ if (!srch->timer) { srch->timer = g_timeout_add (JMMSP_SEARCH_TIMEOUT, timeout_cb, srch); for (i = ((JMMSPHandler*) jsearch)->jmmsps; i != NULL; i = i->next) { JMMSP* jmmsp = (JMMSP*) i->data; jmmsp_send_query (jmmsp, keyword, JMMSP_SEARCH_MAX_HOPS); } } return srcher; } static gboolean timeout_cb (gpointer data) { Search* search = (Search*) data; JMMSPSearch* jsearch = search->jsearch; GSList* list; GSList* i; search->timer = 0; /* Save list - up call my cause search to be repeated */ list = search->searchers; search->searchers = NULL; /* Upcall errors */ for (i = list; i != NULL; i = i->next) { Searcher* srcher = (Searcher*) i->data; (srcher->func)(jsearch, srcher, NULL, srcher->user_data); g_free (srcher); } g_slist_free (list); /* Delete if empty (note a search may have restarted) */ if (!search->searchers) { jsearch->searches = g_slist_remove (jsearch->searches, search); search_delete (search); } return FALSE; } void jmmsp_search_cancel (JMMSPSearch* search, JMMSPSearchID id) { Searcher* srcher = (Searcher*) id; Search* srch; JMMSPSearch* jsearch; g_return_if_fail (search); g_return_if_fail (id); srch = srcher->search; jsearch = srch->jsearch; /* Remove searcher from list */ srch->searchers = g_slist_remove (srch->searchers, srcher); /* If there are no more searchers, delete the search */ if (!srch->searchers) { jsearch->searches = g_slist_remove (jsearch->searches, srch); search_delete (srch); } /* Delete the searcher */ g_free (srcher); } static void search_delete (Search* search) { GSList* i; for (i = search->searchers; i != NULL; i = i->next) { Searcher* srcher = (Searcher*) i->data; g_free (srcher); } g_slist_free (search->searchers); g_free (search->keyword); if (search->timer) g_source_remove (search->timer); g_free (search); } /* **************************************** */ static void search_reply (JMMSPHandler* handler, JMMSP* jmmsp, const gchar* keyword, const JMMSPReply* reply) { JMMSPSearch* jsearch = (JMMSPSearch*) handler; GSList* i; g_return_if_fail (handler && jmmsp && reply); JMMSPP (0x04, "search_reply: %s\n", reply->name); /* Check if a match */ for (i = jsearch->searches; i != NULL; ) { Search* s; s = (Search*) i->data; i = i->next; if (jmmsp_reply_matches(reply, s->keyword)) { GSList* j; /* Match found - call callbacks */ for (j = s->searchers; j != NULL; ) { Searcher* srcher; srcher = (Searcher*) j->data; j = j->next; (srcher->func)(jsearch, srcher, reply, srcher->user_data); } break; } } } const gchar* jmmsp_search_get_keyword (const JMMSPSearchID id) { Searcher* srcher = (Searcher*) id; g_return_val_if_fail (srcher, NULL); g_return_val_if_fail (srcher->search, NULL); return srcher->search->keyword; }