Commit d4bb5ce1 authored by Pekka Pessi's avatar Pekka Pessi

sip: updated doxygen docs. Using aliased links to header groups like @Contact.

darcs-hash:20060914123747-65a35-2e517433f61e69013efdd56beac69abc71f72272.gz
parent e667cc38
/* -*- c -*- */
/**@mainpage SIP Parser, Messages and Headers
/**@MODULEPAGE "sip" - SIP Parser Module
*
* @section sip_meta Module Meta Information
*
......@@ -9,7 +9,7 @@
*
* @CONTACT Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @STATUS Core library
* @STATUS @SofiaSIP Core library
*
* @LICENSE LGPL
*
......@@ -18,21 +18,11 @@
* The structure of each header is defined in @b <sip.h>. In addition to the
* header structure, there is defined a @em header @em class structure and
* some standard functions for each header in the include file @b
* <sip_header.h>. For header @c X, there are types, functions, macros and
* header class as follows:
*
* - @c sip_X_t is the structure used to store parsed header,
* - @c SIP_X_INIT() initializes a static instance of sip_X_t,
* - @c sip_X_init() initializes a dynamic instance of sip_X_t,
* - @c sip_is_X() tests if header object is instance of header X,
* - @c sip_X_make() creates a header X object by decoding given string,
* - @c sip_X_format() creates a header X object by decoding given
* printf() list,
* - @c sip_X_dup() duplicates (deeply copies) the header X,
* - @c sip_X_copy() copies the header X,
* - @c sip_hclass_t @c sip_X_class[] contains the @em header @em class
* for header X.
*
* <sofia-sip/sip_header.h>. For header @c X, there are types, functions,
* macros and header class declared in <sofia-sip/sip_protos.h> and
* <sofia-sip/sip_hclass.h>. See @ref sip_header_x for detailed description
* of these header-specific boilerplate declarations.
*
* In addition to this interface, the @ref sip_parser "SIP parser documentation"
* contains description of the functionality required when a parser is
* extended by a new header. It is possible to add new headers to the SIP
......@@ -103,7 +93,7 @@
* key. There is also a special header class for @e unknown headers, headers
* with a name that is not regocnized by the parser.
*
* For instance, the From header has following syntax:
* For instance, the @From header has following syntax:
*
* @code
* from = ("From" | "f") ":"
......@@ -115,7 +105,7 @@
* tag-param = "tag" "=" ( token | quoted-string )
* @endcode
*
* When a From header is parsed, the header parser function sip_from_d()
* When a @From header is parsed, the header parser function sip_from_d()
* separates the @e display-name, @e addr-spec and each parameter in the @e
* addr-params list. The parsing result is assigned to a #sip_from_t
* structure, which is defined as follows:
......@@ -142,13 +132,14 @@
* It is not enough to represent a SIP message as a collection of headers
* following each other. The programmer also needs a convenient way to
* access certain headers at the SIP message level, for example, accessing
* directly the @b From header instead of going through all headers and
* directly the @From header instead of going through all headers and
* examining their name. The structured view to the SIP message is provided
* via a C struct with type #sip_t.
*
* In other words, a single message is represented by two types, first type
* (#msg_t) is private to the msg module and inaccessable by an application
* programmer, second (#sip_t) is a public structure.
* programmer, second (#sip_t) is a public structure containing the parsed
* headers.
*
* The #sip_t structure is defined as follows:
* @code
......@@ -164,10 +155,10 @@
* sip_request_t *sip_request; // Request line
* sip_status_t *sip_status; // Status line
*
* sip_via_t *sip_via; // Via (v)
* sip_route_t *sip_route; // Route
* sip_record_route_t *sip_record_route; // Record-Route
* sip_max_forwards_t *sip_max_forwards; // Max-Forwards
* sip_via_t *sip_via; // @Via (v)
* sip_route_t *sip_route; // @Route
* sip_record_route_t *sip_record_route; // @RecordRoute
* sip_max_forwards_t *sip_max_forwards; // @MaxForwards
* ...
* } sip_t;
* @endcode
......@@ -215,31 +206,25 @@
*
* The message object has link to the public message structure (@a
* m_object), to the dual-linked fragment chain (@a m_frags) and to the I/O
* buffer (@a m_buffer). The public message structure contains pointers to
* the headers according to their type. If there are multiple headers of
* the same type (like there are two Via headers in the above message), the
* headers are put into a single-linked list.
* buffer (@a m_buffer). The public message header structure contains
* pointers to the headers according to their type. If there are multiple
* headers of the same type (like there are two @Via headers in the above
* message), the headers are put into a single-linked list.
*
* Each fragment has pointers to successing and preceding fragment. It also
* contains pointer to the corresponding data within the I/O buffer and its
* length.
*
* The main purpose of the fragment chain is to preserve the original order
* of the headers. If there were an third Via header after CSeq in the
* message, the fragment representing it would be after the CSeq header in
* the fragment chain but after second Via in the header list.
* of the headers. If there were an third @Via header after @CSeq in the
* message, the fragment representing it would be after the @CSeq header in
* the fragment chain but after the second @Via in the header list.
*
* @}
*/
/**@defgroup sip_headers SIP Headers
*
* SIP headers and other SIP message elements.
*
* @{
*/
/**@page sip_header_x SIP Header Structure Conventions
*
* For each SIP header recognized by the SIP module, there is a header
* structure containing the parsed value. The header structure name is
......@@ -248,36 +233,89 @@
* characters, and then adding prefix @c sip_ and suffix @c _t. For
* instance, the contents of header "MIME-Version" is stored in a structure
* called sip_mime_version_t.
* All header structures contain the common part, a sip_common_t structure
* (@c X_common[]), a link to the next header in list (@c X_next), and a
* various fields describing the header value (in this case, @c X_value).
*
* @{
*/
/**
* @page sip_header_x SIP Header X - Conventions
*
* For a SIP header X, there types, functions, macros and global data
* declared in <sofia-sip/sip_protos.h> and <sofia-sip/sip_hclass.h> as
* follows:
* - #sip_X_t is the structure used to store parsed header,
* - SIP_X_INIT() initializes a static instance of #sip_X_t,
* - sip_X_init() initializes a dynamic instance of #sip_X_t,
* - sip_is_X() tests if header object is instance of header X,
* - sip_X_make() creates a header X object by decoding given string,
* - sip_X_format() creates a header X object by decoding given
* printf() list,
* - sip_X_dup() duplicates (deeply copies) the header X,
* - sip_X_copy() copies the header X,
* - #msg_hclass_t #sip_X_class[] contains the @em header @em class
* for header X.
*
* All header structures contain the common part, a #sip_common_t structure
* (@a X_common[]), a link to the next header in list (@a X_next), and
* various fields describing the header value (in this case, @a X_value).
* The header structure looks like this:
* @code
* typedef struct sip_X_s
* {
* sip_common_t X_common[1];
* sip_X_t *X_next;
* unsigned long X_value;
* struct msg_common_s {
* msg_header_t *h_succ; // Pointer to succeeding fragment
* msg_header_t **h_prev; // Pointer to preceeding fragment
* msg_hclass_t *h_class; // Header class
* void const *h_data; // Encoded data
* usize_t h_len; // Encoding length (including CRLF)
* } X_common[1];
* sip_X_t *X_next; // Link to next X header field
* uint32_t X_value; // Value of X
* msg_param_t *X_param; // List of parameters
* } sip_X_t;
* @endcode
*
* The @c X_common is a structure sip_common_t (aka msg_common_t), which is
* common to each fragment and can be considered as a base class for all
* headers. The structure sip_common_t contains the pointers for dual-linked
* The common structure #msg_common_t (aka #sip_common_t)
* can be considered as a base class for all
* headers. The structure contains the pointers for dual-linked
* fragment chain (@a h_succ, @a h_prev), a pointer to header class (@a
* h_class), a pointer to the text encoding of header contents (@a h_data)
* and the length of the encoding (@a h_len). (X_common is an array of size
* and the length of the encoding (@a h_len). (@a X_common is an array of size
* 1, as it makes it easy to cast a header pointer to a pointer to
* sip_common_t.)
* msg_common_t.)
*
* The @c X_next is a pointer to another header (usually a pointer to
* The @a X_next is a pointer to another header (usually a pointer to
* structure of same type). If there are multiple headers with same name,
* like the two "Via" headers in the example above, the @c X_next is used to
* like the two "Via" headers in the example above, the @a X_next is used to
* link the second header to the first. The fragment chain cannot be used
* for this purpose as the headers with same name are not necessarily
* adjacent.
* adjacent in the parsed message.
*
* The rest of the fields contain the parsed or decoded representation of
* the header. In this case, it is a 32-bit integer followed by a list of
* parameters. The content of parameters is not parsed, they are just
* separated from each other and then stored in an dynamically allocated
* array of string pointers. Pointer to the array is stored to @a X_params.
*
* For more complex header structures, see #sip_contact_t or #sip_rack_t.
*/
/**@ingroup sip_X
*
* The structure #sip_X_t contains representation of a SIP
* @ref sip_header_x "X" header.
*
* The #sip_X_t is defined as follows:
* @code
* typedef struct sip_X_s {
* msg_common_t X_common[1]; // Common fragment info
* sip_X_t *X_next; // Link to next X header field
* uint32_t X_value; // Value of X
* msg_param_t *X_param; // List of parameters
* } sip_X_t;
* @endcode
*/
typedef struct sip_X_s sip_X_t;
/**@ingroup sip_X
* @var msg_hclass_t sip_X_class[];
......@@ -529,10 +567,12 @@ int sip_X_d(su_home_t *home, sip_header_t *h, char *s, int bsiz);
* @return
* The function sip_X_e() returns the number of characters required for the
* encoding.
*
* @}
*/
int sip_X_e(char buf[], int bsiz, sip_header_t const *h, int flags);
/**@}*/
/** @} */
/**@nodefgroup sip SIP Headers and Messages - "sip"
*
......@@ -552,7 +592,7 @@ int sip_X_e(char buf[], int bsiz, sip_header_t const *h, int flags);
* The include file <sip_tag.h> defines tags and tag items for including SIP
* headers in tag item lists or tagged argument lists. For each header,
* there is a tag for pointer to header object and an another tag for string
* containing header value. For example, @b From header has tags
* containing header value. For example, @From header has tags
* SIPTAG_FROM() and SIPTAG_FROM_STR().
*
* It is also possible to include user-defined headers or non-standard
......@@ -571,8 +611,8 @@ int sip_X_e(char buf[], int bsiz, sip_header_t const *h, int flags);
* ...
* @endcode
*
* In the above fragment, the function sip_add_tl() will add @b Content-Type
* and @b User-Agent headers along with message payload to the SIP message.
* The @b Content-Type header is made with value "text/plain".
* In the above fragment, the function sip_add_tl() will add @ContentType
* and @UserAgent headers along with message payload to the SIP message.
* The @ContentType header is made with value "text/plain".
*
*/
This diff is collapsed.
......@@ -25,9 +25,8 @@
/**@CFILE sip_caller_prefs.c
* @brief SIP headers related to Caller Preferences
*
* The file @b sip_caller_prefs.c contains implementation of header classes
* for Caller-Preferences-related SIP headers @b Accept-Contact, @b
* Reject-Contact, and @b Request-Disposition.
* Implementation of header classes for Caller-Preferences-related SIP
* headers @AcceptContact, @RejectContact, and @RequestDisposition.
*
* @author Remeres Jacobs <remeres.jacobs@nokia.com>
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
......@@ -51,11 +50,11 @@
/* ====================================================================== */
/**@SIP_HEADER sip_request_disposition Request-Disposition Header
/**@SIP_HEADER sip_request_disposition Request-Disposition Header
*
* The Request-Disposition header syntax is defined in
* draft-ietf-sip-callerprefs-08.txt section 10 as follows:
*
* @RFC3841 section 10 as follows:
*
* @code
* Request-Disposition = ( "Request-Disposition" | "d" ) HCOLON
* directive *(COMMA directive)
......@@ -70,22 +69,24 @@
* queue-directive = "queue" / "no-queue"
* @endcode
*
*
* The parsed Request-Disposition header
* is stored in #sip_request_disposition_t structure.
*/
/**@ingroup sip_request_disposition
*
/**@ingroup sip_request_disposition
* @typedef typedef struct sip_request_disposition_s sip_request_disposition_t;
*
* The structure sip_request_disposition_t contains representation of @b
* Request-Disposition header.
*
* The sip_request_disposition_t is defined as follows:
* The structure #sip_request_disposition_t contains representation of
* @RequestDisposition header.
*
* The #sip_request_disposition_t is defined as follows:
* @code
* typedef struct sip_request_disposition_s
* {
* sip_common_t rd_common[1]; // Common fragment info
* sip_unknown_t *rd_next; // Link to next (dummy)
* msg_param_t *rd_items;
* msg_param_t *rd_items; // List of directives
* } sip_request_disposition_t;
* @endcode
*/
......@@ -94,15 +95,15 @@ static msg_xtra_f sip_request_disposition_dup_xtra;
static msg_dup_f sip_request_disposition_dup_one;
#define sip_request_disposition_update NULL
msg_hclass_t sip_request_disposition_class[] =
msg_hclass_t sip_request_disposition_class[] =
SIP_HEADER_CLASS(request_disposition, "Request-Disposition", "d", rd_items,
list, request_disposition);
issize_t sip_request_disposition_d(su_home_t *home, sip_header_t *h,
issize_t sip_request_disposition_d(su_home_t *home, sip_header_t *h,
char *s, isize_t slen)
{
sip_request_disposition_t *rd = h->sh_request_disposition;
return msg_commalist_d(home, &s, &rd->rd_items, msg_token_scan);
}
......@@ -114,7 +115,7 @@ issize_t sip_request_disposition_e(char b[], isize_t bsiz, sip_header_t const *h
assert(sip_is_request_disposition(h));
MSG_COMMALIST_E(b, end, o->rd_items, flags);
MSG_COMMALIST_E(b, end, o->rd_items, flags);
return b - b0;
}
......@@ -130,7 +131,7 @@ isize_t sip_request_disposition_dup_xtra(sip_header_t const *h, isize_t offset)
}
/** Duplicate one sip_request_disposition_t object */
/** Duplicate one #sip_request_disposition_t object */
char *sip_request_disposition_dup_one(sip_header_t *dst,
sip_header_t const *src,
char *b, isize_t xtra)
......@@ -149,24 +150,26 @@ char *sip_request_disposition_dup_one(sip_header_t *dst,
/* ====================================================================== */
/**@ingroup sip_caller_prefs
/**@ingroup sip_caller_prefs
*
* Add a parameter to a @b Accept-Contact or @b Reject-Contact header object.
* Add a parameter to a @AcceptContact or @RejectContact header object.
*
* @note This function does not duplicate @p param.
*
* @param home memory home
* @param cp sip_caller_prefs_t object
* @param cp pointer to #sip_accept_contact_t or #sip_reject_contact_t
* @param param parameter string
*
* @retval 0 when successful
* @retval -1 upon an error
*
* @deprecated Use msg_header_replace_param() instead.
*/
int sip_caller_prefs_add_param(su_home_t *home,
sip_caller_prefs_t *cp,
char const *param)
{
return msg_header_replace_param(home, cp->cp_common, param);
return msg_header_replace_param(home, cp->cp_common, param);
}
static
......@@ -177,7 +180,7 @@ size_t span_attribute_value(char *s)
n = span_token_lws(s);
if (n > 0 && s[n] == '=') {
n += 1 + span_lws(s + n + 1);
if (s[n] == '"')
if (s[n] == '"')
n += span_quoted(s + n);
else
n += span_token(s + n);
......@@ -197,7 +200,7 @@ issize_t sip_caller_prefs_d(su_home_t *home, sip_header_t *h, char *s, isize_t s
int kludge;
assert(h);
for (;*s;) {
/* Ignore empty entries (comma-whitespace) */
if (*s == ',') { *s++ = '\0'; skip_lws(&s); continue; }
......@@ -221,21 +224,21 @@ issize_t sip_caller_prefs_d(su_home_t *home, sip_header_t *h, char *s, isize_t s
}
if (kludge) {
if (msg_any_list_d(home, &s, (msg_param_t **)&cp->cp_params,
if (msg_any_list_d(home, &s, (msg_param_t **)&cp->cp_params,
msg_attribute_value_scanner, ';') == -1)
return -1;
}
/* Parse params (and ignore display name and url) */
else if (sip_name_addr_d(home, &s, &ignore, url, &cp->cp_params, NULL)
else if (sip_name_addr_d(home, &s, &ignore, url, &cp->cp_params, NULL)
== -1)
return -1;
/* Be liberal... */
/* if (url->url_type != url_any)
/* if (url->url_type != url_any)
return -1; */
if (*s != '\0' && *s != ',')
return -1;
if (cp->cp_params)
if (cp->cp_params)
msg_header_update_params(cp->cp_common, 0);
h = NULL;
......@@ -247,9 +250,9 @@ issize_t sip_caller_prefs_d(su_home_t *home, sip_header_t *h, char *s, isize_t s
return 0;
}
static
issize_t sip_caller_prefs_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
{
{
sip_caller_prefs_t const *cp = h->sh_caller_prefs;
char *b0 = b, *end = b + bsiz;
......@@ -261,6 +264,7 @@ issize_t sip_caller_prefs_e(char b[], isize_t bsiz, sip_header_t const *h, int f
}
static
isize_t sip_caller_prefs_dup_xtra(sip_header_t const *h, isize_t offset)
{
sip_caller_prefs_t const *cp = h->sh_caller_prefs;
......@@ -270,8 +274,8 @@ isize_t sip_caller_prefs_dup_xtra(sip_header_t const *h, isize_t offset)
return offset;
}
char *sip_caller_prefs_dup_one(sip_header_t *dst, sip_header_t const *src,
static
char *sip_caller_prefs_dup_one(sip_header_t *dst, sip_header_t const *src,
char *b, isize_t xtra)
{
char *end = b + xtra;
......@@ -285,9 +289,73 @@ char *sip_caller_prefs_dup_one(sip_header_t *dst, sip_header_t const *src,
return b;
}
static int sip_caller_prefs_update(msg_common_t *h,
char const *name, isize_t namelen,
char const *value)
/**@SIP_HEADER sip_accept_contact Accept-Contact Header
*
* The Accept-Contact syntax is defined in @RFC3841 section 10 as follows:
*
* @code
* Accept-Contact = ("Accept-Contact" / "a") HCOLON ac-value
* *(COMMA ac-value)
* ac-value = "*" *(SEMI ac-params)
* ac-params = feature-param / req-param
* / explicit-param / generic-param
* ;;feature param from RFC 3840
* ;;generic-param from RFC 3261
* req-param = "require"
* explicit-param = "explicit"
* @endcode
*
* Despite the BNF, there MUST NOT be more than one req-param or
* explicit-param in an ac-params. Furthermore, there can only be one
* instance of any feature tag in feature-param.
*
* @sa @RFC3840, @RFC3841, sip_contact_accept(), sip_contact_score().
*
* The parsed Accept-Contact header
* is stored in #sip_accept_contact_t structure.
*/
/**@ingroup sip_accept_contact
* @typedef struct sip_caller_prefs_s sip_accept_contact_t;
*
* The structure #sip_accept_contact_t contains representation of SIP
* @AcceptContact header.
*
* The #sip_accept_contact_t is defined as follows:
* @code
* typedef struct caller_prefs_s {
* sip_common_t cp_common[1]; // Common fragment info
* sip_caller_prefs_t *cp_next; // Link to next ac-value
* msg_param_t const *cp_params; // List of parameters
* char const *cp_q; // Priority
* unsigned cp_require :1; // Shortcut to "require" parameter
* unsigned cp_explicit :1; // Shortcut to "explicit" parameter
* } sip_accept_contact_t;
* @endcode
*/
static int sip_accept_contact_update(msg_common_t *h,
char const *name, isize_t namelen,
char const *value);
msg_hclass_t sip_accept_contact_class[] =
SIP_HEADER_CLASS(accept_contact, "Accept-Contact", "a", cp_params, append,
accept_contact);
issize_t sip_accept_contact_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
{
return sip_caller_prefs_d(home, h, s, slen);
}
issize_t sip_accept_contact_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
{
return sip_caller_prefs_e(b, bsiz, h, flags);
}
static int sip_accept_contact_update(msg_common_t *h,
char const *name, isize_t namelen,
char const *value)
{
sip_caller_prefs_t *cp = (sip_caller_prefs_t *)h;
......@@ -298,9 +366,11 @@ static int sip_caller_prefs_update(msg_common_t *h,
}
#define MATCH(s) (namelen == strlen(#s) && !strncasecmp(name, #s, strlen(#s)))
#if nomore
else if (MATCH(q)) {
cp->cp_q = value;
}
#endif
else if (MATCH(require)) {
cp->cp_require = value != NULL;
}
......@@ -314,100 +384,52 @@ static int sip_caller_prefs_update(msg_common_t *h,
}
/**@SIP_HEADER sip_accept_contact Accept-Contact Header
/**@SIP_HEADER sip_reject_contact Reject-Contact Header
*
* The Accept-Contact and Reject-Contact syntax is defined in
* draft-ietf-sip-callerprefs-07.txt section 10 as follows:
*
* @code
* Accept-Contact = ("Accept-Contact" / "a") HCOLON ac-value
* *(COMMA ac-value)
* Reject-Contact = ("Reject-Contact" / "j") HCOLON rc-value
* *(COMMA rc-value)
* ac-value = "*" *(SEMI ac-params)
* rc-value = "*" *(SEMI rc-params)
* ac-params = feature-param / c-p-q / req-param
* / explicit-param / generic-param
* rc-params = feature-param / req-param
* / explicit-param / generic-param
* feature-param = enc-feature-tag [EQUAL LDQUOT (tag-value-list
* / string-value ) RDQUOT]
* enc-feature-tag = base-tags / other-tags
* base-tags = "attendant" / "audio" / "automata" /
* "class" / "duplex" / "data" /
* "control" / "mobility" / "description" /
* "events" / "priority" / "methods" /
* "schemes" / "application" / "video" /
* "msgserver" / "language" / "type" /
* "isfocus" / "uri-user" / "uri-domain"
* other-tags = "+" ftag-name
* ftag-name = ALPHA *( ALPHA / DIGIT / "!" / ""' /
* "." / "-" / "%" )
* tag-value-list = tag-value *("," tag-value)
* tag-value = ["!"] (token-nobang / boolean / numeric)
* token-nobang = 1*(alphanum / "-" / "." / "%" / "*"
* / "_" / "+" / "`" / "'" / "~" )
* boolean = "TRUE" / "FALSE"
* numeric = "#" numeric-relation number
* numeric-relation = ">=" / "<=" / "=" / (number ":")
* number = [ "+" / "-" ] 1*DIGIT ["." 0*DIGIT]
* string-value = "<" qdtext ">"
* req-param = "require"
* explicit-param = "explicit"
* @endcode
* The Reject-Contact syntax is defined in @RFC3841 section 10 as follows:
*
* The sip_accept_contact_t or sip_reject_contact_t is defined as follows:
* @code
* typedef struct sip_caller_prefs_s
* {
* sip_common_t cp_common[1]; // Common fragment info
* sip_caller_prefs_t *cp_next; // Link to next
* msg_param_t const *cp_params;
* msg_param_t cp_q; // Priority
* unsigned cp_require;
* unsigned cp_explicit;
* } sip_accept_contact_t, sip_reject_contact_t;
* Reject-Contact = ("Reject-Contact" / "j") HCOLON rc-value
* *(COMMA rc-value)
* rc-value = "*" *(SEMI rc-params)
* rc-params = feature-param / generic-param
* ;;feature param from RFC 3840
* ;;generic-param from RFC 3261
* @endcode
*/
msg_hclass_t sip_accept_contact_class[] =
SIP_HEADER_CLASS(accept_contact, "Accept-Contact", "a", cp_params, append,
caller_prefs);
issize_t sip_accept_contact_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
{