diff -uNr modules/acc/Makefile modules/acc.new/Makefile
--- modules/acc/Makefile	2004-02-24 11:39:45.000000000 +0100
+++ modules/acc.new/Makefile	2004-10-31 12:04:18.000000000 +0100
@@ -11,13 +11,13 @@
 LIBS=
 
 # uncomment the next line if you wish to enable SQL accounting
-#DEFS+=-DSQL_ACC
+#DEFS+=-DSQL_ACC
 
 # uncomment the next two lines if you wish to enable RADIUS accounting
 #DEFS+=-DRAD_ACC -I$(LOCALBASE)/include
 #LIBS=-L$(LOCALBASE)/lib -lradiusclient
 
 # uncomment the next two lines if you wish to enable DIAMETER accounting
-#DEFS+=-DDIAM_ACC
+#DEFS+=-DDIAM_ACC
 
 include ../../Makefile.modules
diff -uNr modules/acc/README modules/acc.new/README
--- modules/acc/README	2004-08-24 10:58:23.000000000 +0200
+++ modules/acc.new/README	2004-10-31 11:41:05.000000000 +0100
@@ -15,36 +15,41 @@
 
               1.1.1. General Example
 
-        1.2. Dependencies
-        1.3. Exported Parameters
-
-              1.3.1. secret (string)
-              1.3.2. log_level (integer)
-              1.3.3. log_fmt (string)
-              1.3.4. early_media (integer)
-              1.3.5. failed_transactions (integer)
-              1.3.6. log_flag (integer)
-              1.3.7. log_missed_flag (integer)
-              1.3.8. report_ack (integer)
-              1.3.9. report_cancels (integer)
-              1.3.10. radius_config (string)
-              1.3.11. service_type (integer)
-              1.3.12. radius_flag (integer)
-              1.3.13. radius_missed_flag (integer)
-              1.3.14. db_url (string)
-              1.3.15. db_flag (integer)
-              1.3.16. db_missed_flag (integer)
-              1.3.17. diameter_flag (integer)
-              1.3.18. diameter_missed_flag (integer)
-              1.3.19. diameter_client_host (string)
-              1.3.20. diameter_client_port (int)
-
-        1.4. Exported Functions
-
-              1.4.1. acc_log_request(comment)
-              1.4.2. acc_db_request(comment, table)
-              1.4.3. acc_rad_request(comment)
-              1.4.4. acc_diam_request(comment)
+        1.2. Extra accounting
+        1.3. Dependencies
+        1.4. Exported Parameters
+
+              1.4.1. secret (string)
+              1.4.2. log_level (integer)
+              1.4.3. log_fmt (string)
+              1.4.4. early_media (integer)
+              1.4.5. failed_transactions (integer)
+              1.4.6. log_flag (integer)
+              1.4.7. log_missed_flag (integer)
+              1.4.8. report_ack (integer)
+              1.4.9. report_cancels (integer)
+              1.4.10. radius_config (string)
+              1.4.11. service_type (integer)
+              1.4.12. radius_flag (integer)
+              1.4.13. radius_missed_flag (integer)
+              1.4.14. db_url (string)
+              1.4.15. db_flag (integer)
+              1.4.16. db_missed_flag (integer)
+              1.4.17. diameter_flag (integer)
+              1.4.18. diameter_missed_flag (integer)
+              1.4.19. diameter_client_host (string)
+              1.4.20. diameter_client_port (int)
+              1.4.21. log_extra (string)
+              1.4.22. db_extra (string)
+              1.4.23. rad_extra (string)
+              1.4.24. dia_extra (string)
+
+        1.5. Exported Functions
+
+              1.5.1. acc_log_request(comment)
+              1.5.2. acc_db_request(comment, table)
+              1.5.3. acc_rad_request(comment)
+              1.5.4. acc_diam_request(comment)
 
    2. Developer's Guide
    3. Frequently Asked Questions
@@ -70,10 +75,14 @@
    1-18. diameter_missed_flag example
    1-19. diameter_client_host example
    1-20. diameter_client_host example
-   1-21. acc_log_request usage
-   1-22. acc_db_request usage
-   1-23. acc_rad_request usage
-   1-24. acc_diam_request usage
+   1-21. log_extra example
+   1-22. db_extra example
+   1-23. rad_extra example
+   1-24. dia_extra example
+   1-25. acc_log_request usage
+   1-26. acc_db_request usage
+   1-27. acc_rad_request usage
+   1-28. acc_diam_request usage
      _________________________________________________________
 
 Chapter 1. User's Guide
@@ -182,7 +191,57 @@
 };
      _________________________________________________________
 
-1.2. Dependencies
+1.2. Extra accounting
+
+   Along the static information defined via FMT-s, ACC modules
+   allows dynamical selection of extra information to be logged.
+   There are two classes of information that are accessible by
+   extra accounting: data from SIP messages (as headers) and
+   internal SER data (as AVPs).
+
+   Selection of extra information is done via xxx_extra
+   parameters by specifying the names of additional headers or
+   AVPs you want to log. The syntax of is: 
+
+     * xxx_extra = extra_definition (';'extra_definition)* 
+     * extra_definition = log_name '=' data_type'/'data['/'flags]
+     * data_type = 'hdr' | 'avp' 
+     * data = header_name | ['s:']AVP_name | 'i:'AVP_id 
+     * flags = 'g' 
+
+   Via log_name you define how/where the data will be logged. Its
+   meaning depends of the accounting support which is used:
+
+     * LOG accounting - log_name will be just printed along with
+       the data in log_name=data format;
+     * DB accounting - log_name will be the name of the DB column
+       where the data will be stored. IMPORTANT: add in db acc
+       table the columns corresponding to each extra data; 
+     * RADIUS accounting - log_name will be the AVP name used for
+       packing the data into RADIUS message. The log_name will be
+       translated to AVP number via the dictionary. IMPORTANT:
+       add in RADIUS dictionary the log_name attribute. 
+     * DIAMETER accounting - log_name will be the AVP code used
+       for packing the data into DIAMETER message. the AVP code
+       is given directly as integer, since DIAMETER has no
+       dictionary support yet. IMPORTANT: log_name must be a
+       number.
+
+   Data can be an header name or an AVP name/ID - depending of
+   the data_type. If header, the search for it into SIP messages
+   will be optimized by converting at start-up the header name
+   (string) into header type (integer) - this is not possible for
+   all headers (only for the the most important); otherwise case
+   insensitive string matching will be used.
+
+   The only defined flag is 'g' - global - which will force
+   logging all values of the given header or AVP. Without this
+   flag, only the first found value will be logged. IMPORTANT for
+   DB logging, this flag is disabled from DB data structure
+   constraints.
+     _________________________________________________________
+
+1.3. Dependencies
 
    The module depends on the following modules (in the other
    words the listed modules must be loaded before this module):
@@ -191,9 +250,9 @@
      * a database module -- If compiled with database support.
      _________________________________________________________
 
-1.3. Exported Parameters
+1.4. Exported Parameters
 
-1.3.1. secret (string)
+1.4.1. secret (string)
 
    Default value is randomly generated string.
 
@@ -201,7 +260,7 @@
 modparam("auth", "secret", "johndoessecretphrase")
      _________________________________________________________
 
-1.3.2. log_level (integer)
+1.4.2. log_level (integer)
 
    Log level at which accounting messages are issued to syslog.
 
@@ -211,7 +270,7 @@
 modparam("acc", "log_level", 2)   # Set log_level to 2
      _________________________________________________________
 
-1.3.3. log_fmt (string)
+1.4.3. log_fmt (string)
 
    Defines what parts of header fields will be printed to syslog,
    see "overview" for list of accepted values.
@@ -222,7 +281,7 @@
 modparam("acc", "log_fmt", "mfs")
      _________________________________________________________
 
-1.3.4. early_media (integer)
+1.4.4. early_media (integer)
 
    Should be early media (183) accounted too ?
 
@@ -232,7 +291,7 @@
 modparam("acc", "early_media", 1)
      _________________________________________________________
 
-1.3.5. failed_transactions (integer)
+1.4.5. failed_transactions (integer)
 
    Should be failed transactions (status>=300) accounted too ?
 
@@ -242,7 +301,7 @@
 modparam("acc", "failed_transactions", 1)
      _________________________________________________________
 
-1.3.6. log_flag (integer)
+1.4.6. log_flag (integer)
 
    Request flag which needs to be set to account a transaction.
 
@@ -252,7 +311,7 @@
 modparam("acc", "log_flag", 2)
      _________________________________________________________
 
-1.3.7. log_missed_flag (integer)
+1.4.7. log_missed_flag (integer)
 
    Request flag which needs to be set to account missed calls.
 
@@ -262,7 +321,7 @@
 modparam("acc", "log_missed_flag", 3)
      _________________________________________________________
 
-1.3.8. report_ack (integer)
+1.4.8. report_ack (integer)
 
    Shall acc attempt to account e2e ACKs too ? Note that this is
    really only an attempt, as e2e ACKs may take a different path
@@ -275,7 +334,7 @@
 modparam("acc", "report_ack", 0)
      _________________________________________________________
 
-1.3.9. report_cancels (integer)
+1.4.9. report_cancels (integer)
 
    By default, CANCEL reporting is disabled -- most accounting
    applications are happy to see INVITE's cancellation status.
@@ -287,7 +346,7 @@
 modparam("acc", "report_cancels", 1)
      _________________________________________________________
 
-1.3.10. radius_config (string)
+1.4.10. radius_config (string)
 
    This parameter is radius specific. Path to radius client
    configuration file, set the referred config file correctly and
@@ -303,7 +362,7 @@
 modparam("acc", "radius_config", "/etc/radiusclient/radiusclient.conf")
      _________________________________________________________
 
-1.3.11. service_type (integer)
+1.4.11. service_type (integer)
 
    Radius service type used for accounting.
 
@@ -313,7 +372,7 @@
 modparam("acc", "service_type", 16)
      _________________________________________________________
 
-1.3.12. radius_flag (integer)
+1.4.12. radius_flag (integer)
 
    Request flag which needs to be set to account a transaction --
    RADIUS specific.
@@ -324,7 +383,7 @@
 modparam("acc", "radius_flag", 2)
      _________________________________________________________
 
-1.3.13. radius_missed_flag (integer)
+1.4.13. radius_missed_flag (integer)
 
    Request flag which needs to be set to account missed calls --
    RADIUS specific.
@@ -335,7 +394,7 @@
 modparam("acc", "radius_missed_flag", 3)
      _________________________________________________________
 
-1.3.14. db_url (string)
+1.4.14. db_url (string)
 
    SQL address -- database specific.
 
@@ -345,7 +404,7 @@
 modparam("acc", "db_url", "mysql://user:password@localhost/ser")
      _________________________________________________________
 
-1.3.15. db_flag (integer)
+1.4.15. db_flag (integer)
 
    Request flag which needs to be set to account a transaction --
    database specific.
@@ -356,7 +415,7 @@
 modparam("acc", "db_flag", 2)
      _________________________________________________________
 
-1.3.16. db_missed_flag (integer)
+1.4.16. db_missed_flag (integer)
 
    Request flag which needs to be set to account missed calls --
    database specific.
@@ -367,7 +426,7 @@
 modparam("acc", "db_missed_flag", 3)
      _________________________________________________________
 
-1.3.17. diameter_flag (integer)
+1.4.17. diameter_flag (integer)
 
    Request flag which needs to be set to account a transaction --
    DIAMETER specific.
@@ -378,7 +437,7 @@
 modparam("acc", "diameter_flag", 2)
      _________________________________________________________
 
-1.3.18. diameter_missed_flag (integer)
+1.4.18. diameter_missed_flag (integer)
 
    Request flag which needs to be set to account missed calls --
    DIAMETER specific.
@@ -389,7 +448,7 @@
 modparam("acc", "diameter_missed_flag", 3)
      _________________________________________________________
 
-1.3.19. diameter_client_host (string)
+1.4.19. diameter_client_host (string)
 
    Hostname of the machine where the DIAMETER Client is running
    -- DIAMETER specific.
@@ -400,7 +459,7 @@
 modparam("acc", "diameter_client_host", "iptel.org")
      _________________________________________________________
 
-1.3.20. diameter_client_port (int)
+1.4.20. diameter_client_port (int)
 
    Port number where the Diameter Client is listening -- DIAMETER
    specific.
@@ -411,9 +470,49 @@
 modparam("acc", "diameter_client_port", 3000)
      _________________________________________________________
 
-1.4. Exported Functions
+1.4.21. log_extra (string)
+
+   Extra values to be logged.
+
+   Default value is NULL.
+
+   Example 1-21. log_extra example
+modparam("acc", "log_extra", "ua=hdr/User-Agent;uuid=avp/i:123")
+     _________________________________________________________
+
+1.4.22. db_extra (string)
+
+   Extra values to be logged into database - DB specific.
+
+   Default value is NULL.
+
+   Example 1-22. db_extra example
+modparam("acc", "db_extra", "ct=hdr/Content-type; email=avp/s:email")
+     _________________________________________________________
+
+1.4.23. rad_extra (string)
+
+   Extra values to be logged via RADIUS - RADIUS specific.
+
+   Default value is NULL.
+
+   Example 1-23. rad_extra example
+modparam("acc", "rad_extra", "via=hdr/Via/g; email=avp/s:email")
+     _________________________________________________________
+
+1.4.24. dia_extra (string)
+
+   Extra values to be logged via DIAMETER - DIAMETER specific.
+
+   Default value is NULL.
+
+   Example 1-24. dia_extra example
+modparam("acc", "dia_extra", "ct=7846/Content-type; 7847=avp/s:email")
+     _________________________________________________________
+
+1.5. Exported Functions
 
-1.4.1. acc_log_request(comment)
+1.5.1. acc_log_request(comment)
 
    acc_request reports on a request, for example, it can be used
    to report on missed calls to off-line users who are replied
@@ -424,13 +523,13 @@
 
      * comment - Comment to be appended.
 
-   Example 1-21. acc_log_request usage
+   Example 1-25. acc_log_request usage
 ...
 acc_log_request("Some comment");
 ...
      _________________________________________________________
 
-1.4.2. acc_db_request(comment, table)
+1.5.2. acc_db_request(comment, table)
 
    Like acc_log_request, acc_db_request reports on a request. The
    report is sent to database at "db_url", in the table referred
@@ -441,13 +540,13 @@
      * comment - Comment to be appended.
      * table - Database table to be used.
 
-   Example 1-22. acc_db_request usage
+   Example 1-26. acc_db_request usage
 ...
 acc_log_request("Some comment", "Some table");
 ...
      _________________________________________________________
 
-1.4.3. acc_rad_request(comment)
+1.5.3. acc_rad_request(comment)
 
    Like acc_log_request, acc_rad_request reports on a request. It
    reports to radius server as configured in "radius_config".
@@ -456,13 +555,13 @@
 
      * comment - Comment to be appended.
 
-   Example 1-23. acc_rad_request usage
+   Example 1-27. acc_rad_request usage
 ...
 acc_rad_request("Some comment");
 ...
      _________________________________________________________
 
-1.4.4. acc_diam_request(comment)
+1.5.4. acc_diam_request(comment)
 
    Like acc_log_request, acc_diam_request reports on a request.
    It reports to Diameter server.
@@ -471,7 +570,7 @@
 
      * comment - Comment to be appended.
 
-   Example 1-24. acc_diam_request usage
+   Example 1-28. acc_diam_request usage
 ...
 acc_diam_request("Some comment");
 ...
diff -uNr modules/acc/acc.c modules/acc.new/acc.c
--- modules/acc/acc.c	2004-09-14 13:44:59.000000000 +0200
+++ modules/acc.new/acc.c	2004-10-31 11:57:10.000000000 +0100
@@ -48,6 +48,7 @@
 #include "../tm/t_funcs.h"
 #include "acc_mod.h"
 #include "acc.h"
+#include "acc_extra.h"
 #include "dict.h"
 #ifdef RAD_ACC
 #include <radiusclient.h>
@@ -72,16 +73,20 @@
 
 static str na={NA, NA_LEN};
 
+extern struct acc_extra *log_extra;
+
 #ifdef RAD_ACC
 /* caution: keep these aligned to RAD_ACC_FMT !! */
 static int rad_attr[] = { A_CALLING_STATION_ID, A_CALLED_STATION_ID,
 	A_SIP_TRANSLATED_REQUEST_URI, A_ACCT_SESSION_ID, A_SIP_TO_TAG,
 	A_SIP_FROM_TAG, A_SIP_CSEQ };
+extern struct acc_extra *rad_extra;
 #endif
 
 #ifdef DIAM_ACC
 extern char *diameter_client_host;
 extern int diameter_client_port;
+extern struct acc_extra *dia_extra;
 
 /* caution: keep these aligned to DIAM_ACC_FMT !! */
 static int diam_attr[] = { AVP_SIP_FROM_URI, AVP_SIP_TO_URI, AVP_SIP_OURI, 
@@ -93,6 +98,7 @@
 static char* acc_db_url=0;
 static db_func_t acc_dbf;
 static db_con_t* db_handle=0;
+extern struct acc_extra *db_extra;
 
 #endif
 
@@ -319,13 +325,13 @@
 int acc_log_request( struct sip_msg *rq, struct hdr_field *to, 
 				str *txt, str *phrase)
 {
+	static str* val_arr[ALL_LOG_FMT_LEN+MAX_ACC_EXTRA];
+	static str atr_arr[ALL_LOG_FMT_LEN+MAX_ACC_EXTRA];
 	int len;
 	char *log_msg;
 	char *p;
 	int attr_cnt;
 	int attr_len;
-	str* val_arr[ALL_LOG_FMT_LEN];
-	str atr_arr[ALL_LOG_FMT_LEN];
 	int i;
 
 	if (skip_cancel(rq)) return 1;
@@ -336,6 +342,10 @@
 		LOG(L_ERR, "ERROR: acc_log_request: fmt2strar failed\n");
 		return -1;
 	}
+	attr_cnt += extra2strar( log_extra, rq,
+		&len, &attr_len,
+		atr_arr+attr_cnt, val_arr+attr_cnt);
+	
 	len+=attr_len+ACC_LEN+txt->len+A_EOL_LEN 
 		+attr_cnt*(A_SEPARATOR_LEN+A_EQ_LEN)-A_SEPARATOR_LEN;
 	log_msg=pkg_malloc(len);
@@ -436,6 +446,9 @@
 
 #ifdef SQL_ACC
 
+/* caution: keys need to be aligned to formatting strings */
+static db_key_t keys[ALL_LOG_FMT_LEN+1+MAX_ACC_EXTRA];
+
 
 /* binds to the corresponding database module
  * returns 0 on success, -1 on error */
@@ -447,16 +460,41 @@
 		return -1;
 	}
 
-	     /* Check database capabilities */
+	/* Check database capabilities */
 	if (!DB_CAPABILITY(acc_dbf, DB_CAP_INSERT)) {
-		LOG(L_ERR, "ERROR: acc_db_init: Database module does not implement insert function\n");
+		LOG(L_ERR, "ERROR: acc_db_init: Database module does not implement "
+			"insert function\n");
 		return -1;
 	}
-	
 	return 0;
 }
 
 
+void acc_db_init_keys()
+{
+	struct acc_extra *extra;
+	int i;
+
+	/* init the static db keys */
+	/* caution: keys need to be aligned to formatting strings */
+	keys[0] = acc_from_uri;
+	keys[1] = acc_to_uri;
+	keys[2] = acc_sip_method_col;
+	keys[3] = acc_i_uri_col;
+	keys[4] = acc_o_uri_col;
+	keys[5] = acc_sip_from_col;
+	keys[6] = acc_sip_callid_col;
+	keys[7] = acc_sip_to_col;
+	keys[8] = acc_sip_status_col;
+	keys[9] = acc_user_col;
+	keys[10] = acc_totag_col;
+	keys[11] = acc_fromtag_col;
+	keys[12] = acc_domain_col;
+	/* init the extra db keys */
+	for(i=0,extra=db_extra; extra && i<MAX_ACC_EXTRA ; i++,extra=extra->next)
+		keys[13+i] = extra->name.s;
+}
+
 
 /* initialize the database connection
  * returns 0 on success, -1 on error */
@@ -469,6 +507,7 @@
 					"database\n");
 			return -1;
 		}
+		acc_db_init_keys();
 		return 0;
 	}else{
 		LOG(L_CRIT, "BUG: acc_db_init: null db url\n");
@@ -477,7 +516,6 @@
 }
 
 
-
 /* close a db connection */
 void acc_db_close()
 {
@@ -485,19 +523,12 @@
 }
 
 
-
 int acc_db_request( struct sip_msg *rq, struct hdr_field *to, 
 				str *phrase, char *table, char *fmt)
 {
-	db_val_t vals[ALL_LOG_FMT_LEN+1];
-	str* val_arr[ALL_LOG_FMT_LEN+1];
-	str atr_arr[ALL_LOG_FMT_LEN+1];
-	/* caution: keys need to be aligned to formatting strings */
-	db_key_t keys[] = {acc_from_uri, acc_to_uri,
-		acc_sip_method_col, acc_i_uri_col, 
-		acc_o_uri_col, acc_sip_from_col, acc_sip_callid_col,
-   		acc_sip_to_col, acc_sip_status_col, acc_user_col, 
-		acc_totag_col, acc_fromtag_col, acc_domain_col, acc_time_col };
+	static db_val_t vals[ALL_LOG_FMT_LEN+1+MAX_ACC_EXTRA];
+	static str* val_arr[ALL_LOG_FMT_LEN+1+MAX_ACC_EXTRA];
+	static str atr_arr[ALL_LOG_FMT_LEN+1+MAX_ACC_EXTRA];
 
 	struct tm *tm;
 	time_t timep;
@@ -519,6 +550,9 @@
 		LOG(L_ERR, "ERROR: acc_db_request: fmt2strar failed\n");
 		return -1;
 	}
+	attr_cnt += extra2strar( db_extra, rq,
+		&dummy_len, &dummy_len,
+		atr_arr+attr_cnt, val_arr+attr_cnt);
 
 	if (!acc_db_url) {
 		LOG(L_ERR, "ERROR: can't log -- no db_url set\n");
@@ -539,6 +573,7 @@
 	VAL_TYPE(vals+i)=DB_STRING;
 	VAL_NULL(vals+i)=0;
 	VAL_STRING(vals+i)=time_s;
+	keys[i] = acc_time_col;
 
 	if (acc_dbf.use_table(db_handle, table) < 0) {
 		LOG(L_ERR, "ERROR: acc_request: "
@@ -546,7 +581,7 @@
 		return -1;
 	}
 	
-	if (acc_dbf.insert(db_handle, keys, vals, i+1) < 0) {
+	if (acc_dbf.insert(db_handle, keys, vals, attr_cnt+1) < 0) {
 		LOG(L_ERR, "ERROR: acc_request: "
 				"Error while inserting to database\n");
 		return -1;
@@ -630,9 +665,10 @@
 int acc_rad_request( struct sip_msg *rq, struct hdr_field *to, 
 		     str *phrase )
 {
-	str* val_arr[ALL_LOG_FMT_LEN+1];
-	str atr_arr[ALL_LOG_FMT_LEN+1];
+	static str* val_arr[RAD_ACC_FMT_LEN+MAX_ACC_EXTRA];
+	static str atr_arr[RAD_ACC_FMT_LEN+MAX_ACC_EXTRA];
 	int attr_cnt;
+	int extra_attr_cnt;
 	VALUE_PAIR *send;
 	UINT4 av_type;
 	int i;
@@ -654,10 +690,14 @@
 
 	attr_cnt=fmt2strar( RAD_ACC_FMT, rq, to, phrase, 
 					&dummy_len, &dummy_len, val_arr, atr_arr);
-	if (attr_cnt!=(sizeof(RAD_ACC_FMT)-1)) {
+	if (attr_cnt!=RAD_ACC_FMT_LEN) {
 		LOG(L_ERR, "ERROR: acc_rad_request: fmt2strar failed\n");
 		goto error;
 	}
+	extra_attr_cnt = extra2strar( rad_extra, rq,
+		&dummy_len, &dummy_len,
+		atr_arr+attr_cnt, val_arr+attr_cnt);
+
 
 	av_type=rad_status(rq, phrase);
 	if (!rc_avpair_add(rh, &send, attrs[A_ACCT_STATUS_TYPE].v, &av_type, -1, 0)) {
@@ -747,7 +787,8 @@
 			}
 		}
 	}
-        /* Remaining attributes from rad_attr vector */
+
+	/* Remaining attributes from rad_attr vector */
 	for(i=0; i<attr_cnt; i++) {
 		if (!rc_avpair_add(rh, &send, attrs[rad_attr[i]].v, 
 				   val_arr[i]->s,val_arr[i]->len, 0)) {
@@ -756,7 +797,16 @@
 			goto error;
 		}
 	}
-		
+	/* add extra also */
+	for(i=attr_cnt; i<attr_cnt+extra_attr_cnt; i++) {
+		if (!rc_avpair_add(rh, &send, attrs[atr_arr[i].len].v,
+				val_arr[i]->s,val_arr[i]->len, 0)) {
+			LOG(L_ERR, "ERROR: acc_rad_request: rc_avpaid_add "
+			    "failed for %s\n", atr_arr[i].s );
+			goto error;
+		}
+	}
+
 	if (rc_acct(rh, SIP_PORT, send)!=OK_RC) {
 		LOG(L_ERR, "ERROR: acc_rad_request: radius-ing failed\n");
 		goto error;
@@ -846,9 +896,10 @@
 
 int acc_diam_request( struct sip_msg *rq, struct hdr_field *to, str *phrase )
 {
-	str* val_arr[ALL_LOG_FMT_LEN+1];
-	str atr_arr[ALL_LOG_FMT_LEN+1];
+	static str* val_arr[DIAM_ACC_FMT_LEN+MAX_ACC_EXTRA];
+	static str atr_arr[DIAM_ACC_FMT_LEN+MAX_ACC_EXTRA];
 	int attr_cnt;
+	int extra_attr_cnt;
 	AAAMessage *send = NULL;
 	AAA_AVP *avp;
 	int i;
@@ -871,12 +922,16 @@
 	attr_cnt=fmt2strar( DIAM_ACC_FMT, rq, to, phrase, 
 					&dummy_len, &dummy_len, val_arr, atr_arr);
 	
-	if (attr_cnt!=(sizeof(DIAM_ACC_FMT)-1)) 
+	if (attr_cnt!=DIAM_ACC_FMT_LEN) 
 	{
 		LOG(L_ERR, "ERROR: acc_diam_request: fmt2strar failed\n");
 		return -1;
 	}
 	
+	extra_attr_cnt = extra2strar( dia_extra, rq,
+		&dummy_len, &dummy_len,
+		atr_arr+attr_cnt, val_arr+attr_cnt);
+
 	if ( (send=AAAInMessage(ACCOUNTING_REQUEST, AAA_APP_NASREQ))==NULL)
 	{
 		LOG(L_ERR, "ERROR: acc_diam_request: new AAA message not created\n");
@@ -1048,7 +1103,23 @@
 			goto error;
 		}
 	}
-		
+	/* also the extra */
+	for(i=attr_cnt; i<attr_cnt+extra_attr_cnt; i++)
+	{
+		if((avp=AAACreateAVP(atr_arr[i].len/*AVP code*/, 0, 0,
+				val_arr[i]->s, val_arr[i]->len, AVP_DUPLICATE_DATA)) == 0)
+		{
+			LOG(L_ERR,"ERROR: acc_diam_request: no more free memory!\n");
+			goto error;
+		}
+		if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS)
+		{
+			LOG(L_ERR, "ERROR: acc_diam_request: avp not added \n");
+			AAAFreeAVP(&avp);
+			goto error;
+		}
+	}
+
 	if (get_uri(rq, &uri) < 0) 
 	{
 		LOG(L_ERR, "ERROR: acc_diam_request: From/To URI not found\n");
diff -uNr modules/acc/acc_extra.c modules/acc.new/acc_extra.c
--- modules/acc/acc_extra.c	1970-01-01 01:00:00.000000000 +0100
+++ modules/acc.new/acc_extra.c	2004-10-31 11:58:15.000000000 +0100
@@ -0,0 +1,467 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2004 Voice Sistem SRL
+ *
+ * This file is part of SIP Express Router.
+ *
+ * ser is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ *
+ * History:
+ * ---------
+ *  2004-10-28  first version (ramona)
+ */
+
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "../../dprint.h"
+#include "../../ut.h"
+#include "../../usr_avp.h"
+#include "../../mem/mem.h"
+#include "../../parser/parse_hname2.h"
+#include "acc_extra.h"
+
+
+#define C1 '='
+#define C2 '/'
+#define C3 ';'
+
+#define AVP_TYPE_S    "avp"
+#define AVP_TYPE_LEN  (sizeof(AVP_TYPE_S)-1)
+#define HDR_TYPE_S    "hdr"
+#define HDR_TYPE_LEN  (sizeof(HDR_TYPE_S)-1)
+
+
+static str na={"n/a", 3};
+/* static arrays used for faster and simpler int to str conversion */
+static char int_buf[INT2STR_MAX_LEN*MAX_ACC_EXTRA];
+static str  str_buf[MAX_ACC_EXTRA];
+
+
+
+void init_acc_extra()
+{
+	int i;
+	for (i=0; i<MAX_ACC_EXTRA; i++)
+	{
+		str_buf[i].s = int_buf + i*INT2STR_MAX_LEN;
+	}
+}
+
+
+/*
+void print_extras( struct acc_extra *extra)
+{
+	DBG("----- start extra list ------ \n");
+	while (extra)
+	{
+		DBG("print_extras: flg=(%d) <%s>=%.*s/%d\n",extra->flags,extra->name.s,
+			extra->sval.len,extra->sval.s, extra->ival);
+		extra = extra->next;
+	}
+}
+*/
+
+#define _HDR_OPTIMIZATION
+struct acc_extra *parse_acc_extra(char *extra_str, int allowed_flags)
+{
+	struct hdr_field  hdr;
+	struct acc_extra *head;
+	struct acc_extra *extra;
+	char *foo;
+	char *s;
+	char bkp;
+	str  val;
+	int  n;
+
+
+	n = 0;
+	head = 0;
+	extra = 0;
+	s = extra_str;
+
+	if (s==0)
+	{
+		LOG(L_ERR,"ERROR:acc:parse_acc_extra: null string received\n");
+		goto error;
+	}
+
+	while (*s)
+	{
+		/* skip white spaces */
+		while (*s && isspace((int)*s))  s++;
+		if (*s==0)
+			goto parse_error;
+		if (n==MAX_ACC_EXTRA)
+		{
+			LOG(L_ERR,"ERROR:acc:parse_acc_extra: too many extras -> please "
+				"increase the internal buffer\n");
+			goto error;
+		}
+		extra = (struct acc_extra*)pkg_malloc(sizeof(struct acc_extra));
+		if (extra==0)
+		{
+			LOG(L_ERR,"ERROR:acc:parse_acc_extra: no more pkg mem 1\n");
+			goto error;
+		}
+		memset( extra, 0, sizeof(struct acc_extra));
+		/* link the new extra */
+		extra->next = head;
+		head = extra;
+		n++;
+
+		/* get name */
+		foo = s;
+		while (*s && !isspace((int)*s) && C1!=*s)  s++;
+		if (*s==0)
+			goto parse_error;
+		if (*s==C1)
+		{
+			extra->name.len = (s++) - foo;
+		} else {
+			extra->name.len = (s++) - foo;
+			/* skip spaces */
+			while (*s && isspace((int)*s))  s++;
+			if (*s!=C1)
+				goto parse_error;
+			s++;
+		}
+		extra->name.s = (char*)pkg_malloc(extra->name.len+1);
+		if (extra->name.s==0)
+		{
+			LOG(L_ERR,"ERROR:acc:parse_acc_extra: no more pkg mem 2\n");
+			goto error;
+		}
+		memcpy(extra->name.s, foo, extra->name.len);
+		extra->name.s[extra->name.len] = 0;
+
+		/* skip spaces */
+		while (*s && isspace((int)*s))  s++;
+
+		/* get value type */
+		if (strncasecmp(s,HDR_TYPE_S,HDR_TYPE_LEN)==0)
+		{
+			extra->flags = ACC_EXTRA_HEADER;
+			s += HDR_TYPE_LEN;
+		} 
+		else
+			if (strncasecmp(s,AVP_TYPE_S,AVP_TYPE_LEN)==0)
+			{
+				extra->flags = ACC_EXTRA_AVP;
+				s += AVP_TYPE_LEN;
+			}
+
+		if (*(s++)!=C2 || !*s)
+			goto parse_error;
+		/* get the value */
+		val.s = s;
+		for( ; *s && *s!=C2 && *s!=C3; s++ );
+		if (*s==0)
+			val.len = strlen(val.s);
+		else
+			val.len = s - val.s;
+		if (val.len==0)
+			goto parse_error;
+
+		/* if AVP -> parse value */
+		if (extra->flags&ACC_EXTRA_AVP)
+		{
+			if ( val.s[0] && val.s[1]==':')
+			{
+				switch (val.s[0])
+				{
+					case 's':
+					case 'S':
+						break;
+					case 'i':
+					case 'I':
+						extra->flags |= ACC_EXTRA_IS_INT;
+						break;
+					default:
+						LOG(L_ERR,"ERROR:acc:parse_acc_extra: unknown "
+							"avp type (%c)\n", *foo);
+						goto error;
+				}
+				val.s += 2;
+				val.len -= 2;
+				if (val.len == 0)
+					goto parse_error;
+			}
+			/* if type int, convert it also as integer */
+			if (extra->flags & ACC_EXTRA_IS_INT && 
+				str2int(&val, (unsigned int*)&extra->ival)!=0)
+			{
+				LOG(L_ERR,"ERROR:acc:parse_acc_extra: avp name <%.*s> is "
+					"not ID as type says(%d)\n", val.len, val.s, extra->flags);
+				goto error;
+			}
+		} else {
+			/* do a terrible hack just to be able to use parse_hnames */
+			bkp = val.s[val.len];
+			val.s[val.len] = ':';
+			val.len++;
+			/* header name - try to parse it and see if it's a known header */
+			if (parse_hname2(val.s, val.s+val.len,&hdr)==0)
+			{
+				LOG(L_ERR,"ERROR:acc:parse_acc_extra: bug??\n");
+				goto error;
+			}
+			val.len--;
+			val.s[val.len] = bkp;
+			extra->ival = hdr.type;
+			if (extra->ival!=HDR_OTHER)
+				LOG(L_INFO,"INFO:acc:parse_acc_extra: optimazing by using "
+					"hdr type (%d) instead of <%.*s>\n",
+					extra->ival,val.len,val.s);
+		}
+		/* get the value as string */
+		extra->sval.s = (char*)pkg_malloc(val.len + 1);
+		if (extra->sval.s==0)
+		{
+			LOG(L_ERR,"ERROR:acc:parse_acc_extra: no more pkg mem 3\n");
+			goto error;
+		}
+		extra->sval.len = val.len;
+		memcpy(extra->sval.s, val.s, val.len);
+		extra->sval.s[extra->sval.len] = 0;
+
+		/* are any flags? */
+		if (*s==C2)
+		{
+			for(s++ ; *s && !isspace((int)*s) && *s!=C3 ; s++)
+				switch (*s)
+				{
+					case 'g': case 'G':
+						extra->flags|=(ACC_EXTRA_GLOBAL&allowed_flags);
+						break;
+					default:
+						LOG(L_ERR,"ERROR:acc:parse_acc_extra: unknown "
+							"flag (%c)\n",*s);
+						goto error;
+				}
+		}
+
+		/* skip spaces */
+		while (*s && isspace((int)*s))  s++;
+		if (*s && (*(s++)!=C3 || *s==0))
+			goto parse_error;
+	}
+
+	/* print_extras(head); */
+	return head;
+parse_error:
+	LOG(L_ERR,"ERROR:acc:parse_acc_extra: parse failed in <%s> "
+		"around position %d\n",extra_str, s-extra_str);
+error:
+	LOG(L_ERR,"acc:parse_acc_extra: error\n");
+	destroy_extras(head);
+	return 0;
+}
+
+
+
+void destroy_extras( struct acc_extra *extra)
+{
+	struct acc_extra *foo;
+
+	while (extra)
+	{
+		foo = extra;
+		extra = extra->next;
+		
+		if (foo->name.s)
+			pkg_free(foo->name.s);
+		if (foo->sval.s)
+			pkg_free(foo->sval.s);
+		pkg_free(foo);
+	}
+}
+
+
+/* extra name is moved as string part of an attribute; str.len will contain an
+ * index to the corresponding attribute
+ */
+void extra2attrs( struct acc_extra *extra, struct attr *attrs, int offset)
+{
+	int i;
+
+	for(i=0 ; extra && i<MAX_ACC_EXTRA ; i++, extra=extra->next)
+	{
+		attrs[offset+i].n = extra->name.s;
+		extra->name.s =0;
+		extra->name.len = offset + i;
+	}
+}
+
+
+/* converts the name of the extra from str to integer 
+ * and stores it over str.len ; str.s is freed and made zero
+ */
+int extra2int( struct acc_extra *extra )
+{
+	unsigned int ui;
+	int i;
+
+	for( i=0 ; extra&&i<MAX_ACC_EXTRA ; i++,extra=extra->next )
+	{
+		if (str2int( &extra->name, &ui)!=0)
+		{
+			LOG(L_ERR,"ERROR:acc:extra2int: <%s> is not number\n",
+				extra->name.s);
+			return -1;
+		}
+		pkg_free( extra->name.s );
+		extra->name.s = 0;
+		extra->name.len = (int)ui;
+	}
+	return 0;
+}
+
+
+static inline struct hdr_field* search_hdr(struct hdr_field *hdr,
+												struct acc_extra *extra)
+{
+	if (extra->ival==HDR_OTHER)
+	{
+		while (hdr)
+		{
+			if (extra->sval.len==hdr->name.len &&
+			strncasecmp(extra->sval.s, hdr->name.s, hdr->name.len)==0)
+				return hdr;
+			hdr = hdr->next;
+		}
+	} else {
+		while (hdr)
+		{
+			if (extra->ival==hdr->type)
+				return hdr;
+			hdr = hdr->next;
+		}
+	}
+	return hdr;
+}
+
+
+
+#define test_overflow( _n, _jumper) \
+	do{\
+		if ((_n)==MAX_ACC_EXTRA) \
+		{ \
+			LOG(L_WARN,"WARNING:acc:extra2strar: array to short " \
+				"-> ommiting extras for accounting\n"); \
+			goto _jumper; \
+		}\
+	} while(0)
+
+#define set_acc( _n, _name, _vals) \
+	do {\
+		attr_arr[_n] = _name; \
+		val_arr[_n] = _vals; \
+		*attr_len += attr_arr[_n].len; \
+		*val_len += val_arr[_n]->len; \
+		(_n)++; \
+	} while(0)
+
+
+int extra2strar( struct acc_extra *extra, /* extra list to account */
+		struct sip_msg *rq, /* accounted message */
+		int *attr_len,  /* total length of accounted attribute names */
+		int *val_len, /* total length of accounted values */
+		str *attr_arr,
+		str **val_arr)
+{
+	struct hdr_field *hdr;
+	struct usr_avp   *avp;
+	unsigned short   avp_type;
+	int_str          avp_name;
+	int_str          avp_val;
+	int    hdr_parsed;
+	char  *p;
+	int    m;
+	int    n;
+
+	n = 0;
+	m = 0;
+	hdr_parsed = 0;
+
+	while (extra) 
+	{
+		if (extra->flags & ACC_EXTRA_AVP)
+		{
+			/* account an AVP */
+			if (extra->flags&ACC_EXTRA_IS_INT)
+			{
+				avp_type = 0;
+				avp_name.n = extra->ival;
+			} else {
+				avp_type = AVP_NAME_STR;
+				avp_name.s = &(extra->sval);
+			}
+			avp = search_first_avp( avp_type, avp_name, &avp_val);
+			if (!avp)
+			{
+				test_overflow( n, done);
+				set_acc( n, extra->name, &na );
+			} else {
+				do
+				{
+					test_overflow( n, done);
+					if (avp->flags & AVP_VAL_STR)
+					{
+						set_acc( n, extra->name, avp_val.s);
+					} else {
+						p = int2str((unsigned long)avp_val.n, &str_buf[m].len);
+						memcpy(str_buf[m].s, p, str_buf[m].len);
+						set_acc( n, extra->name, &str_buf[m]);
+						m++;
+					}
+					if (!(extra->flags&ACC_EXTRA_GLOBAL))
+						break;
+				} while ((avp=search_next_avp(avp, &avp_val))!=0);
+			}
+		} else {
+			/* account a HEADER - first parse them all */
+			if (!hdr_parsed && ++hdr_parsed && parse_headers(rq, HDR_EOH, 0)!=0)
+			{
+				LOG(L_ERR,"ERROR:acc:extra2strar: failed to parse headers ->"
+					" skipping hdr extras\n");
+			}
+			hdr = search_hdr(rq->headers, extra);
+			if (!hdr)
+			{
+				test_overflow(n, done);
+				set_acc(n, extra->name, &na);
+			} else {
+				do
+				{
+					test_overflow(n, done);
+					set_acc(n, extra->name, &hdr->body);
+					if (!(extra->flags & ACC_EXTRA_GLOBAL))
+						break;
+				} while ((hdr=search_hdr(hdr->next, extra))!=0);
+			}
+		}
+
+		extra = extra->next;
+	}
+
+done:
+	return n;
+}
+
diff -uNr modules/acc/acc_extra.h modules/acc.new/acc_extra.h
--- modules/acc/acc_extra.h	1970-01-01 01:00:00.000000000 +0100
+++ modules/acc.new/acc_extra.h	2004-10-31 11:37:54.000000000 +0100
@@ -0,0 +1,69 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2004 Voice Sistem SRL
+ *
+ * This file is part of SIP Express Router.
+ *
+ * ser is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ *
+ * History:
+ * ---------
+ *  2004-10-28  first version (ramona)
+ */
+
+
+#ifndef _ACC_EXTRA_H_
+#define _ACC_EXTRA_H_
+
+#include "../../str.h"
+#include "../../parser/msg_parser.h"
+#include "dict.h"
+
+struct acc_extra
+{
+	int flags;       /* if attr is an avp or a header */
+	str name;       /* name (log comment/ column name) */
+	/* value - hdr name or avp name */
+	str sval;       /* hdr or avp name */
+	int ival;       /* avp ID */
+	struct acc_extra *next;
+};
+
+#define ACC_EXTRA_HEADER      (1<<1)
+#define ACC_EXTRA_AVP         (1<<2)
+#define ACC_EXTRA_IS_INT      (1<<3)
+#define ACC_EXTRA_GLOBAL      (1<<4)
+
+#define MAX_ACC_EXTRA 64
+
+
+
+void init_acc_extra();
+
+struct acc_extra *parse_acc_extra(char *extra, int allowed_flags);
+
+void destroy_extras( struct acc_extra *extra);
+
+int extra2strar( struct acc_extra *extra, struct sip_msg *rq,
+	int *val_len, int *attr_len, str *attrs_arr, str **val_arr);
+
+void extra2attrs( struct acc_extra *extra, struct attr *attrs, int offset);
+
+int extra2int( struct acc_extra *extra );
+
+#endif
+
diff -uNr modules/acc/acc_mod.c modules/acc.new/acc_mod.c
--- modules/acc/acc_mod.c	2004-08-24 10:58:23.000000000 +0200
+++ modules/acc.new/acc_mod.c	2004-10-29 21:09:00.000000000 +0200
@@ -57,6 +57,7 @@
 
 #include "acc_mod.h"
 #include "acc.h"
+#include "acc_extra.h"
 #include "../tm/tm_load.h"
 
 #ifdef RAD_ACC
@@ -106,14 +107,22 @@
 /* noisiness level logging facilities are used */
 int log_level=L_NOTICE;
 char *log_fmt=DEFAULT_LOG_FMT;
+/* log extra variables */
+static char *log_extra_str = 0;
+struct acc_extra *log_extra = 0;
+
+
 #ifdef RAD_ACC
 static char *radius_config = "/usr/local/etc/radiusclient/radiusclient.conf";
 int radius_flag = 0;
 int radius_missed_flag = 0;
 static int service_type = -1;
 void *rh;
-struct attr attrs[A_MAX];
+struct attr attrs[A_MAX+MAX_ACC_EXTRA];
 struct val vals[V_MAX];
+/* rad extra variables */
+static char *rad_extra_str = 0;
+struct acc_extra *rad_extra = 0;
 #endif
 
 /* DIAMETER */
@@ -122,6 +131,9 @@
 int diameter_missed_flag = 2;
 char* diameter_client_host="localhost";
 int diameter_client_port=3000;
+/* diameter extra variables */
+static char *dia_extra_str = 0;
+struct acc_extra *dia_extra = 0;
 #endif
 
 #ifdef SQL_ACC
@@ -155,6 +167,10 @@
 char* acc_user_col          = "username";
 char* acc_time_col          = "time";
 
+/* db extra variables */
+static char *db_extra_str = 0;
+struct acc_extra *db_extra = 0;
+
 /* name of missed calls table, default=="missed_calls" */
 char *db_table_mc="missed_calls";
 #endif
@@ -195,13 +211,15 @@
 	/* syslog specific */
 	{"log_flag",			INT_PARAM, &log_flag         	},
 	{"log_missed_flag",		INT_PARAM, &log_missed_flag		},
-	{"log_level",			INT_PARAM, &log_level            },
-	{"log_fmt",				STR_PARAM, &log_fmt				},
+	{"log_level",			INT_PARAM, &log_level           },
+	{"log_fmt",				STR_PARAM, &log_fmt             },
+	{"log_extra",			STR_PARAM, &log_extra_str       },
 #ifdef RAD_ACC
 	{"radius_config",		STR_PARAM, &radius_config		},
 	{"radius_flag",				INT_PARAM, &radius_flag			},
 	{"radius_missed_flag",		INT_PARAM, &radius_missed_flag		},
 	{"service_type", 		INT_PARAM, &service_type },
+	{"rad_extra",			STR_PARAM, &rad_extra_str       },
 #endif
 /* DIAMETER	*/
 #ifdef DIAM_ACC
@@ -209,6 +227,7 @@
 	{"diameter_missed_flag",INT_PARAM, &diameter_missed_flag},
 	{"diameter_client_host",STR_PARAM, &diameter_client_host},
 	{"diameter_client_port",INT_PARAM, &diameter_client_port},
+	{"dia_extra",			STR_PARAM, &dia_extra_str       },
 #endif
 	/* db-specific */
 #ifdef SQL_ACC
@@ -227,11 +246,12 @@
 	{"acc_sip_callid_column", STR_PARAM, &acc_sip_callid_col},
 	{"acc_user_column",       STR_PARAM, &acc_user_col      },
 	{"acc_time_column",       STR_PARAM, &acc_time_col      },
-	{"acc_from_uri_column",		STR_PARAM, &acc_from_uri },
-	{"acc_to_uri_column",		STR_PARAM, &acc_to_uri },
-	{"acc_totag_column",		STR_PARAM, &acc_totag_col },
-	{"acc_fromtag_column", 		STR_PARAM, &acc_fromtag_col },
-	{"acc_domain_column", 		STR_PARAM, &acc_domain_col },
+	{"acc_from_uri_column",   STR_PARAM, &acc_from_uri      },
+	{"acc_to_uri_column",     STR_PARAM, &acc_to_uri        },
+	{"acc_totag_column",      STR_PARAM, &acc_totag_col     },
+	{"acc_fromtag_column",    STR_PARAM, &acc_fromtag_col   },
+	{"acc_domain_column",     STR_PARAM, &acc_domain_col    },
+	{"db_extra",              STR_PARAM, &db_extra_str      },
 #endif
 	{0,0,0}
 };
@@ -307,15 +327,35 @@
 		return -1;
 	}
 
+	/* init the extra engine */
+	init_acc_extra();
+
+	/* parse the extra string, if any */
+	if (log_extra_str && (log_extra=parse_acc_extra(log_extra_str,-1))==0 ) {
+		LOG(L_ERR,"ERROR:acc:mod_init: failed to parse log_extra param\n");
+		return -1;
+	}
+
 #ifdef SQL_ACC
 	if (acc_db_bind(db_url)<0){
 		LOG(L_ERR, "ERROR:acc_db_init: failed..."
 				"did you load a database module?\n");
 		return -1;
 	}
+	/* parse the extra string, if any */
+	if (db_extra_str && (db_extra=parse_acc_extra(db_extra_str,0))==0 ) {
+		LOG(L_ERR,"ERROR:acc:mod_init: failed to parse db_extra param\n");
+		return -1;
+	}
 #endif
 
 #ifdef RAD_ACC
+	/* parse the extra string, if any */
+	if (rad_extra_str && (rad_extra=parse_acc_extra(rad_extra_str,-1))==0 ) {
+		LOG(L_ERR,"ERROR:acc:mod_init: failed to parse rad_extra param\n");
+		return -1;
+	}
+
 	memset(attrs, 0, sizeof(attrs));
 	memset(attrs, 0, sizeof(vals));
 	attrs[A_CALLING_STATION_ID].n		= "Calling-Station-Id";
@@ -334,6 +374,8 @@
 	vals[V_STATUS_STOP].n			= "Stop";
 	vals[V_STATUS_FAILED].n			= "Failed";
 	vals[V_SIP_SESSION].n			= "Sip-Session";
+	/* add extras as attributes */
+	extra2attrs( rad_extra, attrs, A_MAX);
 
 	/* open log */
 	rc_openlog("ser");
@@ -355,6 +397,19 @@
 		vals[V_SIP_SESSION].v = service_type;
 #endif
 
+#ifdef DIAM_ACC
+	/* parse the extra string, if any */
+	if (dia_extra_str && (dia_extra=parse_acc_extra(dia_extra_str,-1))==0 ) {
+		LOG(L_ERR,"ERROR:acc:mod_init: failed to parse dia_extra param\n");
+		return -1;
+	}
+
+	if (extra2int(dia_extra)!=0) {
+		LOG(L_ERR,"ERROR:acc:mod_init: extar names for DIAMTER must be "
+			" integer AVP codes\n");
+		return -1;
+	}
+#endif
 	return 0;
 }
 
@@ -395,11 +450,21 @@
 
 static void destroy(void)
 {
+	if (log_extra)
+		destroy_extras( log_extra);
 #ifdef SQL_ACC
 	acc_db_close();
+	if (db_extra)
+		destroy_extras( db_extra);
+#endif
+#ifdef RAD_ACC
+	if (rad_extra)
+		destroy_extras( rad_extra);
 #endif
 #ifdef DIAM_ACC
 	close_tcp_connection(sockfd);
+	if (dia_extra)
+		destroy_extras( dia_extra);
 #endif
 }
 
diff -uNr modules/acc/defs.h modules/acc.new/defs.h
--- modules/acc/defs.h	2004-08-24 10:58:23.000000000 +0200
+++ modules/acc.new/defs.h	2004-10-29 21:09:00.000000000 +0200
@@ -53,10 +53,12 @@
 /* caution: keep consistent with definition of rad_attr */
 #ifdef RAD_ACC
 #	define RAD_ACC_FMT "FTocdrn"
+#	define RAD_ACC_FMT_LEN  (sizeof(RAD_ACC_FMT)-1)
 #endif
 
 #ifdef DIAM_ACC
 #	define DIAM_ACC_FMT "FTocdrn"
+#	define DIAM_ACC_FMT_LEN  (sizeof(DIAM_ACC_FMT)-1)
 /* information needed for reading messages from tcp connection */
 typedef struct rd_buf
 {
diff -uNr modules/acc/doc/acc_user.sgml modules/acc.new/doc/acc_user.sgml
--- modules/acc/doc/acc_user.sgml	2004-08-24 10:58:24.000000000 +0200
+++ modules/acc.new/doc/acc_user.sgml	2004-10-30 13:02:00.000000000 +0200
@@ -148,6 +148,81 @@
 
     </section>
     <section>
+		<title>Extra accounting</title>
+		<para>
+		Along the static information defined via FMT-s, ACC modules allows 
+		dynamical selection of extra information to be logged. There are two 
+		classes of information that are accessible by extra accounting: data 
+		from SIP messages (as headers) and internal SER data (as AVPs).
+		</para>
+		<para>
+		Selection of extra information is done via 
+		<emphasis>xxx_extra<emphasis> parameters by specifying the names
+		of additional headers or AVPs you want to log. The syntax of is:
+		<itemizedlist>
+			<listitem><para><emphasis>
+			xxx_extra = extra_definition (';'extra_definition)*
+			</emphasis></para></listitem>
+			<listitem><para><emphasis>
+			extra_definition = log_name '=' data_type'/'data['/'flags]
+			</emphasis></para></listitem>
+			<listitem><para><emphasis>
+			data_type = 'hdr' | 'avp'
+			</emphasis></para></listitem>
+			<listitem><para><emphasis>
+			data = header_name | ['s:']AVP_name | 'i:'AVP_id
+			</emphasis></para></listitem>
+			<listitem><para><emphasis>
+			flags = 'g'
+			</emphasis></para></listitem>
+		</itemizedlist>
+		</para>
+		<para>
+		Via <emphasis>log_name</emphasis> you define how/where the <emphasis>
+		data</emphasis> will be logged. Its meaning depends of the accounting
+		support which is used:
+		<itemizedlist>
+			<listitem><para><emphasis>LOG accounting</emphasis> - log_name 
+			will be just printed along with the data in <emphasis>
+			log_name=data</emphasis> format;
+			</para></listitem>
+			<listitem><para><emphasis>DB accounting</emphasis> - log_name 
+			will be the name of the DB column where the data will be stored.
+			<emphasis>IMPORTANT<emphasis>: add in db <emphasis>acc</emphasis>
+			table the columns corresponding to each extra data;
+			</para></listitem>
+			<listitem><para><emphasis>RADIUS accounting</emphasis> - log_name 
+			will be the AVP name used for packing the data into RADIUS message.
+			The log_name will be translated to AVP number via the dictionary.
+			<emphasis>IMPORTANT<emphasis>: add in RADIUS dictionary the 
+			<emphasis>log_name</emphasis> attribute.
+			</para></listitem>
+			<listitem><para><emphasis>DIAMETER accounting</emphasis> - log_name 
+			will be the AVP code used for packing the data into DIAMETER
+			message. the AVP code is given directly as integer, since DIAMETER
+			has no dictionary support yet.
+			<emphasis>IMPORTANT</emphasis>:	<emphasis>log_name</emphasis>
+			must be a number.
+			</para></listitem>
+		</itemizedlist>
+		</para>
+		<para>
+		<emphasis>Data</emphasis> can be an header name or an AVP name/ID -
+		depending of the <emphasis>data_type</emphasis>. If header, the search
+		for it into SIP messages will be optimized by converting at start-up 
+		the header name (string) into header type (integer) - this is not
+		possible for all headers (only for the the most important); otherwise
+		case insensitive string matching will be used.
+		</para>
+		<para>
+		The only defined <emphasis>flag</emphasis> is 'g' - global - which will
+		force logging all values of the given header or AVP. Without this 
+		flag, only the first found value will be logged.
+		<emphasis>IMPORTANT</emphasis> for DB logging, this flag is disabled
+		from DB data structure constraints.
+		</para>
+	</section>
+    <section>
 	<title>Dependencies</title>
 	<para>
 	    The module depends on the following modules (in the other words the listed modules
@@ -473,6 +548,66 @@
 </programlisting>
 	    </example>
 	</section>
+	<section>
+	    <title><varname>log_extra</varname> (string)</title>
+	    <para>
+		Extra values to be logged.
+	    </para>
+	    <para>
+		Default value is NULL.
+	    </para>
+	    <example>
+		<title>log_extra example</title>
+		<programlisting format="linespecific">
+modparam("acc", "log_extra", "ua=hdr/User-Agent;uuid=avp/i:123")
+</programlisting>
+	    </example>
+	</section>
+	<section>
+	    <title><varname>db_extra</varname> (string)</title>
+	    <para>
+		Extra values to be logged into database - DB specific.
+	    </para>
+	    <para>
+		Default value is NULL.
+	    </para>
+	    <example>
+		<title>db_extra example</title>
+		<programlisting format="linespecific">
+modparam("acc", "db_extra", "ct=hdr/Content-type; email=avp/s:email")
+</programlisting>
+	    </example>
+	</section>
+	<section>
+	    <title><varname>rad_extra</varname> (string)</title>
+	    <para>
+		Extra values to be logged via RADIUS - RADIUS specific.
+	    </para>
+	    <para>
+		Default value is NULL.
+	    </para>
+	    <example>
+		<title>rad_extra example</title>
+		<programlisting format="linespecific">
+modparam("acc", "rad_extra", "via=hdr/Via/g; email=avp/s:email")
+</programlisting>
+	    </example>
+	</section>
+	<section>
+	    <title><varname>dia_extra</varname> (string)</title>
+	    <para>
+		Extra values to be logged via DIAMETER - DIAMETER specific.
+	    </para>
+	    <para>
+		Default value is NULL.
+	    </para>
+	    <example>
+		<title>dia_extra example</title>
+		<programlisting format="linespecific">
+modparam("acc", "dia_extra", "ct=7846/Content-type; 7847=avp/s:email")
+</programlisting>
+	    </example>
+	</section>
 
     </section>
     <section>
