LCOV - code coverage report
Current view: top level - src - handler.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 14 286 4.9 %
Date: 2023-08-10 00:00:00 Functions: 1 21 4.8 %

          Line data    Source code
       1             : /* handler.c
       2             : ** strophe XMPP client library -- event handler management
       3             : **
       4             : ** Copyright (C) 2005-2009 Collecta, Inc.
       5             : **
       6             : **  This software is provided AS-IS with no warranty, either express
       7             : **  or implied.
       8             : **
       9             : **  This program is dual licensed under the MIT and GPLv3 licenses.
      10             : */
      11             : 
      12             : /** @file
      13             :  *  Event handler management.
      14             :  */
      15             : 
      16             : /** @defgroup Handlers Stanza and timed event handlers
      17             :  */
      18             : 
      19             : #include <stdio.h>
      20             : #include <stdlib.h>
      21             : #include <string.h>
      22             : 
      23             : #include "strophe.h"
      24             : #include "common.h"
      25             : #include "ostypes.h"
      26             : 
      27             : typedef int (*xmpp_void_handler)();
      28             : 
      29             : /* Remove item from the list pointed by head, but don't free it.
      30             :  * There can be a situation when user's handler deletes another handler which
      31             :  * is the previous in the list. handler_fire_stanza() and handler_fire_timed()
      32             :  * must handle this situation correctly. Current function helps to avoid
      33             :  * list corruption in described scenario.
      34             :  *
      35             :  * TODO Convert handler lists to double-linked lists. Current implementation
      36             :  * works for O(n).
      37             :  */
      38           0 : static void _handler_item_remove(xmpp_handlist_t **head, xmpp_handlist_t *item)
      39             : {
      40           0 :     while (*head) {
      41           0 :         if (*head == item) {
      42           0 :             *head = item->next;
      43           0 :             break;
      44             :         }
      45           0 :         head = &(*head)->next;
      46             :     }
      47             : }
      48             : 
      49           0 : static void _free_handlist_item(xmpp_ctx_t *ctx, xmpp_handlist_t *item)
      50             : {
      51           0 :     if (item->u.ns)
      52           0 :         strophe_free(ctx, item->u.ns);
      53           0 :     if (item->u.name)
      54           0 :         strophe_free(ctx, item->u.name);
      55           0 :     if (item->u.type)
      56           0 :         strophe_free(ctx, item->u.type);
      57           0 :     strophe_free(ctx, item);
      58           0 : }
      59             : 
      60             : /** Fire off all stanza handlers that match.
      61             :  *  This function is called internally by the event loop whenever stanzas
      62             :  *  are received from the XMPP server.
      63             :  *
      64             :  *  @param conn a Strophe connection object
      65             :  *  @param stanza a Strophe stanza object
      66             :  */
      67           0 : void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
      68             : {
      69           0 :     xmpp_handlist_t *item, *next, *head, *head_old;
      70           0 :     const char *id, *ns, *name, *type;
      71           0 :     int ret;
      72             : 
      73             :     /* call id handlers */
      74           0 :     id = xmpp_stanza_get_id(stanza);
      75           0 :     if (id) {
      76           0 :         head = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
      77             :         /* enable all added handlers */
      78           0 :         for (item = head; item; item = item->next)
      79           0 :             item->enabled = 1;
      80             : 
      81             :         item = head;
      82           0 :         while (item) {
      83             :             /* don't fire user handlers until authentication succeeds and
      84             :                and skip newly added handlers */
      85           0 :             if ((item->user_handler && !conn->authenticated) ||
      86           0 :                 !item->enabled) {
      87           0 :                 item = item->next;
      88           0 :                 continue;
      89             :             }
      90             : 
      91           0 :             ret = ((xmpp_handler)(item->handler))(conn, stanza, item->userdata);
      92           0 :             next = item->next;
      93           0 :             if (!ret) {
      94             :                 /* handler is one-shot, so delete it */
      95           0 :                 head_old = head;
      96           0 :                 _handler_item_remove(&head, item);
      97           0 :                 if (head != head_old) {
      98             :                     /* replace old value */
      99           0 :                     hash_add(conn->id_handlers, id, head);
     100             :                 }
     101           0 :                 strophe_free(conn->ctx, item->u.id);
     102           0 :                 strophe_free(conn->ctx, item);
     103             :             }
     104             :             item = next;
     105             :         }
     106             :     }
     107             : 
     108             :     /* call handlers */
     109           0 :     ns = xmpp_stanza_get_ns(stanza);
     110           0 :     name = xmpp_stanza_get_name(stanza);
     111           0 :     type = xmpp_stanza_get_type(stanza);
     112             : 
     113             :     /* enable all added handlers */
     114           0 :     for (item = conn->handlers; item; item = item->next)
     115           0 :         item->enabled = 1;
     116             : 
     117             :     item = conn->handlers;
     118           0 :     while (item) {
     119             :         /* don't fire user handlers until authentication succeeds and
     120             :            skip newly added handlers */
     121           0 :         if ((item->user_handler && !conn->authenticated) || !item->enabled) {
     122           0 :             item = item->next;
     123           0 :             continue;
     124             :         }
     125             : 
     126           0 :         next = item->next;
     127           0 :         if ((!item->u.ns || (ns && strcmp(ns, item->u.ns) == 0) ||
     128           0 :              xmpp_stanza_get_child_by_ns(stanza, item->u.ns)) &&
     129           0 :             (!item->u.name || (name && strcmp(name, item->u.name) == 0)) &&
     130           0 :             (!item->u.type || (type && strcmp(type, item->u.type) == 0))) {
     131             : 
     132           0 :             ret = ((xmpp_handler)(item->handler))(conn, stanza, item->userdata);
     133             :             /* list may be changed during execution of a handler */
     134           0 :             next = item->next;
     135           0 :             if (!ret) {
     136             :                 /* handler is one-shot, so delete it */
     137           0 :                 _handler_item_remove(&conn->handlers, item);
     138           0 :                 _free_handlist_item(conn->ctx, item);
     139             :             }
     140             :         }
     141             :         item = next;
     142             :     }
     143           0 : }
     144             : 
     145             : /** Fire off all timed handlers that are ready.
     146             :  *  This function is called internally by the event loop.
     147             :  *
     148             :  *  @param ctx a Strophe context object
     149             :  *
     150             :  *  @return the time in milliseconds until the next handler will be ready
     151             :  */
     152           0 : uint64_t handler_fire_timed(xmpp_ctx_t *ctx)
     153             : {
     154           0 :     xmpp_connlist_t *connitem;
     155           0 :     xmpp_handlist_t *item, *next;
     156           0 :     xmpp_conn_t *conn;
     157           0 :     uint64_t elapsed, min;
     158           0 :     uint64_t timestamp;
     159           0 :     int ret;
     160             : 
     161           0 :     min = (uint64_t)(-1);
     162             : 
     163           0 :     connitem = ctx->connlist;
     164           0 :     while (connitem) {
     165           0 :         conn = connitem->conn;
     166           0 :         if (conn->state != XMPP_STATE_CONNECTED) {
     167           0 :             connitem = connitem->next;
     168           0 :             continue;
     169             :         }
     170             : 
     171             :         /* enable all handlers that were added */
     172           0 :         for (item = conn->timed_handlers; item; item = item->next)
     173           0 :             item->enabled = 1;
     174             : 
     175             :         item = conn->timed_handlers;
     176           0 :         while (item) {
     177             :             /* don't fire user handlers until authentication succeeds and
     178             :                skip newly added handlers */
     179           0 :             if ((item->user_handler && !conn->authenticated) ||
     180           0 :                 !item->enabled) {
     181           0 :                 item = item->next;
     182           0 :                 continue;
     183             :             }
     184             : 
     185           0 :             next = item->next;
     186           0 :             timestamp = time_stamp();
     187           0 :             elapsed = time_elapsed(item->u.last_stamp, timestamp);
     188           0 :             if (elapsed >= item->u.period) {
     189             :                 /* fire! */
     190           0 :                 item->u.last_stamp = timestamp;
     191           0 :                 ret = ((xmpp_timed_handler)item->handler)(conn, item->userdata);
     192             :                 /* list may be changed during execution of a handler */
     193           0 :                 next = item->next;
     194           0 :                 if (!ret) {
     195             :                     /* delete handler if it returned false */
     196           0 :                     _handler_item_remove(&conn->timed_handlers, item);
     197           0 :                     strophe_free(ctx, item);
     198             :                 }
     199           0 :             } else if (min > (item->u.period - elapsed))
     200             :                 min = item->u.period - elapsed;
     201             : 
     202             :             item = next;
     203             :         }
     204             : 
     205           0 :         connitem = connitem->next;
     206             :     }
     207             : 
     208             :     /*
     209             :      * Check timed handlers in context. These handlers fire periodically
     210             :      * regardless of connections state.
     211             :      * TODO Reduce copy-paste.
     212             :      */
     213           0 :     item = ctx->timed_handlers;
     214           0 :     while (item) {
     215           0 :         next = item->next;
     216           0 :         timestamp = time_stamp();
     217           0 :         elapsed = time_elapsed(item->u.last_stamp, timestamp);
     218           0 :         if (elapsed >= item->u.period) {
     219             :             /* fire! */
     220           0 :             item->u.last_stamp = timestamp;
     221           0 :             ret =
     222           0 :                 ((xmpp_global_timed_handler)item->handler)(ctx, item->userdata);
     223             :             /* list may be changed during execution of a handler */
     224           0 :             next = item->next;
     225           0 :             if (!ret) {
     226             :                 /* delete handler if it returned false */
     227           0 :                 _handler_item_remove(&ctx->timed_handlers, item);
     228           0 :                 strophe_free(ctx, item);
     229             :             }
     230           0 :         } else if (min > (item->u.period - elapsed))
     231             :             min = item->u.period - elapsed;
     232             : 
     233             :         item = next;
     234             :     }
     235             : 
     236           0 :     return min;
     237             : }
     238             : 
     239             : /** Reset all timed handlers.
     240             :  *  This function is called internally when a connection is successful.
     241             :  *
     242             :  *  @param conn a Strophe connection object
     243             :  *  @param user_only whether to reset all handlers or only user ones
     244             :  */
     245           0 : void handler_reset_timed(xmpp_conn_t *conn, int user_only)
     246             : {
     247           0 :     xmpp_handlist_t *handitem;
     248             : 
     249           0 :     handitem = conn->timed_handlers;
     250           0 :     while (handitem) {
     251           0 :         if ((user_only && handitem->user_handler) || !user_only)
     252           0 :             handitem->u.last_stamp = time_stamp();
     253             : 
     254           0 :         handitem = handitem->next;
     255             :     }
     256           0 : }
     257             : 
     258           0 : static void _timed_handler_add(xmpp_ctx_t *ctx,
     259             :                                xmpp_handlist_t **handlers_list,
     260             :                                xmpp_void_handler handler,
     261             :                                unsigned long period,
     262             :                                void *userdata,
     263             :                                int user_handler)
     264             : {
     265           0 :     xmpp_handlist_t *item;
     266             : 
     267             :     /* check if handler is already in the list */
     268           0 :     for (item = *handlers_list; item; item = item->next) {
     269           0 :         if (item->handler == handler && item->userdata == userdata) {
     270           0 :             strophe_warn(ctx, "xmpp", "Timed handler already exists.");
     271           0 :             break;
     272             :         }
     273             :     }
     274           0 :     if (item)
     275             :         return;
     276             : 
     277             :     /* build new item */
     278           0 :     item = strophe_alloc(ctx, sizeof(xmpp_handlist_t));
     279           0 :     if (!item)
     280             :         return;
     281             : 
     282           0 :     item->user_handler = user_handler;
     283           0 :     item->handler = handler;
     284           0 :     item->userdata = userdata;
     285           0 :     item->enabled = 0;
     286             : 
     287           0 :     item->u.period = period;
     288           0 :     item->u.last_stamp = time_stamp();
     289             : 
     290             :     /* append item to list */
     291           0 :     item->next = *handlers_list;
     292           0 :     *handlers_list = item;
     293             : }
     294             : 
     295           0 : static void _timed_handler_delete(xmpp_ctx_t *ctx,
     296             :                                   xmpp_handlist_t **handlers_list,
     297             :                                   xmpp_void_handler handler)
     298             : {
     299           0 :     xmpp_handlist_t *item;
     300             : 
     301           0 :     while (*handlers_list) {
     302           0 :         item = *handlers_list;
     303           0 :         if (item->handler == handler) {
     304           0 :             *handlers_list = item->next;
     305           0 :             strophe_free(ctx, item);
     306             :         } else {
     307           0 :             handlers_list = &item->next;
     308             :         }
     309             :     }
     310           0 : }
     311             : 
     312             : /** Delete a timed handler.
     313             :  *
     314             :  *  @param conn a Strophe connection object
     315             :  *  @param handler function pointer to the handler
     316             :  *
     317             :  *  @ingroup Handlers
     318             :  */
     319           0 : void xmpp_timed_handler_delete(xmpp_conn_t *conn, xmpp_timed_handler handler)
     320             : {
     321           0 :     _timed_handler_delete(conn->ctx, &conn->timed_handlers, handler);
     322           0 : }
     323             : 
     324           0 : static void _id_handler_add(xmpp_conn_t *conn,
     325             :                             xmpp_handler handler,
     326             :                             const char *id,
     327             :                             void *userdata,
     328             :                             int user_handler)
     329             : {
     330           0 :     xmpp_handlist_t *item, *tail;
     331             : 
     332             :     /* check if handler is already in the list */
     333           0 :     item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
     334           0 :     while (item) {
     335           0 :         if (item->handler == handler && item->userdata == userdata) {
     336           0 :             strophe_warn(conn->ctx, "xmpp", "Id handler already exists.");
     337           0 :             break;
     338             :         }
     339           0 :         item = item->next;
     340             :     }
     341           0 :     if (item)
     342             :         return;
     343             : 
     344             :     /* build new item */
     345           0 :     item = strophe_alloc(conn->ctx, sizeof(xmpp_handlist_t));
     346           0 :     if (!item)
     347             :         return;
     348             : 
     349           0 :     item->user_handler = user_handler;
     350           0 :     item->handler = handler;
     351           0 :     item->userdata = userdata;
     352           0 :     item->enabled = 0;
     353           0 :     item->next = NULL;
     354             : 
     355           0 :     item->u.id = strophe_strdup(conn->ctx, id);
     356           0 :     if (!item->u.id) {
     357           0 :         strophe_free(conn->ctx, item);
     358           0 :         return;
     359             :     }
     360             : 
     361             :     /* put on list in hash table */
     362           0 :     tail = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
     363           0 :     if (!tail)
     364           0 :         hash_add(conn->id_handlers, id, item);
     365             :     else {
     366           0 :         while (tail->next)
     367             :             tail = tail->next;
     368           0 :         tail->next = item;
     369             :     }
     370             : }
     371             : 
     372             : /** Delete an id based stanza handler.
     373             :  *
     374             :  *  @param conn a Strophe connection object
     375             :  *  @param handler a function pointer to a stanza handler
     376             :  *  @param id a string containing the id the handler is for
     377             :  *
     378             :  *  @ingroup Handlers
     379             :  */
     380           0 : void xmpp_id_handler_delete(xmpp_conn_t *conn,
     381             :                             xmpp_handler handler,
     382             :                             const char *id)
     383             : {
     384           0 :     xmpp_handlist_t *item, *prev, *next;
     385             : 
     386           0 :     prev = NULL;
     387           0 :     item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
     388           0 :     if (!item)
     389             :         return;
     390             : 
     391           0 :     while (item) {
     392           0 :         next = item->next;
     393             : 
     394           0 :         if (item->handler == handler) {
     395           0 :             if (prev)
     396           0 :                 prev->next = next;
     397             :             else {
     398           0 :                 hash_drop(conn->id_handlers, id);
     399           0 :                 hash_add(conn->id_handlers, id, next);
     400             :             }
     401             : 
     402           0 :             strophe_free(conn->ctx, item->u.id);
     403           0 :             strophe_free(conn->ctx, item);
     404           0 :             item = next;
     405             :         } else {
     406             :             prev = item;
     407             :             item = next;
     408             :         }
     409             :     }
     410             : }
     411             : 
     412           0 : static int _dup_string(xmpp_ctx_t *ctx, const char *src, char **dest)
     413             : {
     414           0 :     if (src) {
     415           0 :         *dest = strophe_strdup(ctx, src);
     416           0 :         if (!(*dest))
     417             :             return 1;
     418             :     }
     419             :     return 0;
     420             : }
     421             : 
     422             : /* add a stanza handler */
     423           0 : static void _handler_add(xmpp_conn_t *conn,
     424             :                          xmpp_handler handler,
     425             :                          const char *ns,
     426             :                          const char *name,
     427             :                          const char *type,
     428             :                          void *userdata,
     429             :                          int user_handler)
     430             : {
     431           0 :     xmpp_handlist_t *item, *tail;
     432             : 
     433             :     /* check if handler already in list */
     434           0 :     for (item = conn->handlers; item; item = item->next) {
     435             :         /* same handler function can process different stanzas and
     436             :            distinguish them according to userdata. */
     437           0 :         if (item->handler == handler && item->userdata == userdata) {
     438           0 :             strophe_warn(conn->ctx, "xmpp", "Stanza handler already exists.");
     439           0 :             break;
     440             :         }
     441             :     }
     442           0 :     if (item)
     443             :         return;
     444             : 
     445             :     /* build new item */
     446           0 :     item = (xmpp_handlist_t *)strophe_alloc(conn->ctx, sizeof(xmpp_handlist_t));
     447           0 :     if (!item)
     448             :         return;
     449             : 
     450           0 :     memset(item, 0, sizeof(*item));
     451           0 :     item->user_handler = user_handler;
     452           0 :     item->handler = handler;
     453           0 :     item->userdata = userdata;
     454             : 
     455           0 :     if (_dup_string(conn->ctx, ns, &item->u.ns))
     456           0 :         goto error_out;
     457           0 :     if (_dup_string(conn->ctx, name, &item->u.name))
     458           0 :         goto error_out;
     459           0 :     if (_dup_string(conn->ctx, type, &item->u.type))
     460           0 :         goto error_out;
     461             : 
     462             :     /* append to list */
     463           0 :     if (!conn->handlers)
     464           0 :         conn->handlers = item;
     465             :     else {
     466             :         tail = conn->handlers;
     467           0 :         while (tail->next)
     468             :             tail = tail->next;
     469           0 :         tail->next = item;
     470             :     }
     471             : 
     472             :     return;
     473             : 
     474           0 : error_out:
     475           0 :     _free_handlist_item(conn->ctx, item);
     476             : }
     477             : 
     478             : /** Delete a stanza handler.
     479             :  *
     480             :  *  @param conn a Strophe connection object
     481             :  *  @param handler a function pointer to a stanza handler
     482             :  *
     483             :  *  @ingroup Handlers
     484             :  */
     485           0 : void xmpp_handler_delete(xmpp_conn_t *conn, xmpp_handler handler)
     486             : {
     487           0 :     xmpp_handlist_t *prev, *item;
     488             : 
     489           0 :     if (!conn->handlers)
     490             :         return;
     491             : 
     492             :     prev = NULL;
     493             :     item = conn->handlers;
     494           0 :     while (item) {
     495           0 :         if (item->handler == handler) {
     496           0 :             if (prev)
     497           0 :                 prev->next = item->next;
     498             :             else
     499           0 :                 conn->handlers = item->next;
     500             : 
     501           0 :             _free_handlist_item(conn->ctx, item);
     502           0 :             item = prev ? prev->next : conn->handlers;
     503             :         } else {
     504           0 :             prev = item;
     505           0 :             item = item->next;
     506             :         }
     507             :     }
     508             : }
     509             : 
     510             : /** Add a timed handler.
     511             :  *  The handler will fire for the first time once the period has elapsed,
     512             :  *  and continue firing regularly after that.  Strophe will try its best
     513             :  *  to fire handlers as close to the period times as it can, but accuracy
     514             :  *  will vary depending on the resolution of the event loop.
     515             :  *
     516             :  *  If the handler function returns true, it will be kept, and if it
     517             :  *  returns false, it will be deleted from the list of handlers.
     518             :  *
     519             :  *  @param conn a Strophe connection object
     520             :  *  @param handler a function pointer to a timed handler
     521             :  *  @param period the time in milliseconds between firings
     522             :  *  @param userdata an opaque data pointer that will be passed to the handler
     523             :  *
     524             :  *  @ingroup Handlers
     525             :  */
     526           0 : void xmpp_timed_handler_add(xmpp_conn_t *conn,
     527             :                             xmpp_timed_handler handler,
     528             :                             unsigned long period,
     529             :                             void *userdata)
     530             : {
     531           0 :     _timed_handler_add(conn->ctx, &conn->timed_handlers, handler, period,
     532             :                        userdata, 1);
     533           0 : }
     534             : 
     535             : /** Add a timed system handler.
     536             :  *  This function is used to add internal timed handlers and should not be
     537             :  *  used outside of the library.
     538             :  *
     539             :  *  @param conn a Strophe connection object
     540             :  *  @param handler a function pointer to a timed handler
     541             :  *  @param period the time in milliseconds between firings
     542             :  *  @param userdata an opaque data pointer that will be passed to the handler
     543             :  */
     544           0 : void handler_add_timed(xmpp_conn_t *conn,
     545             :                        xmpp_timed_handler handler,
     546             :                        unsigned long period,
     547             :                        void *userdata)
     548             : {
     549           0 :     _timed_handler_add(conn->ctx, &conn->timed_handlers, handler, period,
     550             :                        userdata, 0);
     551           0 : }
     552             : 
     553             : /** Add an id based stanza handler.
     554             : 
     555             :  *  This function adds a stanza handler for an &lt;iq/&gt; stanza of
     556             :  *  type 'result' or 'error' with a specific id attribute.  This can
     557             :  *  be used to handle responses to specific &lt;iq/&gt;s.
     558             :  *
     559             :  *  If the handler function returns true, it will be kept, and if it
     560             :  *  returns false, it will be deleted from the list of handlers.
     561             :  *
     562             :  *  @param conn a Strophe connection object
     563             :  *  @param handler a function pointer to a stanza handler
     564             :  *  @param id a string with the id
     565             :  *  @param userdata an opaque data pointer that will be passed to the handler
     566             :  *
     567             :  *  @ingroup Handlers
     568             :  */
     569           0 : void xmpp_id_handler_add(xmpp_conn_t *conn,
     570             :                          xmpp_handler handler,
     571             :                          const char *id,
     572             :                          void *userdata)
     573             : {
     574           0 :     _id_handler_add(conn, handler, id, userdata, 1);
     575           0 : }
     576             : 
     577             : /** Add an id based system stanza handler.
     578             :  *  This function is used to add internal id based stanza handlers and should
     579             :  *  not be used outside of the library.
     580             :  *
     581             :  *  @param conn a Strophe connection object
     582             :  *  @param handler a function pointer to a stanza handler
     583             :  *  @param id a string with the id
     584             :  *  @param userdata an opaque data pointer that will be passed to the handler
     585             :  */
     586           0 : void handler_add_id(xmpp_conn_t *conn,
     587             :                     xmpp_handler handler,
     588             :                     const char *id,
     589             :                     void *userdata)
     590             : {
     591           0 :     _id_handler_add(conn, handler, id, userdata, 0);
     592           0 : }
     593             : 
     594             : /** Add a stanza handler.
     595             :  *  This function is used to add a stanza handler to a connection.
     596             :  *  The handler will be called when the any of the filters match.  The
     597             :  *  name filter matches to the top level stanza name.  The type filter
     598             :  *  matches the 'type' attribute of the top level stanza.  The ns
     599             :  *  filter matches the namespace ('xmlns' attribute) of either the top
     600             :  *  level stanza or any of it's immediate children (this allows you do
     601             :  *  handle specific &lt;iq/&gt; stanzas based on the &lt;query/&gt;
     602             :  *  child namespace.
     603             :  *
     604             :  *  If the handler function returns true, it will be kept, and if it
     605             :  *  returns false, it will be deleted from the list of handlers.
     606             :  *
     607             :  *  @param conn a Strophe connection object
     608             :  *  @param handler a function pointer to a stanza handler
     609             :  *  @param ns a string with the namespace to match
     610             :  *  @param name a string with the stanza name to match
     611             :  *  @param type a string with the 'type' attribute to match
     612             :  *  @param userdata an opaque data pointer that will be passed to the handler
     613             :  *
     614             :  *  @ingroup Handlers
     615             :  */
     616           0 : void xmpp_handler_add(xmpp_conn_t *conn,
     617             :                       xmpp_handler handler,
     618             :                       const char *ns,
     619             :                       const char *name,
     620             :                       const char *type,
     621             :                       void *userdata)
     622             : {
     623           0 :     _handler_add(conn, handler, ns, name, type, userdata, 1);
     624           0 : }
     625             : 
     626             : /** Add a system stanza handler.
     627             :  *  This function is used to add internal stanza handlers and should
     628             :  *  not be used outside of the library.
     629             :  *
     630             :  *  @param conn a Strophe connection object
     631             :  *  @param handler a function pointer to a stanza handler
     632             :  *  @param ns a string with the namespace to match
     633             :  *  @param name a string with the stanza name to match
     634             :  *  @param type a string with the 'type' attribute value to match
     635             :  *  @param userdata an opaque data pointer that will be passed to the handler
     636             :  */
     637           0 : void handler_add(xmpp_conn_t *conn,
     638             :                  xmpp_handler handler,
     639             :                  const char *ns,
     640             :                  const char *name,
     641             :                  const char *type,
     642             :                  void *userdata)
     643             : {
     644           0 :     _handler_add(conn, handler, ns, name, type, userdata, 0);
     645           0 : }
     646             : 
     647             : /** Delete all system handlers.
     648             :  *  This function is used to reset conn object before re-connecting.
     649             :  *
     650             :  *  @param conn a Strophe connection object
     651             :  */
     652           8 : void handler_system_delete_all(xmpp_conn_t *conn)
     653             : {
     654           8 :     xmpp_handlist_t *item, *next, *head, *head_old;
     655           8 :     hash_iterator_t *iter;
     656           8 :     const char *key, *key2;
     657             : 
     658             :     /* TODO unify all kinds of handlers and avoid copy-paste below */
     659             : 
     660           8 :     item = conn->handlers;
     661           8 :     while (item) {
     662           0 :         if (!item->user_handler) {
     663           0 :             next = item->next;
     664           0 :             _handler_item_remove(&conn->handlers, item);
     665           0 :             _free_handlist_item(conn->ctx, item);
     666             :             item = next;
     667             :         } else
     668           0 :             item = item->next;
     669             :     }
     670             : 
     671           8 :     item = conn->timed_handlers;
     672           8 :     while (item) {
     673           0 :         if (!item->user_handler) {
     674           0 :             next = item->next;
     675           0 :             _handler_item_remove(&conn->timed_handlers, item);
     676           0 :             strophe_free(conn->ctx, item);
     677             :             item = next;
     678             :         } else
     679           0 :             item = item->next;
     680             :     }
     681             : 
     682           8 :     iter = hash_iter_new(conn->id_handlers);
     683           8 :     key = iter == NULL ? NULL : hash_iter_next(iter);
     684           8 :     while (key != NULL) {
     685           0 :         head = head_old = (xmpp_handlist_t *)hash_get(conn->id_handlers, key);
     686           0 :         item = head;
     687           0 :         while (item) {
     688           0 :             if (!item->user_handler) {
     689           0 :                 next = item->next;
     690           0 :                 _handler_item_remove(&head, item);
     691           0 :                 strophe_free(conn->ctx, item->u.id);
     692           0 :                 strophe_free(conn->ctx, item);
     693             :                 item = next;
     694             :             } else
     695           0 :                 item = item->next;
     696             :         }
     697             :         /* Hash table implementation is not perfect, so we need to find next
     698             :            key before dropping current one. Otherwise, we will get access to
     699             :            freed memory. */
     700           0 :         key2 = hash_iter_next(iter);
     701           0 :         if (head != head_old) {
     702             :             /* hash_add() replaces value if the key exists */
     703           0 :             if (head != NULL)
     704           0 :                 hash_add(conn->id_handlers, key, head);
     705             :             else
     706           0 :                 hash_drop(conn->id_handlers, key);
     707             :         }
     708             :         key = key2;
     709             :     }
     710           8 :     if (iter)
     711           8 :         hash_iter_release(iter);
     712           8 : }
     713             : 
     714             : /** Add a global timed handler.
     715             :  *  The handler will fire for the first time once the period has elapsed,
     716             :  *  and continue firing regularly after that.  Strophe will try its best
     717             :  *  to fire handlers as close to the period times as it can, but accuracy
     718             :  *  will vary depending on the resolution of the event loop.
     719             :  *
     720             :  *  The main difference between global and ordinary handlers:
     721             :  *  - Ordinary handler is related to a connection, fires only when the
     722             :  *    connection is in connected state and is removed once the connection is
     723             :  *    destroyed.
     724             :  *  - Global handler fires regardless of connections state and is related to
     725             :  *    a Strophe context.
     726             :  *
     727             :  *  The handler is executed in context of the respective event loop.
     728             :  *
     729             :  *  If the handler function returns true, it will be kept, and if it
     730             :  *  returns false, it will be deleted from the list of handlers.
     731             :  *
     732             :  *  Notice, the same handler pointer may be added multiple times with different
     733             :  *  userdata pointers. However, xmpp_global_timed_handler_delete() deletes
     734             :  *  all occurrences.
     735             :  *
     736             :  *  @param ctx a Strophe context object
     737             :  *  @param handler a function pointer to a timed handler
     738             :  *  @param period the time in milliseconds between firings
     739             :  *  @param userdata an opaque data pointer that will be passed to the handler
     740             :  *
     741             :  *  @ingroup Handlers
     742             :  */
     743           0 : void xmpp_global_timed_handler_add(xmpp_ctx_t *ctx,
     744             :                                    xmpp_global_timed_handler handler,
     745             :                                    unsigned long period,
     746             :                                    void *userdata)
     747             : {
     748           0 :     _timed_handler_add(ctx, &ctx->timed_handlers, handler, period, userdata, 1);
     749           0 : }
     750             : 
     751             : /** Delete a global timed handler.
     752             :  *
     753             :  *  @param ctx a Strophe context object
     754             :  *  @param handler function pointer to the handler
     755             :  *
     756             :  *  @ingroup Handlers
     757             :  */
     758           0 : void xmpp_global_timed_handler_delete(xmpp_ctx_t *ctx,
     759             :                                       xmpp_global_timed_handler handler)
     760             : {
     761           0 :     _timed_handler_delete(ctx, &ctx->timed_handlers, handler);
     762           0 : }

Generated by: LCOV version 1.14