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(a)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(a)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(a)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\">\r\n&q…)ot;>\r\n");
if (presence_list_changed) {
len += sprintf(body.s + len, " <document
uri=\"http://%.*s/presence-lists/users/%.*s/presence.xml\">\r\n",
pa_domain.len, pa_domain.s, _p->uri.len, _p->uri.s);
len += sprintf(body.s + len, " <change
method=\"PUT\">someone(a)example.com</change>\r\n")t;/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\">\r\n",
pa_domain.len, pa_domain.s, _p->uri.len, _p->uri.s);
len += sprintf(body.s + len, " <change
method=\"PUT\">someone(a)example.com</change>\r\n")t;/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(a)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(a)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(a)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(a)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(a)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 */