LCOV - code coverage report
Current view: top level - src - handler.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 14 290 4.8 %
Date: 2024-02-03 11:54:46 Functions: 1 19 5.3 %

          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             : 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           0 :                 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           0 :             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             : 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             : }
     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           0 :         return;
     345             : 
     346             :     /* build new item */
     347           0 :     item = strophe_alloc(conn->ctx, sizeof(xmpp_handlist_t));
     348           0 :     if (!item)
     349           0 :         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             : 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           0 :             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           0 :         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           0 :         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 1.14