Index: chan_sip.c
===================================================================
--- chan_sip.c	(revision 90150)
+++ chan_sip.c	(working copy)
@@ -388,6 +388,7 @@
 
 /*! \brief Modes in which Asterisk can be configured to run SIP Session-Timers */
 enum st_mode {
+        SESSION_TIMER_MODE_INVALID = 0, /*!< Invalid value */ 
         SESSION_TIMER_MODE_ACCEPT,      /*!< Honor inbound Session-Timer requests */
         SESSION_TIMER_MODE_ORIGINATE,   /*!< Originate outbound and honor inbound requests */
         SESSION_TIMER_MODE_REFUSE       /*!< Ignore inbound Session-Timers requests */
@@ -1233,6 +1234,10 @@
 	enum st_refresher st_ref;               /*!< Session-Timers session refresher */
 	int st_expirys;                         /*!< Session-Timers number of expirys */
 	int st_active_peer_ua;                  /*!< Session-Timers on/off in peer UA */
+	int st_cached_min_se;                   /*!< Session-Timers cached Min-SE */
+	int st_cached_max_se;                   /*!< Session-Timers cached Session-Expires */
+	enum st_mode st_cached_mode;            /*!< Session-Timers cached M.O. */
+	enum st_refresher st_cached_ref;        /*!< Session-Timers cached refresher */
 };
 
 
@@ -5174,6 +5179,10 @@
 	p->st_ref = 0;				/* Session-Timers session refresher */
 	p->st_expirys = 0;			/* Session-Timers number of expirys */
 	p->st_active_peer_ua = FALSE;		/* Session-Timers on/off in peer UA */
+	p->st_cached_min_se = 0;                /* Session-Timers cached Min-SE */
+	p->st_cached_max_se = 0;                /* Session-Timers cached Session-Expires */
+	p->st_cached_ref = 0;                   /* Session-Timers cached refresher */
+	p->st_cached_mode = 0;                  /* Session-Timers cached mode */
 	p->prefs = default_prefs;		/* Set default codecs for this call */
 
 	if (intended_method != SIP_OPTIONS)	/* Peerpoke has it's own system */
@@ -12574,11 +12583,15 @@
 
  			ast_cli(a->fd, "  Session-Timer:          %s\n", cur->st_active ? "Active" : "Inactive");
  			if (cur->st_active == TRUE) {
- 				ast_cli(a->fd, "  Session-Timer Interval:  %d\n", cur->st_interval);
- 				ast_cli(a->fd, "  Session-Timer Refresher: %s\n", strefresher2str(cur->st_ref));
- 				ast_cli(a->fd, "  Session-Timer Expirys:   %d\n", cur->st_expirys);
- 				ast_cli(a->fd, "  Session-Timer Sched Id:  %d\n", cur->st_schedid);
- 				ast_cli(a->fd, "  Session-Timer Peer Sts:  %s\n", cur->st_active_peer_ua ? "Active" : "Inactive");
+ 				ast_cli(a->fd, "  S-Timer Interval:       %d\n", cur->st_interval);
+ 				ast_cli(a->fd, "  S-Timer Refresher:      %s\n", strefresher2str(cur->st_ref));
+ 				ast_cli(a->fd, "  S-Timer Expirys:        %d\n", cur->st_expirys);
+ 				ast_cli(a->fd, "  S-Timer Sched Id:       %d\n", cur->st_schedid);
+ 				ast_cli(a->fd, "  S-Timer Peer Sts:       %s\n", cur->st_active_peer_ua ? "Active" : "Inactive");
+ 				ast_cli(a->fd, "  S-Timer Cached Min-SE:  %d\n", cur->st_cached_min_se);
+ 				ast_cli(a->fd, "  S-Timer Cached SE:      %d\n", cur->st_cached_max_se);
+ 				ast_cli(a->fd, "  S-Timer Cached Ref:     %s\n", strefresher2str(cur->st_cached_ref));
+ 				ast_cli(a->fd, "  S-Timer Cached Mode:    %s\n", stmode2str(cur->st_cached_mode));
  			}
 
 			ast_cli(a->fd, "\n\n");
@@ -17648,56 +17661,108 @@
 
 /*! \brief Get Max or Min SE (session timer expiry)
 	\param max if true, get max se, otherwise min se
-
-	This functions will cause havoc with realtime. 
-	We should cache the values in the pvt at start.
 */
 int st_get_se(struct sip_pvt *p, int max)
 {
-	if (p->username) {
-		struct sip_user *up = find_user(p->username, 1);
-		if (up)
-			return (max ? up->st_max_se : up->st_min_se);
-	} 
-	if (p->peername) {
-		struct sip_peer *pp = find_peer(p->peername, NULL, 1);
-		if (pp) 
-			return (max ? pp->st_max_se : pp->st_min_se);
+	if (max == TRUE) {
+		if (p->st_cached_max_se) {
+			return p->st_cached_max_se;
+		} else {
+			if (p->username) {
+				struct sip_user *up = find_user(p->username, 1);
+				if (up) {
+					p->st_cached_max_se = up->st_max_se;
+					return (p->st_cached_max_se);
+				}
+			} 
+			if (p->peername) {
+				struct sip_peer *pp = find_peer(p->peername, NULL, 1);
+				if (pp) {
+					p->st_cached_max_se = pp->st_max_se;
+					return (p->st_cached_max_se);
+				}
+			}
+		}
+		p->st_cached_max_se = global_max_se;
+		return (p->st_cached_max_se);
+	} else {
+		if (p->st_cached_min_se) {
+			return p->st_cached_min_se;
+		} else {
+			if (p->username) {
+				struct sip_user *up = find_user(p->username, 1);
+				if (up) {
+					p->st_cached_min_se = up->st_min_se;
+					return (p->st_cached_min_se);
+				}
+			} 
+			if (p->peername) {
+				struct sip_peer *pp = find_peer(p->peername, NULL, 1);
+				if (pp) {
+					p->st_cached_min_se = pp->st_min_se;
+					return (p->st_cached_min_se);
+				}
+			}
+		}
+		p->st_cached_min_se = global_min_se;
+		return (p->st_cached_min_se);
 	}
-	return global_max_se;
 }
 
+
+/*! \brief Get the entity (UAC or UAS) that's acting as the session-timer refresher 
+	\param sip_pvt pointer to the SIP dialog 
+*/
 enum st_refresher st_get_refresher(struct sip_pvt *p)
 {
+	if (p->st_cached_ref != SESSION_TIMER_REFRESHER_AUTO) 
+		return p->st_cached_ref;
+
 	if (p->username) {
 		struct sip_user *up = find_user(p->username, 1);
 		if (up) {
+			p->st_cached_ref = up->st_ref;
 			return up->st_ref;
 		}
 	} 
+
 	if (p->peername) {
 		struct sip_peer *pp = find_peer(p->peername, NULL, 1);
 		if (pp) {
+			p->st_cached_ref = pp->st_ref;
 			return pp->st_ref;
 		}
 	}
+	
+	p->st_cached_ref = global_st_refresher;
 	return global_st_refresher;
 }
 
+
+/*! \brief Get the session-timer mode 
+	\param sip_pvt pointer to the SIP dialog 
+*/
 enum st_mode st_get_mode(struct sip_pvt *p)
 {
+	if (p->st_cached_mode != SESSION_TIMER_MODE_INVALID) 
+		return p->st_cached_mode;
+
 	if (p->username) {
 		struct sip_user *up = find_user(p->username, 1);
 		if (up) {
+			p->st_cached_mode = up->st_mode_oper;
 			return up->st_mode_oper;
 		}
 	} 
 	if (p->peername) {
 		struct sip_peer *pp = find_peer(p->peername, NULL, 1);
 		if (pp) {
+			p->st_cached_mode = pp->st_mode_oper;
 			return pp->st_mode_oper;
 		}
 	}
+
+	p->st_cached_mode = global_st_mode;
 	return global_st_mode;
 }
 
