Back to index

citadel  8.12
Classes | Defines | Typedefs | Enumerations | Functions | Variables
serv_xmpp.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  _citxmpp
struct  xmpp_event

Defines

#define XMPP   ((citxmpp *)CC->session_specific_data)
#define DBGLOG(LEVEL)   if ((LEVEL != LOG_DEBUG) || (XMPPSrvDebugEnable != 0))
#define XMPP_syslog(LEVEL, FORMAT,...)
#define XMPPM_syslog(LEVEL, FORMAT)

Typedefs

typedef struct _citxmpp citxmpp

Enumerations

enum  { XMPP_EVT_LOGIN, XMPP_EVT_LOGOUT }

Functions

void xmpp_cleanup_function (void)
void xmpp_greeting (void)
void xmpp_command_loop (void)
void xmpp_async_loop (void)
void xmpp_sasl_auth (char *, char *)
void xmpp_output_auth_mechs (void)
void xmpp_query_namespace (char *, char *, char *, char *)
void xmpp_wholist_presence_dump (void)
void xmpp_output_incoming_messages (void)
void xmpp_queue_event (int, char *)
void xmpp_process_events (void)
void xmpp_presence_notify (char *, int)
void xmpp_roster_item (struct CitContext *)
void xmpp_send_message (char *, char *)
void xmpp_non_sasl_authenticate (char *, char *, char *, char *)
void xmpp_massacre_roster (void)
void xmpp_delete_old_buddies_who_no_longer_exist_from_the_client_roster (void)
int xmpp_is_visible (struct CitContext *from, struct CitContext *to_whom)
char * xmlesc (char *buf, char *str, int bufsiz)

Variables

struct xmpp_eventxmpp_queue
int queue_event_seq
int XMPPSrvDebugEnable

Class Documentation

struct _citxmpp

Definition at line 19 of file serv_xmpp.h.

Class Members
int bind_requested
char * chardata
int chardata_alloc
int chardata_len
char client_jid
int html_tag_level
char iq_client_password
char iq_client_resource
char iq_client_username
char iq_from
char iq_id
char iq_query_xmlns
int iq_session
char iq_to
char iq_type
int last_event_processed
char * message_body
char message_to
int ping_requested
char sasl_auth_mech
char server_name
XML_Parser xp
struct xmpp_event

Definition at line 50 of file serv_xmpp.h.

Collaboration diagram for xmpp_event:
Class Members
char event_jid
int event_seq
time_t event_time
int event_type
struct xmpp_event * next
int session_which_generated_this_event

Define Documentation

#define DBGLOG (   LEVEL)    if ((LEVEL != LOG_DEBUG) || (XMPPSrvDebugEnable != 0))

Definition at line 89 of file serv_xmpp.h.

#define XMPP   ((citxmpp *)CC->session_specific_data)

Definition at line 48 of file serv_xmpp.h.

#define XMPP_syslog (   LEVEL,
  FORMAT,
  ... 
)
Value:
DBGLOG(LEVEL) syslog(LEVEL,                      \
                          "XMPP: " FORMAT, __VA_ARGS__)

Definition at line 91 of file serv_xmpp.h.

#define XMPPM_syslog (   LEVEL,
  FORMAT 
)
Value:
DBGLOG(LEVEL) syslog(LEVEL,        \
                          "XMPP: " FORMAT);

Definition at line 95 of file serv_xmpp.h.


Typedef Documentation

typedef struct _citxmpp citxmpp

Enumeration Type Documentation

anonymous enum
Enumerator:
XMPP_EVT_LOGIN 
XMPP_EVT_LOGOUT 

Definition at line 62 of file serv_xmpp.h.


Function Documentation

char* xmlesc ( char *  buf,
char *  str,
int  bufsiz 
)

Definition at line 93 of file serv_xmpp.c.

{
       char *ptr;
       unsigned char ch;
       int len = 0;

       if (!buf) return(NULL);
       buf[0] = 0;
       len = 0;
       if (!str) {
              return(buf);
       }

       for (ptr=str; *ptr; ptr++) {
              ch = *ptr;
              if (ch == '<') {
                     strcpy(&buf[len], "&lt;");
                     len += 4;
              }
              else if (ch == '>') {
                     strcpy(&buf[len], "&gt;");
                     len += 4;
              }
              else if (ch == '&') {
                     strcpy(&buf[len], "&amp;");
                     len += 5;
              }
              else if ((ch >= 0x20) && (ch <= 0x7F)) {
                     buf[len++] = ch;
                     buf[len] = 0;
              }
              else if (ch < 0x20) {
                     /* we probably shouldn't be doing this */
                     buf[len++] = '_';
                     buf[len] = 0;
              }
              else {
                     char oct[10];
                     sprintf(oct, "&#%o;", ch);
                     strcpy(&buf[len], oct);
                     len += strlen(oct);
              }
              if ((len + 6) > bufsiz) {
                     return(buf);
              }
       }
       return(buf);
}

Here is the caller graph for this function:

void xmpp_async_loop ( void  )

Definition at line 597 of file serv_xmpp.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void xmpp_cleanup_function ( void  )

Definition at line 516 of file serv_xmpp.c.

                                 {

       /* Don't do this stuff if this is not a XMPP session! */
       if (CC->h_command_function != xmpp_command_loop) return;

       if (XMPP->chardata != NULL) {
              free(XMPP->chardata);
              XMPP->chardata = NULL;
              XMPP->chardata_len = 0;
              XMPP->chardata_alloc = 0;
              if (XMPP->message_body != NULL) {
                     free(XMPP->message_body);
              }
       }
       XML_ParserFree(XMPP->xp);
       free(XMPP);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void xmpp_command_loop ( void  )

Definition at line 577 of file serv_xmpp.c.

                             {
       int rc;
       StrBuf *stream_input = NewStrBuf();

       time(&CC->lastcmd);
       rc = client_read_random_blob(stream_input, 30);
       if (rc > 0) {
              XML_Parse(XMPP->xp, ChrPtr(stream_input), rc, 0);
       }
       else {
              XMPPM_syslog(LOG_ERR, "client disconnected: ending session.\n");
              CC->kill_me = KILLME_CLIENT_DISCONNECTED;
       }
       FreeStrBuf(&stream_input);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 376 of file xmpp_presence.c.

{
       long len;
       void *Value;
       const char *Key;
       struct CitContext *cptr;
       int nContexts, i;
       int online_now = 0;
       HashList *mortuary = xmpp_fetch_mortuary();
       HashPos *HashPos = GetNewHashPos(mortuary, 0);

       /* we need to omit anyone who is currently online */
       cptr = CtdlGetContextArray(&nContexts);

       /* go through the list of users in the mortuary... */
       while (GetNextHashPos(mortuary, HashPos, &len, &Key, &Value) != 0)
       {

              online_now = 0;
              if (cptr) for (i=0; i<nContexts; i++) {
                     if (xmpp_is_visible(&cptr[i], CC)) {
                            if (!strcasecmp(cptr[i].cs_inet_email, (char *)Value)) {
                                   online_now = 1;
                            }
                     }
              }

              if (!online_now) {
                     xmpp_destroy_buddy((char *)Value, 1);     /* aggressive presence update */
              }

       }
       DeleteHashPos(&HashPos);
       DeleteHash(&mortuary);
       free(cptr);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void xmpp_greeting ( void  )

Definition at line 539 of file serv_xmpp.c.

                         {
       client_set_inbound_buf(4);
       strcpy(CC->cs_clientname, "XMPP session");
       CC->session_specific_data = malloc(sizeof(citxmpp));
       memset(XMPP, 0, sizeof(citxmpp));
       XMPP->last_event_processed = queue_event_seq;

       /* XMPP does not use a greeting, but we still have to initialize some things. */

       XMPP->xp = XML_ParserCreateNS("UTF-8", ':');
       if (XMPP->xp == NULL) {
              XMPPM_syslog(LOG_ALERT, "Cannot create XML parser!\n");
              CC->kill_me = KILLME_XML_PARSER;
              return;
       }

       XML_SetElementHandler(XMPP->xp, xmpp_xml_start, xmpp_xml_end);
       XML_SetCharacterDataHandler(XMPP->xp, xmpp_xml_chardata);
       // XML_SetUserData(XMPP->xp, something...);

       /* Prevent the "billion laughs" attack against expat by disabling
        * internal entity expansion.  With 2.x, forcibly stop the parser
        * if an entity is declared - this is safer and a more obvious
        * failure mode.  With older versions, simply prevent expansion
        * of such entities. */
#ifdef HAVE_XML_STOPPARSER
       XML_SetEntityDeclHandler(XMPP->xp, xmpp_entity_declaration);
#else
       XML_SetDefaultHandler(XMPP->xp, NULL);
#endif

       CC->can_receive_im = 1;            /* This protocol is capable of receiving instant messages */
}

Here is the call graph for this function:

Here is the caller graph for this function:

int xmpp_is_visible ( struct CitContext from,
struct CitContext to_whom 
)

Definition at line 80 of file xmpp_presence.c.

                                                                         {
       int aide = (to_whom->user.axlevel >= AxAideU);

       if (   (cptr->logged_in)
              &&     (((cptr->cs_flags&CS_STEALTH)==0) || (aide))     /* aides see everyone */
              &&     (cptr->user.usernum != to_whom->user.usernum)    /* don't show myself */
              &&     (cptr->can_receive_im)                           /* IM-capable session */
       ) {
              return(1);
       }
       else {
              return(0);
       }
}

Here is the caller graph for this function:

void xmpp_massacre_roster ( void  )

Definition at line 339 of file xmpp_presence.c.

{
       struct CitContext *cptr;
       int nContexts, i;
       HashList *mortuary = xmpp_fetch_mortuary();

       cptr = CtdlGetContextArray(&nContexts);
       if (cptr) {
              for (i=0; i<nContexts; i++) {
                     if (xmpp_is_visible(&cptr[i], CC)) {
                            if (mortuary) {
                                   char *buddy = strdup(cptr[i].cs_inet_email);
                                   Put(mortuary, buddy, strlen(buddy), buddy, NULL);
                            }
                     }
              }
              free (cptr);
       }

       if (mortuary) {
              xmpp_store_mortuary(mortuary);
              DeleteHash(&mortuary);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void xmpp_non_sasl_authenticate ( char *  ,
char *  ,
char *  ,
char *   
)

Definition at line 157 of file xmpp_sasl_service.c.

                                                                                             {
       int result;
       char xmlbuf[256];

        if (CC->logged_in) CtdlUserLogout();  /* Client may try to log in twice.  Handle this. */

       result = CtdlLoginExistingUser(NULL, username);
       if (result == login_ok) {
              result = CtdlTryPassword(password, strlen(password));
              if (result == pass_ok) {
                     cprintf("<iq type=\"result\" id=\"%s\"></iq>", xmlesc(xmlbuf, iq_id, sizeof xmlbuf));      /* success */
                     return;
              }
       }

       /* failure */
       cprintf("<iq type=\"error\" id=\"%s\">", xmlesc(xmlbuf, iq_id, sizeof xmlbuf));
       cprintf("<error code=\"401\" type=\"auth\">"
              "<not-authorized xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
              "</error>"
              "</iq>"
       );
}

Here is the call graph for this function:

Here is the caller graph for this function:

void xmpp_output_auth_mechs ( void  )

Definition at line 115 of file xmpp_sasl_service.c.

                                  {
       cprintf("<mechanisms xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
       cprintf("<mechanism>PLAIN</mechanism>");
       cprintf("</mechanisms>");
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 65 of file xmpp_messages.c.

                                         {

       struct ExpressMessage *ptr;
       char xmlbuf1[4096];
       char xmlbuf2[4096];

       while (CC->FirstExpressMessage != NULL) {

              begin_critical_section(S_SESSION_TABLE);
              ptr = CC->FirstExpressMessage;
              CC->FirstExpressMessage = CC->FirstExpressMessage->next;
              end_critical_section(S_SESSION_TABLE);

              cprintf("<message to=\"%s\" from=\"%s\" type=\"chat\">",
                     xmlesc(xmlbuf1, XMPP->client_jid, sizeof xmlbuf1),
                     xmlesc(xmlbuf2, ptr->sender_email, sizeof xmlbuf2)
              );
              if (ptr->text != NULL) {
                     striplt(ptr->text);
                     cprintf("<body>%s</body>", xmlesc(xmlbuf1, ptr->text, sizeof xmlbuf1));
                     free(ptr->text);
              }
              cprintf("</message>");
              free(ptr);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void xmpp_presence_notify ( char *  ,
int   
)

Definition at line 172 of file xmpp_presence.c.

                                                              {
       struct CitContext *cptr;
       static int unsolicited_id;
       int visible_sessions = 0;
       int nContexts, i;
       int which_cptr_is_relevant = (-1);

       if (IsEmptyStr(presence_jid)) return;
       if (CC->kill_me) return;

       cptr = CtdlGetContextArray(&nContexts);
       if (!cptr) {
              return;
       }

       /* Count the visible sessions for this user */
       for (i=0; i<nContexts; i++) {
              if ( (!strcasecmp(cptr[i].cs_inet_email, presence_jid))
                 && (xmpp_is_visible(&cptr[i], CC))
              )  {
                     ++visible_sessions;
                     which_cptr_is_relevant = i;
              }
       }

       XMPP_syslog(LOG_DEBUG, "%d sessions for <%s> are now visible to session %d\n",
                  visible_sessions, presence_jid, CC->cs_pid);

       if ( (event_type == XMPP_EVT_LOGIN) && (visible_sessions == 1) ) {

              XMPP_syslog(LOG_DEBUG, "Telling session %d that <%s> logged in\n",
                         CC->cs_pid, presence_jid);

              /* Do an unsolicited roster update that adds a new contact. */
              assert(which_cptr_is_relevant >= 0);
              cprintf("<iq id=\"unsolicited_%x\" type=\"result\">", ++unsolicited_id);
              cprintf("<query xmlns=\"jabber:iq:roster\">");
              xmpp_roster_item(&cptr[which_cptr_is_relevant]);
              cprintf("</query></iq>");

              /* Transmit presence information */
              xmpp_indicate_presence(presence_jid);
       }

       if (visible_sessions == 0) {
              XMPP_syslog(LOG_DEBUG, "Telling session %d that <%s> logged out\n",
                         CC->cs_pid, presence_jid);
              xmpp_destroy_buddy(presence_jid, 0);      /* non aggressive presence update */
       }

       free(cptr);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void xmpp_process_events ( void  )

Definition at line 124 of file xmpp_queue.c.

                               {
       struct xmpp_event *xptr = NULL;
       int highest_event = 0;

       for (xptr=xmpp_queue; xptr!=NULL; xptr=xptr->next) {
              if (xptr->event_seq > XMPP->last_event_processed) {

                     switch(xptr->event_type) {

                            case XMPP_EVT_LOGIN:
                            case XMPP_EVT_LOGOUT:
                                   if (xptr->session_which_generated_this_event != CC->cs_pid) {
                                          xmpp_presence_notify(xptr->event_jid, xptr->event_type);
                                   }
                                   break;
                     }

                     if (xptr->event_seq > highest_event) {
                            highest_event = xptr->event_seq;
                     }
              }
       }

       XMPP->last_event_processed = highest_event;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void xmpp_query_namespace ( char *  ,
char *  ,
char *  ,
char *   
)

Definition at line 110 of file xmpp_query_namespace.c.

{
       int supported_namespace = 0;
       int roster_query = 0;
       char xmlbuf[256];

       /* We need to know before we begin the response whether this is a supported namespace, so
        * unfortunately all supported namespaces need to be defined here *and* down below where
        * they are handled.
        */
       if (
              (!strcasecmp(query_xmlns, "jabber:iq:roster:query"))
              || (!strcasecmp(query_xmlns, "jabber:iq:auth:query"))
       ) {
              supported_namespace = 1;
       }

       XMPP_syslog(LOG_DEBUG, "xmpp_query_namespace(%s, %s, %s, %s)\n", iq_id, iq_from, iq_to, query_xmlns);

       /*
        * Beginning of query result.
        */
       if (supported_namespace) {
              cprintf("<iq type=\"result\" ");
       }
       else {
              cprintf("<iq type=\"error\" ");
       }
       if (!IsEmptyStr(iq_from)) {
              cprintf("to=\"%s\" ", xmlesc(xmlbuf, iq_from, sizeof xmlbuf));
       }
       cprintf("id=\"%s\">", xmlesc(xmlbuf, iq_id, sizeof xmlbuf));

       /*
        * Is this a query we know how to handle?
        */

       if (!strcasecmp(query_xmlns, "jabber:iq:roster:query")) {
              roster_query = 1;
              xmpp_iq_roster_query();
       }

       else if (!strcasecmp(query_xmlns, "jabber:iq:auth:query")) {
              cprintf("<query xmlns=\"jabber:iq:auth\">"
                     "<username/><password/><resource/>"
                     "</query>"
              );
       }

       /*
        * If we didn't hit any known query namespaces then we should deliver a
        * "service unavailable" error (see RFC3921 section 2.4 and 11.1.5.4)
        */

       else {
              XMPP_syslog(LOG_DEBUG,
                         "Unknown query namespace '%s' - returning <service-unavailable/>\n",
                         query_xmlns
              );
              cprintf("<error code=\"503\" type=\"cancel\">"
                     "<service-unavailable xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
                     "</error>"
              );
       }

       cprintf("</iq>");

       /* If we told the client who is on the roster, we also need to tell the client
        * who is *not* on the roster.  (It's down here because we can't do it in the same
        * stanza; this will be an unsolicited push.)
        */
       if (roster_query) {
              xmpp_delete_old_buddies_who_no_longer_exist_from_the_client_roster();
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void xmpp_queue_event ( int  ,
char *   
)

Definition at line 61 of file xmpp_queue.c.

                                                        {

       struct xmpp_event *xptr = NULL;
       struct xmpp_event *new_event = NULL;
       struct xmpp_event *last = NULL;
       int purged_something = 0;
       struct CitContext *cptr;

       XMPP_syslog(LOG_DEBUG, "xmpp_queue_event(%d, %s)\n", event_type, email_addr);

       /* Purge events more than a minute old */
       begin_critical_section(S_XMPP_QUEUE);
       do {
              purged_something = 0;
              if (xmpp_queue != NULL) {
                     if ((time(NULL) - xmpp_queue->event_time) > 60) {
                            xptr = xmpp_queue->next;
                            free(xmpp_queue);
                            xmpp_queue = xptr;
                            purged_something = 1;
                     }
              }
       } while(purged_something);
       end_critical_section(S_XMPP_QUEUE);

       /* Create a new event */
       new_event = (struct xmpp_event *) malloc(sizeof(struct xmpp_event));
       new_event->next = NULL;
       new_event->event_time = time(NULL);
       new_event->event_seq = ++queue_event_seq;
       new_event->event_type = event_type;
       new_event->session_which_generated_this_event = CC->cs_pid;
       safestrncpy(new_event->event_jid, email_addr, sizeof new_event->event_jid);

       /* Add it to the list */
       begin_critical_section(S_XMPP_QUEUE);
       if (xmpp_queue == NULL) {
              xmpp_queue = new_event;
       }
       else {
              for (xptr = xmpp_queue; xptr != NULL; xptr = xptr->next) {
                     if (xptr->next == NULL) {
                            last = xptr;
                     }
              }
              last->next = new_event;
       }
       end_critical_section(S_XMPP_QUEUE);

       /* Tell the sessions that something is happening */
       begin_critical_section(S_SESSION_TABLE);
       for (cptr = ContextList; cptr != NULL; cptr = cptr->next) {
              if ((cptr->logged_in) && (cptr->h_async_function == xmpp_async_loop)) {
                     set_async_waiting(cptr);
              }
       }
       end_critical_section(S_SESSION_TABLE);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void xmpp_roster_item ( struct CitContext )

Definition at line 62 of file xmpp_query_namespace.c.

                                               {
       char xmlbuf1[256];
       char xmlbuf2[256];

       cprintf("<item jid=\"%s\" name=\"%s\" subscription=\"both\">",
              xmlesc(xmlbuf1, cptr->cs_inet_email, sizeof xmlbuf1),
              xmlesc(xmlbuf2, cptr->user.fullname, sizeof xmlbuf2)
       );
       cprintf("<group>%s</group>", xmlesc(xmlbuf1, config.c_humannode, sizeof xmlbuf1));
       cprintf("</item>");
}

Here is the call graph for this function:

Here is the caller graph for this function:

void xmpp_sasl_auth ( char *  ,
char *   
)

Definition at line 124 of file xmpp_sasl_service.c.

                                                            {

       if (strcasecmp(sasl_auth_mech, "PLAIN")) {
              cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
              cprintf("<invalid-mechanism/>");
              cprintf("</failure>");
              return;
       }

        if (CC->logged_in) CtdlUserLogout();  /* Client may try to log in twice.  Handle this. */

       if (CC->nologin) {
              cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
              cprintf("<system-shutdown/>");
              cprintf("</failure>");
       }

       else if (xmpp_auth_plain(authstring) == 0) {
              cprintf("<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"/>");
       }

       else {
              cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
              cprintf("<not-authorized/>");
              cprintf("</failure>");
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void xmpp_send_message ( char *  ,
char *   
)

Definition at line 95 of file xmpp_messages.c.

                                                             {
       char *recp = NULL;
       struct CitContext *cptr;

       if (message_body == NULL) return;
       if (message_to == NULL) return;
       if (IsEmptyStr(message_to)) return;
       if (!CC->logged_in) return;

       for (cptr = ContextList; cptr != NULL; cptr = cptr->next) {
              if (   (cptr->logged_in)
                     && (cptr->can_receive_im)
                     && (!strcasecmp(cptr->cs_inet_email, message_to))
              ) {
                     recp = cptr->user.fullname;
              }
       }

       if (recp) {
              PerformXmsgHooks(CC->user.fullname, CC->cs_inet_email, recp, message_body);
       }

       free(XMPP->message_body);
       XMPP->message_body = NULL;
       XMPP->message_to[0] = 0;
       time(&CC->lastidle);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void xmpp_wholist_presence_dump ( void  )

Definition at line 99 of file xmpp_presence.c.

{
       struct CitContext *cptr = NULL;
       int nContexts, i;
       
       cptr = CtdlGetContextArray(&nContexts);
       if (!cptr) {
              return;
       }

       for (i=0; i<nContexts; i++) {
              if (xmpp_is_visible(&cptr[i], CC)) {
                     xmpp_indicate_presence(cptr[i].cs_inet_email);
              }
       }
       free(cptr);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 59 of file xmpp_queue.c.

Definition at line 65 of file serv_xmpp.c.

Definition at line 67 of file serv_xmpp.c.