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

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

Generated by: LCOV version 2.0-1