Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:00:57 2007

Asterisk developer's documentation :: Codename Pineapple


sip3_subscribe.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  * and Edvina AB, Sollentuna, Sweden (chan_sip3 changes/additions)
00006  *
00007  * Mark Spencer <markster@digium.com>
00008  *
00009  *
00010  * See http://www.asterisk.org for more information about
00011  * the Asterisk project. Please do not directly contact
00012  * any of the maintainers of this project for assistance;
00013  * the project provides a web site, mailing lists and IRC
00014  * channels for your use.
00015  *
00016  * This program is free software, distributed under the terms of
00017  * the GNU General Public License Version 2. See the LICENSE file
00018  * at the top of the source tree.
00019  */
00020 
00021 /*!
00022  * \file
00023  * \brief Various SIP network interface functions
00024  * Version 3 of chan_sip
00025  *
00026  * \author Mark Spencer <markster@digium.com>
00027  * \author Olle E. Johansson <oej@edvina.net> (all the chan_sip3 changes)
00028  *
00029  * See Also:
00030  * \arg \ref AstCREDITS
00031  *
00032  */
00033 
00034 #include "asterisk.h"
00035 
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 53128 $")
00037 
00038 #include <stdio.h>
00039 #include <ctype.h>
00040 #include <string.h>
00041 #include <unistd.h>
00042 #include <sys/socket.h>
00043 #include <sys/ioctl.h>
00044 #include <net/if.h>
00045 #include <errno.h>
00046 #include <stdlib.h>
00047 #include <fcntl.h>
00048 #include <netdb.h>
00049 #include <signal.h>
00050 #include <sys/signal.h>
00051 #include <netinet/in.h>
00052 #include <netinet/in_systm.h>
00053 #include <arpa/inet.h>
00054 #include <netinet/ip.h>
00055 #include <regex.h>
00056 
00057 #include "asterisk/lock.h"
00058 #include "asterisk/channel.h"
00059 #include "asterisk/config.h"
00060 #include "asterisk/logger.h"
00061 #include "asterisk/module.h"
00062 #include "asterisk/pbx.h"
00063 #include "asterisk/options.h"
00064 #include "asterisk/sched.h"
00065 #include "asterisk/io.h"
00066 #include "asterisk/rtp.h"
00067 #include "asterisk/udptl.h"
00068 #include "asterisk/acl.h"
00069 #include "asterisk/manager.h"
00070 #include "asterisk/callerid.h"
00071 #include "asterisk/cli.h"
00072 #include "asterisk/app.h"
00073 #include "asterisk/dsp.h"
00074 #include "asterisk/features.h"
00075 #include "asterisk/srv.h"
00076 #include "asterisk/astdb.h"
00077 #include "asterisk/causes.h"
00078 #include "asterisk/utils.h"
00079 #include "asterisk/file.h"
00080 #include "asterisk/astobj.h"
00081 #include "asterisk/dnsmgr.h"
00082 #include "asterisk/devicestate.h"
00083 #include "asterisk/linkedlists.h"
00084 #include "asterisk/stringfields.h"
00085 #include "asterisk/monitor.h"
00086 #include "asterisk/localtime.h"
00087 #include "asterisk/abstract_jb.h"
00088 #include "asterisk/compiler.h"
00089 
00090 #include "sip3.h"
00091 #include "sip3funcs.h"
00092 
00093 
00094 /*! \brief List of subscription event types for SUBSCRIBE requests */
00095 static const struct cfsubscription_types subscription_types[] = {
00096    { NONE,        "-",        "unknown",               "unknown" },
00097    /* RFC 4235: SIP Dialog event package */
00098    { DIALOG_INFO_XML, "dialog",   "application/dialog-info+xml", "dialog-info+xml" },
00099    { CPIM_PIDF_XML,   "presence", "application/cpim-pidf+xml",   "cpim-pidf+xml" },  /* RFC 3863 */
00100    { PIDF_XML,        "presence", "application/pidf+xml",        "pidf+xml" },       /* RFC 3863 */
00101    { XPIDF_XML,       "presence", "application/xpidf+xml",       "xpidf+xml" },       /* Pre-RFC 3863 with MS additions */
00102    { MWI_NOTIFICATION,  "message-summary", "application/simple-message-summary", "mwi" } /* RFC 3842: Mailbox notification */
00103 };
00104 
00105 /*! \brief Show subscription type in string format */
00106 const char *subscription_type2str(enum subscriptiontype subtype)
00107 {
00108    int i;
00109 
00110    for (i = 1; (i < (sizeof(subscription_types) / sizeof(subscription_types[0]))); i++) {
00111       if (subscription_types[i].type == subtype) {
00112          return subscription_types[i].text;
00113       }
00114    }
00115    return subscription_types[0].text;
00116 }
00117 
00118 /*! \brief Find subscription type in array */
00119 const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype)
00120 {
00121    int i;
00122 
00123    for (i = 1; (i < (sizeof(subscription_types) / sizeof(subscription_types[0]))); i++) {
00124       if (subscription_types[i].type == subtype) {
00125          return &subscription_types[i];
00126       }
00127    }
00128    return &subscription_types[0];
00129 }
00130 
00131 /*! \brief Used in the SUBSCRIBE notification subsystem */
00132 GNURK int transmit_state_notify(struct sip_dialog *p, int state, int full, int timeout)
00133 {
00134    char tmp[4000], from[256], to[256];
00135    char *t = tmp, *c, *mfrom, *mto;
00136    size_t maxbytes = sizeof(tmp);
00137    struct sip_request *req;
00138    char hint[AST_MAX_EXTENSION];
00139    char *statestring = "terminated";
00140    const struct cfsubscription_types *subscriptiontype;
00141    enum state { NOTIFY_OPEN, NOTIFY_INUSE, NOTIFY_CLOSED } local_state = NOTIFY_OPEN;
00142    char *pidfstate = "--";
00143    char *pidfnote= "Ready";
00144 
00145    req = siprequest_alloc(SIP_MAX_PACKET, &sipnet);
00146 
00147    memset(from, 0, sizeof(from));
00148    memset(to, 0, sizeof(to));
00149    memset(tmp, 0, sizeof(tmp));
00150 
00151    switch (state) {
00152    case (AST_EXTENSION_RINGING | AST_EXTENSION_INUSE):
00153       statestring = (global.notifyringing) ? "early" : "confirmed";
00154       local_state = NOTIFY_INUSE;
00155       pidfstate = "busy";
00156       pidfnote = "Ringing";
00157       break;
00158    case AST_EXTENSION_RINGING:
00159       statestring = "early";
00160       local_state = NOTIFY_INUSE;
00161       pidfstate = "busy";
00162       pidfnote = "Ringing";
00163       break;
00164    case AST_EXTENSION_INUSE:
00165       statestring = "confirmed";
00166       local_state = NOTIFY_INUSE;
00167       pidfstate = "busy";
00168       pidfnote = "On the phone";
00169       break;
00170    case AST_EXTENSION_BUSY:
00171       statestring = "confirmed";
00172       local_state = NOTIFY_CLOSED;
00173       pidfstate = "busy";
00174       pidfnote = "On the phone";
00175       break;
00176    case AST_EXTENSION_UNAVAILABLE:
00177       statestring = "terminated";
00178       local_state = NOTIFY_CLOSED;
00179       pidfstate = "away";
00180       pidfnote = "Unavailable";
00181       break;
00182    case AST_EXTENSION_ONHOLD:
00183       statestring = "confirmed";
00184       local_state = NOTIFY_INUSE;
00185       pidfstate = "busy";
00186       pidfnote = "On hold";
00187       break;
00188    case AST_EXTENSION_NOT_INUSE:
00189    default:
00190       /* Default setting */
00191       break;
00192    }
00193 
00194    subscriptiontype = find_subscription_type(p->subscribed);
00195    
00196    /* Check which device/devices we are watching  and if they are registered */
00197    if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, p->context, p->exten)) {
00198       /* If they are not registered, we will override notification and show no availability */
00199       if (ast_device_state(hint) == AST_DEVICE_UNAVAILABLE) {
00200          local_state = NOTIFY_CLOSED;
00201          pidfstate = "away";
00202          pidfnote = "Not online";
00203       }
00204    }
00205 
00206    ast_copy_string(from, get_header(p->initreq, "From"), sizeof(from));
00207    c = get_in_brackets(from);
00208    if (strncmp(c, "sip:", 4)) {
00209       ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", c);
00210       return -1;
00211    }
00212    mfrom = strsep(&c, ";");   /* trim ; and beyond */
00213 
00214    ast_copy_string(to, get_header(p->initreq, "To"), sizeof(to));
00215    c = get_in_brackets(to);
00216    if (strncmp(c, "sip:", 4)) {
00217       ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", c);
00218       return -1;
00219    }
00220    mto = strsep(&c, ";");  /* trim ; and beyond */
00221 
00222    reqprep(req, p, SIP_NOTIFY, 0, TRUE);
00223 
00224    
00225    add_header(req, "Event", subscriptiontype->event);
00226    add_header(req, "Content-Type", subscriptiontype->mediatype);
00227    switch(state) {
00228    case AST_EXTENSION_DEACTIVATED:
00229       if (timeout)
00230          add_header(req, "Subscription-State", "terminated;reason=timeout");
00231       else {
00232          add_header(req, "Subscription-State", "terminated;reason=probation");
00233          add_header(req, "Retry-After", "60");
00234       }
00235       break;
00236    case AST_EXTENSION_REMOVED:
00237       add_header(req, "Subscription-State", "terminated;reason=noresource");
00238       break;
00239    default:
00240       if (p->expiry)
00241          add_header(req, "Subscription-State", "active");
00242       else  /* Expired */
00243          add_header(req, "Subscription-State", "terminated;reason=timeout");
00244    }
00245    switch (p->subscribed) {
00246    case XPIDF_XML:
00247    case CPIM_PIDF_XML:
00248       ast_build_string(&t, &maxbytes, "<?xml version=\"1.0\"?>\n");
00249       ast_build_string(&t, &maxbytes, "<!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n");
00250       ast_build_string(&t, &maxbytes, "<presence>\n");
00251       ast_build_string(&t, &maxbytes, "<presentity uri=\"%s;method=SUBSCRIBE\" />\n", mfrom);
00252       ast_build_string(&t, &maxbytes, "<atom id=\"%s\">\n", p->exten);
00253       ast_build_string(&t, &maxbytes, "<address uri=\"%s;user=ip\" priority=\"0.800000\">\n", mto);
00254       ast_build_string(&t, &maxbytes, "<status status=\"%s\" />\n", (local_state ==  NOTIFY_OPEN) ? "open" : (local_state == NOTIFY_INUSE) ? "inuse" : "closed");
00255       ast_build_string(&t, &maxbytes, "<msnsubstatus substatus=\"%s\" />\n", (local_state == NOTIFY_OPEN) ? "online" : (local_state == NOTIFY_INUSE) ? "onthephone" : "offline");
00256       ast_build_string(&t, &maxbytes, "</address>\n</atom>\n</presence>\n");
00257       break;
00258    case PIDF_XML: /* Eyebeam supports this format */
00259       ast_build_string(&t, &maxbytes, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
00260       ast_build_string(&t, &maxbytes, "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \nxmlns:pp=\"urn:ietf:params:xml:ns:pidf:person\"\nxmlns:es=\"urn:ietf:params:xml:ns:pidf:rpid:status:rpid-status\"\nxmlns:ep=\"urn:ietf:params:xml:ns:pidf:rpid:rpid-person\"\nentity=\"%s\">\n", mfrom);
00261       ast_build_string(&t, &maxbytes, "<pp:person><status>\n");
00262       if (pidfstate[0] != '-')
00263          ast_build_string(&t, &maxbytes, "<ep:activities><ep:%s/></ep:activities>\n", pidfstate);
00264       ast_build_string(&t, &maxbytes, "</status></pp:person>\n");
00265       ast_build_string(&t, &maxbytes, "<note>%s</note>\n", pidfnote); /* Note */
00266       ast_build_string(&t, &maxbytes, "<tuple id=\"%s\">\n", p->exten); /* Tuple start */
00267       ast_build_string(&t, &maxbytes, "<contact priority=\"1\">%s</contact>\n", mto);
00268       if (pidfstate[0] == 'b') /* Busy? Still open ... */
00269          ast_build_string(&t, &maxbytes, "<status><basic>open</basic></status>\n");
00270       else
00271          ast_build_string(&t, &maxbytes, "<status><basic>%s</basic></status>\n", (local_state != NOTIFY_CLOSED) ? "open" : "closed");
00272       ast_build_string(&t, &maxbytes, "</tuple>\n</presence>\n");
00273       break;
00274    case DIALOG_INFO_XML: /* SNOM subscribes in this format */
00275       ast_build_string(&t, &maxbytes, "<?xml version=\"1.0\"?>\n");
00276       ast_build_string(&t, &maxbytes, "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\"%d\" state=\"%s\" entity=\"%s\">\n", p->dialogver++, full ? "full":"partial", mto);
00277       if ((state & AST_EXTENSION_RINGING) && global.notifyringing)
00278          ast_build_string(&t, &maxbytes, "<dialog id=\"%s\" direction=\"recipient\">\n", p->exten);
00279       else
00280          ast_build_string(&t, &maxbytes, "<dialog id=\"%s\">\n", p->exten);
00281       ast_build_string(&t, &maxbytes, "<state>%s</state>\n", statestring);
00282       if (state == AST_EXTENSION_ONHOLD) {
00283          ast_build_string(&t, &maxbytes, "<local>\n<target uri=\"%s\">\n"
00284             "<param pname=\"+sip.rendering\" pvalue=\"no\">\n"
00285             "</target>\n</local>\n", mto);
00286       }
00287       ast_build_string(&t, &maxbytes, "</dialog>\n</dialog-info>\n");
00288       break;
00289    case NONE:
00290    default:
00291       break;
00292    }
00293 
00294    if (t > tmp + sizeof(tmp))
00295       ast_log(LOG_WARNING, "Buffer overflow detected!!  (Please file a bug report)\n");
00296 
00297    add_header_contentLength(req, strlen(tmp));
00298    add_line(req, tmp);
00299 
00300    return send_request(p, req, XMIT_RELIABLE);
00301 }
00302 

Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen