LibSip_Steps.ttcn 108 KB
Newer Older
 	function f_setHeaders_2ndREGISTER() runs on SipComponent
	{
	  var CommaParam_List v_challenge;
		
	  vc_branch := c_branchCookie & f_getRndTag();

	  vc_via_REG :={
		fieldName := VIA_E,
		viaBody 	 := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))}
	  };
	  
	  // Extract challenge and calculate credentials for a response.
	  v_challenge := vc_response.msgHeader.wwwAuthenticate.challenge.otherChallenge.authParams;
	            
	  // Increment CSeq sequence number 
	  vc_cSeq.seqNumber := vc_cSeq.seqNumber + 1;
      
      // Prepair right answer      
	  vc_authorization := 
		   {
			 fieldName := AUTHORIZATION_E,
			 body := f_calculatecCredentials(vc_userprofile, "REGISTER", v_challenge)
		   }
				
	}// end function f_setHeaders_2ndREGISTER

	/**
	 * 
	 * @desc function sets via, cseq and authorization header for the next outgoing (protected) REGISTER
	 * NO response in Authorization header to cause an error
	 * @verdict 
	 */
	function f_setHeaders_2ndREGISTER_wo_response() runs on SipComponent
	{
	  var CommaParam_List v_challenge;
		
	  vc_branch := c_branchCookie & f_getRndTag();

	  vc_via_REG :={
		fieldName := VIA_E,
		viaBody 	 := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))}
	  };
	  
	  // Extract challenge and calculate credentials for a response.
	  v_challenge := vc_response.msgHeader.wwwAuthenticate.challenge.otherChallenge.authParams;
	            
	  // Increment CSeq sequence number 
	  vc_cSeq.seqNumber := vc_cSeq.seqNumber + 1;
      
	  // Prepair right answer      
	  vc_authorization := 
		   {
			 fieldName := AUTHORIZATION_E,
			 body := f_calculatecCredentials_wo_response(vc_userprofile, "REGISTER", v_challenge)
		   }
				
	}// end function f_setHeaders_2ndREGISTER_wo_response

	/**
	 * 
	 * @desc function sets via, cseq and authorization header with different private name for the next outgoing (protected) REGISTER
	 * @verdict 
	 */
 	function f_setHeaders_2ndREGISTER_authorizationWithDifferentUserName() runs on SipComponent
	{
	  var CommaParam_List v_challenge;
		
	  vc_branch := c_branchCookie & f_getRndTag();

	  vc_via_REG :={
		fieldName := VIA_E,
		viaBody 	 := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))}
	  };
	  
	  // Extract challenge and calculate credentials for a response.
	  v_challenge := vc_response.msgHeader.wwwAuthenticate.challenge.otherChallenge.authParams;
	            
	  // Increment CSeq sequence number 
	  vc_cSeq.seqNumber := vc_cSeq.seqNumber + 1;
      
      // Prepair right answer      
	  vc_authorization := 
		   {
			 fieldName := AUTHORIZATION_E,
			 body := f_calculatecCredentialsAndChangeUserName(vc_userprofile, "REGISTER", v_challenge)
		   }
				
	}// end function f_setHeaders_2ndREGISTER_authorizationWithDifferentUserName


	/**
	 * 
	 * @desc function sets header fields for the next outgoing REGISTER (de-registration)
	 * @param p_cSeq_s cSeq to be used
	 * @verdict 
	 */
 	function f_setHeaders_deREGISTER(inout CSeq p_cSeq_s) runs on SipComponent
	{
	f_setHeaders_REGISTER(p_cSeq_s);
	vc_contact := 
		{
		  fieldName := CONTACT_E,
		  contactBody := {wildcard := "*" } 
		};
	} // end function f_setHeaders_deREGISTER


	/**
	 * 
	 * @desc setting of general and basic Invite header fields
	 * 		in additon to the addresses (To, From, ReqUri)
	 * @param p_cSeq_s
	 */
	function f_setHeadersINVITE(inout CSeq p_cSeq_s) runs on SipComponent
	{      
	  f_setHeadersGeneral(p_cSeq_s, "INVITE"); // cseq, contact, branch, via

	  vc_callId := { fieldName:=CALL_ID_E, callid:=f_getRndCallId(p_cSeq_s) & c_AT & vc_userprofile.currIpaddr };

	  vc_cancel_To := vc_to;
	  vc_caller_To := vc_to;
      
	  vc_caller_From := vc_from;
            
	  vc_reqHostPort := vc_requestUri.hostPort;
      
	}// end function f_setHeadersINVITE

	/**
	 * 
	 * @desc setting of general and basic Message header fields
	 * 		in additon to the addresses (To, From, ReqUri)
	 * @param p_cSeq_s
	 */
	function f_setHeadersMESSAGE(inout CSeq p_cSeq_s) runs on SipComponent
	{      
	  f_setHeadersGeneral(p_cSeq_s, "MESSAGE"); // cseq, contact, branch, via

	  vc_callId := { fieldName:=CALL_ID_E, callid:=f_getRndCallId(p_cSeq_s) & c_AT & vc_userprofile.currIpaddr };

	  vc_cancel_To := vc_to;
	  vc_caller_To := vc_to;
      
	  vc_caller_From := vc_from;
            
	  vc_reqHostPort := vc_requestUri.hostPort;
      
	}// end function f_setHeadersMESSAGE

	/**
	 * 
	 * @desc function sets header field for the next outgoing SUBSCRIBE message
	 * @param p_cSeq_s CSeq parameter to be applied
	 */
 	function f_setHeaders_SUBSCRIBE(inout CSeq p_cSeq_s) runs on SipComponent
	{
	  f_setHeadersGeneral(p_cSeq_s, "SUBSCRIBE"); // cseq, contact, branch, via
  
  	  vc_requestUri:=valueof(m_SipUrl_currDomain(vc_userprofile))
      
	}// end function setHeaders_SUBSCRIBE
	
	
	/**
	 * 
	 * @desc setting of general and basic REFER header fields
	 * 		in additon to the addresses (To, From, ReqUri)
	 * @param p_cSeq_s
	 */
	function f_setHeadersREFER(inout CSeq p_cSeq_s) runs on SipComponent
	{      
	  f_setHeadersGeneral(p_cSeq_s, "REFER"); // cseq, contact, branch, via

	  vc_callId := { fieldName:=CALL_ID_E, callid:=f_getRndCallId(p_cSeq_s) & c_AT & vc_userprofile.currIpaddr };

	  vc_cancel_To := vc_to;
	  vc_caller_To := vc_to;
      
	  vc_caller_From := vc_from;
            
	  vc_reqHostPort := vc_requestUri.hostPort;
      
	}// end function f_setHeadersREFER
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592

	/**
	 * 
	 * @desc This function reads all necessary headers from the received REGISTER message and generate the tag for the answer
	 * @param p_Request REGISTER that has been received
	 */
	function f_setHeadersOnReceiptOfREGISTER(Request p_Request)
	runs on SipComponent {

	  f_setHeadersOnReceiptOfRequest(p_Request);
	
	  vc_callId := p_Request.msgHeader.callId;
	  vc_caller_From := vc_from;
	  f_addTagInTo(vc_to);
	  vc_caller_To := vc_to;
	  vc_requestUri := p_Request.requestLine.requestUri;
      
	  vc_cancel_To := p_Request.msgHeader.toField;
      
	  if (ispresent(p_Request.msgHeader.contact)) {
		vc_reqHostPort := f_getContactAddr(p_Request.msgHeader.contact.contactBody.contactAddresses[0]);
	  	}
      
	  // update callee information and pick up tag if the call need to be canceled
	  vc_callee_To := {fieldName := TO_E,
		addressField := vc_caller_From.addressField,
		toParams := vc_caller_From.fromParams};
      
	  vc_callee_From := {fieldName := FROM_E,
		addressField := vc_caller_To.addressField,
		fromParams := vc_caller_To.toParams};
      
	} // end f_setHeadersOnReceiptOfREGISTER

	/**
	 * 
	 * @desc This function reads all necessary headers from the received SUBSCRIBE message and generate the tag for the answer
	 * @param p_Request SUBSCRIBE that has been received
	 */
	function f_setHeadersOnReceiptOfSUBSCRIBE(Request p_Request)
	runs on SipComponent {

	  f_setHeadersOnReceiptOfRequest(p_Request);
	
	  vc_callId := p_Request.msgHeader.callId;
	  vc_caller_From := vc_from;
	  f_addTagInTo(vc_to);
	  vc_caller_To := vc_to;
	  vc_requestUri := p_Request.requestLine.requestUri;
      
	  vc_cancel_To := p_Request.msgHeader.toField;
      
	  if (ispresent(p_Request.msgHeader.contact)) {
		vc_reqHostPort := f_getContactAddr(p_Request.msgHeader.contact.contactBody.contactAddresses[0]);
		}
      
	  // update callee information and pick up tag if the call need to be canceled
	  vc_callee_To := {fieldName := TO_E,
		addressField := vc_caller_From.addressField,
		toParams := vc_caller_From.fromParams};
      
	  vc_callee_From := {fieldName := FROM_E,
		addressField := vc_caller_To.addressField,
		fromParams := vc_caller_To.toParams};
      
	} // end f_setHeadersOnReceiptOfSUBSCRIBE
   
	/**
	 * 
	 * @desc function reads all necessary headers from 
	 * the received INVITE message and generate the tag for the answer
	 * @param p_Request received INVITE message
	 * @verdict 
	 */
	function f_setHeadersOnReceiptOfINVITE(Request p_Request) runs on SipComponent {

	f_setHeadersOnReceiptOfRequest(p_Request);

	vc_callId := p_Request.msgHeader.callId;

	vc_requestUri := p_Request.requestLine.requestUri;
      
	vc_cancel_To := p_Request.msgHeader.toField;
	f_addTagInTo(vc_to);
	vc_caller_From := vc_from;
	vc_caller_To := vc_to;
      
	if (ispresent(p_Request.msgHeader.contact)) {
	   	vc_reqHostPort := 
	  	f_getContactAddr(p_Request.msgHeader.contact.contactBody.contactAddresses[0]);
	 	};
      
	 // update callee information and pick up tag if the call need to be canceled
	vc_callee_To := {fieldName := TO_E,
	   addressField := vc_caller_From.addressField,
	   toParams := vc_caller_From.fromParams};
      
	vc_callee_From := {fieldName := FROM_E,
	   addressField := vc_caller_To.addressField,
	   fromParams := vc_caller_To.toParams};
        
	if (ispresent(p_Request.msgHeader.privacy)) {
		vc_privacy := p_Request.msgHeader.privacy;
		};
        
	if (ispresent(p_Request.messageBody)) { 
		//cleaning of attributes before assignment
		if (ispresent(vc_sdp_remote.media_list))
		{
				for (var integer i:=0; i<sizeof(vc_sdp_remote.media_list); i:=i+1)
				{			
						if (ispresent(vc_sdp_remote.media_list[i].attributes))
						{
							for (var integer j:=0; j<sizeof(vc_sdp_remote.media_list[i].attributes); j:=j+1)
							{		  	
					vc_sdp_remote.media_list[i].attributes[j] := omit ; 
							}
						}
				};
		}		
		
		// save SDP if present
		if ( ischosen(p_Request.messageBody.sdpMessageBody)) 
		{
			vc_sdp_remote := p_Request.messageBody.sdpMessageBody;		  
			vc_sdp_remote_is_valid := true;
			f_prepare_SDP_answer();			 			
		};
		
		// save XML if present
		if ( ischosen(p_Request.messageBody.xmlBody))
		{
			vc_xml_remote := p_Request.messageBody.xmlBody;		 			
		}

		if ( ischosen(p_Request.messageBody.mimeMessageBody))
		{
			
			for (var integer j:=0; j<sizeof(p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList); j:=j+1){
				if (match(p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type,c_sdpAplication))
				{
					vc_sdp_remote := p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.sdpMessageBody;
					vc_sdp_remote_is_valid := true;
					f_prepare_SDP_answer();
				};
				if (match(p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type,c_xmlAplication))
				{
					vc_xml_remote := p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.xmlBody;
				};			
			}	
		}	
	};
	   
	if (ispresent(p_Request.msgHeader.supported.optionsTags)) {
		for (var integer i := sizeof(p_Request.msgHeader.supported.optionsTags); i>0; i:=i-1)
		   {
			   if (p_Request.msgHeader.supported.optionsTags[i-1]=="100rel")
			   { vc_supported_100rel := true };
			   if (p_Request.msgHeader.supported.optionsTags[i-1]=="precondition")
			   { vc_supported_precondition := true }
		   }
	   	};
      
   } // end f_setHeadersOnReceiptOfINVITE

	/**
	 * 
	 * @desc function reads header field of a received BYE message 
	 * @param p_Request received BYE
	 */
   function f_setHeadersOnReceiptOfBYE(Request p_BYE_Request)
   runs on SipComponent
   {
   	
	 f_setHeadersOnReceiptOfRequest(p_BYE_Request);
	 vc_callId := p_BYE_Request.msgHeader.callId;

   } // end f_setHeadersOnReceiptOfBYE

	/**
	 * 
	 * @desc function reads header field from an incoming Request message
	 * @param p_Request received Request message
	 */
	function f_setHeadersOnReceiptOfRequest(Request p_Request) runs on SipComponent {
     vc_request := p_Request;
	 vc_cSeq := p_Request.msgHeader.cSeq;
	 vc_iut_CSeq  := p_Request.msgHeader.cSeq;
	 vc_from := p_Request.msgHeader.fromField;
	 vc_to := p_Request.msgHeader.toField;
	 vc_via := p_Request.msgHeader.via;
	 // update sent_label according to received via header field
	 f_getViaReplyAddr(vc_via.viaBody, vc_sent_label);
	  
	 // Catch route
	 vc_boo_recordRoute:=false;
	  
	 if (ispresent(p_Request.msgHeader.recordRoute))
	 {
	   vc_boo_recordRoute:=true;
	   vc_recordRoute := p_Request.msgHeader.recordRoute;
	 }
   	} // end f_setHeadersOnReceiptOfRequest

	/**
	 * 
	 * @desc functions reads header fields from an incoming Response message
	 * @param p_cSeq
	 * @param p_response received response message
	 * @verdict 
	 */
    function f_setHeadersOnReceiptOfResponse(inout CSeq p_cSeq, Response p_response) runs on SipComponent
   {
	 var integer v_i, v_j, v_nbroute;
	 var Contact v_contact; //only for local purpose
	       
	 vc_response := p_response;
	 //vc_cSeq := p_cSeq; //must not save global c_seq because it can overwrite temporary cSeq
	 vc_to :=p_response.msgHeader.toField;
	 vc_from :=p_response.msgHeader.fromField;
	 vc_caller_To := vc_to;
	 vc_caller_From := vc_from;
      
	 if (ispresent(p_response.msgHeader.contact))
	 {
	   v_contact := p_response.msgHeader.contact;
	   if (ischosen(v_contact.contactBody.contactAddresses))
	   {
		 vc_reqHostPort := f_getContactAddr(v_contact.contactBody.contactAddresses[0]);
	   }
	 }
	 else
	 {
	   if (ischosen(vc_to.addressField.nameAddr))
	   {
		 vc_reqHostPort := vc_to.addressField.nameAddr.addrSpec.hostPort;
	   }
	   else
	   {
		 vc_reqHostPort := vc_to.addressField.addrSpecUnion.hostPort;
	   }
	 }
      
	 vc_callee_To:={fieldName := TO_E,
	   addressField := vc_caller_From.addressField,
	   toParams := vc_caller_From.fromParams};
      
	 vc_callee_From:= {fieldName := FROM_E,
	   addressField := vc_caller_To.addressField,
	   fromParams := vc_caller_To.toParams};
	 
	 vc_via:= p_response.msgHeader.via;
      
	 // Route Management
	 if (ispresent(p_response.msgHeader.recordRoute))
	 {
	   vc_recordRoute := p_response.msgHeader.recordRoute;
	   v_nbroute := sizeof(vc_recordRoute.routeBody);
	   // copy and reverse the order of the routes in route header
	   for (v_i:=0; v_i<=(v_nbroute - 1); v_i:=v_i+1)
	   {
		 v_j:= v_nbroute - 1 - v_i;
		 vc_route.routeBody[v_j]:=vc_recordRoute.routeBody[v_i];
	   }
	   vc_route.fieldName := ROUTE_E;
	   vc_boo_recordRoute := true;
	   vc_boo_route := true;
	 }
	 else
	 {
	   vc_boo_recordRoute := false;
	   vc_boo_route := false;
	 };


	 // extentions due to new fields in PRACK and UPDATE messages
	 if (ispresent(p_response.msgHeader.rSeq)) {
	 	vc_rAck := 
			 { fieldName := RACK_E, 
			   responseNum := valueof(p_response.msgHeader.rSeq.responseNum),
			   seqNumber := valueof(p_response.msgHeader.cSeq.seqNumber),
			   method := valueof(p_response.msgHeader.cSeq.method)
			 };
		 };

	 // extentions due to new HistoryInfo fields 180 or 200OK messages
	 if (ispresent(p_response.msgHeader.historyInfo)) {
	 	vc_historyInfoList := valueof(p_response.msgHeader.historyInfo.historyInfoList);
		vc_history_is_valid := true
		}
	   else {vc_history_is_valid := false};

	 //sdpMessageBody answer
	 if (ispresent(p_response.messageBody)) { 
		if ( ischosen(p_response.messageBody.sdpMessageBody))
		{
			vc_sdp_remote := p_response.messageBody.sdpMessageBody;		  
			vc_sdp_remote_is_valid := true;
	 	}

		if ( ischosen(p_response.messageBody.xmlBody))
		{
			vc_xml_remote := p_response.messageBody.xmlBody;		 			
		}

		if ( ischosen(p_response.messageBody.mimeMessageBody))
		{
			
			for (var integer j:=0; j<sizeof(p_response.messageBody.mimeMessageBody.mimeEncapsulatedList); j:=j+1){
				if (match(p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type,c_sdpAplication))
				{
					vc_sdp_remote := p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.sdpMessageBody;
				};
				if (match(p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type,c_xmlAplication))
				{
					vc_xml_remote := p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.xmlBody;
				};			
			}	
		}
	 };

   }// end function f_setHeadersOnReceiptOfResponse

   /**
	* 
	* @desc functions reads ServiceRoute header field from an incoming 200 Response message in registration
	* @param p_cSeq
	* @param p_response received response message
	*/
    function f_getServiceRouteMapIntoRouteInRegistration(inout CSeq p_cSeq, Response p_response) runs on SipComponent
   {
	 var integer v_i, v_j, v_nbroute;
	 var ServiceRoute v_serviceRoute;
	       
	 // Route Management
	 if (ispresent(p_response.msgHeader.serviceRoute))
	 {
	   v_serviceRoute := p_response.msgHeader.serviceRoute;
	   v_nbroute := sizeof(v_serviceRoute.routeBody);
	   // copy and reverse the order of the routes in route header
	   for (v_i:=0; v_i<=(v_nbroute - 1); v_i:=v_i+1)
	   {
		 v_j:= v_nbroute - 1 - v_i;
		 vc_route.routeBody[v_j]:=v_serviceRoute.routeBody[v_i];
	   }
	   vc_route.fieldName := ROUTE_E;
	 }

   }// end function f_getServiceRouteMapIntoRouteInRegistration


} // end group SetHeaders
   
} // end group FieldOperations

group SDPOperations{
	
	/** 
	*  @desc check if message body include SDP attribute (2nd parameter)
	*        for any media 
	*		 
	*/
	function f_check_attribute(in SDP_Message p_sdp, in template SDP_attribute p_attribute) runs on SipComponent return boolean {
		
    	if (ispresent(p_sdp.media_list)) {
    		for (var integer j:=0; j<sizeof(p_sdp.media_list); j:=j+1){			
    			if (ispresent(p_sdp.media_list[j].attributes)) {
    				for (var integer i:=0; i<sizeof(p_sdp.media_list[j].attributes); i:=i+1){			
    					if (match(p_sdp.media_list[j].attributes[i],p_attribute)) 
    						{return(true);};
    					};
    			}
    			};
    	}
    	if (ispresent(p_sdp.attributes)) {
    		for (var integer j:=0; j<sizeof(p_sdp.attributes); j:=j+1){			
    			if (match(p_sdp.attributes[j],p_attribute)) {return(true);};
    			};
    	}
    	
    	return(false);
	}		

	/** 
	*  @desc find and return SDP direction attribute (session or first media attribute)
	*		 
	*/
	function f_get_attribute_answer(in SDP_Message p_sdp, in template SDP_attribute p_attribute) runs on SipComponent return SDP_attribute {

	var template SDP_attribute v_attribute := p_attribute;
		
					if (ispresent(p_sdp.attributes)) {
						for (var integer j:=0; j<sizeof(p_sdp.attributes); j:=j+1){			
							if (match(p_sdp.attributes[j],p_attribute)) {v_attribute := p_sdp.attributes[j];};
							};
					}
    	
					if (ispresent(p_sdp.media_list)) {
						for (var integer j:=0; j<sizeof(p_sdp.media_list); j:=j+1){			
							if (ispresent(p_sdp.media_list[j].attributes)) {
								for (var integer i:=0; i<sizeof(p_sdp.media_list[j].attributes); i:=i+1){			
									if (match(p_sdp.media_list[j].attributes[i],p_attribute)) 
										{v_attribute := p_sdp.media_list[j].attributes[i];};
									};
							}
							};
					}
					select (v_attribute)
					{
						//case (mw_attribute_sendrecv) {return(m_attribute_sendrecv);}
						case (mw_attribute_sendrecv) {return(valueof(m_attribute_sendrecv));}//MRO	
						case (mw_attribute_inactive) {return(valueof(m_attribute_inactive));}//MRO
						case (mw_attribute_recvonly) {return(valueof(m_attribute_sendonly));}//MRO
					return(valueof(m_attribute_sendrecv));//MRO
					//return(v_attribute); // not needed due to case else
	}

	/** 
	*  @desc check if message body include SDP bandwidth (2nd parameter)
	*		 either for the session or a media description
	*/
	function f_check_bandwidth(in SDP_Message loc_sdp, in template SDP_bandwidth loc_bandw) runs on SipComponent return boolean {
	
					if (ispresent(loc_sdp.bandwidth)) {
						for (var integer j:=0; j<sizeof(loc_sdp.bandwidth); j:=j+1){			
							if (match(loc_sdp.bandwidth[j],loc_bandw)) {return(true);};
							};
					};
					if (ispresent(loc_sdp.media_list)) {
						for (var integer j:=0; j<sizeof(loc_sdp.media_list); j:=j+1){
							if (ispresent(loc_sdp.media_list[j].bandwidth)) {						
								if (match(loc_sdp.media_list[j].bandwidth,loc_bandw)) {return(true);};
								};
							};
					};
    	
		return(false);
	}

	/** 
	*  @desc check if message body include SDP media (2nd parameter)
	*		 
	*/
	function f_check_media(in SDP_Message loc_sdp, in template SDP_media_desc loc_media) runs on SipComponent return boolean {
		
    	if (ispresent(loc_sdp.media_list)) {
    		for (var integer j:=0; j<sizeof(loc_sdp.media_list); j:=j+1){			
    			if (match(loc_sdp.media_list[j].media_field.transport,loc_media.media_field.transport) and
    				match(loc_sdp.media_list[j].media_field.fmts,loc_media.media_field.fmts)) 
    				{return(true);};
    			};
    	}
    	return(false);
poglitsch's avatar
poglitsch committed
	}
	
	/**
	 * @desc
	 *     check if message body include precondition mechanism (a=des and
	 *     a=curr) retrun true, else false
	 * @param loc_sdp SDP message
	 */
	function f_check_precondition(in SDP_Message loc_sdp) runs on SipComponent return boolean {
    	if (f_check_attribute(loc_sdp, mw_attribute_des) or
    		f_check_attribute(loc_sdp, mw_attribute_curr)) 
    		{return(true);}
    		
    	return(false);
	}	
			

	/** 
	*  @desc check if message body include SDP media direction return true, else false
	*		 
	*/
	function f_check_media_direction(in SDP_Message loc_sdp) runs on SipComponent return boolean {
		
    	if (f_check_attribute(loc_sdp, mw_attribute_sendonly) or
    		f_check_attribute(loc_sdp, mw_attribute_recvonly) or
    		f_check_attribute(loc_sdp, mw_attribute_sendrecv) or
    		f_check_attribute(loc_sdp, mw_attribute_inactive)) 
    		{return(true);}
    		
    	return(false);
	}		

	/** 
	*  @desc copy media/attribute lines from remote to local SDP variable
	*		 
	*/
	function f_check_SDP(integer loc_sdp, integer loc_codec) runs on SipComponent
	return boolean
	{
		var SDP_media_desc v_media := f_prepare_media(loc_sdp,loc_codec);
		log("log0"); 
		if (vc_sdp_remote.media_list[0].media_field.media != v_media.media_field.media)
			{ log("log1"); return false };
		if (vc_sdp_remote.media_list[0].media_field.transport != v_media.media_field.transport)
			{ log("log2"); return false };
		if (vc_sdp_remote.media_list[0].media_field.fmts != v_media.media_field.fmts)
			{ log("remote:",vc_sdp_remote.media_list[0].media_field.fmts,"expect:",v_media.media_field.fmts); return false };
			
		return true
	}
	
poglitsch's avatar
poglitsch committed
	/**
	 * @desc replace the first curr media attribute with the given value.
	 * @param p_sdp SDP message to modify
	 * @param p_curr new curr attribute
	 */
	function f_replace_curr_attribute(inout SDP_Message p_sdp, in SDP_attribute_curr p_curr) {
		if(ispresent(p_sdp.media_list)) {
			var integer mn := sizeof(p_sdp.media_list[0].attributes);
			for(var integer i := 0; i<=mn; i := i+1) {
				if(ischosen(p_sdp.media_list[0].attributes[i].curr)){
					p_sdp.media_list[0].attributes[i].curr := p_curr;
					i:=mn; 
				}	
			}
		}
	}
	
	/**
	 * @desc append new media attribute to the first media description.
	 * @param p_sdp SDP message to modify
	 * @param p_att SDP attribute to appand
	 */
	function f_append_media_attribute(inout SDP_Message p_sdp, in SDP_attribute p_att) {
		if(ispresent(p_sdp.media_list)) {
			var integer mn := sizeof(p_sdp.media_list[0].attributes);
			p_sdp.media_list[0].attributes[mn] := p_att;
		}
	}
	
	
	/** 
	*  @desc append new media to the existing media list in SDP
	*		 
	*/
	function f_append_media(inout SDP_Message loc_SDP, in template SDP_media_desc loc_media)
	{
		var integer mn := sizeof(loc_SDP.media_list);
		loc_SDP.media_list[mn] := valueof(loc_media);
	}
	/** 
	*  @desc repare media/attribute lines
	*		 
	*/
	function f_prepare_media(integer loc_sdp, integer loc_codec) runs on SipComponent
	return SDP_media_desc
	{
		var charstring v_codecs[32] := {
			"PCMU/8000", "GSM/8000", "G723/8000", "DVI4/8000",
			"DVI4/16000", "LPC/8000", "PCMA/8000", "G722/8000",
			"L16/44100/2", "L16/44100", "QCELP/8000", "CN/8000",
			"MPA/90000", "G728/8000", "DVI4/11025", "DVI4/22050",
			"G729/8000", "G726-40/8000", "G726-32/8000", "G726-24/8000",
			"G726-16/8000", "G726D/8000", "G726E/8000", "GSM-EFR/8000",
			"CelB/90000", "JPEG/90000", "Nv/90000", "H261/90000",
			"MPV/90000", "MP2T/90000", "H263/90000", "H263-1998/90000"
		}
		var SDP_media_desc v_media :=
			{
				media_field := {
					media := "audio",
					ports := { 
						port_number := 10000, 
						num_of_ports:=omit },
					transport := "RTP/AVP",
					fmts := { "0" }
				}, //m=audio 8500 RTP/AVP 0
				information := omit,
				connections := omit,
				bandwidth := omit,
				key := omit,						
				attributes := omit
			};
			
		if (32<loc_codec or loc_codec<1) {
			log("Unexpected SDP variant");
			setverdict(inconc); 
			return (v_media)}

		if (loc_sdp == 1) {}
		else if (loc_sdp == 2) {
			v_media.media_field.fmts := {PX_SIP_SDP_dyn}; //{ "98", "0" };
			v_media.attributes := {{
			rtpmap := { attr_value := PX_SIP_SDP_dyn & " " & v_codecs[loc_codec-1] } // PX_SIP_SDP_dyn := 98
			}}
		} else if (loc_sdp == 3) {
			v_media.media_field.fmts := { "8" }
		} else if (loc_sdp == 4) {
			v_media.media_field.fmts := { "99", "8" };
			v_media.attributes := {{
				rtpmap := { attr_value := "99 " & v_codecs[loc_codec-1] }
						}}
		} else if (loc_sdp == 5) {
			v_media.media_field.media := "image";
			v_media.media_field.transport := "udptl";
			v_media.media_field.fmts := { "t38" }
		} else if (loc_sdp == 6) {
			v_media.media_field.media := "image";
			v_media.media_field.transport := "tcptl";
			v_media.media_field.fmts := { "t38" }
		} else {
			log("Unexpected SDP variant"); setverdict(inconc) 
		};
			
		return (v_media);
	}

	/** 
	*  @desc repare media/attribute lines
	*		 
	*/
	function f_prepare_SDP(integer loc_sdp, integer loc_codec) runs on SipComponent
	{

		vc_sdp_local.media_list := {f_prepare_media(loc_sdp,loc_codec)};
	}
	
	/**
	* 
	* @desc function that copy media/attribute lines from remote to local SDP variable
	*/
	function f_prepare_SDP_answer() runs on SipComponent
	{
		var integer mn, cn := 0, i, j, k :=0;
		var charstring v_PT, v_rtpmap := "";
		var SDP_attribute_list v_mediaAttributes := {};
		//increase session version
		vc_sdp_local.origin.session_version := 	int2str(str2int(vc_sdp_local.origin.session_version)+1);
		// if more than one codec, select the firs one
		mn:= sizeof(vc_sdp_local.media_list);
		for (i :=0;  i < mn; i := i+1)
		{
			//for every single media
			if (ispresent(vc_sdp_local.media_list[i].attributes))
			{
				cn := sizeof(vc_sdp_local.media_list[i].attributes);
			};
			if (sizeof(vc_sdp_local.media_list[i].media_field.fmts)>1) 
			{
				// select the first one
				v_PT := vc_sdp_local.media_list[i].media_field.fmts[0];
				vc_sdp_local.media_list[i].media_field.fmts := {v_PT};
				for (j :=0; j<cn; j:=j+1)
				{
					if (ischosen(vc_sdp_local.media_list[i].attributes[j].rtpmap))
					{
						if (v_PT == regexp(vc_sdp_local.media_list[i].attributes[j].rtpmap.attr_value,	"[ \t]#(0,)([/d]+)*",	0))
						{
							v_rtpmap := vc_sdp_local.media_list[i].attributes[j].
							rtpmap.attr_value;
							v_mediaAttributes[k] := {rtpmap := {attr_value := v_rtpmap}};
							k := k+1;
						} // else line is not copied
					}


					// simplified handling of status attributes (copy/keep status from peer):
					// a) copy/keep SDP_attribute_curr (invert tags if applicable)
					if (ischosen(vc_sdp_local.media_list[i].attributes[j].curr))
					{
						// invert local/remote status tags
						if (vc_sdp_local.media_list[i].attributes[j].curr.statusType == "local")
							{vc_sdp_local.media_list[i].attributes[j].curr.statusType := "remote"};
						if (vc_sdp_local.media_list[i].attributes[j].curr.statusType == "remote")
							{vc_sdp_local.media_list[i].attributes[j].curr.statusType := "local"};
						// invert send/recv direction tags
						if (vc_sdp_local.media_list[i].attributes[j].curr.direction == "send")
							{vc_sdp_local.media_list[i].attributes[j].curr.direction := "recv"};
						if (vc_sdp_local.media_list[i].attributes[j].curr.direction == "recv")
							{vc_sdp_local.media_list[i].attributes[j].curr.direction := "send"};
					}				
					// b) copy/keep SDP_attribute_des (keep strength, invert tags if applicable)	
					else if (ischosen(vc_sdp_local.media_list[i].attributes[j].des))
					{
						// invert local/remote status tags
						if (vc_sdp_local.media_list[i].attributes[j].des.statusType == "local")
							{vc_sdp_local.media_list[i].attributes[j].des.statusType := "remote"};
						if (vc_sdp_local.media_list[i].attributes[j].des.statusType == "remote")
							{vc_sdp_local.media_list[i].attributes[j].des.statusType := "local"};
						// invert send/recv direction tags
						if (vc_sdp_local.media_list[i].attributes[j].des.direction == "send")
							{vc_sdp_local.media_list[i].attributes[j].des.direction := "recv"};
						if (vc_sdp_local.media_list[i].attributes[j].des.direction == "recv")
							{vc_sdp_local.media_list[i].attributes[j].des.direction := "send"};
					}				
					// c) simplification: assume no SDP_attribute_conf	
					else if (ischosen(vc_sdp_local.media_list[i].attributes[j].conf))
					{
						// todo: handle SDP_attribute_conf
					}					
						
					 
					else 
					{
						// simple copy of attribute
						v_mediaAttributes[k] := vc_sdp_local.media_list[i].attributes[j];
						k := k+1;
					}
				}
				vc_sdp_local.media_list[i].attributes := v_mediaAttributes;
			}
		}
		// add handling of prenegotiation, change ports if required etc.
		//if prenegotiation...
	}

	/** 
	*  @desc reject SDP offer by setting media ports to 0
	*		 
	*/
	function f_reject_SDP_offer() runs on SipComponent
	{
		var integer mn, i;
		f_copy_SDP(); // TO BE DONE with more details!
		//increase session version
		vc_sdp_local.origin.session_version := int2str(str2int(vc_sdp_local.origin.session_version)+1);
		// if more than one codec, select the firs one
		mn:= sizeof(vc_sdp_local.media_list);
		for (i :=0;  i < mn; i := i+1)
		{
			vc_sdp_local.media_list[i].media_field.ports := {0, omit};
			vc_sdp_local.media_list[i].attributes := omit; //{};
		};
	}

	/** 
	*  @desc modify media/attribute direction
	*		 
	*/
	function f_SIP_modMediaDirection(integer p_medianum, template SDP_attribute p_direction) runs on SipComponent
	{
		var boolean v_set_direction;
		var integer v_mn, v_cn := 0, i, j, k :=0;
		var SDP_attribute_list v_mediaAttributes := {};
		f_copy_SDP(); 
		//increase session version
		vc_sdp_local.origin.session_version := int2str(str2int(vc_sdp_local.origin.session_version)+1);
		// if more than one codec, select the firs one
		v_mn:= sizeof(vc_sdp_local.media_list);

		if (p_medianum == 0) //specific media requested
		{
			p_medianum := 1; // start checking from first media
		};
		if (p_medianum > 0) //specific media requested
		{
			if (not(p_medianum > v_mn)) {v_mn := p_medianum}
		};
		for (i :=0;  i < v_mn; i := i+1)
		{
			//for every single media (that is not omit)
			v_cn := 0;
		
//			if (ispresent(vc_sdp_local.media_list[i].media_field))//MRO media_field is not optional
//			{
						
				log("vc_sdp_local.media_list[i] ",vc_sdp_local.media_list[i]);
//				if (valueof(vc_sdp_local.media_list[i]) != omit)
//				{
					if (ispresent(vc_sdp_local.media_list[i].attributes))
					{
						v_cn := sizeof(vc_sdp_local.media_list[i].attributes);
					};
//				};
				v_set_direction := false;
				//if (sizeof(vc_sdp_local.media_list[i].media_field.fmts)>1) 
				// select the first one
    				for (j :=0; j<v_cn; j:=j+1)
    				{ 
    					if (ischosen(vc_sdp_local.media_list[i].attributes[j].recvonly)
    							or ischosen(vc_sdp_local.media_list[i].attributes[j].sendonly)
    							or ischosen(vc_sdp_local.media_list[i].attributes[j].inactive)
    							or ischosen(vc_sdp_local.media_list[i].attributes[j].sendrecv))
    					{
    						log("axr3");
    						v_mediaAttributes[k] := valueof(p_direction); v_set_direction := true;
    					}
    				 	else 
    					{
    						// simple copy of attribute
    						v_mediaAttributes[k] := vc_sdp_local.media_list[i].attributes[j];
    						log("axr new attribute index ", k);
    						k := k+1;
    					}
    				 
    				}
    				if (not v_set_direction) 
    					{ v_mediaAttributes[k] := valueof(p_direction)};
    				vc_sdp_local.media_list[i].attributes := v_mediaAttributes;
				// }
		}	 
		// add handling of prenegotiation, change ports if required etc.
		//if prenegotiation...
	}
	
     /** 
     *  @desc modify session and media attributes direction
     *		 
     */
     function f_SIP_modSessionDirection(template SDP_attribute p_direction) runs on SipComponent
     {
      var boolean v_set_direction;
      var integer v_mn:= 0, i:=0;
      var SDP_attribute_list v_mediaAttributes := {};
      
	  if (ispresent(vc_sdp_local.attributes))
		{ v_mn:= sizeof(vc_sdp_local.attributes);			
       
          for (i :=0;  i < v_mn; i := i+1)
          {//for every single attribute (that is not omit)    
                 if (ischosen(vc_sdp_local.attributes[i].recvonly)