Hi Jamey!
Meanwhile a student of mine extended the pa module as part of his master thesis and SUBSCRIBE/NOTIFY works with the RTC-API - it was not difficult.
As soon as I get the code from the student I will post it somewhere, together with the thesis - which is german :-(
regards, klaus
Jamey Hicks wrote:
Klaus Darilion wrote:
Hi Jamey!
Thanks for the information. One of my students here at the university tries to implement a system where you can watch mobile user running around and call them by clicking on the moving point at the map - all with SIP. Currently we produce the location information at the mobile client (ipaq + xlite) by reading the GPS data from a bluetooth GPS receiver.
On the other side, we would like to have a Windows based client, which uses the RTC API. So the idea was to include the GPS information into the presence by using the "user-provided presence info" (like "x=123;y=456" instead of "i'm at lunch and come back at 2:30"). Nevertheless, therefore it would be necessary that the RTC API accepts the notficiations from ser.
The RTC api sends its notifieys as application/xpidf+xml, not as application/cpim-pidf+xml. Is this the same format with a different name? I tried to find the definition of them, but I found several outdated drafts. I took a closer look at the drafts from the impp working group, but for example i couldn't find the definition of the <presentitiy> tag. Can you point me to a document which describes the format used by the RTC. Btw: which format uses the sipc or other commerical SIP-based IM applications?
I also found no description of adding the exact geographical location into the presence information in a more generic way (not the workaround described above). Have you ever thought of this (as the columns are already defined in the database tables)? E.g. it could be a dedicated tag or an attribute in the location tag.
Hi Klaus,
I was just checking through my mail and saw this note again. I do not know how extensible xpidf is, but you including location in the user-provided presence info field should work. I have not had any luck with ser handling a subscribe from a microsoft RTC client, but I'm sure someone with some time and a packet tracer could get that working.
sipc and commercial SIP-based IM applications use application/cpim-pidf+xml. This format is still undergoing revision in the SIMPLE working group.
The SER PA includes location information for each registered contact in a separate tuple. I wrote this up here: http://pic.internet2.edu/docs/pals-ua-reqs.pdf
Jamey
Klaus Darilion wrote:
Hi Jamey!
Meanwhile a student of mine extended the pa module as part of his master thesis and SUBSCRIBE/NOTIFY works with the RTC-API - it was not difficult.
As soon as I get the code from the student I will post it somewhere, together with the thesis - which is german :-(
Cool! Please send me a pointer to the code or even send me the code itself and I'll make sure to work that support into the ser PA.
Jamey
Hi Jamey!
Attached are the files which were modified by the student (Dimitre Tachkov). At the end of the email, there is also a "cvs diff".
I will shortly explain what the project was: An IPAQ with a GPS receiver received the GPS coordinates and they were transmitted with a PUBLISH to the server. The coordnates received from the GPS receiver are in the NMEA format:
$GPRMC,POS_UTC,POS_STAT,LAT,LAT_REF,LON,LON_REF,SPD,HDG,DATE,MAG_VAR,MAG_REF*CC<cr><lf>
e.g. $GPRMC,105759.180,A,2821.7359,N,01923.7878,E,0.00,,190404,,*0C ^^^^^x^^^^^ ^^^^y^^^^ x=28° 21.7359' (minutes) y=...
The received x and y coordinates were put into the PUBLISH request in between <x> and <y> tags:
PUBLISH sip:tachkov@methusalix.ict.tuwien.ac.at SIP/2.0 Via: SIP/2.0/UDP methusalix.ict.tuwien.ac.at:5060;rport From: sip:tachkov@methusalix.ict.tuwien.ac.at;tag=8343f82348d1022ace010a43c363e58f To: sip:tachkov@methusalix.ixt.tuwien.ac.at Call-ID: f8b9ac03ca12a9ddd03aa4ef368fa46c@methusalix.ict.tuwien.ac.at CSeq: 3961 PUBLISH Max-Forwards: 30 Event: presence Accept: aplpication/cpim-pidf+xml Expires: 50 User-Agent: SIP Example Tester Content-Type: application/cpim-pidf+xml Content-Length: 280
<?xml version="1.0" encoding="UTF-8"?> <presence xmlns="urn:ietf:params:xml:ns:pidf" entity="pres:tachkov@methusalix.ict.tuwien.ac.at"> <tuple id="sg89ae"> <status> <basic>offline</basic> <geopriv><location-info><civilAddress> <x>01923.7878</x> <y>2821.7359</y> </civilAddress></location-info></geopriv> </status> <contact priority="0.8">Dimitar Tashkov</contact> </tuple> </presence>
So, I guess the module which processes this request was modified to handle the x and y coordinates.
And now to the messenger part. I don't know the original problem with Messenger, I only know that it works now (my student showed it to me). Messenger transports the presence status in the msnsubstatus tags. This was extended to transport the coordinates, as following (NOTIFY from ser to messenger with content-type application/xpidf+xml):
<?xml version="1.0"?> <!DOCTYPE presence PUBLIC "//IETF//DTD RFCxxxx XPIDF 1.0//EN" "xpidf.dtd"> <presence> <presentity uri="sip:tachkov@methusalix.ict.tuwien.ac.at;method=SUBSCRIBE"/> <atom id="9r28r49"> <address uri="sip:tachkov@methusalix.ict.tuwien.ac.at;user=ip" priority="0,800000"> <status status="open"> <msnsubstatus substatus="online"/> <note>1923.7878 2821.7359</note> </status> </address> </atom> </presence>
The <note> tag can be read and written with the RTC API.
A problem was the "offline" status. Sending a NOTIFY with substatus="offline" does not work. To see a buddy as "offline" in Messenger, ser has to send a NOTIFY with Expires: 0 and empty body:
NOTIFY sip:128.131.80.101:13359 SIP/2.0 Via: SIP/2.0/UDP 128.131.80.174;branch=z9hG4bK2101.825b6a47.0 To: "messenger" sip:messenger@methusalix.ict.tuwien.ac.at;tag=2bbdb0d6-6a85 From: sip:tachkov@methusalix.ict.tuwien.ac.at;tag=a6a1c5f60faecf035a1ae5b6e CSeq: 1 NOTIFY Call-ID: c0013a85-47fe-41b4-8369-e2de22fd17cf@128.131.80.101 Content-Length: 0 User-Agent: Sip EXpress router(0.8.13-dev-23-merged (i386/linux)) Event: presence Content-Type: application/xpidf+xml Subscription-State: terminated;reason=deactivated Expires: 0
After this NOTIFY, Messenger tries to SUBSCRIBE again. Therefore, the existing subscription must be terminated in ser after sending the NOTIFY with Expires: 0. Therefore, the methodes static inline int add_subs_state_hf(...) tatic inline int create_headers(...) were extended with a "flag" which signals if a NOTIFY with Expires: 0 should be sent.
Here some statements from the student about wrong implementations in the pa module: - It does not differentiate between application/cpim-pidf+xml and application/pidf+xml - ser didn't send a NOTIFY after a SUBSCRIBE message, only after received PUBLISH requests. - The espires header in the publish request is not interpreted. - The header field "SIP-If-Match" is not implemented in the pa module.
Finally, the received coordinates are displayed on a modified kphone (see the attached screenshot).
regards, Klaus
cvs server: Diffing . Index: notify.c =================================================================== RCS file: /cvsroot/ser/sip_router/modules/pa/notify.c,v retrieving revision 1.14 diff -r1.14 notify.c 120a121,125
// added from tachkov #define EXPIRES_HEADER_0 "Expires: 0" #define EXPIRES_HEADER_0_L (sizeof(EXPIRES_HEADER_0)-1) // tachkov end
247c252 < static inline int add_subs_state_hf(str* _h, int _l, subs_state_t _s, ss_reason_t _r, time_t _e) ---
static inline int add_subs_state_hf(str* _h, int _l, subs_state_t _s,
ss_reason_t _r, time_t _e, int flag) 251,258c256,274 < < if (_l < SUBSCRIPTION_STATE_L + subs_states[_s].len + SS_EXPIRES_L + < SS_REASON_L + reason[_r].len + CRLF_L) { < paerrno = PA_SMALL_BUFFER; < LOG(L_ERR, "add_subs_state_hf(): Buffer too small\n"); < return -1; < } < ---
// modified by tachkov (EXPIRES_HEADER_0_L) if (flag) { if (_l < SUBSCRIPTION_STATE_L + EXPIRES_HEADER_0_L +
subs_states[_s].len + SS_EXPIRES_L +
SS_REASON_L + reason[_r].len + CRLF_L) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "add_subs_state_hf(): Buffer too small\n"); return -1; } } else { if (_l < SUBSCRIPTION_STATE_L + subs_states[_s].len +
SS_EXPIRES_L +
SS_REASON_L + reason[_r].len + CRLF_L) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "add_subs_state_hf(): Buffer too small\n"); return -1; } }
279c295,299 < return 0; ---
// added from tachkov if (flag) str_append(_h, EXPIRES_HEADER_0 CRLF, EXPIRES_HEADER_0_L +
CRLF_L);
// tachkov end return 0;
283c303 < static inline int create_headers(struct watcher* _w) ---
static inline int create_headers(struct watcher* _w, int flag)
289,292c309,312 < < if (add_event_hf(&headers, BUF_LEN, _w->accept) < 0) { < LOG(L_ERR, "create_headers(): Error while adding Event header field\n"); < return -1; ---
if (add_event_hf(&headers, BUF_LEN, _w->accept) < 0) { LOG(L_ERR, "create_headers(): Error while adding Event header
field\n");
return -1;
296,297c316,317 < LOG(L_ERR, "create_headers(): Error while adding Content-Type header field\n"); < return -2; ---
LOG(L_ERR, "create_headers(): Error while adding Content-Type
header field\n");
return -2;
299c319 < ---
309,313c329,353 < if (add_subs_state_hf(&headers, BUF_LEN - headers.len, s, SR_TIMEOUT, t) < 0) { < LOG(L_ERR, "create_headers(): Error while adding Subscription-State\n"); < return -3; < } < ---
// modified by tachkov /* if (!flag) { if (add_subs_state_hf(&headers, BUF_LEN - headers.len, s,
SR_TIMEOUT, t,0) < 0) {
LOG(L_ERR, "create_headers(): Error while adding
Subscription-State\n");
return -3; } } else str_append(&headers, EXPIRES_HEADER_0 CRLF, EXPIRES_HEADER_0_L
+ CRLF_L);
*/ if (flag) { if (add_subs_state_hf(&headers, BUF_LEN - headers.len,
SS_TERMINATED, SR_DEACTIVATED, 0,1) < 0) {
LOG(L_ERR, "create_headers(): Error while adding
Subscription-State\n");
return -3; } } else { if (add_subs_state_hf(&headers, BUF_LEN - headers.len, s,
SR_TIMEOUT, t,0) < 0) {
LOG(L_ERR, "create_headers(): Error while adding
Subscription-State\n");
return -3; } }
328c368,372 < ---
// modified by tachkov (by offline state don't add body into NOTIFY
Request
// (Microsoft Messanger compatibillity) int offline = 1; if (tuple->state == PS_ONLINE) { offline = 0;
345,348c389,400 < if (xpidf_add_address(&body, BUF_LEN - body.len, &_p->uri, st) < 0) { < LOG(L_ERR, "send_xpidf_notify(): xpidf_add_address failed\n"); < return -3; < } ---
// modified by tachkov //if (st != XPIDF_ST_CLOSED) { double _x = -1; double _y = -1; if (tuple->location.x) _x = tuple->location.x; if (tuple->location.y) _y = tuple->location.y; if (xpidf_add_address(&body, BUF_LEN - body.len, &_p->uri,
_x, _y, st) < 0) {
LOG(L_ERR, "send_xpidf_notify(): xpidf_add_address
failed\n");
return -3; } //}
351,352c403,404 < } < if (end_xpidf_doc(&body, BUF_LEN - body.len) < 0) { ---
} if (end_xpidf_doc(&body, BUF_LEN - body.len) < 0) {
355c407,408 < } ---
}
} // end create body
357c410,411 < if (create_headers(_w) < 0) { ---
// modified by tachkov if (create_headers(_w,offline) < 0) {
362a417,436
// added from tachkov int et = EVENT_PRESENCE; // can be changed & implemented to
process other events too
if (offline) { if (et == EVENT_PRESENCE) { if (remove_watcher(_p, _w) < 0) { LOG(L_ERR, "send_xpidf_notify(): Error while deleting
winfo watcher\n");
return -7; } } else { if (remove_winfo_watcher(_p, _w) < 0) { LOG(L_ERR, "send_xpidf_notify(): Error while deleting
winfo watcher\n");
return -8; } } return -99; } // tachkov end
392c466,467 < if (create_headers(_w) < 0) { ---
// modified by tachkov if (create_headers(_w,0) < 0) {
458c533,534 < if (create_headers(_w) < 0) { ---
// modified by tachkov if (create_headers(_w,0) < 0) {
501c577,578 < if (create_headers(_w) < 0) { ---
// modified by tachkov if (create_headers(_w,0) < 0) {
535c612,613 < if (create_headers(_w) < 0) { ---
// modified by tachkov if (create_headers(_w,0) < 0) {
580c658,659 < if (create_headers(_w) < 0) { ---
// modified by tachkov if (create_headers(_w,0) < 0) {
Index: pdomain.c =================================================================== RCS file: /cvsroot/ser/sip_router/modules/pa/pdomain.c,v retrieving revision 1.10 diff -r1.10 pdomain.c 164c164 < if (timer_presentity(ptr) < 0) { ---
if (timer_presentity(ptr, _d) < 0) {
Index: presentity.c =================================================================== RCS file: /cvsroot/ser/sip_router/modules/pa/presentity.c,v retrieving revision 1.11 diff -r1.11 presentity.c 463c463,464 < int timer_presentity(presentity_t* _p) ---
// modified by tachkov int timer_presentity(presentity_t* _p, struct pdomain *_d)
493c494 < notify_watchers(_p); ---
notify_watchers(_p,_d);
588c589,590 < int notify_watchers(presentity_t* _p) ---
// modified by tachkov int notify_watchers(presentity_t* _p, struct pdomain *_d)
593a596,597
// added & modified by tachkov int remove = 0;
595c599,605 < send_notify(_p, ptr); ---
remove = 0; remove = send_notify(_p, ptr); if (remove == -99) { if (!_p->watchers && !_p->winfo_watchers) remove_presentity(_d, _p); ptr->expires = 0; /* The watcher will be freed after
NOTIFY is sent */
}
759a770,771
Index: presentity.h =================================================================== RCS file: /cvsroot/ser/sip_router/modules/pa/presentity.h,v retrieving revision 1.10 diff -r1.10 presentity.h 120c120 < int timer_presentity(presentity_t* _p); ---
int timer_presentity(presentity_t* _p, struct pdomain *_d);
163c163,164 < int notify_watchers(presentity_t* _p); ---
// modified by tachkov int notify_watchers(presentity_t* _p, struct pdomain *_d);
Index: xpidf.c =================================================================== RCS file: /cvsroot/ser/sip_router/modules/pa/xpidf.c,v retrieving revision 1.7 diff -r1.7 xpidf.c 66c66 < #define PRESENTITY_START "<presentity uri="" ---
#define PRESENTITY_START "<presentity uri="sip:"
75c75 < #define ADDRESS_START "<address uri="" ---
#define ADDRESS_START "<address uri="sip:"
77c77 < ---
/*
79a80,85
*/
// tachkov #define ADDRESS_END ";user=ip" priority="0,800000">" #define ADDRESS_END_L (sizeof(ADDRESS_END) - 1) // tachkov end
80a87
/*
88a96,118
*/
// tachkov #define STATUS_OPEN "<status status="open">\r\n" #define STATUS_OPEN_L (sizeof(STATUS_OPEN) - 1)
#define STATUS_CLOSED "<status status="closed">\r\n" #define STATUS_CLOSED_L (sizeof(STATUS_CLOSED) - 1)
#define STATUS_INUSE "<status status="inuse">\r\n" #define STATUS_INUSE_L (sizeof(STATUS_INUSE) - 1)
#define MSNSUBSTATUS_ONLINE "<msnsubstatus substatus="online"/>\r\n" #define MSNSUBSTATUS_ONLINE_L (sizeof(MSNSUBSTATUS_ONLINE)-1)
#define MSNSUBSTATUS_OFFLINE "<msnsubstatus substatus="offline"/>\r\n" #define MSNSUBSTATUS_OFFLINE_L (sizeof(MSNSUBSTATUS_OFFLINE)-1)
#define NOTE_BEGIN "<note>" #define NOTE_BEGIN_L (sizeof(NOTE_BEGIN)-1)
#define NOTE_END "</note>\r\n" #define NOTE_END_L (sizeof(NOTE_END)-1)
89a120,122
#define STATUS_END "</status>" #define STATUS_END_L (sizeof(STATUS_END)-1) // tachkov end
135c168,169 < int xpidf_add_address(str* _b, int _l, str* _addr, xpidf_status_t _st) ---
// modified by tachkov (x & y information will be send too) int xpidf_add_address(str* _b, int _l, str* _addr, double _x, double
_y, xpidf_status_t _st) 140,144c174,191 < switch(_st) { < case XPIDF_ST_OPEN: p = STATUS_OPEN; len = STATUS_OPEN_L; break; < case XPIDF_ST_CLOSED: p = STATUS_CLOSED; len = STATUS_CLOSED_L; break; < case XPIDF_ST_INUSE: p = STATUS_INUSE; len = STATUS_INUSE_L; break; < default: p = STATUS_CLOSED; len = STATUS_CLOSED_L; break; /* Makes gcc happy */ ---
// tachkov int len_available = 0; char * available; // tachkov end switch(_st) { // modified by tachkov case XPIDF_ST_OPEN: p = STATUS_OPEN; len = STATUS_OPEN_L; available =
MSNSUBSTATUS_ONLINE; len_available = MSNSUBSTATUS_ONLINE_L;
break; case XPIDF_ST_CLOSED: p = STATUS_CLOSED; len = STATUS_CLOSED_L; available =
MSNSUBSTATUS_OFFLINE; len_available = MSNSUBSTATUS_OFFLINE_L;
break; case XPIDF_ST_INUSE: p = STATUS_INUSE; len = STATUS_INUSE_L; available =
MSNSUBSTATUS_OFFLINE; len_available = MSNSUBSTATUS_OFFLINE_L;
break; default: p = STATUS_CLOSED; len
= STATUS_CLOSED_L;
available =
MSNSUBSTATUS_OFFLINE; len_available = MSNSUBSTATUS_OFFLINE_L;
break; /* Makes gcc
happy */ 146a194,203
// added from tachkov char buf_x[128]; int len_x = 0; char buf_y[128]; int len_y = 0; len_x = sprintf(buf_x, "%.4f", _x); len_y = sprintf(buf_y, "%.4f", _y); // tachkov end
153c210,217 < len + ---
len + len_available + // added from tachkov NOTE_BEGIN_L + // added from tachkov len_x + // added from tachkov 1 + // one space between x and y coords len_y + // added from tachkov NOTE_END_L + // added from tachkov STATUS_END_L + // added from tachkov
169a234,242
// tachkov str_append(_b,available, len_available); str_append(_b,NOTE_BEGIN, NOTE_BEGIN_L); str_append(_b,buf_x,len_x); str_append(_b," ",1); str_append(_b,buf_y,len_y); str_append(_b,NOTE_END,NOTE_END_L); str_append(_b,STATUS_END,STATUS_END_L); // tachkov end
Index: xpidf.h =================================================================== RCS file: /cvsroot/ser/sip_router/modules/pa/xpidf.h,v retrieving revision 1.3 diff -r1.3 xpidf.h 58c58 < int xpidf_add_address(str* _b, int _l, str* _addr, xpidf_status_t _st); ---
int xpidf_add_address(str* _b, int _l, str* _addr, double _x, double
_y, xpidf_status_t _st); cvs server: Diffing doc
/* * Presence Agent, notifications * * $Id: notify.c,v 1.14 2004/01/21 18:16:03 jamey Exp $ * * Copyright (C) 2001-2003 Fhg Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2003-02-28 protocolization of t_uac_dlg completed (jiri) */
#include "../../str.h" #include "../../dprint.h" #include "../../trim.h" #include "../../parser/parse_event.h" #include "pa_mod.h" #include "lpidf.h" #include "xpidf.h" #include "pidf.h" #include "common.h" #include "paerrno.h" #include "notify.h" #include "watcher.h" #include "location.h"
#define CONTENT_TYPE "Content-Type: " #define CONTENT_TYPE_L (sizeof(CONTENT_TYPE) - 1)
#define EVENT "Event: " #define EVENT_L (sizeof(EVENT) - 1)
#define PRESENCE_TEXT "presence" #define PRESENCE_TEXT_L (sizeof(PRESENCE_TEXT) - 1)
#define WINFO_TEXT "presence.winfo" #define WINFO_TEXT_L (sizeof(WINFO_TEXT) - 1)
#define XCAP_CHANGE_TEXT "xcap-change" #define XCAP_CHANGE_TEXT_L (sizeof(XCAP_CHANGE_TEXT) - 1)
#define CONT_TYPE_XPIDF "application/xpidf+xml" #define CONT_TYPE_XPIDF_L (sizeof(CONT_TYPE_XPIDF) - 1)
#define CONT_TYPE_LPIDF "text/lpidf" #define CONT_TYPE_LPIDF_L (sizeof(CONT_TYPE_LPIDF) - 1)
#define CONT_TYPE_PIDF "application/cpim-pidf+xml" #define CONT_TYPE_PIDF_L (sizeof(CONT_TYPE_PIDF) - 1)
#define CONT_TYPE_WINFO "application/watcherinfo+xml" #define CONT_TYPE_WINFO_L (sizeof(CONT_TYPE_WINFO) - 1)
#define CONT_TYPE_XCAP_CHANGE "application/xcap-change+xml" #define CONT_TYPE_XCAP_CHANGE_L (sizeof(CONT_TYPE_XCAP_CHANGE) - 1)
#define SUBSCRIPTION_STATE "Subscription-State: " #define SUBSCRIPTION_STATE_L (sizeof(SUBSCRIPTION_STATE) - 1)
#define SS_EXPIRES ";expires=" #define SS_EXPIRES_L (sizeof(SS_EXPIRES) - 1)
#define SS_REASON ";reason=" #define SS_REASON_L (sizeof(SS_REASON) - 1)
#define CRLF "\r\n" #define CRLF_L (sizeof(CRLF) - 1)
#define ST_ACTIVE "active" #define ST_ACTIVE_L (sizeof(ST_ACTIVE) - 1)
#define ST_TERMINATED "terminated" #define ST_TERMINATED_L (sizeof(ST_TERMINATED) - 1)
#define ST_PENDING "pending" #define ST_PENDING_L (sizeof(ST_PENDING) - 1)
#define REASON_DEACTIVATED "deactivated" #define REASON_DEACTIVATED_L (sizeof(REASON_DEACTIVATED) - 1)
#define REASON_NORESOURCE "noresource" #define REASON_NORESOURCE_L (sizeof(REASON_NORESOURCE) - 1)
#define REASON_PROBATION "probation" #define REASON_PROBATION_L (sizeof(REASON_PROBATION) - 1)
#define REASON_REJECTED "rejected" #define REASON_REJECTED_L (sizeof(REASON_REJECTED) - 1)
#define REASON_TIMEOUT "timeout" #define REASON_TIMEOUT_L (sizeof(REASON_TIMEOUT) - 1)
#define REASON_GIVEUP "giveup" #define REASON_GIVEUP_L (sizeof(REASON_GIVEUP) - 1)
#define METHOD_NOTIFY "NOTIFY" #define METHOD_NOTIFY_L (sizeof(METHOD_NOTIFY) - 1)
// added from tachkov #define EXPIRES_HEADER_0 "Expires: 0" #define EXPIRES_HEADER_0_L (sizeof(EXPIRES_HEADER_0)-1) // tachkov end
/* * Subscription-State values */ static str subs_states[] = { {ST_ACTIVE, ST_ACTIVE_L }, {ST_TERMINATED, ST_TERMINATED_L}, {ST_PENDING, ST_PENDING_L } };
/* * Subscription-State reason parameter values */ static str reason[] = { {REASON_DEACTIVATED, REASON_DEACTIVATED_L}, {REASON_NORESOURCE, REASON_NORESOURCE_L }, {REASON_PROBATION, REASON_PROBATION_L }, {REASON_REJECTED, REASON_REJECTED_L }, {REASON_TIMEOUT, REASON_TIMEOUT_L }, {REASON_GIVEUP, REASON_GIVEUP_L } };
static str method = {METHOD_NOTIFY, METHOD_NOTIFY_L};
#define BUF_LEN 4096
static char headers_buf[BUF_LEN]; static char buffer[BUF_LEN];
static str headers = {headers_buf, 0}; static str body = {buffer, 0};
static inline int add_event_hf(str* _h, int _l, int accept) { int event_l; char *event; if (accept == DOC_WINFO) { event = WINFO_TEXT; event_l = WINFO_TEXT_L; } else if (accept == DOC_XCAP_CHANGE) { event = XCAP_CHANGE_TEXT; event_l = XCAP_CHANGE_TEXT_L; } else { event = PRESENCE_TEXT; event_l = PRESENCE_TEXT_L; }
if (_l < EVENT_L + event_l + CRLF_L) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "add_event_hf(): Buffer too small\n"); return -1; }
str_append(_h, EVENT, EVENT_L); str_append(_h, event, event_l); str_append(_h, CRLF, CRLF_L); return 0; }
static inline int add_cont_type_hf(str* _h, int _l, doctype_t _d) { switch(_d) { case DOC_XPIDF: if (_l < CONTENT_TYPE_L + CONT_TYPE_XPIDF_L + CRLF_L) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "add_cont_type_hf(): Buffer too small\n"); return -1; } str_append(_h, CONTENT_TYPE CONT_TYPE_XPIDF CRLF, CONTENT_TYPE_L + CONT_TYPE_XPIDF_L + CRLF_L); return 0; case DOC_LPIDF: if (_l < CONTENT_TYPE_L + CONT_TYPE_LPIDF_L + CRLF_L) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "add_cont_type_hf(): Buffer too small\n"); return -2; } str_append(_h, CONTENT_TYPE CONT_TYPE_LPIDF CRLF, CONTENT_TYPE_L + CONT_TYPE_LPIDF_L + CRLF_L); return 0;
case DOC_PIDF: if (_l < CONTENT_TYPE_L + CONT_TYPE_PIDF_L + CRLF_L) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "add_cont_type_hf(): Buffer too small\n"); return -2; } str_append(_h, CONTENT_TYPE CONT_TYPE_PIDF CRLF, CONTENT_TYPE_L + CONT_TYPE_PIDF_L + CRLF_L); return 0;
case DOC_WINFO: if (_l < CONTENT_TYPE_L + CONT_TYPE_WINFO_L + CRLF_L) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "add_cont_type_hf(): Buffer too small\n"); return -2; } str_append(_h, CONTENT_TYPE CONT_TYPE_WINFO CRLF, CONTENT_TYPE_L + CONT_TYPE_WINFO_L + CRLF_L); return 0;
case DOC_XCAP_CHANGE: if (_l < CONTENT_TYPE_L + CONT_TYPE_XCAP_CHANGE_L + CRLF_L) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "add_cont_type_hf(): Buffer too small\n"); return -2; } str_append(_h, CONTENT_TYPE CONT_TYPE_XCAP_CHANGE CRLF, CONTENT_TYPE_L + CONT_TYPE_XCAP_CHANGE_L + CRLF_L); return 0;
default: paerrno = PA_UNSUPP_DOC; LOG(L_ERR, "add_cont_type_hf(): Unsupported document type\n"); return -3; } }
static inline int add_subs_state_hf(str* _h, int _l, subs_state_t _s, ss_reason_t _r, time_t _e, int flag) { char* num; int len;
// modified by tachkov (EXPIRES_HEADER_0_L) if (flag) { if (_l < SUBSCRIPTION_STATE_L + EXPIRES_HEADER_0_L + subs_states[_s].len + SS_EXPIRES_L + SS_REASON_L + reason[_r].len + CRLF_L) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "add_subs_state_hf(): Buffer too small\n"); return -1; } } else { if (_l < SUBSCRIPTION_STATE_L + subs_states[_s].len + SS_EXPIRES_L + SS_REASON_L + reason[_r].len + CRLF_L) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "add_subs_state_hf(): Buffer too small\n"); return -1; } }
str_append(_h, SUBSCRIPTION_STATE, SUBSCRIPTION_STATE_L); str_append(_h, subs_states[_s].s, subs_states[_s].len); switch(_s) { case SS_ACTIVE: str_append(_h, SS_EXPIRES, SS_EXPIRES_L); num = int2str((unsigned int)_e, &len); str_append(_h, num, len); break;
case SS_TERMINATED: str_append(_h, SS_REASON, SS_REASON_L); str_append(_h, reason[_r].s, reason[_r].len); break;
case SS_PENDING: break; }
str_append(_h, CRLF, CRLF_L); // added from tachkov if (flag) str_append(_h, EXPIRES_HEADER_0 CRLF, EXPIRES_HEADER_0_L + CRLF_L); // tachkov end return 0; }
static inline int create_headers(struct watcher* _w, int flag) { time_t t; subs_state_t s;
headers.len = 0;
if (add_event_hf(&headers, BUF_LEN, _w->accept) < 0) { LOG(L_ERR, "create_headers(): Error while adding Event header field\n"); return -1; }
if (add_cont_type_hf(&headers, BUF_LEN - headers.len, _w->accept) < 0) { LOG(L_ERR, "create_headers(): Error while adding Content-Type header field\n"); return -2; }
if (_w && _w->expires) t = _w->expires - time(0); else t = 0;
if (t == 0) { s = SS_TERMINATED; } else { s = SS_ACTIVE; }
// modified by tachkov /* if (!flag) { if (add_subs_state_hf(&headers, BUF_LEN - headers.len, s, SR_TIMEOUT, t,0) < 0) { LOG(L_ERR, "create_headers(): Error while adding Subscription-State\n"); return -3; } } else str_append(&headers, EXPIRES_HEADER_0 CRLF, EXPIRES_HEADER_0_L + CRLF_L); */
if (flag) { if (add_subs_state_hf(&headers, BUF_LEN - headers.len, SS_TERMINATED, SR_DEACTIVATED, 0,1) < 0) { LOG(L_ERR, "create_headers(): Error while adding Subscription-State\n"); return -3; } } else { if (add_subs_state_hf(&headers, BUF_LEN - headers.len, s, SR_TIMEOUT, t,0) < 0) { LOG(L_ERR, "create_headers(): Error while adding Subscription-State\n"); return -3; } }
return 0; }
static int send_xpidf_notify(struct presentity* _p, struct watcher* _w) { xpidf_status_t st; presence_tuple_t *tuple = _p->tuples;
/* Send a notify, saved Contact will be put in * Request-URI, To will be put in from and new tag * will be generated, callid will be callid, * from will be put in to including tag */ // modified by tachkov (by offline state don't add body into NOTIFY Request // (Microsoft Messanger compatibillity) int offline = 1; if (tuple->state == PS_ONLINE) { offline = 0; if (start_xpidf_doc(&body, BUF_LEN) < 0) { LOG(L_ERR, "send_xpidf_notify(): start_xpidf_doc failed\n"); return -1; }
if (xpidf_add_presentity(&body, BUF_LEN - body.len, &_p->uri) < 0) { LOG(L_ERR, "send_xpidf_notify(): xpidf_add_presentity failed\n"); return -3; } while (tuple) {
switch(tuple->state) { case PS_ONLINE: st = XPIDF_ST_OPEN; break; default: st = XPIDF_ST_CLOSED; break; }
// modified by tachkov //if (st != XPIDF_ST_CLOSED) { double _x = -1; double _y = -1; if (tuple->location.x) _x = tuple->location.x; if (tuple->location.y) _y = tuple->location.y;
if (xpidf_add_address(&body, BUF_LEN - body.len, &_p->uri, _x, _y, st) < 0) { LOG(L_ERR, "send_xpidf_notify(): xpidf_add_address failed\n"); return -3; } //}
tuple = tuple->next; } if (end_xpidf_doc(&body, BUF_LEN - body.len) < 0) { LOG(L_ERR, "send_xpidf_notify(): end_xpidf_doc failed\n"); return -5; } } // end create body
// modified by tachkov if (create_headers(_w,offline) < 0) { LOG(L_ERR, "send_xpidf_notify(): Error while adding headers\n"); return -6; }
tmb.t_request_within(&method, &headers, &body, _w->dialog, 0, 0);
// added from tachkov int et = EVENT_PRESENCE; // can be changed & implemented to process other events too if (offline) { if (et == EVENT_PRESENCE) { if (remove_watcher(_p, _w) < 0) { LOG(L_ERR, "send_xpidf_notify(): Error while deleting winfo watcher\n"); return -7; } } else { if (remove_winfo_watcher(_p, _w) < 0) { LOG(L_ERR, "send_xpidf_notify(): Error while deleting winfo watcher\n"); return -8; } } return -99; } // tachkov end
return 0;
}
static int send_lpidf_notify(struct presentity* _p, struct watcher* _w) { lpidf_status_t st; presence_tuple_t *tuple = _p->tuples;
if (lpidf_add_presentity(&body, BUF_LEN - body.len, &_p->uri) < 0) { LOG(L_ERR, "send_lpidf_notify(): Error in lpidf_add_presentity\n"); return -2; }
while (tuple) { switch(tuple->state) { case PS_OFFLINE: st = LPIDF_ST_CLOSED; break; default: st = LPIDF_ST_OPEN; break; }
if (lpidf_add_address(&body, BUF_LEN - body.len, &_p->uri, st) < 0) { LOG(L_ERR, "send_lpidf_notify(): lpidf_add_address failed\n"); return -3; }
tuple = tuple->next; }
// modified by tachkov if (create_headers(_w,0) < 0) { LOG(L_ERR, "send_lpidf_notify(): Error while adding headers\n"); return -4; }
tmb.t_request_within(&method, &headers, &body, _w->dialog, 0, 0); return 0; }
static int send_pidf_notify(struct presentity* _p, struct watcher* _w) { xpidf_status_t st; presence_tuple_t *tuple = _p->tuples;
/* Send a notify, saved Contact will be put in * Request-URI, To will be put in from and new tag * will be generated, callid will be callid, * from will be put in to including tag */
if (start_pidf_doc(&body, BUF_LEN) < 0) { LOG(L_ERR, "send_pidf_notify(): start_pidf_doc failed\n"); return -1; }
if (pidf_add_presentity(&body, BUF_LEN - body.len, &_p->uri) < 0) { LOG(L_ERR, "send_pidf_notify(): pidf_add_presentity failed\n"); return -3; }
while (tuple) { if (start_pidf_tuple(&body, BUF_LEN - body.len) < 0) { LOG(L_ERR, "send_pidf_notify(): start_pidf_tuple failed\n"); return -4; }
switch(tuple->state) { case PS_ONLINE: st = XPIDF_ST_OPEN; break; default: st = XPIDF_ST_CLOSED; break; }
if (pidf_add_address(&body, BUF_LEN - body.len, &tuple->contact, st) < 0) { LOG(L_ERR, "send_pidf_notify(): pidf_add_address failed\n"); return -3; }
if (pidf_add_location(&body, BUF_LEN - body.len, &tuple->location.loc, &tuple->location.site, &tuple->location.floor, &tuple->location.room, tuple->location.x, tuple->location.y, tuple->location.radius) < 0) { LOG(L_ERR, "send_pidf_notify(): pidf_add_location failed\n"); return -4; }
if (end_pidf_tuple(&body, BUF_LEN - body.len) < 0) { LOG(L_ERR, "send_pidf_notify(): end_pidf_tuple failed\n"); return -5; } tuple = tuple->next; }
if (end_pidf_doc(&body, BUF_LEN - body.len) < 0) { LOG(L_ERR, "send_pidf_notify(): end_xpidf_doc failed\n"); return -6; }
// modified by tachkov if (create_headers(_w,0) < 0) { LOG(L_ERR, "send_pidf_notify(): Error while adding headers\n"); return -7; }
tmb.t_request_within(&method, &headers, &body, _w->dialog, 0, 0); return 0; }
static int send_winfo_notify(struct presentity* _p, struct watcher* _w) { watcher_t *watcher = _p->watchers;
LOG(L_INFO, "send_winfo_notify: watcher=%p winfo_watcher=%p\n", watcher, _w); if (start_winfo_doc(&body, BUF_LEN) < 0) { LOG(L_ERR, "send_winfo_notify(): start_winfo_doc failed\n"); return -1; }
if (winfo_start_resource(&body, BUF_LEN - body.len, &_p->uri, _w) < 0) { LOG(L_ERR, "send_winfo_notify(): winfo_add_resource failed\n"); return -3; }
while (watcher) { if (winfo_add_watcher(&body, BUF_LEN - body.len, watcher) < 0) { LOG(L_ERR, "send_winfo_notify(): winfo_add_watcher failed\n"); return -3; }
watcher = watcher->next; }
if (winfo_end_resource(&body, BUF_LEN - body.len) < 0) { LOG(L_ERR, "send_winfo_notify(): winfo_add_resource failed\n"); return -5; }
if (end_winfo_doc(&body, BUF_LEN - body.len) < 0) { LOG(L_ERR, "send_winfo_notify(): end_xwinfo_doc failed\n"); return -6; }
// modified by tachkov if (create_headers(_w,0) < 0) { LOG(L_ERR, "send_winfo_notify(): Error while adding headers\n"); return -7; }
tmb.t_request_within(&method, &headers, &body, _w->dialog, 0, 0); return 0; }
static int send_xcap_change_notify(struct presentity* _p, struct watcher* _w) { int len = 0; int presence_list_changed = _p->flags & PFLAG_PRESENCE_LISTS_CHANGED; int watcherinfo_changed = _p->flags & PFLAG_WATCHERINFO_CHANGED; /* clear the flag */ _p->flags &= ~(PFLAG_PRESENCE_LISTS_CHANGED | PFLAG_WATCHERINFO_CHANGED);
len += sprintf(body.s + len, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"); len += sprintf(body.s + len, "<documents xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance%5C%22%3E%5Cr%5Cn"); if (presence_list_changed) { len += sprintf(body.s + len, " <document uri="http://%.*s/presence-lists/users/%.*s/presence.xml%5C%22%3E%5Cr%5Cn", pa_domain.len, pa_domain.s, _p->uri.len, _p->uri.s); len += sprintf(body.s + len, " <change method="PUT">someone@example.com</change>\r\n"); len += sprintf(body.s + len, " </document>\r\n"); } if (watcherinfo_changed) { len += sprintf(body.s + len, " <document uri="http://%.*s/watcherinfo/users/%.*s/watcherinfo.xml%5C%22%3E%5Cr%5Cn", pa_domain.len, pa_domain.s, _p->uri.len, _p->uri.s); len += sprintf(body.s + len, " <change method="PUT">someone@example.com</change>\r\n"); len += sprintf(body.s + len, " </document>\r\n"); } len += sprintf(body.s + len, "</documents>\r\n"); body.len = len;
// modified by tachkov if (create_headers(_w,0) < 0) { LOG(L_ERR, "send_location_notify(): Error while adding headers\n"); return -7; }
tmb.t_request_within(&method, &headers, &body, _w->dialog, 0, 0); return 0; }
int send_location_notify(struct presentity* _p, struct watcher* _w) { resource_list_t *user = _p->location_package.users;
LOG(L_ERR, "xcap_change_notify should be sent to watcher %.*s\n", _w->uri.len, _w->uri.s);
if (location_doc_start(&body, BUF_LEN) < 0) { LOG(L_ERR, "send_location_notify(): start_location_doc failed\n"); return -1; }
if (location_doc_start_userlist(&body, BUF_LEN - body.len, &_p->uri) < 0) { LOG(L_ERR, "send_location_notify(): location_add_uri failed\n"); return -3; }
while (user) { if (location_doc_add_user(&body, BUF_LEN - body.len, &user->uri) < 0) { LOG(L_ERR, "send_location_notify(): location_add_watcher failed\n"); return -3; }
user = user->next; }
if (location_doc_end_resource(&body, BUF_LEN - body.len) < 0) { LOG(L_ERR, "send_location_notify(): location_add_resource failed\n"); return -5; }
if (location_doc_end(&body, BUF_LEN - body.len) < 0) { LOG(L_ERR, "send_location_notify(): end_xlocation_doc failed\n"); return -6; }
// modified by tachkov if (create_headers(_w,0) < 0) { LOG(L_ERR, "send_location_notify(): Error while adding headers\n"); return -7; }
tmb.t_request_within(&method, &headers, &body, _w->dialog, 0, 0); return 0; }
int send_notify(struct presentity* _p, struct watcher* _w) { int rc; body.len = 0;
if (_w->uri.s == NULL) { LOG(L_ERR, "watcher uri.s is NULL\n"); return -1; } if (strlen(_w->uri.s) == 0) { LOG(L_ERR, "watcher uri.s is zero length\n"); return -2; }
LOG(L_ERR, "notifying %.*s _p->flags=%x _w->event_type=%d _w->accept=%d\n", _w->uri.len, _w->uri.s, _p->flags, _w->event_type, _w->accept); if ((_p->flags & (PFLAG_PRESENCE_CHANGED|PFLAG_WATCHERINFO_CHANGED)) && (_w->event_type == EVENT_PRESENCE)) { switch(_w->accept) { case DOC_XPIDF: return send_xpidf_notify(_p, _w); return 0;
case DOC_LPIDF: return send_lpidf_notify(_p, _w); return 0;
case DOC_PIDF: return send_pidf_notify(_p, _w); return 0; default: /* inapplicable */ ; }
} if ((_p->flags & PFLAG_WATCHERINFO_CHANGED) && (_w->event_type == EVENT_PRESENCE_WINFO)) { switch(_w->accept) { case DOC_WINFO: rc = send_winfo_notify(_p, _w); if (rc) LOG(L_ERR, "send_winfo_notify returned %d\n", rc); return rc; default: /* inapplicable */ ; } } if ((_p->flags & PFLAG_XCAP_CHANGED) && (_w->event_type == EVENT_XCAP_CHANGE)) { switch(_w->accept) { case DOC_XCAP_CHANGE: default: rc = send_xcap_change_notify(_p, _w); if (rc) LOG(L_ERR, "send_xcap_change_notify returned %d\n", rc); return rc; /* inapplicable */ } } if ((_p->flags & PFLAG_LOCATION_CHANGED) && (_w->event_type == EVENT_LOCATION)) { switch(_w->accept) { case DOC_LOCATION: rc = send_location_notify(_p, _w); if (rc) LOG(L_ERR, "send_location_notify returned %d\n", rc); return rc; default: /* inapplicable */ ; } }
return -1; }
/* * Presence Agent, domain support * * $Id: pdomain.c,v 1.10 2004/01/21 18:16:03 jamey Exp $ * * Copyright (C) 2001-2003 Fhg Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * History: * -------- * 2003-03-11 converted to the new locking scheme: locking.h (andrei) */
#include "pdomain.h" #include "paerrno.h" #include "../../ut.h" #include "../../dprint.h" #include "../../mem/shm_mem.h"
/* * Hash function */ static inline int hash_func(pdomain_t* _d, char* _s, int _l) { int res = 0, i; for(i = 0; i < _l; i++) { res += _s[i]; } return res % _d->size; }
/* * Create a new domain structure * _n is pointer to str representing * name of the domain, the string is * not copied, it should point to str * structure stored in domain list * _s is hash table size */ int new_pdomain(str* _n, int _s, pdomain_t** _d, register_watcher_t _r, unregister_watcher_t _u) { int i; pdomain_t* ptr; ptr = (pdomain_t*)shm_malloc(sizeof(pdomain_t)); if (!ptr) { paerrno = PA_NO_MEMORY; LOG(L_ERR, "new_pdomain(): No memory left\n"); return -1; } memset(ptr, 0, sizeof(pdomain_t)); ptr->table = (hslot_t*)shm_malloc(sizeof(hslot_t) * _s); if (!ptr->table) { paerrno = PA_NO_MEMORY; LOG(L_ERR, "new_pdomain(): No memory left 2\n"); shm_free(ptr); return -2; }
ptr->name = _n; for(i = 0; i < _s; i++) { init_slot(ptr, &ptr->table[i]); }
ptr->size = _s; lock_init(&ptr->lock); ptr->users = 0; ptr->expired = 0; ptr->reg = _r; ptr->unreg = _u; *_d = ptr; return 0; }
/* * Free all memory allocated for * the domain */ void free_pdomain(pdomain_t* _d) { int i; lock_pdomain(_d); if (_d->table) { for(i = 0; i < _d->size; i++) { deinit_slot(_d->table + i); } shm_free(_d->table); } unlock_pdomain(_d);
shm_free(_d); }
/* * Just for debugging */ void print_pdomain(FILE* _f, pdomain_t* _d) { struct presentity* p;
fprintf(_f, "---pdomain---\n"); fprintf(_f, "name : '%.*s'\n", _d->name->len, ZSW(_d->name->s)); fprintf(_f, "size : %d\n", _d->size); fprintf(_f, "table: %p\n", _d->table); fprintf(_f, "first: %p\n", _d->first); fprintf(_f, "last : %p\n", _d->last); /* fprintf(_f, "lock : %d\n", _d->lock);*/ /*it can be a struct --andrei*/
if (_d->first) { fprintf(_f, "\n"); p = _d->first; while(p) { print_presentity(_f, p); p = p->next; } fprintf(_f, "\n"); }
fprintf(_f, "---pdomain---\n"); }
int timer_pdomain(pdomain_t* _d) { struct presentity* ptr, *t;
lock_pdomain(_d);
ptr = _d->first;
while(ptr) { if (timer_presentity(ptr, _d) < 0) { LOG(L_ERR, "timer_pdomain(): Error in timer_pdomain\n"); unlock_pdomain(_d); return -1; } /* Remove the entire record * if it is empty */ if (ptr->watchers == 0 && ptr->winfo_watchers==0) { t = ptr; ptr = ptr->next; remove_presentity(_d, t); free_presentity(t); } else { ptr = ptr->next; } } unlock_pdomain(_d); return 0; }
/* * Get lock */ void lock_pdomain(pdomain_t* _d) { LOG(L_INFO, "lock_pdomain\n"); lock_get(&_d->lock); }
/* * Release lock */ void unlock_pdomain(pdomain_t* _d) { LOG(L_INFO, "unlock_pdomain\n"); lock_release(&_d->lock); }
/* * Find a presentity in domain */ int find_presentity(pdomain_t* _d, str* _uri, struct presentity** _p) { int sl, i; struct presentity* p; sl = hash_func(_d, _uri->s, _uri->len); p = _d->table[sl].first; for(i = 0; i < _d->table[sl].n; i++) { if ((p->uri.len == _uri->len) && !memcmp(p->uri.s, _uri->s, _uri->len)) { *_p = p; return 0; } p = p->next; }
return 1; /* Nothing found */ }
void add_presentity(pdomain_t* _d, struct presentity* _p) { int sl;
LOG(L_WARN, "add_presentity _p=%p p_uri=%.*s\n", _p, _p->uri.len, _p->uri.s);
sl = hash_func(_d, _p->uri.s, _p->uri.len);
slot_add(&_d->table[sl], _p, &_d->first, &_d->last); }
void remove_presentity(pdomain_t* _d, struct presentity* _p) { return; LOG(L_WARN, "remove_presentity _p=%p p_uri=%.*s\n", _p, _p->uri.len, _p->uri.s); slot_rem(_p->slot, _p, &_d->first, &_d->last); }
/* * Presence Agent, presentity structure and related functions * * $Id: presentity.c,v 1.11 2004/01/21 18:16:03 jamey Exp $ * * Copyright (C) 2001-2003 Fhg Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <stdio.h> #include <string.h> #include "../../db/db.h" #include "../../dprint.h" #include "../../mem/shm_mem.h" #include "../../ut.h" #include "paerrno.h" #include "notify.h" #include "presentity.h" #include "ptime.h" #include "pa_mod.h" #include "location.h"
extern db_con_t* pa_db; extern int use_db; extern char *presentity_table;
str pstate_name[PS_NSTATES] = { { "unknown", sizeof("unknown") - 1 }, { "online", sizeof("online") - 1 }, { "offline", sizeof("offline") - 1 }, { "away", sizeof("away") - 1 }, { "xaway", sizeof("xaway") - 1 }, { "dnd", sizeof("dnd") - 1 }, { "typing", sizeof("typing") - 1 }, };
int basic2status(str basic) { int i; for ( i= 0; i < PS_NSTATES; i++ ) { if (strcmp(pstate_name[i].s, basic.s) == 0) { return i; } } return 0; }
str str_strdup(str string) { str new_string; new_string.s = shm_malloc(string.len + 1); new_string.len = string.len; strncpy(new_string.s, string.s, string.len); new_string.s[string.len] = 0; return new_string; }
/* * Create a new presentity */ int new_presentity(struct pdomain *pdomain, str* _uri, int event_package, presentity_t** _p) { presentity_t* presentity; int size = 0;
if (!_uri || !_p) { paerrno = PA_INTERNAL_ERROR; LOG(L_ERR, "new_presentity(): Invalid parameter value\n"); return -1; }
size = sizeof(presentity_t) + _uri->len + 1; presentity = (presentity_t*)shm_malloc(size); if (!presentity) { paerrno = PA_NO_MEMORY; LOG(L_ERR, "new_presentity(): No memory left\n"); return -1; } memset(presentity, 0, sizeof(presentity_t));
presentity->uri.s = ((char*)presentity) + sizeof(presentity_t); strncpy(presentity->uri.s, _uri->s, _uri->len); presentity->uri.s[_uri->len] = 0; presentity->uri.len = _uri->len; presentity->pdomain = pdomain; presentity->event_package = event_package;
*_p = presentity;
LOG(L_ERR, "new_presentity=%p for uri=%.*s\n", presentity, presentity->uri.len, presentity->uri.s);
return 0; }
/* * Free all memory associated with a presentity */ void free_presentity(presentity_t* _p) { watcher_t* ptr; presence_tuple_t *tuple;
return; while(_p->watchers) { ptr = _p->watchers; _p->watchers = _p->watchers->next; free_watcher(ptr); }
while(_p->winfo_watchers) { ptr = _p->winfo_watchers; _p->winfo_watchers = _p->winfo_watchers->next; free_watcher(ptr); } while(_p->tuples) { tuple = _p->tuples; _p->tuples = _p->tuples->next; free_presence_tuple(tuple); }
shm_free(_p); }
/* * Sync presentity to db if db is in use */ int db_update_presentity(presentity_t* _p) { if (use_db) { presence_tuple_t *tuple = _p->tuples; db_key_t query_cols[2]; db_op_t query_ops[2]; db_val_t query_vals[2]; int n_selectors = 2;
db_key_t update_cols[20]; db_val_t update_vals[20]; int n_updates = 1;
while (tuple) {
LOG(L_ERR, "db_update_presentity starting: use_place_table=%d\n", use_place_table); query_cols[0] = "uri"; query_ops[0] = OP_EQ; query_vals[0].type = DB_STR; query_vals[0].nul = 0; query_vals[0].val.str_val.s = _p->uri.s; query_vals[0].val.str_val.len = _p->uri.len; LOG(L_ERR, "db_update_presentity: _p->uri=%.*s len=%d\n", _p->uri.len, _p->uri.s, _p->uri.len);
query_cols[1] = "contact"; query_ops[1] = OP_EQ; query_vals[1].type = DB_STR; query_vals[1].nul = 0; query_vals[1].val.str_val.s = tuple->contact.s; query_vals[1].val.str_val.len = tuple->contact.len; LOG(L_DBG, "db_update_presentity: tuple->contact=%.*s len=%d\n", tuple->contact.len, tuple->contact.s, tuple->contact.len);
update_cols[0] = "basic"; update_vals[0].type = DB_STR; update_vals[0].nul = 0; update_vals[0].val.str_val.s = pstate_name[tuple->state].s; update_vals[0].val.str_val.len = strlen(pstate_name[tuple->state].s);
if (use_place_table) { LOG(L_ERR, "db_update_presentity: room=%.*s\n", tuple->location.room.len, tuple->location.room.s); if (tuple->location.room.len && tuple->location.room.s) { update_cols[n_updates] = "placeid"; update_vals[n_updates].type = DB_INT; update_vals[n_updates].nul = 0; location_lookup_placeid(&tuple->location.room, &update_vals[n_updates].val.int_val); n_updates++; } } else { if (tuple->location.loc.len && tuple->location.loc.s) { update_cols[n_updates] = "location"; update_vals[n_updates].type = DB_STR; update_vals[n_updates].nul = 0; update_vals[n_updates].val.str_val = tuple->location.loc; LOG(L_ERR, "db_update_presentity: tuple->location.loc=%s len=%d\n", tuple->location.loc.s, tuple->location.loc.len); n_updates++; } if (tuple->location.site.len && tuple->location.site.s) { update_cols[n_updates] = "site"; update_vals[n_updates].type = DB_STR; update_vals[n_updates].nul = 0; update_vals[n_updates].val.str_val = tuple->location.site; n_updates++; } if (tuple->location.floor.len && tuple->location.floor.s) { update_cols[n_updates] = "floor"; update_vals[n_updates].type = DB_STR; update_vals[n_updates].nul = 0; update_vals[n_updates].val.str_val = tuple->location.floor; n_updates++; } if (tuple->location.room.len && tuple->location.room.s) { update_cols[n_updates] = "room"; update_vals[n_updates].type = DB_STR; update_vals[n_updates].nul = 0; update_vals[n_updates].val.str_val = tuple->location.room; n_updates++; } } if (tuple->location.x != 0) { update_cols[n_updates] = "x"; update_vals[n_updates].type = DB_DOUBLE; update_vals[n_updates].nul = 0; update_vals[n_updates].val.double_val = tuple->location.x; n_updates++; } if (tuple->location.y != 0) { update_cols[n_updates] = "y"; update_vals[n_updates].type = DB_DOUBLE; update_vals[n_updates].nul = 0; update_vals[n_updates].val.double_val = tuple->location.y; n_updates++; } if (tuple->location.radius != 0) { update_cols[n_updates] = "radius"; update_vals[n_updates].type = DB_DOUBLE; update_vals[n_updates].nul = 0; update_vals[n_updates].val.double_val = tuple->location.radius; n_updates++; }
db_use_table(pa_db, presentity_table);
if (n_updates > (sizeof(update_cols)/sizeof(db_key_t))) LOG(L_ERR, "too many update values. n_selectors=%d, n_updates=%d dbf.update=%p\n", n_selectors, n_updates, dbf.update);
if (db_update(pa_db, query_cols, query_ops, query_vals, update_cols, update_vals, n_selectors, n_updates) < 0) { LOG(L_ERR, "db_update_presentity: Error while updating database\n"); return -1; }
tuple = tuple->next; } } return 0; }
/* * Create a new presence_tuple */ int new_presence_tuple(str* _contact, presentity_t *_p, presence_tuple_t ** _t) { presence_tuple_t* tuple; int size = 0;
if (!_contact || !_t) { paerrno = PA_INTERNAL_ERROR; LOG(L_ERR, "new_presence_tuple(): Invalid parameter value\n"); return -1; }
size = sizeof(presence_tuple_t) + TUPLE_LOCATION_STR_LEN + _contact->len + 1; tuple = (presence_tuple_t*)shm_malloc(size); if (!tuple) { paerrno = PA_NO_MEMORY; LOG(L_ERR, "new_presence_tuple(): No memory left\n"); return -1; } memset(tuple, 0, sizeof(presence_tuple_t));
tuple->contact.s = ((char*)tuple) + sizeof(presence_tuple_t) + TUPLE_LOCATION_STR_LEN; strncpy(tuple->contact.s, _contact->s, _contact->len); _contact->s[_contact->len] = 0; tuple->contact.len = _contact->len; tuple->location.loc.s = ((char*)tuple) + sizeof(presence_tuple_t) + TUPLE_LOCATION_LOC_OFFSET; tuple->location.site.s = ((char*)tuple) + sizeof(presence_tuple_t) + TUPLE_LOCATION_SITE_OFFSET; tuple->location.floor.s = ((char*)tuple) + sizeof(presence_tuple_t) + TUPLE_LOCATION_FLOOR_OFFSET; tuple->location.room.s = ((char*)tuple) + sizeof(presence_tuple_t) + TUPLE_LOCATION_ROOM_OFFSET; tuple->location.packet_loss.s = ((char*)tuple) + sizeof(presence_tuple_t) + TUPLE_LOCATION_PACKET_LOSS_OFFSET;
*_t = tuple;
LOG(L_ERR, "new_tuple=%p for aor=%.*s contact=%.*s\n", tuple, _p->uri.len, _p->uri.s, tuple->contact.len, tuple->contact.s); if (use_db) { db_key_t query_cols[2]; db_op_t query_ops[2]; db_val_t query_vals[2];
db_key_t result_cols[4]; db_res_t *res; int n_query_cols = 2; int n_result_cols = 0; int basic_col, status_col, location_col;
query_cols[0] = "uri"; query_ops[0] = OP_EQ; query_vals[0].type = DB_STR; query_vals[0].nul = 0; query_vals[0].val.str_val = _p->uri;
query_cols[1] = "contact"; query_ops[1] = OP_EQ; query_vals[1].type = DB_STR; query_vals[1].nul = 0; query_vals[1].val.str_val = *_contact;
result_cols[basic_col = n_result_cols++] = "basic"; result_cols[status_col = n_result_cols++] = "status"; result_cols[location_col = n_result_cols++] = "location";
db_use_table(pa_db, presentity_table); if (db_query (pa_db, query_cols, query_ops, query_vals, result_cols, n_query_cols, n_result_cols, 0, &res) < 0) { LOG(L_ERR, "db_new_tuple(): Error while querying tuple\n"); return -1; } if (res && res->n > 0) { /* fill in tuple structure from database query result */ db_row_t *row = &res->rows[0]; db_val_t *row_vals = ROW_VALUES(row); str basic = row_vals[basic_col].val.str_val; // str status = row_vals[status_col].val.str_val; str location = row_vals[location_col].val.str_val; if (location.s) location.len = strlen(location.s);
LOG(L_INFO, " basic=%s location=%s\n", basic.s, location.s);
tuple->state = basic2status(basic); if (location.len) strncpy(tuple->location.loc.s, location.s, location.len);
} else { /* insert new record into database */ LOG(L_INFO, "new_tuple: inserting into table\n"); if (db_insert(pa_db, query_cols, query_vals, n_query_cols) < 0) { LOG(L_ERR, "db_new_tuple(): Error while inserting tuple\n"); return -1; } } db_free_query(pa_db, res); }
return 0; }
/* * Find a presence_tuple for contact _contact on presentity _p */ int find_presence_tuple(str* _contact, presentity_t *_p, presence_tuple_t ** _t) { presence_tuple_t *tuple; if (!_contact || !_contact->len || !_p || !_t) { paerrno = PA_INTERNAL_ERROR; LOG(L_ERR, "find_presence_tuple(): Invalid parameter value\n"); return -1; } tuple = _p->tuples; LOG(L_ERR, "find_presence_tuple: _p=%p _p->tuples=%p\n", _p, _p->tuples); while (tuple) { if (strncmp(tuple->contact.s, _contact->s, _contact->len) == 0) { *_t = tuple; return 0; } tuple = tuple->next; } return 1; }
void add_presence_tuple(presentity_t *_p, presence_tuple_t *_t) { presence_tuple_t *tuples = _p->tuples; _p->tuples = _t; _t->next = tuples; if (tuples) { tuples->prev = _t; } }
void remove_presence_tuple(presentity_t *_p, presence_tuple_t *_t) { presence_tuple_t *tuples = _p->tuples; if (tuples == _t) { _p->tuples = _t->next; } if (_t->prev) { _t->prev->next = _t->next; } if (_t->next) { _t->next->prev = _t->prev; } }
/* * Free all memory associated with a presence_tuple */ void free_presence_tuple(presence_tuple_t * _t) { shm_free(_t); }
/* * Print a presentity */ void print_presentity(FILE* _f, presentity_t* _p) { watcher_t* ptr;
fprintf(_f, "--presentity_t---\n"); fprintf(_f, "uri: '%.*s'\n", _p->uri.len, ZSW(_p->uri.s)); if (_p->watchers) { ptr = _p->watchers; while(ptr) { print_watcher(_f, ptr); ptr = ptr->next; } }
if (_p->winfo_watchers) { ptr = _p->winfo_watchers; while(ptr) { print_watcher(_f, ptr); ptr = ptr->next; } }
fprintf(_f, "---/presentity_t---\n"); }
// modified by tachkov int timer_presentity(presentity_t* _p, struct pdomain *_d) { watcher_t* ptr, *t;
if (_p->flags & PFLAG_WATCHERINFO_CHANGED) { watcher_t *w = _p->watchers; while (w) { if (w->flags & WFLAG_SUBSCRIPTION_CHANGED) { if (send_notify(_p, w) < 0) { LOG(L_ERR, "handle_subscription(): Error while sending notify\n"); /* FIXME: watcher and presentity should be test for removal here * (and possibly in other error cases too */ } w->flags &= ~WFLAG_SUBSCRIPTION_CHANGED; } w = w->next; }
notify_winfo_watchers(_p); _p->flags &= ~PFLAG_WATCHERINFO_CHANGED; /* We remove it here because a notify needs to be send first */ // if (w->expires == 0) free_watcher(w); // if (p->slot == 0) free_presentity(p); }
if (_p->flags & (PFLAG_PRESENCE_CHANGED |PFLAG_PRESENCE_LISTS_CHANGED |PFLAG_XCAP_CHANGED |PFLAG_LOCATION_CHANGED)) { notify_watchers(_p,_d); _p->flags &= ~(PFLAG_PRESENCE_CHANGED |PFLAG_PRESENCE_LISTS_CHANGED |PFLAG_XCAP_CHANGED |PFLAG_LOCATION_CHANGED); }
ptr = _p->watchers;
if (0) print_presentity(stdout, _p); while(ptr) { if (ptr->expires <= act_time) { LOG(L_ERR, "Removing watcher %.*s\n", ptr->uri.len, ptr->uri.s); ptr->expires = 0; send_notify(_p, ptr); t = ptr; ptr = ptr->next; remove_watcher(_p, t); free_watcher(t); continue; } ptr = ptr->next; }
ptr = _p->winfo_watchers;
while(ptr) { if (ptr->expires <= act_time) { LOG(L_ERR, "Removing watcher %.*s\n", ptr->uri.len, ptr->uri.s); ptr->expires = 0; send_notify(_p, ptr); t = ptr; ptr = ptr->next; remove_winfo_watcher(_p, t); free_watcher(t); continue; } ptr = ptr->next; } return 0; }
/* * Add a new watcher to the list */ int add_watcher(presentity_t* _p, str* _uri, time_t _e, int event_type, doctype_t _a, dlg_t* _dlg, str *_dn, struct watcher** _w) { if (new_watcher(_p, _uri, _e, event_type, _a, _dlg, _dn, _w) < 0) { LOG(L_ERR, "add_watcher(): Error while creating new watcher structure\n"); return -1; }
(*_w)->next = _p->watchers; _p->watchers = *_w; return 0; }
/* * Remove a watcher from the list */ int remove_watcher(presentity_t* _p, watcher_t* _w) { watcher_t* ptr, *prev;
ptr = _p->watchers; prev = 0; while(ptr) { if (ptr == _w) { if (prev) { prev->next = ptr->next; } else { _p->watchers = ptr->next; } return 0; }
prev = ptr; ptr = ptr->next; } /* Not found */ DBG("remove_watcher(): Watcher not found in the list\n"); return 1; }
/* * Notify all watchers in the list */ // modified by tachkov int notify_watchers(presentity_t* _p, struct pdomain *_d) { struct watcher* ptr;
ptr = _p->watchers;
// added & modified by tachkov int remove = 0; while(ptr) { remove = 0; remove = send_notify(_p, ptr); if (remove == -99) { if (!_p->watchers && !_p->winfo_watchers) remove_presentity(_d, _p); ptr->expires = 0; /* The watcher will be freed after NOTIFY is sent */ } ptr = ptr->next; } return 0; }
/* * Notify all winfo watchers in the list */ int notify_winfo_watchers(presentity_t* _p) { struct watcher* watcher;
watcher = _p->winfo_watchers;
LOG(L_ERR, "notify_winfo_watchers: presentity=%.*s winfo_watchers=%p\n", _p->uri.len, _p->uri.s, watcher); while(watcher) { LOG(L_ERR, "notify_winfo_watchers: watcher=%.*s\n", watcher->uri.len, watcher->uri.s); send_notify(_p, watcher); watcher = watcher->next; } return 0; }
/* * Add a new watcher to the winfo_watcher list */ int add_winfo_watcher(presentity_t* _p, str* _uri, time_t _e, int event_type, doctype_t _a, dlg_t* _dlg, str *_dn, struct watcher** _w) { if (new_watcher(_p, _uri, _e, event_type, _a, _dlg, _dn, _w) < 0) { LOG(L_ERR, "add_winfo_watcher(): Error while creating new watcher structure\n"); return -1; }
(*_w)->accept = DOC_WINFO; (*_w)->next = _p->winfo_watchers; _p->winfo_watchers = *_w; return 0; }
/* * Remove a watcher from the list */ int remove_winfo_watcher(presentity_t* _p, watcher_t* _w) { watcher_t* ptr, *prev;
ptr = _p->winfo_watchers; prev = 0; while(ptr) { if (ptr == _w) { if (prev) { prev->next = ptr->next; } else { _p->winfo_watchers = ptr->next; } return 0; }
prev = ptr; ptr = ptr->next; } /* Not found */ DBG("remove_winfo_watcher(): Watcher not found in the list\n"); return 1; }
/* * Find a given watcher in the list */ int find_watcher(struct presentity* _p, str* _uri, int _et, watcher_t** _w) { watcher_t* ptr;
/* first look for watchers */ ptr = _p->watchers;
while(ptr) { if ((_uri->len == ptr->uri.len) && (!memcmp(_uri->s, ptr->uri.s, _uri->len)) && (ptr->event_type == _et)) {
*_w = ptr; return 0; } ptr = ptr->next; }
/* now look for winfo watchers */ ptr = _p->winfo_watchers;
while(ptr) { if ((_uri->len == ptr->uri.len) && (!memcmp(_uri->s, ptr->uri.s, _uri->len)) && (ptr->event_type == _et)) {
*_w = ptr; return 0; } ptr = ptr->next; } return 1; }
resource_list_t *resource_list_append_unique(resource_list_t *list, str *uri) { resource_list_t *head = list; resource_list_t *last = NULL; fprintf(stderr, "resource_lists_append_unique: list=%p uri=%.*s\n", list, uri->len, uri->s); while (list) { if (strncmp(list->uri.s, uri->s, uri->len) == 0) return head; last = list; list = list->next; } list = (resource_list_t *)shm_malloc(sizeof(resource_list_t) + uri->len + 1); list->uri.len = uri->len; list->uri.s = ((char*)list) + sizeof(resource_list_t); strncpy(list->uri.s, uri->s, uri->len); list->uri.s[uri->len] = 0; if (last) { list->prev = last; last->next = list; } if (head) { return head; } else { return list; } }
resource_list_t *resource_list_remove(resource_list_t *list, str *uri) { resource_list_t *head = list; resource_list_t *last = NULL; resource_list_t *next = NULL; while (list) { if (strncmp(list->uri.s, uri->s, uri->len) == 0) goto remove; last = list; list = list->next; } return head; remove: next = list->next; if (last) last->next = next; if (next) next->prev = last;
shm_free(list);
if (head == list) return next; else return head; }
/* * Presence Agent, presentity structure and related functions * * $Id: presentity.h,v 1.10 2004/01/21 18:16:03 jamey Exp $ * * Copyright (C) 2001-2003 Fhg Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef PRESENTITY_H #define PRESENTITY_H
#include "../../str.h" #include "../tm/dlg.h" #include "watcher.h" #include "hslot.h" #include "pstate.h"
#define TUPLE_LOCATION_STR_LEN (128 + 32 + 32 + 64 + 32) #define TUPLE_LOCATION_LOC_OFFSET 0 #define TUPLE_LOCATION_SITE_OFFSET 128 #define TUPLE_LOCATION_FLOOR_OFFSET (128+32) #define TUPLE_LOCATION_ROOM_OFFSET (128+32+32) #define TUPLE_LOCATION_PACKET_LOSS_OFFSET (128+32+32+64)
typedef struct location { str loc; /* human readable description of location */ str site; str floor; str room; str packet_loss; double x; double y; double radius; } location_t;
typedef struct resource_list { str uri; struct resource_list *next; struct resource_list *prev; } resource_list_t;
typedef struct location_package { resource_list_t *users; resource_list_t *phones; } location_package_t;
typedef struct presence_tuple { str contact; pstate_t state; location_t location; struct presence_tuple *next; struct presence_tuple *prev; } presence_tuple_t;
struct pdomain;
typedef enum pflag { PFLAG_PRESENCE_CHANGED=1, PFLAG_PRESENCE_LISTS_CHANGED=2, PFLAG_WATCHERINFO_CHANGED=4, PFLAG_XCAP_CHANGED=8, PFLAG_LOCATION_CHANGED=16 } pflag_t;
typedef struct presentity { str uri; /* URI of presentity */ int event_package; /* parsed event package */ presence_tuple_t *tuples; location_package_t location_package; watcher_t* watchers; /* List of watchers */ watcher_t* winfo_watchers; /* Watchers subscribed to winfo */ pflag_t flags; struct pdomain *pdomain; struct presentity* next; /* Next presentity */ struct presentity* prev; /* Previous presentity in list */ struct hslot* slot; /* Hash table collision slot we belong to */ } presentity_t;
/* * Create a new presentity */ int new_presentity(struct pdomain *pdomain, str* _uri, int event_package, presentity_t** _p);
/* * Free all memory associated with a presentity */ void free_presentity(presentity_t* _p);
/* * Sync presentity to db if db is in use */ int db_update_presentity(presentity_t* _p);
/* * Run a timer handler on the presentity */ int timer_presentity(presentity_t* _p, struct pdomain *_d);
/* * Create a new presence_tuple */ int new_presence_tuple(str* _contact, presentity_t *_p, presence_tuple_t ** _t);
/* * Find a presence_tuple for contact _contact on presentity _p */ int find_presence_tuple(str* _contact, presentity_t *_p, presence_tuple_t ** _t); void add_presence_tuple(presentity_t *_p, presence_tuple_t *_t); void remove_presence_tuple(presentity_t *_p, presence_tuple_t *_t);
/* * Free all memory associated with a presence_tuple */ void free_presence_tuple(presence_tuple_t * _t);
/* * Add a watcher to the watcher list */ int add_watcher(presentity_t* _p, str* _uri, time_t _e, int event_type, doctype_t _a, dlg_t* _dlg, str *_dn, struct watcher** _w);
/* * Remove a watcher from the watcher list */ int remove_watcher(presentity_t* _p, watcher_t* _w);
/* * Find a watcher on the watcher list */ int find_watcher(presentity_t* _p, str* _uri, int etc, struct watcher** _w);
/* * Notify all watchers on the list */ // modified by tachkov int notify_watchers(presentity_t* _p, struct pdomain *_d);
/* * Add a watcher to the winfo watcher list */ int add_winfo_watcher(presentity_t* _p, str* _uri, time_t _e, int event_type, doctype_t _a, dlg_t* _dlg, str *_dn, struct watcher** _w);
/* * Remove a watcher from the winfo watcher list */ int remove_winfo_watcher(presentity_t* _p, watcher_t* _w);
/* * Notify all winfo watchers in the list */ int notify_winfo_watchers(presentity_t* _p);
/* * Print a presentity, just for debugging */ void print_presentity(FILE* _f, presentity_t* _p);
resource_list_t *resource_list_append_unique(resource_list_t *list, str *uri); resource_list_t *resource_list_remove(resource_list_t *list, str *uri);
#endif /* PRESENTITY_H */
/* * Presence Agent, XPIDF document support * * $Id: xpidf.c,v 1.7 2003/11/10 15:56:06 janakj Exp $ * * Copyright (C) 2001-2003 Fhg Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <string.h> #include "../../dprint.h" #include "paerrno.h" #include "common.h" #include "xpidf.h"
#define CRLF "\r\n" #define CRLF_L (sizeof(CRLF) - 1)
#define PUBLIC_ID "//IETF//DTD RFCxxxx XPIDF 1.0//EN" #define PUBLIC_ID_L (sizeof(PUBLIC_ID) - 1)
#define MIME_TYPE "application/xpidf+xml" #define MIME_TYPE_L (sizeof(MIME_TYPE) - 1)
#define XML_VERSION "<?xml version=\"1.0\"?>" #define XML_VERSION_L (sizeof(XML_VERSION) - 1)
#define PRESENCE_STAG "<presence>" #define PRESENCE_STAG_L (sizeof(PRESENCE_STAG) - 1)
#define PRESENCE_ETAG "</presence>" #define PRESENCE_ETAG_L (sizeof(PRESENCE_ETAG) - 1)
#define ADDRESS_ETAG "</address>" #define ADDRESS_ETAG_L (sizeof(ADDRESS_ETAG) - 1)
#define ATOM_ETAG "</atom>" #define ATOM_ETAG_L (sizeof(ATOM_ETAG) - 1)
#define XPIDF_DTD "xpidf.dtd" #define XPIDF_DTD_L (sizeof(XPDIF_DTD) - 1)
#define DOCTYPE "<!DOCTYPE presence PUBLIC \"" PUBLIC_ID "\" \"" XPIDF_DTD "\">" #define DOCTYPE_L (sizeof(DOCTYPE) - 1)
#define PRESENTITY_START "<presentity uri="sip:" #define PRESENTITY_START_L (sizeof(PRESENTITY_START) - 1)
#define PRESENTITY_END ";method=SUBSCRIBE"/>" #define PRESENTITY_END_L (sizeof(PRESENTITY_END) - 1)
#define ATOM_STAG "<atom id="9r28r49">" #define ATOM_STAG_L (sizeof(ATOM_STAG) - 1)
#define ADDRESS_START "<address uri="sip:" #define ADDRESS_START_L (sizeof(ADDRESS_START) - 1) /* #define ADDRESS_END "">" #define ADDRESS_END_L (sizeof(ADDRESS_END) - 1) */
// tachkov #define ADDRESS_END ";user=ip" priority="0,800000">" #define ADDRESS_END_L (sizeof(ADDRESS_END) - 1) // tachkov end
/* #define STATUS_OPEN "<status status="open"/>" #define STATUS_OPEN_L (sizeof(STATUS_OPEN) - 1)
#define STATUS_CLOSED "<status status="closed"/>" #define STATUS_CLOSED_L (sizeof(STATUS_CLOSED) - 1)
#define STATUS_INUSE "<status status="inuse"/>" #define STATUS_INUSE_L (sizeof(STATUS_INUSE) - 1) */
// tachkov #define STATUS_OPEN "<status status="open">\r\n" #define STATUS_OPEN_L (sizeof(STATUS_OPEN) - 1)
#define STATUS_CLOSED "<status status="closed">\r\n" #define STATUS_CLOSED_L (sizeof(STATUS_CLOSED) - 1)
#define STATUS_INUSE "<status status="inuse">\r\n" #define STATUS_INUSE_L (sizeof(STATUS_INUSE) - 1)
#define MSNSUBSTATUS_ONLINE "<msnsubstatus substatus="online"/>\r\n" #define MSNSUBSTATUS_ONLINE_L (sizeof(MSNSUBSTATUS_ONLINE)-1)
#define MSNSUBSTATUS_OFFLINE "<msnsubstatus substatus="offline"/>\r\n" #define MSNSUBSTATUS_OFFLINE_L (sizeof(MSNSUBSTATUS_OFFLINE)-1)
#define NOTE_BEGIN "<note>" #define NOTE_BEGIN_L (sizeof(NOTE_BEGIN)-1)
#define NOTE_END "</note>\r\n" #define NOTE_END_L (sizeof(NOTE_END)-1)
#define STATUS_END "</status>" #define STATUS_END_L (sizeof(STATUS_END)-1) // tachkov end
/* * Create start of pidf document */ int start_xpidf_doc(str* _b, int _l) { if ((XML_VERSION_L + CRLF_L + DOCTYPE_L + CRLF_L + PRESENCE_STAG_L + CRLF_L ) > _l) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "start_xpidf_doc(): Buffer too small\n"); return -1; }
str_append(_b, XML_VERSION CRLF DOCTYPE CRLF PRESENCE_STAG CRLF, XML_VERSION_L + CRLF_L + DOCTYPE_L + CRLF_L + PRESENCE_STAG_L + CRLF_L); return 0; }
/* * Add a presentity information */ int xpidf_add_presentity(str* _b, int _l, str* _uri) { if (_l < PRESENTITY_START_L + _uri->len + PRESENTITY_END_L + CRLF_L) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "pidf_add_presentity(): Buffer too small\n"); return -1; }
str_append(_b, PRESENTITY_START, PRESENTITY_START_L); str_append(_b, _uri->s, _uri->len); str_append(_b, PRESENTITY_END CRLF, PRESENTITY_END_L + CRLF_L); return 0; }
/* * Add a contact address with given status */ // modified by tachkov (x & y information will be send too) int xpidf_add_address(str* _b, int _l, str* _addr, double _x, double _y, xpidf_status_t _st) { int len = 0; char* p;
// tachkov int len_available = 0; char * available; // tachkov end
switch(_st) { // modified by tachkov case XPIDF_ST_OPEN: p = STATUS_OPEN; len = STATUS_OPEN_L; available = MSNSUBSTATUS_ONLINE; len_available = MSNSUBSTATUS_ONLINE_L; break; case XPIDF_ST_CLOSED: p = STATUS_CLOSED; len = STATUS_CLOSED_L; available = MSNSUBSTATUS_OFFLINE; len_available = MSNSUBSTATUS_OFFLINE_L; break; case XPIDF_ST_INUSE: p = STATUS_INUSE; len = STATUS_INUSE_L; available = MSNSUBSTATUS_OFFLINE; len_available = MSNSUBSTATUS_OFFLINE_L; break; default: p = STATUS_CLOSED; len = STATUS_CLOSED_L; available = MSNSUBSTATUS_OFFLINE; len_available = MSNSUBSTATUS_OFFLINE_L; break; /* Makes gcc happy */ }
// added from tachkov char buf_x[128]; int len_x = 0; char buf_y[128]; int len_y = 0;
len_x = sprintf(buf_x, "%.4f", _x); len_y = sprintf(buf_y, "%.4f", _y); // tachkov end
if (_l < (ATOM_STAG_L + CRLF_L + ADDRESS_START_L + _addr->len + ADDRESS_END_L + CRLF_L + len + len_available + // added from tachkov NOTE_BEGIN_L + // added from tachkov len_x + // added from tachkov 1 + // one space between x and y coords len_y + // added from tachkov NOTE_END_L + // added from tachkov STATUS_END_L + // added from tachkov CRLF_L + ADDRESS_ETAG_L + CRLF_L + ATOM_ETAG_L + CRLF_L ) ) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "xpidf_add_address(): Buffer too small\n"); return -1; }
str_append(_b, ATOM_STAG CRLF ADDRESS_START, ATOM_STAG_L + CRLF_L + ADDRESS_START_L); str_append(_b, _addr->s, _addr->len); str_append(_b, ADDRESS_END CRLF, ADDRESS_END_L + CRLF_L); str_append(_b, p, len); // tachkov str_append(_b,available, len_available); str_append(_b,NOTE_BEGIN, NOTE_BEGIN_L); str_append(_b,buf_x,len_x); str_append(_b," ",1); str_append(_b,buf_y,len_y); str_append(_b,NOTE_END,NOTE_END_L); str_append(_b,STATUS_END,STATUS_END_L); // tachkov end str_append(_b, CRLF ADDRESS_ETAG CRLF ATOM_ETAG CRLF, CRLF_L + ADDRESS_ETAG_L + CRLF_L + ATOM_ETAG_L + CRLF_L);
return 0; }
/* * End the document */ int end_xpidf_doc(str* _b, int _l) { if (_l < (PRESENCE_ETAG_L + CRLF_L)) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "end_xpidf_doc(): Buffer too small\n"); return -1; }
str_append(_b, PRESENCE_ETAG CRLF, PRESENCE_ETAG_L + CRLF_L); return 0; }
/* * Presence Agent, XPIDF document support * * $Id: xpidf.h,v 1.3 2003/11/10 15:56:06 janakj Exp $ * * Copyright (C) 2001-2003 Fhg Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef XPIDF_H #define XPIDF_H
#include "../../str.h"
typedef enum xpidf_status { XPIDF_ST_OPEN, XPIDF_ST_CLOSED, XPIDF_ST_INUSE } xpidf_status_t;
/* * Create start of pidf document */ int start_xpidf_doc(str* _b, int _l);
/* * Add a presentity information */ int xpidf_add_presentity(str* _b, int _l, str* _uri);
/* * Add a contact address with given status */ int xpidf_add_address(str* _b, int _l, str* _addr, double _x, double _y, xpidf_status_t _st);
/* * End the document */ int end_xpidf_doc(str* _b, int _l);
#endif /* XPIDF_H */
I've try the patch, with Windows Messenger 5.0. works only partially. When user signed on, notification to others is ok, but the user can't see others already online. And status message not getting through SER.
Ray -----Original Message----- From: serusers-bounces@iptel.org [mailto:serusers-bounces@lists.iptel.org] On Behalf Of Klaus Darilion Sent: Friday, May 28, 2004 11:39 PM To: Jamey Hicks Cc: Serusers; Dimitar Tachkov Subject: Re: [Serusers] Re: problem for using the latest pa module
Hi Jamey!
Attached are the files which were modified by the student (Dimitre Tachkov). At the end of the email, there is also a "cvs diff".
I will shortly explain what the project was: An IPAQ with a GPS receiver received the GPS coordinates and they were transmitted with a PUBLISH to the server. The coordnates received from the GPS receiver are in the NMEA format:
$GPRMC,POS_UTC,POS_STAT,LAT,LAT_REF,LON,LON_REF,SPD,HDG,DATE,MAG_VAR,MAG_REF *CC<cr><lf>
e.g. $GPRMC,105759.180,A,2821.7359,N,01923.7878,E,0.00,,190404,,*0C ^^^^^x^^^^^ ^^^^y^^^^ x=28° 21.7359' (minutes) y=...
The received x and y coordinates were put into the PUBLISH request in between <x> and <y> tags:
PUBLISH sip:tachkov@methusalix.ict.tuwien.ac.at SIP/2.0 Via: SIP/2.0/UDP methusalix.ict.tuwien.ac.at:5060;rport From: sip:tachkov@methusalix.ict.tuwien.ac.at;tag=8343f82348d1022ace010a43c363e58f To: sip:tachkov@methusalix.ixt.tuwien.ac.at Call-ID: f8b9ac03ca12a9ddd03aa4ef368fa46c@methusalix.ict.tuwien.ac.at CSeq: 3961 PUBLISH Max-Forwards: 30 Event: presence Accept: aplpication/cpim-pidf+xml Expires: 50 User-Agent: SIP Example Tester Content-Type: application/cpim-pidf+xml Content-Length: 280
<?xml version="1.0" encoding="UTF-8"?> <presence xmlns="urn:ietf:params:xml:ns:pidf" entity="pres:tachkov@methusalix.ict.tuwien.ac.at"> <tuple id="sg89ae"> <status> <basic>offline</basic> <geopriv><location-info><civilAddress> <x>01923.7878</x> <y>2821.7359</y> </civilAddress></location-info></geopriv> </status> <contact priority="0.8">Dimitar Tashkov</contact> </tuple> </presence>
So, I guess the module which processes this request was modified to handle the x and y coordinates.
And now to the messenger part. I don't know the original problem with Messenger, I only know that it works now (my student showed it to me). Messenger transports the presence status in the msnsubstatus tags. This was extended to transport the coordinates, as following (NOTIFY from ser to messenger with content-type application/xpidf+xml):
<?xml version="1.0"?> <!DOCTYPE presence PUBLIC "//IETF//DTD RFCxxxx XPIDF 1.0//EN" "xpidf.dtd"> <presence> <presentity uri="sip:tachkov@methusalix.ict.tuwien.ac.at;method=SUBSCRIBE"/> <atom id="9r28r49"> <address uri="sip:tachkov@methusalix.ict.tuwien.ac.at;user=ip" priority="0,800000"> <status status="open"> <msnsubstatus substatus="online"/> <note>1923.7878 2821.7359</note> </status> </address> </atom> </presence>
The <note> tag can be read and written with the RTC API.
A problem was the "offline" status. Sending a NOTIFY with substatus="offline" does not work. To see a buddy as "offline" in Messenger, ser has to send a NOTIFY with Expires: 0 and empty body:
NOTIFY sip:128.131.80.101:13359 SIP/2.0 Via: SIP/2.0/UDP 128.131.80.174;branch=z9hG4bK2101.825b6a47.0 To: "messenger" sip:messenger@methusalix.ict.tuwien.ac.at;tag=2bbdb0d6-6a85 From: sip:tachkov@methusalix.ict.tuwien.ac.at;tag=a6a1c5f60faecf035a1ae5b6e CSeq: 1 NOTIFY Call-ID: c0013a85-47fe-41b4-8369-e2de22fd17cf@128.131.80.101 Content-Length: 0 User-Agent: Sip EXpress router(0.8.13-dev-23-merged (i386/linux)) Event: presence Content-Type: application/xpidf+xml Subscription-State: terminated;reason=deactivated Expires: 0
After this NOTIFY, Messenger tries to SUBSCRIBE again. Therefore, the existing subscription must be terminated in ser after sending the NOTIFY with Expires: 0. Therefore, the methodes static inline int add_subs_state_hf(...) tatic inline int create_headers(...) were extended with a "flag" which signals if a NOTIFY with Expires: 0 should be sent.
Here some statements from the student about wrong implementations in the pa module: - It does not differentiate between application/cpim-pidf+xml and application/pidf+xml - ser didn't send a NOTIFY after a SUBSCRIBE message, only after received PUBLISH requests. - The espires header in the publish request is not interpreted. - The header field "SIP-If-Match" is not implemented in the pa module.
Finally, the received coordinates are displayed on a modified kphone (see the attached screenshot).
regards, Klaus
cvs server: Diffing . Index: notify.c =================================================================== RCS file: /cvsroot/ser/sip_router/modules/pa/notify.c,v retrieving revision 1.14 diff -r1.14 notify.c 120a121,125
// added from tachkov #define EXPIRES_HEADER_0 "Expires: 0" #define EXPIRES_HEADER_0_L (sizeof(EXPIRES_HEADER_0)-1) // tachkov end
247c252 < static inline int add_subs_state_hf(str* _h, int _l, subs_state_t _s, ss_reason_t _r, time_t _e) ---
static inline int add_subs_state_hf(str* _h, int _l, subs_state_t _s,
ss_reason_t _r, time_t _e, int flag) 251,258c256,274 < < if (_l < SUBSCRIPTION_STATE_L + subs_states[_s].len + SS_EXPIRES_L + < SS_REASON_L + reason[_r].len + CRLF_L) { < paerrno = PA_SMALL_BUFFER; < LOG(L_ERR, "add_subs_state_hf(): Buffer too small\n"); < return -1; < } < ---
// modified by tachkov (EXPIRES_HEADER_0_L) if (flag) { if (_l < SUBSCRIPTION_STATE_L + EXPIRES_HEADER_0_L +
subs_states[_s].len + SS_EXPIRES_L +
SS_REASON_L + reason[_r].len + CRLF_L) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "add_subs_state_hf(): Buffer too small\n"); return -1; } } else { if (_l < SUBSCRIPTION_STATE_L + subs_states[_s].len +
SS_EXPIRES_L +
SS_REASON_L + reason[_r].len + CRLF_L) { paerrno = PA_SMALL_BUFFER; LOG(L_ERR, "add_subs_state_hf(): Buffer too small\n"); return -1; } }
279c295,299 < return 0; ---
// added from tachkov if (flag) str_append(_h, EXPIRES_HEADER_0 CRLF, EXPIRES_HEADER_0_L +
CRLF_L);
// tachkov end return 0;
283c303 < static inline int create_headers(struct watcher* _w) ---
static inline int create_headers(struct watcher* _w, int flag)
289,292c309,312 < < if (add_event_hf(&headers, BUF_LEN, _w->accept) < 0) { < LOG(L_ERR, "create_headers(): Error while adding Event header field\n"); < return -1; ---
if (add_event_hf(&headers, BUF_LEN, _w->accept) < 0) { LOG(L_ERR, "create_headers(): Error while adding Event header
field\n");
return -1;
296,297c316,317 < LOG(L_ERR, "create_headers(): Error while adding Content-Type header field\n"); < return -2; ---
LOG(L_ERR, "create_headers(): Error while adding Content-Type
header field\n");
return -2;
299c319 < ---
309,313c329,353 < if (add_subs_state_hf(&headers, BUF_LEN - headers.len, s, SR_TIMEOUT, t) < 0) { < LOG(L_ERR, "create_headers(): Error while adding Subscription-State\n"); < return -3; < } < ---
// modified by tachkov /* if (!flag) { if (add_subs_state_hf(&headers, BUF_LEN - headers.len, s,
SR_TIMEOUT, t,0) < 0) {
LOG(L_ERR, "create_headers(): Error while adding
Subscription-State\n");
return -3; } } else str_append(&headers, EXPIRES_HEADER_0 CRLF, EXPIRES_HEADER_0_L
+ CRLF_L);
*/ if (flag) { if (add_subs_state_hf(&headers, BUF_LEN - headers.len,
SS_TERMINATED, SR_DEACTIVATED, 0,1) < 0) {
LOG(L_ERR, "create_headers(): Error while adding
Subscription-State\n");
return -3; } } else { if (add_subs_state_hf(&headers, BUF_LEN - headers.len, s,
SR_TIMEOUT, t,0) < 0) {
LOG(L_ERR, "create_headers(): Error while adding
Subscription-State\n");
return -3; } }
328c368,372 < ---
// modified by tachkov (by offline state don't add body into NOTIFY
Request
// (Microsoft Messanger compatibillity) int offline = 1; if (tuple->state == PS_ONLINE) { offline = 0;
345,348c389,400 < if (xpidf_add_address(&body, BUF_LEN - body.len, &_p->uri, st) < 0) { < LOG(L_ERR, "send_xpidf_notify(): xpidf_add_address failed\n"); < return -3; < } ---
// modified by tachkov //if (st != XPIDF_ST_CLOSED) { double _x = -1; double _y = -1; if (tuple->location.x) _x = tuple->location.x; if (tuple->location.y) _y = tuple->location.y; if (xpidf_add_address(&body, BUF_LEN - body.len, &_p->uri,
_x, _y, st) < 0) {
LOG(L_ERR, "send_xpidf_notify(): xpidf_add_address
failed\n");
return -3; } //}
351,352c403,404 < } < if (end_xpidf_doc(&body, BUF_LEN - body.len) < 0) { ---
} if (end_xpidf_doc(&body, BUF_LEN - body.len) < 0) {
355c407,408 < } ---
}
} // end create body
357c410,411 < if (create_headers(_w) < 0) { ---
// modified by tachkov if (create_headers(_w,offline) < 0) {
362a417,436
// added from tachkov int et = EVENT_PRESENCE; // can be changed & implemented to
process other events too
if (offline) { if (et == EVENT_PRESENCE) { if (remove_watcher(_p, _w) < 0) { LOG(L_ERR, "send_xpidf_notify(): Error while deleting
winfo watcher\n");
return -7; } } else { if (remove_winfo_watcher(_p, _w) < 0) { LOG(L_ERR, "send_xpidf_notify(): Error while deleting
winfo watcher\n");
return -8; } } return -99; } // tachkov end
392c466,467 < if (create_headers(_w) < 0) { ---
// modified by tachkov if (create_headers(_w,0) < 0) {
458c533,534 < if (create_headers(_w) < 0) { ---
// modified by tachkov if (create_headers(_w,0) < 0) {
501c577,578 < if (create_headers(_w) < 0) { ---
// modified by tachkov if (create_headers(_w,0) < 0) {
535c612,613 < if (create_headers(_w) < 0) { ---
// modified by tachkov if (create_headers(_w,0) < 0) {
580c658,659 < if (create_headers(_w) < 0) { ---
// modified by tachkov if (create_headers(_w,0) < 0) {
Index: pdomain.c =================================================================== RCS file: /cvsroot/ser/sip_router/modules/pa/pdomain.c,v retrieving revision 1.10 diff -r1.10 pdomain.c 164c164 < if (timer_presentity(ptr) < 0) { ---
if (timer_presentity(ptr, _d) < 0) {
Index: presentity.c =================================================================== RCS file: /cvsroot/ser/sip_router/modules/pa/presentity.c,v retrieving revision 1.11 diff -r1.11 presentity.c 463c463,464 < int timer_presentity(presentity_t* _p) ---
// modified by tachkov int timer_presentity(presentity_t* _p, struct pdomain *_d)
493c494 < notify_watchers(_p); ---
notify_watchers(_p,_d);
588c589,590 < int notify_watchers(presentity_t* _p) ---
// modified by tachkov int notify_watchers(presentity_t* _p, struct pdomain *_d)
593a596,597
// added & modified by tachkov int remove = 0;
595c599,605 < send_notify(_p, ptr); ---
remove = 0; remove = send_notify(_p, ptr); if (remove == -99) { if (!_p->watchers && !_p->winfo_watchers) remove_presentity(_d, _p); ptr->expires = 0; /* The watcher will be freed after
NOTIFY is sent */
}
759a770,771
Index: presentity.h =================================================================== RCS file: /cvsroot/ser/sip_router/modules/pa/presentity.h,v retrieving revision 1.10 diff -r1.10 presentity.h 120c120 < int timer_presentity(presentity_t* _p); ---
int timer_presentity(presentity_t* _p, struct pdomain *_d);
163c163,164 < int notify_watchers(presentity_t* _p); ---
// modified by tachkov int notify_watchers(presentity_t* _p, struct pdomain *_d);
Index: xpidf.c =================================================================== RCS file: /cvsroot/ser/sip_router/modules/pa/xpidf.c,v retrieving revision 1.7 diff -r1.7 xpidf.c 66c66 < #define PRESENTITY_START "<presentity uri="" ---
#define PRESENTITY_START "<presentity uri="sip:"
75c75 < #define ADDRESS_START "<address uri="" ---
#define ADDRESS_START "<address uri="sip:"
77c77 < ---
/*
79a80,85
*/
// tachkov #define ADDRESS_END ";user=ip" priority="0,800000">" #define ADDRESS_END_L (sizeof(ADDRESS_END) - 1) // tachkov end
80a87
/*
88a96,118
*/
// tachkov #define STATUS_OPEN "<status status="open">\r\n" #define STATUS_OPEN_L (sizeof(STATUS_OPEN) - 1)
#define STATUS_CLOSED "<status status="closed">\r\n" #define STATUS_CLOSED_L (sizeof(STATUS_CLOSED) - 1)
#define STATUS_INUSE "<status status="inuse">\r\n" #define STATUS_INUSE_L (sizeof(STATUS_INUSE) - 1)
#define MSNSUBSTATUS_ONLINE "<msnsubstatus substatus="online"/>\r\n" #define MSNSUBSTATUS_ONLINE_L (sizeof(MSNSUBSTATUS_ONLINE)-1)
#define MSNSUBSTATUS_OFFLINE "<msnsubstatus substatus="offline"/>\r\n" #define MSNSUBSTATUS_OFFLINE_L (sizeof(MSNSUBSTATUS_OFFLINE)-1)
#define NOTE_BEGIN "<note>" #define NOTE_BEGIN_L (sizeof(NOTE_BEGIN)-1)
#define NOTE_END "</note>\r\n" #define NOTE_END_L (sizeof(NOTE_END)-1)
89a120,122
#define STATUS_END "</status>" #define STATUS_END_L (sizeof(STATUS_END)-1) // tachkov end
135c168,169 < int xpidf_add_address(str* _b, int _l, str* _addr, xpidf_status_t _st) ---
// modified by tachkov (x & y information will be send too) int xpidf_add_address(str* _b, int _l, str* _addr, double _x, double
_y, xpidf_status_t _st) 140,144c174,191 < switch(_st) { < case XPIDF_ST_OPEN: p = STATUS_OPEN; len = STATUS_OPEN_L; break; < case XPIDF_ST_CLOSED: p = STATUS_CLOSED; len = STATUS_CLOSED_L; break; < case XPIDF_ST_INUSE: p = STATUS_INUSE; len = STATUS_INUSE_L; break; < default: p = STATUS_CLOSED; len = STATUS_CLOSED_L; break; /* Makes gcc happy */ ---
// tachkov int len_available = 0; char * available; // tachkov end switch(_st) { // modified by tachkov case XPIDF_ST_OPEN: p = STATUS_OPEN; len = STATUS_OPEN_L; available =
MSNSUBSTATUS_ONLINE; len_available = MSNSUBSTATUS_ONLINE_L;
break; case XPIDF_ST_CLOSED: p = STATUS_CLOSED; len = STATUS_CLOSED_L; available =
MSNSUBSTATUS_OFFLINE; len_available = MSNSUBSTATUS_OFFLINE_L;
break; case XPIDF_ST_INUSE: p = STATUS_INUSE; len = STATUS_INUSE_L; available =
MSNSUBSTATUS_OFFLINE; len_available = MSNSUBSTATUS_OFFLINE_L;
break; default: p = STATUS_CLOSED; len
= STATUS_CLOSED_L;
available =
MSNSUBSTATUS_OFFLINE; len_available = MSNSUBSTATUS_OFFLINE_L;
break; /* Makes gcc
happy */ 146a194,203
// added from tachkov char buf_x[128]; int len_x = 0; char buf_y[128]; int len_y = 0; len_x = sprintf(buf_x, "%.4f", _x); len_y = sprintf(buf_y, "%.4f", _y); // tachkov end
153c210,217 < len + ---
len + len_available + // added from tachkov NOTE_BEGIN_L + // added from tachkov len_x + // added from tachkov 1 + // one space between x and y coords len_y + // added from tachkov NOTE_END_L + // added from tachkov STATUS_END_L + // added from tachkov
169a234,242
// tachkov str_append(_b,available, len_available); str_append(_b,NOTE_BEGIN, NOTE_BEGIN_L); str_append(_b,buf_x,len_x); str_append(_b," ",1); str_append(_b,buf_y,len_y); str_append(_b,NOTE_END,NOTE_END_L); str_append(_b,STATUS_END,STATUS_END_L); // tachkov end
Index: xpidf.h =================================================================== RCS file: /cvsroot/ser/sip_router/modules/pa/xpidf.h,v retrieving revision 1.3 diff -r1.3 xpidf.h 58c58 < int xpidf_add_address(str* _b, int _l, str* _addr, xpidf_status_t _st); ---
int xpidf_add_address(str* _b, int _l, str* _addr, double _x, double
_y, xpidf_status_t _st); cvs server: Diffing doc