![]() |
Home page |
Mailing list |
Docs
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