浏览代码

presence handbook updated a bit (still not fully done)

Vaclav Kubart 18 年之前
父节点
当前提交
981aebf69b

+ 2 - 2
doc/presence/biblio.xml

@@ -14,8 +14,8 @@ draft on <ulink url="http://www.ietf.org">IETF</ulink> by name.</para></note>
 
 <biblioentry id="pres_draft_xcap">
 <abbrev>xcap</abbrev>
-<title><ulink url="http://www.ietf.org/internet-drafts/draft-ietf-simple-xcap-07.txt"
->draft-ietf-simple-xcap-07.txt</ulink> - XCAP specification</title></biblioentry>
+<title><ulink url="http://www.ietf.org/internet-drafts/draft-ietf-simple-xcap-12.txt"
+>draft-ietf-simple-xcap-12.txt</ulink> - XCAP specification</title></biblioentry>
 
 <biblioentry id="pres_draft_xcap_change">
 <abbrev>xcap_diff</abbrev>

+ 527 - 0
doc/presence/cfg/full_ps.cfg

@@ -0,0 +1,527 @@
+debug=3         # debug level (cmd line: -dddddddddd)
+#memdbg=100
+#fork=yes
+#log_stderror=no	# (cmd line: -E)
+#memlog=5 # memory debug log level
+#log_facility=LOG_LOCAL0 # sets the facility used for logging (see syslog(3))
+
+check_via=no	# (cmd. line: -v)
+dns=no           # (cmd. line: -r)
+rev_dns=no      # (cmd. line: -R)
+port=5060
+children=2
+alias="test-domain.com"
+alias="t-online.de"
+
+#user=ser
+#group=ser
+#open_fd_limit=1024 # sets the open file descriptors limit
+mhomed=yes  # usefull for multihomed hosts, small performance penalty
+
+#disable_tcp=yes 
+tcp_accept_aliases=yes # accepts the tcp alias via option (see NEWS)
+#tcp_poll_method="sigio_rt"
+
+tcp_send_timeout=1
+tcp_children=32
+tcp_connect_timeout=1
+tcp_connection_lifetime=600
+tcp_max_connections=50000
+
+# ------------------ module loading ----------------------------------
+
+# Uncomment this if you want to use SQL database
+loadmodule "/usr/lib/ser/modules/xcap.so"
+loadmodule "/usr/lib/ser/modules/sl.so"
+loadmodule "/usr/lib/ser/modules/avp.so"
+loadmodule "/usr/lib/ser/modules/avpops.so"
+loadmodule "/usr/lib/ser/modules/tm.so"
+loadmodule "/usr/lib/ser/modules/rr.so"
+loadmodule "/usr/lib/ser/modules/maxfwd.so"
+loadmodule "/usr/lib/ser/modules/usrloc.so"
+loadmodule "/usr/lib/ser/modules/registrar.so"
+loadmodule "/usr/lib/ser/modules/textops.so"
+loadmodule "/usr/lib/ser/modules/mysql.so"
+loadmodule "/usr/lib/ser/modules/dialog.so"
+loadmodule "/usr/lib/ser/modules/rls.so"
+loadmodule "/usr/lib/ser/modules/pa.so"
+loadmodule "/usr/lib/ser/modules/presence_b2b.so"
+loadmodule "/usr/lib/ser/modules/uri.so"
+loadmodule "/usr/lib/ser/modules/uri_db.so"
+loadmodule "/usr/lib/ser/modules/domain.so"
+loadmodule "/usr/lib/ser/modules/fifo.so"
+loadmodule "/usr/lib/ser/modules/xmlrpc.so"
+loadmodule "/usr/lib/ser/modules/xlog.so"
+#loadmodule "/usr/lib/ser/modules/unixsock.so"
+
+# binrpc
+loadmodule "/usr/lib/ser/modules/ctl.so"
+
+# Uncomment this if you want digest authentication
+# mysql.so must be loaded !
+loadmodule "/usr/lib/ser/modules/auth.so"
+loadmodule "/usr/lib/ser/modules/auth_db.so"
+loadmodule "/usr/lib/ser/modules/msilo.so"
+
+# ----------------- setting module-specific parameters ---------------
+
+# modparam("msilo","registrar","sip:[email protected]")
+modparam("msilo","use_contact",0)
+modparam("msilo","expire_time",7200)
+
+# -- usrloc params --
+
+# -- auth params --
+# Uncomment if you are using auth module
+#
+modparam("auth_db", "calculate_ha1", yes)
+#
+# If you set "calculate_ha1" parameter to yes (which true in this config), 
+# uncomment also the following parameter)
+#
+modparam("auth_db", "password_column", "password")
+
+# -- rr params --
+# add value to ;lr param to make some broken UAs happy
+modparam("rr", "enable_full_lr", 1)
+
+modparam("rls", "min_expiration", 300)
+modparam("rls", "max_expiration", 300)
+modparam("rls", "default_expiration", 300)
+modparam("rls", "expiration_timer_period", 30)
+modparam("rls", "auth", "none")
+modparam("rls", "reduce_xcap_needs", 1)
+modparam("rls", "db_mode", 1)
+modparam("rls", "timer_interval", 10)
+modparam("rls", "max_notifications_at_once", 100);
+modparam("rls", "max_list_nesting_level", 4);
+
+modparam("pa", "use_db", 1)
+# allow storing authorization requests for offline users into database
+modparam("pa", "use_offline_winfo", 1)
+# how often try to remove old stored authorization requests
+modparam("pa", "offline_winfo_timer", 600)
+# how long stored authorization requests live
+modparam("pa", "offline_winfo_expiration", 600)
+# mode of PA authorization: none, implicit or xcap
+modparam("pa", "auth", "xcap")
+# do not authorize watcherinfo subscriptions
+modparam("pa", "winfo_auth", "none")
+# use only published information if set to 0
+modparam("pa", "use_callbacks", 1)
+# don't accept internal subscriptions from RLS, ...
+modparam("pa", "accept_internal_subscriptions", 0)
+# maximum value of Expires for subscriptions
+modparam("pa", "max_subscription_expiration", 300)
+# maximum value of Expires for publications
+modparam("pa", "max_publish_expiration", 300)
+# how often test if something changes and send NOTIFY
+modparam("pa", "timer_interval", 1)
+modparam("pa", "async_auth_queries", 0)
+modparam("pa", "auth_rules_refresh_time", 60)
+modparam("pa", "max_auth_requests_per_tick", 1000)
+modparam("pa", "ignore_408_on_notify", 1)
+#modparam("pa", "pres_rules_file", "presence-rules.xml")
+#experimental:
+#modparam("pa", "subscribe_to_users", 1);
+#modparam("pa", "pa_subscription_uri", "sip:[email protected]");
+
+
+# route for generated SUBSCRIBE requests for presence
+#modparam("presence_b2b", "presence_route", "<sip:127.0.0.1;transport=tcp;lr>")
+modparam("presence_b2b", "presence_outbound_proxy", "sip:127.0.0.1;transport=tcp")
+#modparam("presence_b2b", "presence_outbound_proxy", "sip:127.0.0.1")
+# waiting time from error to new attepmt about SUBSCRIBE
+modparam("presence_b2b", "on_error_retry_time", 60)
+# how long wait for NOTIFY with Subscription-Status=terminated after unsubscribe
+modparam("presence_b2b", "wait_for_term_notify", 33)
+# how long before expiration send renewal SUBSCRIBE request
+modparam("presence_b2b", "resubscribe_delta", 30)
+# minimal time to send renewal SUBSCRIBE request from receiving previous response
+modparam("presence_b2b", "min_resubscribe_time", 60)
+# default expiration timeout
+modparam("presence_b2b", "default_expiration", 3600)
+# process internal subscriptions to presence events
+modparam("presence_b2b", "handle_presence_subscriptions", 1)
+#additional headers for presence
+#modparam("presence_b2b", "additional_presence_headers", "P-Generated: yes\r\nP-Regenreated: no\r\n")
+# randomized SUBSCRIBE requests?
+modparam("presence_b2b", "max_subscribe_delay", 10)
+
+#modparam("usrloc", "reg_avp_flag", "regavps")
+modparam("usrloc", "db_mode", 0)
+
+modparam("domain", "db_mode", 1)
+modparam("domain", "load_domain_attrs", 1)
+#modparam("domain|uri_db|acc|auth_db|usrloc|msilo|rls|pa", "db_url", "mysql://ser:heslo@spsdb:3306/ser")
+modparam("domain|uri_db|acc|auth_db|usrloc|msilo|rls|pa", "db_url", "mysql://ser:[email protected]:3306/ser")
+
+modparam("fifo", "fifo_file", "/tmp/ser_fifo")
+
+#modparam("xcap", "xcap_root", "http://pulpuk/xcap")
+modparam("xcap", "xcap_root", "http://localhost/xcap")
+
+# -------------------------  request routing logic -------------------
+
+# main routing logic
+
+avpflags regavps;
+
+route{
+	# XML RPC
+	if (method == "POST" ||  method == "GET") {
+		dispatch_rpc();
+		break;
+	}
+
+	# initial sanity checks -- messages with
+	# max_forwards==0, or excessively long requests
+	if (!mf_process_maxfwd_header("10")) {
+		sl_send_reply("483","Too Many Hops");
+		break;
+	};
+	if (msg:len >=  max_len ) {
+		sl_send_reply("513", "Message too big");
+		break;
+	};
+	
+	# we record-route all messages -- to make sure that
+	# subsequent messages will go through our proxy; that's
+	# particularly good if upstream and downstream entities
+	# use different transport protocol
+	if (!method=="REGISTER") record_route();	
+
+	# subsequent messages withing a dialog should take the
+	# path determined by record-routing
+	if (loose_route()) {
+		# mark routing logic in request
+		append_hf("P-hint: rr-enforced\r\n"); 
+		route(1);
+		break;
+	};
+					
+					
+#	lookup_domain("To");
+#	lookup_user("To");
+#			
+#	xlog("L_ERR", "Dispatch request %rm to: %tu from: %fu\n");
+#	ds_select_new("1", "3");  /* request uri */
+#	sl_send_reply("302", "Moved temporarily");
+#	break;
+
+	if (!lookup_domain("$td", "@to.uri.host")) {
+		xlog("L_ERR", "Unknown domain to: %tu from: %fu\n");
+		route(1);
+		break;
+	}
+
+#	xlog("L_INFO", "xcap_root: %$t.xcap_root\n");
+	
+	if (method=="SUBSCRIBE") {
+#		if ((@msg.supported=~"eventlist")) {
+#			xlog("L_ERR","!!! Support for event lists: %@msg.supported\n");
+#		}
+#		else {
+#			xlog("L_ERR","!!! NON-Support for event lists: %@msg.supported\n");
+#		}
+
+		if (search("^(From|f):.*sip:presence-server@test-domain")) {
+			log(1,"subscription from PA!\n");
+			# subscriptions from PA to user !!!
+			if (!lookup("location")) {
+				sl_send_reply("404", "Not Found");
+				break;
+			};
+		#	append_hf("P-hint: usrloc applied\r\n"); 
+			route(1);
+			drop;
+		};
+		
+		if (!t_newtran()) {
+			sl_reply_error();
+			break;
+		};
+		
+		if (@to.tag=="") { 
+			# only for new subscriptions (with empty to tag)
+
+			if (lookup_user("$tu.uid", "@to.uri")) {
+				# existing user -> it is subscription to PA
+
+				# xcap parameters
+#					set_xcap_root("hTTp://localhost/xcap");
+#					set_xcap_filename("pres.xml");
+#					xlog("L_INFO", "Hopla\n");
+				
+				$xcap_root = "pokus";
+#				set_xcap_root("http://nekde.nic.cz");
+				set_xcap_filename("pre.xml");
+
+				xlog("L_ERR", "XCAP_ROOT before: %$xcap_root\n");
+				if (handle_subscription("registrar")) {
+					xlog("L_ERR", "XCAP_ROOT after: %$xcap_root\n");
+					break;
+
+					if ((@msg.event=~"presence\.winfo")) {
+						# new watcher info subscription
+						# sends one watcher info NOTIFY message with all saved authorization requests
+						#xlog("L_ERR", "dumping stored winfo to %fu\n");
+						dump_stored_winfo("registrar", "presence");
+					}
+					else {
+						# new presence subscription
+						#if ((@msg.event=~"presence") && check_subscription_status("pending")) {
+						if ((@msg.event=~"presence")) {
+							# if offline user and new pending subscription 
+							if (!target_online("registrar")) {
+								#xlog("L_ERR", "storing 'pending' winfo to: %tu, from: %fu\n");
+								store_winfo("registrar");
+							}
+						}
+					}
+				}
+				break;
+			}
+			
+			if ((@msg.supported=~"eventlist")) {
+				# such user doesn't exist and Supported header field
+				#    -> probably RLS subscription
+				
+				#set_xcap_root("HttP://LOCALhost/xcap");
+				
+				if (lookup_domain("$fd", "@from.uri.host")) {
+					if (lookup_user("$fu.uid","@from.uri")) {
+						if (is_simple_rls_target("$uid-list")) {
+						# if (is_simple_rls_target("contact-list")) {
+							# log(1, "it is simple subscription!\n");
+							# takes From UID and makes XCAP query for user's 
+							# list named "default"
+							if (!query_resource_list("default")) {
+								t_reply("404", "No such user list");
+								break;
+							}
+						}
+						else {
+							if (is_simple_rls_target("contact-list")) {
+								if (!query_resource_list("testing")) {
+									t_reply("404", "No such user contact list");
+									break;
+								}
+							}
+						}
+					}
+				}
+			
+				if (!have_flat_list()) {
+					# query_resource_list failed or was not called
+					# do standard RLS query acording to To/AOR
+					if (!query_rls_services()) {
+						log(1, "XCAP query failed\n");
+						t_reply("404", "No such list URI");
+						break;
+					}
+				}
+			
+				# uncomment this if you want to authenticate first SUBSCRIBE request to resource list
+#					if (!proxy_authenticate("test-domain.com", "credentials")) {
+#						proxy_challenge( "test-domain.com", "0");
+#						break;
+#					};	
+				
+				handle_rls_subscription("1");
+			}
+			else {
+				# not resource list subscription -> invalid user
+				#xlog("L_ERR", "subscription to invalid user %tu\n");
+				t_reply("404", "User not found");
+			}
+			
+			break;
+		}
+		else {
+			# renewal subscriptions - try to handle it as RLS and if failed, handle it as PA subscription
+			# FIXME: better will be test like existing_rls_subscription() 
+			#        and existing_subscription("registrar")
+			if (!handle_rls_subscription("0")) {
+				lookup_user("$tu.uid", "@to.uri"); # needed to get correct UID (internal call converts it to lowercase!)
+				handle_subscription("registrar");
+			}
+			break;
+		}
+	};
+
+	if (method=="NOTIFY") {
+		if (search("^(To|t):.*sip:presence-server@test-domain")) {
+			log(1,"notify to PA!\n");
+			# notification to PA from user !!!
+			if (!t_newtran()) {
+			   log(1, "newtran error\n");
+			   sl_reply_error();
+			   break;
+			};
+			# handle notification sent in internal subscriptions (presence_b2b)
+			if (!handle_notify()) {
+				t_reply("481", "Unable to handle notification for PA");
+			}
+			break;
+		}
+	};
+		
+	# get user (common for all other messages than SUBSCRIBE)
+	if (!lookup_user("$tu.uid", "@to.uri")) {
+		xlog("L_ERR", "Unknown user, To: %tu?");
+		# break;
+		#append_hf("P-hint: unknown user\r\n"); 
+		sl_send_reply("404", "Unknown user");
+		#route(1);
+		break;
+	}
+	
+	if (method=="PUBLISH") {
+		if (!t_newtran()) {
+#			   log(1, "newtran error\n");
+		   sl_reply_error();
+		   break;
+		};
+		handle_publish("registrar");
+
+		# deliver messages to online user
+		# TODO: only if user goes from offline to online?
+		if (target_online("registrar")) {
+			# log(1, "Dumping stored messages\n");
+			# dump stored messages - route it through myself (otherwise routed via DNS!)
+			if (m_dump("sip:127.0.0.1")) {
+				#xlog("L_ERR", "MSILO: offline messages for %fu dumped\n");
+				break;
+			}
+		}
+
+		break;
+	};
+
+	if (method=="NOTIFY") {
+		if (!t_newtran()) {
+		   log(1, "newtran error\n");
+		   sl_reply_error();
+		   break;
+		};
+		# handle notification sent in internal subscriptions (presence_b2b)
+		if (!handle_notify()) {
+			t_reply("481", "Unable to handle notification");
+		}
+		break;
+	};
+	
+	if (method=="MESSAGE") {
+
+		if (authorize_message("im-rules.xml")) {
+			
+			# use usrloc for delivery
+			if (lookup("location")) {
+			
+				#log(1, "Delivering MESSAGE using usrloc\n");
+				t_on_failure("1");
+				if (!t_relay()) {
+					sl_reply_error();
+				}
+				
+				break;
+			}
+			else {
+				# store messages for offline user
+				#xlog("L_ERR", "MSILO: storing MESSAGE for %tu\n");
+				
+				if (!t_newtran()) {
+				   log(1, "newtran error\n");
+				   sl_reply_error();
+				   break;
+				};
+
+				# store only text messages NOT isComposing... !
+				if (search("^(Content-Type|c):.*application/im-iscomposing\+xml.*")) {
+					#log(1, "it is only isComposing message - ignored\n");
+					t_reply("202", "Ignored");
+					break;
+				}
+				
+				if (m_store("0", "sip:127.0.0.1")) {
+#	                #log(1, "MSILO: offline message stored\n");
+					if (!t_reply("202", "Accepted")) {
+						sl_reply_error();
+					};
+				} else {
+					log(1, "MSILO: error storing offline message\n");
+					if (!t_reply("503", "Service Unavailable")) {
+						sl_reply_error();
+					};
+				};
+				break;
+			}
+			break;
+		}
+		else {
+			# log(1, "unauthorized message\n");
+			sl_reply("403", "Forbidden");
+		}
+		break;
+	}
+	
+	if (method=="REGISTER") {
+		# uncomment this if you want to authenticate REGISTER request
+#			if (!www_authenticate("test-domain.com", "credentials")) {
+#				www_challenge( "test-domain.com", "0");
+#				break;
+#			};
+	
+		$t.a = @msg.cseq;
+		setavpflag("$t.a","regavps");
+		save("location");
+		
+		# dump stored messages - route it through myself (otherwise routed via DNS!)
+		if (m_dump("sip:127.0.0.1")) {
+			#xlog("L_ERR", "MSILO: offline messages for %fu dumped\n");
+			break;
+		}
+		break;
+	};
+
+	# native SIP destinations are handled using our USRLOC DB
+	t_on_branch("1");
+	if (!lookup("location")) {
+		sl_send_reply("404", "Not Found");
+		break;
+	};
+#	append_hf("P-hint: usrloc applied\r\n"); 
+	route(1);
+}
+
+branch_route[1]
+{
+#	xlog("L_ERR", "on_branch: to: %tu, from: %fu\n");
+#	xlog("L_ERR", "ruri: %ru uid: %$t.uid\n");
+	read_reg_avps("location", "$t.uid");
+	xlog("L_ERR", "$t.a = %$t.a");
+}
+route[1] 
+{
+	# send it out now; use stateful forwarding as it works reliably
+	# even for UDP2TCP
+	if (!t_relay()) {
+		sl_reply_error();
+	};
+}
+
+
+failure_route[1] {
+	# forwarding failed -- check if the request was a MESSAGE
+	if (!method=="MESSAGE") { break; };
+	#log(1, "MSILO: MESSAGE forward failed - storing it\n");
+	
+    # we have changed the R-URI with the contact address, ignore it now
+	if (m_store("0", "")) {
+		t_reply("202", "Accepted");
+	} else {
+		log(1, "MSILO: offline message NOT stored\n");
+		t_reply("503", "Service Unavailable");
+	};
+}

+ 568 - 0
doc/presence/cfg/ps.cfg

@@ -0,0 +1,568 @@
+#
+# $Id$
+#
+
+# First start SER sample config script with:
+#   database, accounting, authentication, multi-domain support
+#   PSTN GW section, named flags, named routes, global-,
+#   domain- and user-preferences with AVPs
+# Several of these features are only here for demonstration purpose
+# what can be achieved with the SER config script language.
+#
+# If you look for a simpler version with a lot less dependencies
+# please refer to the ser-basic.cfg file in your SER distribution.
+
+# To get this config running you need to execute the following commands
+# with the new serctl (the capital word are just place holders)
+# - ser_ctl domain add DOMAINNAME
+# - ser_ctl user add USERNAME@DOMAINNAME -p PASSWORD
+# If you want to have PID header for your user
+# - ser_attr add uid=UID asserted_id="PID"
+# If you want to have gateway support
+# - ser_db add attr_types name=gw_ip rich_type=string raw_type=2 description="The gateway IP for the default ser.cfg" default_flags=33
+# - ser_attr add global gw_ip=GATEWAY-IP
+
+# ----------- global configuration parameters ------------------------
+
+debug=3         # debug level (cmd line: -dddddddddd)
+memdbg=10 # memory debug log level
+#memlog=10 # memory statistics log level
+#log_facility=LOG_LOCAL0 # sets the facility used for logging (see syslog(3))
+
+/* Uncomment these lines to enter debugging mode 
+fork=no
+log_stderror=yes
+*/
+
+check_via=no    # (cmd. line: -v)
+dns=no          # (cmd. line: -r)
+rev_dns=no      # (cmd. line: -R)
+#port=5060
+#children=4
+#user=ser
+#group=ser
+#disable_core=yes #disables core dumping
+#open_fd_limit=1024 # sets the open file descriptors limit
+#mhomed=yes  # usefull for multihomed hosts, small performance penalty
+#disable_tcp=yes 
+#tcp_accept_aliases=yes # accepts the tcp alias via option (see NEWS)
+
+#
+
+# ------------------ module loading ----------------------------------
+
+# load a SQL database for authentication, domains, user AVPs etc.
+loadmodule "/home/kubartv/SER/lib/ser/modules/mysql.so"
+
+loadmodule "/home/kubartv/SER/lib/ser/modules/sl.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/tm.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/rr.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/maxfwd.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/usrloc.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/registrar.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/xlog.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/textops.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/ctl.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/fifo.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/auth.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/auth_db.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/gflags.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/domain.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/uri_db.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/avp.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/avp_db.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/acc_db.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/xmlrpc.so"
+
+# presence related modules
+loadmodule "/home/kubartv/SER/lib/ser/modules/pa.so"
+loadmodule "/home/kubartv/SER/lib/ser/modules/dialog.so"
+
+# ----------------- setting script FLAGS -----------------------------
+flags
+  FLAG_ACC         : 1  # include message in accouting
+
+avpflags
+  dialog_cookie;        # handled by rr module
+
+# ----------------- setting module-specific parameters ---------------
+
+# specify the path to you database here
+modparam("acc_db|auth_db|avp_db|domain|gflags|usrloc|uri_db", "db_url", "mysql://ser:[email protected]/ser")
+
+# -- usrloc params --
+
+# as we use the database anyway we will use it for usrloc as well
+modparam("usrloc", "db_mode", 1)
+
+# -- auth params --
+modparam("auth_db", "calculate_ha1", yes)
+modparam("auth_db", "password_column", "password")
+
+# -- rr params --
+# add value to ;lr param to make some broken UAs happy
+modparam("rr", "enable_full_lr", 1)
+#
+# limit the length of the AVP cookie to only necessary ones
+modparam("rr", "cookie_filter", "(account)")
+#
+# you probably do not want that someone can simply read and change
+# the AVP cookie in your Routes, thus should really change this
+# secret value below
+modparam("rr", "cookie_secret", "MyRRAVPcookiesecret")
+
+# -- gflags params --
+# load the global AVPs
+modparam("gflags", "load_global_attrs", 1)
+
+# -- domain params --
+# load the domain AVPs
+modparam("domain", "load_domain_attrs", 1)
+
+# -- ctl params --
+# by default ctl listens on unixs:/tmp/ser_ctl if no other address is
+# specified in modparams; this is also the default for sercmd
+modparam("ctl", "binrpc", "unixs:/tmp/ser_ctl")
+# listen on the "standard" fifo for backward compatibility
+modparam("ctl", "fifo", "fifo:/tmp/ser_fifo")
+# listen on tcp, localhost
+#modparam("ctl", "binrpc", "tcp:localhost:2046")
+
+# -- acc_db params --
+# failed transactions (=negative responses) should be logged to
+modparam("acc_db", "failed_transactions", 1)
+
+# comment the next line if you dont want to have accouting to DB
+modparam("acc_db", "log_flag", "FLAG_ACC")
+
+# -- tm params --
+# uncomment the following line if you want to avoid that each new reply
+# restarts the resend timer (see INBOUND route below)
+#modparam("tm", "restart_fr_on_each_reply", "0")
+
+# -- presence modules parameters --
+modparam("pa", "use_db", 1)
+modparam("pa", "auth", "none")
+modparam("pa", "winfo_auth", "none")
+
+modparam("pa", "db_url", "mysql://ser:[email protected]/ser")
+
+# -------------------------  request routing logic -------------------
+
+# main routing logic
+
+route{
+	# if you have a PSTN gateway just un-comment the follwoing line and 
+	# specify the IP address of it to route calls to it
+	#$gw_ip = "1.2.3.4"
+
+	# first do some initial sanity checks
+	route(INIT);
+
+	# check if the request is routed via Route header or
+	# needs a Record-Route header
+	route(RR);
+
+	# check if the request belongs to our proxy
+	route(DOMAIN);
+
+	# handle REGISTER requests
+	route(REGISTRAR);
+		
+	# handle requests destined for presence server (SUBSCRIBE, PUBLISH, ...)
+	route(PRESENCE);
+
+	# from here on we want to know you is calling
+	route(AUTHENTICATION);
+
+	# check if we should be outbound proxy for a local user
+	route(OUTBOUND);
+
+	# check if the request is for a local user
+	route(INBOUND);
+
+	# here you coud for example try to an ENUM lookup before
+	# the call gets routed to the PSTN
+	#route(ENUM);
+
+	# lets see if someone wants to call a PSTN number
+	route(PSTN);
+
+	# nothing matched, reject it finally
+	sl_send_reply("404", "No route matched");
+}
+
+route[FORWARD]
+{
+	# here you could decide wether this call needs a RTP relay or not
+
+	# send it out now; use stateful forwarding as it works reliably
+	# even for UDP2TCP
+	if (!t_relay()) {
+		sl_reply_error();
+	};
+	drop;
+}
+
+route[INIT]
+{
+	# as soon as it is save to distinguish HTTP from SIP
+	# we can un-comment the next line
+	route(RPC);
+
+	# initial sanity checks -- messages with
+	# max_forwards==0, or excessively long requests
+	if (!mf_process_maxfwd_header("10")) {
+		sl_send_reply("483","Too Many Hops");
+		drop;
+	};
+
+	if (msg:len >=  max_len ) {
+		sl_send_reply("513", "Message too big");
+		drop;
+	};
+
+	# you could add some NAT detection here for example
+
+	# or you cuold call here some of the check from the sanity module
+
+	# lets account all initial INVITEs and the BYEs
+	# if (method=="INVITE" && @to.tag=="" || method=="BYE") {
+	if (method=="INVITE" && @to.tag=="") {
+		setflag(FLAG_ACC);
+	}
+}
+
+route[RPC]
+{
+	# allow XMLRPC from localhost
+	if ((method=="POST" || method=="GET") &&
+		src_ip==127.0.0.1) {
+
+		if (msg:len >= 8192) {
+			sl_send_reply("513", "Request to big");
+			drop;
+		}
+
+		# lets see if a module want to answer this
+		dispatch_rpc();
+		drop;
+	}
+}
+
+route[RR]
+{
+	# subsequent messages withing a dialog should take the
+	# path determined by record-routing
+	if (loose_route()) {
+		# mark routing logic in request
+		append_hf("P-hint: rr-enforced\r\n"); 
+
+		# if the Route contained the accounting AVP cookie we
+		# set the accounting flag for the acc_db module.
+		# this is more for demonstration purpose as this could
+		# also be solved without RR cookies.
+		# Note: this means all in-dialog request will show up in the
+		# accouting tables, so prepare your accounting software for this ;-)
+		if ($account == "yes") {
+			setflag(FLAG_ACC);
+		}
+
+		# for broken devices which overwrite their Route's with each
+		# (not present) RR from within dialog requests it is better
+		# to repeat the RRing
+		# and if we call rr after loose_route the AVP cookies are restored
+		# automatically :)
+		record_route();
+
+		route(FORWARD);
+	} else if (!method=="REGISTER") {
+		# we record-route all messages -- to make sure that
+		# subsequent messages will go through our proxy; that's
+		# particularly good if upstream and downstream entities
+		# use different transport protocol
+
+		# if the inital INVITE got the ACC flag store this in
+		# an RR AVP cookie. this is more for demonstration purpose
+		if (isflagset(FLAG_ACC)) {
+			$account = "yes";
+			setavpflag($account, "dialog_cookie");
+		}
+
+		record_route();
+	}
+}
+
+route[DOMAIN]
+{
+	# check if the caller is from a local domain
+	lookup_domain("$fd", "@from.uri.host");
+
+	# check if the callee is at a local domain [presence: we can not use @ruri
+	# here because in consequent SUBSCRIBEs will be there our IP and not the
+	# domain]
+	lookup_domain("$td", "@to.uri.host");
+
+	# we dont know the domain of the caller and also not
+	# the domain of the callee -> somone uses our proxy as
+	# a relay
+	if (!$t.did && !$f.did) {
+		sl_send_reply("403", "Relaying Forbidden");
+		drop;
+	}
+}
+
+route[REGISTRAR]
+{
+	# if the request is a REGISTER lets take care of it
+	if (method=="REGISTER") {
+		# check if the REGISTER if for one of our local domains
+		if (!$t.did) {
+			sl_send_reply("403", "Register forwarding forbidden");
+			drop;
+		}
+
+		# we want only authenticated users to be registered
+#		if (!www_authenticate("$fd.digest_realm", "credentials")) {
+#			if ($? == -2) {
+#				sl_send_reply("500", "Internal Server Error");
+#			} else if ($? == -3) {
+#				sl_send_reply("400", "Bad Request");
+#			} else {
+#				if ($digest_challenge) {
+#					append_to_reply("%$digest_challenge");
+#				}
+#				sl_send_reply("401", "Unauthorized");
+#			}
+#			drop;
+#		};
+
+		# check if the authenticated user is the same as the target user
+		if (!lookup_user("$tu.uid", "@to.uri")) {
+			sl_send_reply("404", "Unknown user in To");
+			drop;
+		}
+
+		if ($f.uid != $t.uid) {
+			sl_send_reply("403", "Authentication and To-Header mismatch");
+			drop;
+		}
+
+		# check if the authenticated user is the same as the request originator
+		# you may uncomment it if you care, what uri is in From header
+		#if (!lookup_user("$fu.uid", "@from.uri")) {
+		#	sl_send_reply("404", "Unknown user in From");
+		#	drop;
+		#}
+		#if ($fu.uid != $tu.uid) {
+		#	sl_send_reply("403", "Authentication and From-Header mismatch");
+		#	drop;
+		#}
+
+		# everyhting is fine so lets store the binding
+		save_contacts("location");
+		drop;
+	};
+}
+
+route[AUTHENTICATION]
+{
+	if (method=="CANCEL" || method=="ACK") {
+		# you are not allowed to challenge these methods
+		break;
+	}
+
+	# requests from non-local to local domains should be permitted
+	# remove this if you want a walled garden
+	if (! $f.did) {
+		break;
+	}
+
+	# as gateways are usually not able to authenticate for their
+	# requests you will have trust them base on some other information
+	# like the source IP address. WARNING: if at all this is only safe
+	# in a local network!!!
+	#if (src_ip==a.b.c.d) {
+	#	break;
+	#}
+
+	if (!proxy_authenticate("$fd.digest_realm", "credentials")) {
+		if ($? == -2) {
+			sl_send_reply("500", "Internal Server Error");
+		} else if ($? == -3) {
+			sl_send_reply("400", "Bad Request");
+		} else {
+			if ($digest_challenge) {
+				append_to_reply("%$digest_challenge");
+			}
+			sl_send_reply("407", "Proxy Authentication Required");
+		}
+		drop;
+	}
+
+	# check if the UID from the authentication meets the From header
+	$authuid = $uid;
+	if (!lookup_user("$fu.uid", "@from.uri")) {
+		del_attr("$uid");
+	}
+	if ($fu.uid != $fr.authuid) {
+		sl_send_reply("403", "Fake Identity");
+		drop;
+	}
+	# load the user AVPs (preferences) of the caller, e.g. for RPID header
+	load_attrs("$fu", "$f.uid");
+}
+
+route[OUTBOUND]
+{
+	# if a local user calls to a foreign domain we play outbound proxy for him
+	# comment this out if you want a walled garden
+	if ($f.did && ! $t.did) {
+		append_hf("P-hint: outbound\r\n");
+		route(FORWARD);
+	}
+}
+
+route[INBOUND]
+{
+	# lets see if know the callee
+	if (lookup_user("$tu.uid", "@ruri")) {
+
+		# load the preferences of the callee to have his timeout values loaded
+		load_attrs("$tu", "$t.uid");
+
+		# if you want to know if the callee username was an alias
+		# check it like this
+		#if (! $tu.uri_canonical) {
+			# if the alias URI has different AVPs/preferences
+			# you can load them into the URI track like this
+			#load_attrs("$tr", "@ruri");
+		#}
+
+		# native SIP destinations are handled using our USRLOC DB
+		if (lookup_contacts("location")) {
+			append_hf("P-hint: usrloc applied\r\n");
+
+			# we set the TM module timers according to the prefences
+			# of the callee (avoid too long ringing of his phones)
+			# Note1: timer values have to be in ms now!
+			# Note2: this makes even more sense if you switch to a voicemail
+			#        in a FAILURE route
+			if ($t.fr_inv_timer) {
+				if ($t.fr_timer) {
+					t_set_fr("$t.fr_inv_timer", "$t.fr_timer");
+				} else {
+					t_set_fr("$t.fr_inv_timer");
+				}
+			}
+
+			route(FORWARD);
+		} else {
+			sl_send_reply("480", "User temporarily not available");
+			drop;
+		}
+	};
+}
+
+route[PSTN]
+{
+	# Only if the AVP 'gw_ip' is set and the request URI contains
+	# only a number we consider sending this to the PSTN GW.
+	# Only users from a local domain are permitted to make calls.
+	# Additionally you might want to check the acl AVP to verify
+	# that the user is allowed to make such expensives calls.
+	if ($f.did && $gw_ip &&
+		uri=~"sips?:\+?[0-9]{3,18}@.*") {
+		# probably you need to convert the number in the request
+		# URI according to the requirements of your gateway here
+
+		# if an AVP 'asserted_id' is set we insert an RPID header
+		if ($asserted_id) {
+			xlset_attr("$rpidheader", "<sip:%$asserted_id@%@ruri.host>;screen=yes");
+			replace_attr_hf("Remote-Party-ID", "$rpidheader");
+		}
+
+		# just replace the domain part of the RURI with the
+		# value from the AVP and send it out
+		attr2uri("$gw_ip", "domain");
+		route(FORWARD);
+	}
+}
+
+route[PRES_AUTHENTICATE]
+{
+	# we want only authenticated users to be registered
+	if (!www_authenticate("$fd.digest_realm", "credentials")) {
+		if ($? == -2) {
+			sl_send_reply("500", "Internal Server Error");
+		} else if ($? == -3) {
+			sl_send_reply("400", "Bad Request");
+		} else {
+			if ($digest_challenge) {
+				append_to_reply("%$digest_challenge");
+			}
+			sl_send_reply("401", "Unauthorized");
+		}
+		drop;
+	};
+
+	# check if the UID from the authentication meets the From header
+	$authuid = $uid;
+	if (!lookup_user("$fu.uid", "@from.uri")) {
+		del_attr("$uid");
+	}
+	if ($fu.uid != $fr.authuid) {
+		sl_send_reply("403", "Fake Identity");
+		drop;
+	}
+}
+
+route[RLS]
+{
+	# to be done ... ;-)
+	break;
+}
+
+route[PRESENCE]
+{
+	# if the request is one of presence messages lets take care of it
+	if (!((method=="SUBSCRIBE") || (method=="PUBLISH"))) {
+		# it is not presence related message let it be
+		break;
+	}
+
+	# check if the request is for one of our local domains
+	if (!$t.did) {
+		xlog("L_ERR", "Unknown domain in presence related message\n");
+		sl_send_reply("403", "Will not forward presence");
+		drop;
+	}
+
+	# authenticate the user in From using www_authenticate
+	# route(PRES_AUTHENTICATE);
+
+	if (!t_newtran()) {
+		sl_send_reply("500", "Internal error (t_newtran)");
+		drop;
+	}
+
+	if (!lookup_user("$tu.uid", "@to.uri")) {
+		if (method=="SUBSCRIBE") {
+			# SUBSCRIBE to nonexisting user -> try to handle it
+			# with RLS
+			route(RLS);
+		}
+
+		t_reply("404", "Unknown user in To");
+		drop;
+	}
+
+	if (method=="SUBSCRIBE") {
+		handle_subscription("registrar");
+	}
+	if (method=="PUBLISH") {
+		handle_publish("registrar");
+	}
+
+	drop;
+}

+ 7 - 1
doc/presence/draft_iptel_im_rules.xml

@@ -36,7 +36,13 @@ type of common policy documents defined there - application/auth-policy+xml.
 </para>
 
 <para>All XML elements designed in this document belong to 
-<quote>urn:iptel:xml:ns:im-rules</quote> namespace.</para>
+<quote>urn:iptel:xml:ns:im-rules</quote> namespace.
+<note>
+<para>This namespace breaks conventions mentioned in the document which was used
+as source but it will stay here due to compatibility reasons if there will be no
+problems with it.</para>
+</note>
+</para>
 
 <section><title>Conditions</title>
 <para>Conditions are processed according specification in <xref linkend="common_auth"/>.

+ 16 - 694
doc/presence/examples.xml

@@ -4,700 +4,28 @@
 
 <section><title>Examples</title>
 
-<section><title>Database initialization</title>
-<para>Database needed for SER can ge created using script located in source tree
-in <filename>scripts</filename> directory. There are some directories for some DB
-systems (mysql, postgres). In these directories is located database creation SQL
-script and for some databases is there a shell script which creates or destroys
-the database using tools (like <application>mysql</application> for MySQL).
+<para>This section is under construction...
 </para>
-<example><title>database creation</title>
-<screen>kubartv@~/src/sip_router$ cd scripts/mysql
-kubartv@~/src/sip_router/scripts/mysql$ ./ser_mysql.sh create
-Enter password for MySQL user root (hit enter for no password): 
-Creating SER database
-</screen>
-</example>
-
-<para>Created database can be filled with data using
-<application>serctl</application> (set of commandline utilities). It is located
-in source tree in <filename>tools/serctl</filename> directory. All serctl
-programs show help if running without any arguments. For more information about
-them look on their documentation.</para>
-<example><title>data initialization</title>
-<screen>kubartv@~/src/sip_router$ cd tools/serctl
 
-kubartv@~/src/sip_router/tools/serctl$ ./ser_domain add test-domain.com test
-kubartv@~/src/sip_router/tools/serctl$ ./ser_user add smith
-kubartv@~/src/sip_router/tools/serctl$ ./ser_user change smith -F +sft
-kubartv@~/src/sip_router/tools/serctl$ ./ser_uri add [email protected] smith
-kubartv@~/src/sip_router/tools/serctl$ ./ser_cred add smith test-domain.com smith heslo
-</screen>
-<para>This sequence of commands adds new domain with URI
-<quote>test-domain.com</quote> and user <quote>smith</quote> with password
-<quote>heslo</quote> in it.
+<para>I found a bug during testing sample configs - one TM module change caused
+impossibility of sending request to predefined destination. As far as I know
+affected modules are presence_b2b and msilo.
 </para>
-</example>
-</section>
-
-<section><title>Configuration without database</title>
-<para>There is a sample config file containing simple usage of PA and RLS
-module without database. It does MESSAGE authorization and handles subscriptions
-to resource lists and to standalone users.</para>
-<example><title>without database</title>
-<programlisting><![CDATA[
-debug=3         # debug level (cmd line: -dddddddddd)
-
-check_via=no	# (cmd. line: -v)
-dns=no           # (cmd. line: -r)
-rev_dns=no      # (cmd. line: -R)
-port=5060
-children=2
-alias="test-domain.com"
-
-mhomed=yes  # usefull for multihomed hosts, small performance penalty
-
-#tcp_accept_aliases=yes # accepts the tcp alias via option (see NEWS)
-#tcp_poll_method="sigio_rt"
-
-# ------------------ module loading ----------------------------------
-
-loadmodule "/usr/lib/ser/modules/xcap.so"
-loadmodule "/usr/lib/ser/modules/sl.so"
-loadmodule "/usr/lib/ser/modules/avp.so"
-loadmodule "/usr/lib/ser/modules/avpops.so"
-loadmodule "/usr/lib/ser/modules/tm.so"
-loadmodule "/usr/lib/ser/modules/rr.so"
-loadmodule "/usr/lib/ser/modules/maxfwd.so"
-loadmodule "/usr/lib/ser/modules/usrloc.so"
-loadmodule "/usr/lib/ser/modules/registrar.so"
-loadmodule "/usr/lib/ser/modules/textops.so"
-loadmodule "/usr/lib/ser/modules/dialog.so"
-loadmodule "/usr/lib/ser/modules/rls.so"
-loadmodule "/usr/lib/ser/modules/pa.so"
-loadmodule "/usr/lib/ser/modules/presence_b2b.so"
-loadmodule "/usr/lib/ser/modules/uri.so"
-loadmodule "/usr/lib/ser/modules/fifo.so"
-loadmodule "/usr/lib/ser/modules/xmlrpc.so"
-loadmodule "/usr/lib/ser/modules/xlog.so"
-
-# ----------------- setting module-specific parameters ---------------
-
-# add value to ;lr param to make some broken UAs happy
-modparam("rr", "enable_full_lr", 1)
 
-modparam("rls", "min_expiration", 120)
-modparam("rls", "max_expiration", 120)
-modparam("rls", "default_expiration", 120)
-modparam("rls", "auth", "none")
-modparam("rls", "xcap_root", "http://localhost/xcap")
-modparam("rls", "reduce_xcap_needs", 1)
-modparam("rls", "db_mode", 0)
-# modparam("rls", "db_url", "mysql://ser:[email protected]:3306/ser")
-
-modparam("pa", "use_db", 0)
-modparam("pa", "offline_winfo_timer", 600)
-modparam("pa", "offline_winfo_expiration", 600)
-# modparam("pa", "db_url", "mysql://ser:[email protected]:3306/ser")
-# mode of PA authorization: none, implicit or xcap
-modparam("pa", "auth", "xcap")
-modparam("pa", "auth_xcap_root", "http://localhost/xcap")
-modparam("pa", "winfo_auth", "none")
-modparam("pa", "use_callbacks", 1)
-modparam("pa", "accept_internal_subscriptions", 0)
-modparam("pa", "max_subscription_expiration", 120)
-modparam("pa", "timer_interval", 1)
-
-modparam("presence_b2b", "presence_route", "<sip:127.0.0.1;lr>")
-# modparam("presence_b2b", "presence_route", "<sip:127.0.0.1;transport=tcp;lr>")
-modparam("presence_b2b", "on_error_retry_time", 60)
-modparam("presence_b2b", "wait_for_term_notify", 33)
-modparam("presence_b2b", "resubscribe_delta", 30)
-modparam("presence_b2b", "min_resubscribe_time", 60)
-modparam("presence_b2b", "default_expiration", 3600)
-modparam("presence_b2b", "handle_presence_subscriptions", 1)
-
-modparam("usrloc", "db_mode", 0)
-# modparam("domain|uri_db|acc|auth_db|usrloc|msilo", "db_url", "mysql://ser:[email protected]:3306/ser")
-
-modparam("fifo", "fifo_file", "/tmp/ser_fifo")
-
-# -------------------------  request routing logic -------------------
-
-# main routing logic
-
-route{
-	# XML RPC
-	if (method == "POST" ||  method == "GET") {
-		create_via();
-		dispatch_rpc();
-		break;
-	}
-
-	# initial sanity checks -- messages with
-	# max_forwards==0, or excessively long requests
-	if (!mf_process_maxfwd_header("10")) {
-		sl_send_reply("483","Too Many Hops");
-		break;
-	};
-	if (msg:len >=  max_len ) {
-		sl_send_reply("513", "Message too big");
-		break;
-	};
-	
-	# we record-route all messages -- to make sure that
-	# subsequent messages will go through our proxy; that's
-	# particularly good if upstream and downstream entities
-	# use different transport protocol
-	if (!method=="REGISTER") record_route();	
-
-	# subsequent messages withing a dialog should take the
-	# path determined by record-routing
-	if (loose_route()) {
-		# mark routing logic in request
-		append_hf("P-hint: rr-enforced\r\n"); 
-		route(1);
-		break;
-	};
-
-	if (uri==myself) {
-	
-		if (method=="SUBSCRIBE") {
-			if (!t_newtran()) {
-				sl_reply_error();
-				break;
-			};
-			
-			# new subscription
-			if (@to.tag=="") { 
-				if ((@msg.supported=~"eventlist")) {
-					# Supported header field
-					#    -> may be RLS subscription
-
-					if (is_simple_rls_target("$uid-list")) {
-						# log(1, "it is simple subscription!\n");
-						# handle_rls_subscription("1");
-						# takes From UID and makes XCAP query
-						# for user's list named "default"
-						if (@to.tag=="") { 
-							# only for new subscriptions (with empty to tag
-							if (!query_resource_list("default")) {
-								t_reply("500", "XCAP query error");
-								break;
-							}
-						}
-					}
-					
-					if (!have_flat_list()) {
-						# query_resource_list failed or was not called
-						# do standard RLS query acording to To/AOR
-						query_rls_services();
-					}
-					
-					if (have_flat_list()) {
-						handle_rls_subscription("1");
-						break;
-					}
-				}
-					
-				# SUBSCRIBE to existing user
-				# xlog("L_ERR", "PA: handling subscription: %tu from: %fu\n");
-				handle_subscription("registrar");
-				
-				break;
-			}
-			else { # renewal subscription
-				if (!handle_rls_subscription("0")) {
-					lookup_user("To");
-					handle_subscription("registrar");
-				}
-				break;
-			}
-			
-		}
-
-		if (method=="REGISTER") {
-			save("location");
-			break;
-		};
-		
-			
-		if (method=="PUBLISH") {
-			if (!t_newtran()) {
-			   sl_reply_error();
-			   break;
-			};
-			handle_publish("registrar");
-			break;
-		};
-		
- 		if (method=="NOTIFY") {
- 			if (!t_newtran()) {
- 			   log(1, "newtran error\n");
- 			   sl_reply_error();
-			   break;
- 			};
- 			if (!handle_notify()) {
- 				t_reply("481", "Unable to handle notification");
- 			}
- 			break;
- 		};
-	
-		# message authorization
-		if (method=="MESSAGE") {
-			log(1, "MESSAGE authorization\n");
-			if (!authorize_message("http://localhost/xcap")) {
-				sl_reply("403", "Forbidden");
-				break;
-			}
-		}
-	
-		# native SIP destinations are handled using our USRLOC DB
-		if (!lookup("location")) {
-			sl_send_reply("404", "Not Found");
-			break;
-		};
-	};
-#	append_hf("P-hint: usrloc applied\r\n"); 
-	route(1);
-}
-
-route[1] 
-{
-	# send it out now; use stateful forwarding as it works reliably
-	# even for UDP2TCP
-	if (!t_relay()) {
-		sl_reply_error();
-	};
-}
-]]>
-</programlisting>
-</example>
-</section>
-
-<section><title>Full configuration with database</title>
-<para>There is a sample config file containing full usage of presence modules.
-It does MESSAGE authorization, stores MESSAGEs for offline users, stores
-<quote>pending</quote> subscriptions when presentity is offline and dumps them,
-after presentity subscribes to its watcherinfo.</para>
-<para>If you want to authenticate SUBSCRIBE request you can uncomment marked code in
-configuration. In this case only first SUBSCRIBE request to resource list URI
-will be authenticated. It is due to that subscriptions created internaly from
-RLS module are NOT able to authenticate the user.
+<section><title>Full presence server</title>
+<para>This config file has grown from previous versions of presence server
+configurations. It has to be re-tested with Ottendorf and de-uglyfied. (TBD soon)
 </para>
-<para>You can uncomment authentication in handling REGISTER - in this case will
-be needed password for registration. You can put that piece of code into
-handling PUBLISH or MESSAGE for their authentication too.
+<para><ulink url="cfg/full_ps.cfg">cfg/full_ps.cfg</ulink>
 </para>
-<para>To have this configuration working you have to have initialized database
-with presence tables, silo, domain, etc.
-</para>
-<example><title>Full configuration</title>
-<programlisting><![CDATA[
-debug=3         # debug level (cmd line: -dddddddddd)
-check_via=no	# (cmd. line: -v)
-dns=no           # (cmd. line: -r)
-rev_dns=no      # (cmd. line: -R)
-port=5060
-children=2
-alias="test-domain.com"
-mhomed=yes  # usefull for multihomed hosts, small performance penalty
-#tcp_accept_aliases=yes # accepts the tcp alias via option (see NEWS)
-#tcp_poll_method="sigio_rt"
-
-# ------------------ module loading ----------------------------------
-
-loadmodule "/usr/lib/ser/modules/xcap.so"
-loadmodule "/usr/lib/ser/modules/sl.so"
-loadmodule "/usr/lib/ser/modules/avp.so"
-loadmodule "/usr/lib/ser/modules/avpops.so"
-loadmodule "/usr/lib/ser/modules/tm.so"
-loadmodule "/usr/lib/ser/modules/rr.so"
-loadmodule "/usr/lib/ser/modules/maxfwd.so"
-loadmodule "/usr/lib/ser/modules/usrloc.so"
-loadmodule "/usr/lib/ser/modules/registrar.so"
-loadmodule "/usr/lib/ser/modules/textops.so"
-loadmodule "/usr/lib/ser/modules/mysql.so"
-loadmodule "/usr/lib/ser/modules/dialog.so"
-loadmodule "/usr/lib/ser/modules/rls.so"
-loadmodule "/usr/lib/ser/modules/pa.so"
-loadmodule "/usr/lib/ser/modules/presence_b2b.so"
-loadmodule "/usr/lib/ser/modules/uri.so"
-loadmodule "/usr/lib/ser/modules/uri_db.so"
-loadmodule "/usr/lib/ser/modules/domain.so"
-loadmodule "/usr/lib/ser/modules/fifo.so"
-loadmodule "/usr/lib/ser/modules/xmlrpc.so"
-loadmodule "/usr/lib/ser/modules/xlog.so"
-#loadmodule "/usr/lib/ser/modules/unixsock.so"
-loadmodule "/usr/lib/ser/modules/msilo.so"
-
-# Uncomment this if you want digest authentication
-# mysql.so must be loaded !
-loadmodule "/usr/lib/ser/modules/auth.so"
-loadmodule "/usr/lib/ser/modules/auth_db.so"
-
-# ----------------- setting module-specific parameters ---------------
-
-# modparam("msilo","registrar","sip:[email protected]")
-modparam("msilo","use_contact",0)
-modparam("msilo","expire_time",7200)
-
-# -- usrloc params --
-
-# -- auth params --
-# Uncomment if you are using auth module
-#
-modparam("auth_db", "calculate_ha1", yes)
-#
-# If you set "calculate_ha1" parameter to yes (which true in this config), 
-# uncomment also the following parameter)
-#
-modparam("auth_db", "password_column", "password")
-
-# -- rr params --
-# add value to ;lr param to make some broken UAs happy
-modparam("rr", "enable_full_lr", 1)
-
-modparam("rls", "min_expiration", 200)
-modparam("rls", "max_expiration", 300)
-modparam("rls", "default_expiration", 300)
-modparam("rls", "auth", "none")
-modparam("rls", "xcap_root", "http://localhost/xcap")
-modparam("rls", "reduce_xcap_needs", 1)
-modparam("rls", "db_mode", 0)
-modparam("rls", "db_url", "mysql://ser:heslo@localhost:3306/ser")
-
-modparam("pa", "use_db", 0)
-# allow storing authorization requests for offline users into database
-modparam("pa", "use_offline_winfo", 1)
-# how often try to remove old stored authorization requests
-modparam("pa", "offline_winfo_timer", 600)
-# how long stored authorization requests live
-modparam("pa", "offline_winfo_expiration", 600)
-modparam("pa", "db_url", "mysql://ser:heslo@localhost:3306/ser")
-# mode of PA authorization: none, implicit or xcap
-modparam("pa", "auth", "xcap")
-modparam("pa", "auth_xcap_root", "http://localhost/xcap")
-# do not authorize watcherinfo subscriptions
-modparam("pa", "winfo_auth", "none")
-# use only published information if set to 0
-modparam("pa", "use_callbacks", 1)
-# don't accept internal subscriptions from RLS, ...
-modparam("pa", "accept_internal_subscriptions", 0)
-# maximum value of Expires for subscriptions
-modparam("pa", "max_subscription_expiration", 600)
-# maximum value of Expires for publications
-modparam("pa", "max_publish_expiration", 120)
-# how often test if something changes and send NOTIFY
-modparam("pa", "timer_interval", 10)
-
-# route for generated SUBSCRIBE requests for presence
-modparam("presence_b2b", "presence_route", "<sip:127.0.0.1;transport=tcp;lr>")
-# waiting time from error to new attepmt about SUBSCRIBE
-modparam("presence_b2b", "on_error_retry_time", 60)
-# how long wait for NOTIFY with Subscription-Status=terminated after unsubscribe
-modparam("presence_b2b", "wait_for_term_notify", 33)
-# how long before expiration send renewal SUBSCRIBE request
-modparam("presence_b2b", "resubscribe_delta", 30)
-# minimal time to send renewal SUBSCRIBE request from receiving previous response
-modparam("presence_b2b", "min_resubscribe_time", 60)
-# default expiration timeout
-modparam("presence_b2b", "default_expiration", 3600)
-# process internal subscriptions to presence events
-modparam("presence_b2b", "handle_presence_subscriptions", 1)
-
-modparam("usrloc", "db_mode", 0)
-modparam("domain", "db_mode", 1)
-modparam("domain|uri_db|acc|auth_db|usrloc|msilo", "db_url", "mysql://ser:heslo@localhost:3306/ser")
-
-modparam("fifo", "fifo_file", "/tmp/ser_fifo")
-
-# -------------------------  request routing logic -------------------
-
-# main routing logic
-
-route{
-	# XML RPC
-	if (method == "POST" ||  method == "GET") {
-		create_via();
-		dispatch_rpc();
-		break;
-	}
-
-	# initial sanity checks -- messages with
-	# max_forwards==0, or excessively long requests
-	if (!mf_process_maxfwd_header("10")) {
-		sl_send_reply("483","Too Many Hops");
-		break;
-	};
-	if (msg:len >=  max_len ) {
-		sl_send_reply("513", "Message too big");
-		break;
-	};
-	
-	# we record-route all messages -- to make sure that
-	# subsequent messages will go through our proxy; that's
-	# particularly good if upstream and downstream entities
-	# use different transport protocol
-	if (!method=="REGISTER") record_route();	
-
-	# subsequent messages withing a dialog should take the
-	# path determined by record-routing
-	if (loose_route()) {
-		# mark routing logic in request
-		append_hf("P-hint: rr-enforced\r\n"); 
-		route(1);
-		break;
-	};
-
-	# if the request is for other domain use UsrLoc
-	# (in case, it does not work, use the following command
-	# with proper names and addresses in it)
-	if (uri==myself) {
-	
-		if (!lookup_domain("To")) {
-			xlog("L_ERR", "Unknown domain to: %tu from: %fu\n");
-			route(1);
-			break;
-		}
-		
-		if (method=="SUBSCRIBE") {
-			if (!t_newtran()) {
-				sl_reply_error();
-				break;
-			};
-			
-			if (@to.tag=="") { 
-				# only for new subscriptions (with empty to tag)
-
-				if (lookup_user("To")) {
-					# existing user -> it is subscription to PA
-					if (handle_subscription("registrar")) {
-						if ((@msg.event=~"presence\.winfo")) {
-							# new watcher info subscription
-							# sends one watcher info NOTIFY message with all saved authorization requests
-							xlog("L_ERR", "dumping stored winfo to %fu\n");
-							dump_stored_winfo("registrar", "presence");
-						}
-						else {
-							# new presence subscription
-							if ((@msg.event=~"presence") &&	(check_subscription_status("pending"))) {
-								# if offline user and new pending subscription 
-								if (!target_online("registrar")) {
-									xlog("L_ERR", "storing 'pending' winfo to: %tu, from: %fu\n");
-									store_winfo("registrar");
-								}
-							}
-						}
-					}
-					break;
-				}
-				
-				if ((@msg.supported=~"eventlist")) {
-					# such user doesn't exist and Supported header field
-					#    -> probably RLS subscription
-				
-					if (lookup_domain("From")) {
-						if (lookup_user("From")) {
-							if (is_simple_rls_target("$uid-list")) {
-								# log(1, "it is simple subscription!\n");
-								# takes From UID and makes XCAP query for user's 
-								# list named "default"
-								if (!query_resource_list("default")) {
-									t_reply("404", "No such user list");
-									break;
-								}
-							}
-						}
-					}
-				
-					if (!have_flat_list()) {
-						# query_resource_list failed or was not called
-						# do standard RLS query acording to To/AOR
-						if (!query_rls_services()) {
-							log(1, "XCAP query failed\n");
-							t_reply("404", "No such list URI");
-							break;
-						}
-					}
-					
-					# uncomment this if you want authenticate first SUBSCRIBE request to resource list
-#					if (!proxy_authenticate("test-domain.com", "credentials")) {
-#						proxy_challenge( "test-domain.com", "0");
-#						break;
-#					};	
-				
-					handle_rls_subscription("1");
-				}
-				else {
-					# not resource list subscription -> invalid user
-					xlog("L_ERR", "subscription to invalid user %tu\n");
-					t_reply("404", "User not found");
-				}
-				
-				break;
-			}
-			else {
-				# renewal subscriptions - try to handle it as RLS and if failed, handle it as PA subscription
-				# FIXME: better will be test like existing_rls_subscription() 
-				#        and existing_subscription("registrar")
-				if (!handle_rls_subscription("0")) {
-					lookup_user("To");
-					handle_subscription("registrar");
-				}
-				break;
-			}
-		};
-
-		# get user (common for all other messages than SUBSCRIBE)
-		if (!lookup_user("To")) {
-			# log(1, "Unknown user - message should be forwarded?");
-#			# break;
-			append_hf("P-hint: unknown user\r\n"); 
-			route(1);
-			break;
-		}
-		
-		if (method=="PUBLISH") {
-			if (!t_newtran()) {
-#			   log(1, "newtran error\n");
-			   sl_reply_error();
-			   break;
-			};
-			handle_publish("registrar");
-
-			# deliver messages to online user
-			# TODO: only if user goes from offline to online?
-			if (target_online("registrar")) {
-				# log(1, "Dumping stored messages\n");
-				# dump stored messages - route it through myself (otherwise routed via DNS!)
-				if (m_dump("sip:127.0.0.1")) {
-					xlog("L_ERR", "MSILO: offline messages for %fu dumped\n");
-				}
-			}
-
-			break;
-		};
-	
- 		if (method=="NOTIFY") {
- 			if (!t_newtran()) {
- 			   log(1, "newtran error\n");
- 			   sl_reply_error();
-			   break;
- 			};
-			# handle notification sent in internal subscriptions (presence_b2b)
- 			if (!handle_notify()) {
- 				t_reply("481", "Unable to handle notification");
- 			}
- 			break;
- 		};
-		
-		if (method=="MESSAGE") {
-
-			if (authorize_message("http://localhost/xcap")) {
-				
-				# use usrloc for delivery
-				if (lookup("location")) {
-				
-					log(1, "Delivering MESSAGE using usrloc\n");
-					t_on_failure("1");
-					if (!t_relay()) {
-						sl_reply_error();
-					}
-					
-					break;
-				}
-				else {
-					# store messages for offline user
-					xlog("L_ERR", "MSILO: storing MESSAGE for %tu\n");
-					
-					if (!t_newtran()) {
-					   log(1, "newtran error\n");
-					   sl_reply_error();
-					   break;
-					};
-
-					# store only text messages NOT isComposing... !
-					if (search("^(Content-Type|c):.*application/im-iscomposing\+xml.*")) {
-						log(1, "it is only isComposing message - ignored\n");
-						t_reply("202", "Ignored");
-						break;
-					}
-					
-					if (m_store("0", "sip:127.0.0.1")) {
-						# log(1, "MSILO: offline message stored\n");
-						if (!t_reply("202", "Accepted")) {
-							sl_reply_error();
-						};
-					} else {
-						log(1, "MSILO: error storing offline message\n");
-						if (!t_reply("503", "Service Unavailable")) {
-							sl_reply_error();
-						};
-					};
-					break;
-				}
-				break;
-			}
-			else {
-				# log(1, "unauthorized message\n");
-				sl_reply("403", "Forbidden");
-			}
-			break;
-		}
-		
-		if (method=="REGISTER") {
-			# uncomment this if you want authenticate REGISTER request
-#			if (!www_authenticate("test-domain.com", "credentials")) {
-#				www_challenge( "test-domain.com", "0");
-#				break;
-#			};
-		
-			save("location");
-			
-			# dump stored messages - route it through myself (otherwise routed via DNS!)
-			if (m_dump("sip:127.0.0.1")) {
-				xlog("L_ERR", "MSILO: offline messages for %fu dumped\n");
-			}
-			break;
-		};
-
-		# native SIP destinations are handled using our USRLOC DB
-		if (!lookup("location")) {
-			sl_send_reply("404", "Not Found");
-			break;
-		};
-	};
-#	append_hf("P-hint: usrloc applied\r\n"); 
-	route(1);
-}
-
-route[1] 
-{
-	# send it out now; use stateful forwarding as it works reliably
-	# even for UDP2TCP
-	if (!t_relay()) {
-		sl_reply_error();
-	};
-}
-
+</section>
 
-failure_route[1] {
-	# forwarding failed -- check if the request was a MESSAGE
-	if (!method=="MESSAGE") { break; };
-	log(1, "MSILO: MESSAGE forward failed - storing it\n");
-	
-	# we have changed the R-URI with the contact address, ignore it now
-	if (m_store("0", "")) {
-		t_reply("202", "Accepted");
-	} else {
-		log(1, "MSILO: offline message NOT stored\n");
-		t_reply("503", "Service Unavailable");
-	};
-}
-]]>
-</programlisting>
-</example>
+<section><title>Presence server with no authorization and without RLS</title>
+<para>Following config file is based on demo config file installed with SER
+(Ottendorf). It
+is not finished yet. I recommend to use a variant of the config file above right
+now.</para>
+<para><ulink url="cfg/ps.cfg">cfg/ps.cfg</ulink></para>
 </section>
 
 <section><title>Forwarding to presence server</title>
@@ -713,12 +41,6 @@ use following piece of code for that. Instead of
 if ((method=="SUBSCRIBE") || (method=="PUBLISH") || (method=="MESSAGE")) {
 	log(1, "Forwarding request\n");
 	
-	# uncomment this if you want authenticate the request
-#	if (!proxy_authenticate("test-domain.com", "credentials")) {
-#		proxy_challenge( "test-domain.com", "0");
-#		break;
-#	};	
-	
 	if (!t_newtran()) {
 		log(1, "newtran error\n");
 		sl_reply_error();
@@ -727,7 +49,7 @@ if ((method=="SUBSCRIBE") || (method=="PUBLISH") || (method=="MESSAGE")) {
 	
 	if (!t_forward_nonack("presence-server.test-domain.com", "5060")) {
 		log(1, "Forward to presence server failed\n");
-		sl_reply_error();
+		t_reply("500", "forward to presence server failed");
 	}
 	break;
 };

+ 56 - 34
doc/presence/install.xml

@@ -39,48 +39,34 @@ on common libraries which have their own dependencies as mentioned below.
 with shared libraries into directory /base/ser/directory (if no directory specified - 
 no prefix parameter given - default value is used: /usr/local/)
 <orderedlist>
-	<listitem><para>Download current ser sources:</para>
+	<listitem><para>Download current SER sources:</para>
 	<para><userinput>cvs -d :pserver:[email protected]:/cvsroot/ser checkout sip_router</userinput>
 	</para></listitem>
+	
+	<listitem><para>Download very useful <application>ser_ctl</application> utility
+	(not necessary, but it is handy for adding data into database, running
+	XML-RPC functions etc):</para>
+	<para><userinput>cvs -d :pserver:[email protected]:/cvsroot/ser checkout serctl</userinput>
+	</para></listitem>
 
-	<listitem><para>Compile and install libraries for usage with SER:</para>
-	<para><userinput>cd sip_router/lib</userinput></para>
-	<para><userinput>make -f Makefile.ser install prefix=/base/ser/directory</userinput></para>
-	<para>This procedure may fail in the case of unsatisfied library
-	dependencies. You need to install all external libraries introduced in <xref
-	linkend="pres.dependencies"/></para>
-	</listitem>
-
-	<listitem><para>Compile and install SER with presence modules</para>
-	<para><userinput>cd ..</userinput></para>
-	<para><userinput>make install include_modules="dialog pa rls presence_b2b xcap mysql xmlrpc" prefix=/base/ser/directory</userinput></para>
+	<listitem><para>Compile and install SER with presence modules. Common
+	libraries should be compiled automaticaly - it may fail in the case of
+	unsatisfied library dependencies. You need to install all external libraries
+	introduced in <xref linkend="pres.dependencies"/></para>
+	<para><userinput>cd sip_router</userinput></para>
+	<para><userinput>make install group_include="standard,presence,standard-dep" prefix=/base/ser/directory</userinput></para>
 	</listitem>
 </orderedlist>
 </para>
 </section> <!-- Installation from CVS -->
 
-<section><title>Installation from presence-snapshot</title>
-
-<para>There are snapshots of sources from CVS named "presence snapshots" on our
-FTP server ftp://ftp.iptel.org/pub/ser/presence/.</para>
-
-<para>Presence snapshot contains example config files, has modified Makefiles for
-simplier compilation and installation and it is a bit tested for presence
-functions. Snapshot compiles only modules needed by presence!</para>
-
-<para>There is an example of steps which need to be done while installing SER
-from presence snapshot into directory /base/ser/directory (if no directory specified - 
-no prefix parameter given - default value is used: /usr/local/)
-<orderedlist>
-	<listitem><para>Download last versiom from
-	ftp://ftp.iptel.org/pub/ser/presence/</para></listitem>
-
-	<listitem><para>Compile and install</para>
-	<para><userinput>make install prefix=/base/ser/directory</userinput></para>
-	</listitem>
-</orderedlist>
+<section><title>Presence snapshots</title>
+<para>In past there were published <quote>presence snapshots</quote> with stable
+and tested code and up to date documentation. This will change - tested and
+documented stable features will be probably imported into stable SER branch
+(Ottendorf) and unstable ones will remain in CVS head.
 </para>
-</section> <!-- Installation from snapshot -->
+</section> <!-- snapshots -->
 
 <section><title>Running SER</title>
 <para>Linker used for dynamic linking must know, where to find these libraries.
@@ -90,7 +76,43 @@ startup.</para>
 <para><userinput>/base/ser/directory/sbin/ser -f /base/ser/directory/etc/ser/ser.cfg</userinput></para> 
 
 <warning>If you want to run SER under sudo like <quote>sudo /base/ser/directory/sbin/ser -f
-/base/ser/directory/etc/ser/ser.cfg</quote> it might not work!</warning>
+/base/ser/directory/etc/ser/ser.cfg</quote> it need not work - it is possible
+that LD_LIBRARY_PATH will not be propagated in this case!</warning>
 </section> <!-- running SER -->
 
+<section><title>Database initialization</title>
+<warning>
+<para>This paragraph can be out-of-dated by changes in DB init scripts or in
+ser_ctl. It has only informative value!</para>
+</warning>
+<para>It is very handy to use SER together with database - at least domains and
+users with attributes can be stored there. First must be database created -
+there are scripts to do this in SER's source tree in directory scripts; for
+example "scripts/mysql/ser_mysql.sh create" will create the database for MySQL.
+<note><para>Later MySQL versions can complain with current script, if so, you
+can try to remove qotes around $PW in script to get it into work.</para></note>
+</para>
+
+<para>After database creation you can add data using
+<application>ser_ctl</application> utility:
+<itemizedlist>
+	<listitem><para>add domain:</para>
+	<para><userinput>ser_domain add test test-domain.com</userinput></para></listitem>
+	<listitem><para>add user <quote>parf</quote> with password <quote>parf</quote>:</para>
+	<para><userinput>ser_user add parf</userinput></para>
+	<para><userinput>ser_uri add parf [email protected]</userinput></para>
+	<para><userinput>ser_cred add parf parf test test-domain.com parf</userinput></para>
+	</listitem>
+</itemizedlist>
+</para>
+
+<note>
+<para>Running ser_xxx without arguments shows help.</para>
+<para>You can specify database URI used by <application>ser_ctl</application>;
+for example you can use <quote>postgres://...</quote> instead of default
+<quote>mysql://...</quote> etc.</para>
+</note>
+
+</section>
+
 </section>

+ 84 - 3
doc/presence/intro.xml

@@ -1,13 +1,16 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <!DOCTYPE section PUBLIC '-//OASIS//DTD DocBook XML V4.2//EN'
-	'http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd'>
+	'http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd' [
+<!ENTITY % local.common.attrib "xml:base  CDATA  #IMPLIED"> 
+]>
 	
 <section><title>Introduction</title>
 <para>This document describes usage of SIP Express Router as a presence server.
 <!-- TODO: What is presence, ... (use doc from PIC-SE wiki?) -->
 </para>
-<para>Main features:
-<itemizedlist>
+
+<section><title>Main features</title>
+<para><itemizedlist>
 	<listitem><para>presence events with XCAP authorization and watcher info
 	support</para></listitem>
 	<listitem><para>resource list server (only for presence now)</para></listitem>
@@ -16,3 +19,81 @@
 </itemizedlist>
 </para>
 </section>
+		
+<section><title>SER presence basics</title>
+
+<para>Presence is one of quite important components of SER. It allows users to
+watch presence state of other users, process lists of them and manipulate one's 
+own presence state.</para>
+
+<para>Configuration data can be stored on a XCAP server <xref
+linkend="pres_draft_xcap"/> by user's client software and processed by SER. This
+may be useful for lists of watched users (resource lists) and for authorization
+rules.</para>
+
+<para>There is a few of modules which serve as parts of "presence":
+<itemizedlist>
+	<listitem><para><link linkend="pa">PA</link> acts as a presence
+	server. Its main function is processing of subscriptions to presence
+	state of standalone users and processing presence state publications for
+	them.</para></listitem>
+	<listitem><para><link linkend="pres_rls">RLS</link> - Resource list server - this
+	module processes subscriptions to lists of resources. It gets presence
+	information for standalone users from internal queries to PA module or
+	remote presence server queries and build them
+	together into list notifications.</para></listitem>
+	<listitem><para><link linkend="presence_b2b">PRESENCE_B2B</link> can be used
+	to subscribe to presence state on remote server. It can be used by RLS for
+	remote presence server queries.</para></listitem>
+	<listitem><para><link linkend="xcap_module">XCAP</link> offers internal functions
+	for querying XCAP server. <!-- TODO caching responses and monitoring changes
+	in documents stored on XCAP server. --></para></listitem>
+	<listitem><para><emphasis>DIALOG</emphasis> module is a helper module used
+	by other presence modules for some
+	dialog operations. It was intended to contain dialog management functions
+	but it was not finished.</para></listitem>
+<!--	<listitem><para><emphasis>RPA </emphasis>Reg events server. Will be used by
+	PA instead of direct callbacks into usrloc. Will be added
+	soon.</para></listitem>-->
+</itemizedlist>
+</para>
+
+<para>All <quote>presence</quote> modules share common code stored in SER
+libraries. Their interface is described in standalone documents.
+</para>
+
+<section><title>Persistence</title>
+<para>Modules can store their status (working data) into database. This data is
+automatically reloaded on startup, so it is possible to restart SER and
+clients don't note it. Established SIP dialogs are stored in database too.</para>
+<para>Details about database storage are described for each module separately in
+module documentation.
+
+<!-- TODO: db modes (cache mode) -->
+</para>
+</section>
+
+<section><title>Authorization</title>
+<para>Authorization is very important in presence services. The server
+must take care about authorization rules defined by user about whom and
+whom not allow access to user's presence status. More about authorization
+rules may be found in <xref linkend="pres_draft_common_auth"/> and 
+<xref linkend="pres_draft_auth"/>.</para>
+
+<!-- TODO: types of authorization common for all presence modules -->
+
+<para>Only XCAP storage of authorization rules is supported at this moment. It is 
+<emphasis>not fully implemented</emphasis> now - only basic rule conditions, no sphere 
+and time conditions. Transformations defined in <xref linkend="pres_draft_auth"/> are 
+ignored.
+May be, that in the
+future will be possible to use other variants like webdav or storing
+authorization rules in SER's own database.</para>
+
+<!-- TODO: XCAP module and authorization ? at least link into XCAP doc? -->
+
+</section>
+
+</section> <!-- presence basics -->
+
+</section> <!-- introduction -->

+ 0 - 68
doc/presence/presence.xml

@@ -1,68 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?>
-
-<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
-   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<section>
-<title>SER presence basics</title>
-
-<para>Presence is one of quite important components of SER. It allows users to
-watch presence state of other users, process lists of them and manipulate one's 
-own presence state.</para>
-
-<para>Configuration data can be stored on a XCAP server <xref
-linkend="pres_draft_xcap"/> by user's client software and processed by SER
-automaticaly. This may be useful for lists of watched users (resource lists) and
-for authorization rules.</para>
-
-<para>There is a few of modules which serve as parts of "presence".
-<itemizedlist>
-	<listitem><para><link linkend="pa">PA</link> This module acts as a presence
-	server - its main function is processing of subscriptions to presence
-	state and processing presence state publications.</para></listitem>
-	<listitem><para><link linkend="pres_rls">RLS</link> Resource list server - this
-	module processes subscriptions to lists of resources.</para></listitem>
-	<listitem><para><emphasis>RPA </emphasis>Reg events server. Will be used by
-	PA instead of direct callbacks into usrloc. Will be added
-	soon.</para></listitem>
-</itemizedlist>
-</para>
-
-<para>All <quote>presence</quote> modules share common code stored in SER
-libraries. Their interface is described in standalone documents.
-</para>
-
-<section><title>Persistence</title>
-<para>Modules can store their status (working data) into database. This data is
-automatically reloaded on startup, so it is possible to restart SER and
-clients don't note it. Established SIP dialogs are stored in database too.</para>
-<para>Details about database storage are described for each module separately in
-module documentation.
-</para>
-</section>
-
-<section><title>Authorization</title>
-<para>Authorization is one of important things in presence services. The server
-must take care about authorization rules defined by user about whom and
-whom not allow access to user's presence status. More about common authorization
-rules may be found in <xref linkend="pres_draft_common_auth"/> and 
-<xref linkend="pres_draft_auth"/>.</para>
-
-<!-- TODO: types of authorization common for all presence modules -->
-
-<para>Only XCAP storage of authorization rules is supported at this moment. It is 
-<emphasis>not fully implemented</emphasis> now - only basic rule conditions, no sphere 
-and time conditions. Transformations defined in <xref linkend="pres_draft_auth"/> are 
-ignored.
-May be, that in the
-future will be possible other variants like webdav or storing
-authorization rules in SER's own database.</para>
-
-<!-- TODO: examples of authorization documents with description of processing ! -->
-
-<para>Authorization settings may vary from module to module. It is in detail 
-described in documentation of individual modules.</para>
-</section>
-		
-</section>
-

+ 3 - 3
doc/presence/presence_book.xml

@@ -9,11 +9,12 @@ http://www.sagehill.net/docbookxsl/ValidXinclude.htm -->
 
 
 <article>
-	<title>SER presence handbook (v. 5) </title>
+	<title>SER presence handbook (v. Ottendorf.pre1) </title>
 	
 	<include xmlns="http://www.w3.org/2001/XInclude" href="intro.xml"/>
-	<include xmlns="http://www.w3.org/2001/XInclude" href="xcap.xml"/>
 	<include xmlns="http://www.w3.org/2001/XInclude" href="install.xml"/>
+	<include xmlns="http://www.w3.org/2001/XInclude" href="trouble.xml"/>
+	<include xmlns="http://www.w3.org/2001/XInclude" href="xcap.xml"/>
 <!--	<section><title>Presence modules</title> -->
 	<include xmlns="http://www.w3.org/2001/XInclude" href="../../modules/pa/doc/pa_incl.xml"/>
 	<include xmlns="http://www.w3.org/2001/XInclude" href="../../modules/rls/doc/rls_incl.xml"/>
@@ -33,7 +34,6 @@ href="../../modules/xcap/doc/xcap.xml"/> -->
 	
 <!--	<chapter id="pres"><title>Presence in SER</title>-->
 <!--
-		<include xmlns="http://www.w3.org/2001/XInclude" href="presence.xml"/>
 		<include xmlns="http://www.w3.org/2001/XInclude" href="install.xml"/>
 		<include xmlns="http://www.w3.org/2001/XInclude" href="../../modules/pa/doc/pa.xml"/>
 		<include xmlns="http://www.w3.org/2001/XInclude" href="../../modules/rls/doc/rls.xml"/>

+ 120 - 0
doc/presence/trouble.xml

@@ -0,0 +1,120 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!DOCTYPE section PUBLIC '-//OASIS//DTD DocBook XML V4.2//EN'
+	'http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd'>
+
+<section><title>Tracing of trouble</title>
+<para>Sometimes it is needed to solve problems with presence related stuff...
+;-)</para>
+
+<section><title>Known problems</title>
+<para>
+<itemizedlist>
+	<listitem><para>AVPs might not work properly with presence. If you create
+	AVPs they can disappear after call to handle_subscription or similar
+	function. The reason is that from such functions is created new transaction
+	(sent a NOTIFY request) and AVPs are not returned correctly to previous
+	one.</para></listitem>
+	<listitem><para>There are some standard
+	incompliances in presence modules, often caused by standard ambiguity
+	or contradiction or by partial implementation only. Please refer to specific
+	module documentation in such situations.</para></listitem>
+	<listitem><para>SIP clients often use broken data, not corresponding with
+	data format specification. Look into specification in such cases (for
+	example <xref linkend="pres_rfc_pidf"/>).</para></listitem>
+</itemizedlist>
+</para>
+</section>
+
+<section><title>Reporting problems</title>
+<para>If you can not find the source of your problem or if you are not sure how
+to do this or that, you can: 
+<itemizedlist>
+	<listitem><para>Try to search for similar problem in mailing lists on
+	<ulink url="http://www.iptel.org/listsearch">iptel's page</ulink> or in
+	<ulink url="http://lists.iptel.org/">list archives</ulink>.
+	</para></listitem>
+
+	<listitem><para>Send and email to <ulink
+	url="mailto:[email protected]">[email protected]</ulink> for
+	user related problem or
+	<ulink url="mailto:[email protected]">[email protected]</ulink>
+	for development related things. There are lots of interesting people on
+	these lists with
+	lots of experiences with SIP related stuff ;-).
+	</para></listitem>
+
+	<listitem><para>For presence-only related things you can send me an email
+	directly to [email protected], but I highly prefer to use one of
+	mailing lists above because many people may be interested in the same
+	problem you have.</para></listitem>
+</itemizedlist>
+</para>
+
+<para>If you find a bug, please report it to our <ulink
+url="http://tracker.iptel.org/browse/SER">bug tracker</ulink>
+or send an email to lists mentioned above or directly to me (email above).</para>
+
+</section>
+
+<section><title>New features</title>
+<para>There is a list of features to be implemented in my TODO list. I will put them
+into our bug tracker as soon as I will have more time for it. ;-)
+</para>
+
+<para>If you are interested in a feature you can search or ask in mailing lists
+or you can add your feature into bug tracker and might be that it will be
+implemented or at least discussed.
+</para>
+</section> <!-- new features -->
+
+<section><title>Searching a problem</title>
+<para>Most of presence modules have <quote>trace</quote> method which can be
+invoked through SER's XML-RPC interface. Such method often dumps current status,
+existing subscriptions etc.
+</para>
+
+<para>For calling XML-RPC methods you can simply use set of
+<application>ser_ctl</application> utilities (don't mess with deprecated serctl
+utility which is from unknown reason still installed with SER) or
+<application>binrpc</application> which uses more effective binary
+protocol.</para>
+
+<example id="searching_problem_trace">
+<title>Using ser_ctl for debugging problems</title>
+<para>
+<programlisting>
+<userinput>kubartv@~/src/serctl$ ./ser_rpc -t pa.trace 2</userinput>
+<![CDATA[+------------------------------------------------------------------------------------------------------------------------+
+| value                                                                                                                  |
++------------------------------------------------------------------------------------------------------------------------+
+| registrar                                                                                                              |
+| * sip:[email protected] (uid=parf)                                                                                  |
+|  - tuples:                                                                                                             |
+|     6574y1y45d334fay6e9d7c60 contact='sip:[email protected]:6198;transport=udp' exp=976014034 status=0 published=0 (id=) |
+|       notes:                                                                                                           |
+|       extension elements:                                                                                              |
+|       status extension elements:                                                                                       |
+|                                                                                                                        |
+|  - watchers:                                                                                                           |
+|  - winfo watchers:                                                                                                     |
+|     sip:[email protected] status=1 exp=3545                                                                         |
+|  - internal watchers:                                                                                                  |
+|  - notes:                                                                                                              |
+|  - extension elements:                                                                                                 |
+| * sip:[email protected] (uid=gozner)                                                                              |
+|  - tuples:                                                                                                             |
+|  - watchers:                                                                                                           |
+|     sip:[email protected] status=1 exp=3562                                                                         |
+|  - winfo watchers:                                                                                                     |
+|  - internal watchers:                                                                                                  |
+|  - notes:                                                                                                              |
+|  - extension elements:                                                                                                 |
+| presentity count: 2                                                                                                    |
++------------------------------------------------------------------------------------------------------------------------+
+]]></programlisting>
+</para>
+</example>
+
+</section>
+
+</section>

+ 1 - 1
doc/presence/xcap.xml

@@ -65,7 +65,7 @@ not much client software supporting it.
 
 <section id="xcap.examples"><title>XCAP examples</title>
 <note><para>XCAP documents examples published there doesn't use correct XML
-namespaces due to problems with XCAP server used for tests (probles querying
+namespaces due to problems with XCAP server used for tests (problems querying
 partial documents with namespaces).</para></note>
 
 <example><title>Storing XCAP documents</title>