void testReservedCharsInParameters() { OsSysLog::add(FAC_SUPERVISOR, PRI_DEBUG, "AlarmServerTest::testReservedCharsInParameters"); UtlString localhost("localhost"); UtlString alarmId("PARAMETER_WITH_RESERVED_CHARS"); UtlSList alarmParams; UtlString alarmParam("<sample>; \"x=y\""); alarmParams.append(&alarmParam); cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams); OsTask::delay(DELAY); UtlString actualString; UtlString expectedString = "Parameters may contain xml reserved characters e.g. '<sample>; \\\"x=y\\\"'"; tail(mAlarmFile, actualString); char msg[1000]; sprintf(msg, "incorrect message was logged: actualString '%s' expected '%s'", actualString.data(), expectedString.data()); CPPUNIT_ASSERT_MESSAGE(msg, actualString.contains(expectedString)); }
void testNewlinesInStrings() { OsSysLog::add(FAC_SUPERVISOR, PRI_DEBUG, "AlarmServerTest::testNewlinesInStrings"); UtlString localhost("localhost"); UtlString alarmId("MESSAGE_WITH_NEWLINES"); UtlSList alarmParams; UtlString alarmParam("1"); alarmParams.append(&alarmParam); UtlString alarmParam2 = "\nparam on new line"; alarmParams.append(&alarmParam2); cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams); OsTask::delay(DELAY); UtlString actualString; UtlString expectedString = "param on new line"; tail(mAlarmFile, actualString); char msg[1000]; sprintf(msg, "incorrect message was logged: actualString '%s' expected '%s'", actualString.data(), expectedString.data()); CPPUNIT_ASSERT_MESSAGE(msg, actualString.contains(expectedString)); }
void testParameterSubstitution() { OsSysLog::add(FAC_SUPERVISOR, PRI_DEBUG, "AlarmServerTest::testParameterSubstitution"); UtlString localhost("localhost"); UtlString alarmId("PARAMETER_SUBSTITUTION"); UtlSList alarmParams; UtlString alarmParam("1"); alarmParams.append(&alarmParam); UtlString alarmParam2 = "2"; alarmParams.append(&alarmParam2); cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams); OsTask::delay(DELAY); UtlString actualString; UtlString expectedString = "Parameter 2, then parameter 1"; tail(mAlarmFile, actualString); char msg[1000]; sprintf(msg, "incorrect message was logged: actualString '%s' expected '%s'", actualString.data(), expectedString.data()); CPPUNIT_ASSERT_MESSAGE(msg, actualString.contains(expectedString)); }
UtlBoolean SipRegistrar::handleMessage( OsMsg& eventMessage ) { UtlBoolean handled = FALSE; int msgType = eventMessage.getMsgType(); int msgSubType = eventMessage.getMsgSubType(); if ( (msgType == OsMsg::PHONE_APP) && (msgSubType == SipMessage::NET_SIP_MESSAGE) ) { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipRegistrar::handleMessage()" " Start processing SIP message") ; const SipMessage* message = ((SipMessageEvent&)eventMessage).getMessage(); UtlString callId; if ( message ) { message->getCallIdField(&callId); UtlString method; message->getRequestMethod(&method); if ( !message->isResponse() ) // is a request ? { if ( method.compareTo(SIP_REGISTER_METHOD) == 0 ) { //send to Register Thread sendToRegistrarServer(eventMessage); } else if ( method.compareTo(SIP_OPTIONS_METHOD) == 0 ) { UtlString requestUri; message->getRequestUri(&requestUri); // Check if the OPTIONS request URI is addressed to a user or // to the domain. if (!requestUri.contains("@")) { UtlString contentEncoding; message->getContentEncodingField(&contentEncoding); UtlString disallowedExtensions; int extensionIndex = 0; UtlString extension; disallowedExtensions.remove(0); while(message->getRequireExtension(extensionIndex, &extension)) { if(!(mSipUserAgent->isExtensionAllowed(extension.data())) ) { if(!disallowedExtensions.isNull()) { disallowedExtensions.append(SIP_MULTIFIELD_SEPARATOR); disallowedExtensions.append(SIP_SINGLE_SPACE); } disallowedExtensions.append(extension.data()); } extensionIndex++; } //delete leading and trailing white spaces disallowedExtensions = disallowedExtensions.strip(UtlString::both); SipMessage response; // Check if the extensions are supported if(!disallowedExtensions.isNull() ) { // error response - bad extension response.setRequestBadExtension(message, disallowedExtensions); } // Check if the encoding is supported // i.e. no encoding else if(!contentEncoding.isNull()) { // error response - content encoding response.setRequestBadContentEncoding(message,""); } else { // Send an OK, the allowed field will get added to all final responses. // Options 200 response response.setResponseData(message, SIP_OK_CODE, SIP_OK_TEXT); } mSipUserAgent->send(response); } else { //OPTIONS is addressed to a user, send to redirect thread sendToRedirectServer(eventMessage); } } else { //send to redirect thread sendToRedirectServer(eventMessage); } } else { // responses are ignored. } } else { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipRegistrar::handleMessage no message." ) ; } handled = TRUE; } else if ( OsMsg::OS_SHUTDOWN == msgType ) { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipRegistrar::handleMessage shutting down all tasks"); // Do an orderly shutdown of all the various threads. if ( mSipUserAgent ) { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipRegistrar::handleMessage shutting down SipUserAgent"); mSipUserAgent->shutdown(); delete mSipUserAgent ; mSipUserAgent = NULL ; } if ( mRegistrarPersist ) { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipRegistrar::handleMessage shutting down RegistrarPersist"); mRegistrarPersist->requestShutdown(); delete mRegistrarPersist; mRegistrarPersist = NULL; } if ( mRedirectServer ) { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipRegistrar::handleMessage shutting down RedirectServer"); mRedirectServer->requestShutdown(); delete mRedirectServer; mRedirectServer = NULL; mRedirectMsgQ = NULL; } if ( mRegistrarServer ) { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipRegistrar::handleMessage shutting down RegistrarServer"); mRegistrarServer->requestShutdown(); delete mRegistrarServer; mRegistrarServer = NULL; mRegistrarMsgQ = NULL; } if ( mRegisterEventServer ) { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipRegistrar::handleMessage shutting down RegisterEventServer"); delete mRegisterEventServer; mRegisterEventServer = NULL; } OsTask::requestShutdown(); // tell OsServerTask::run to exit handled = TRUE; } else { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipRegistrar::handleMessage unhandled type %d/%d", msgType, msgSubType ) ; } return handled; }
UtlBoolean TestRegistrar::handleRegisterRequest(SipMessage message) { UtlBoolean messageProcessed = false; SipMessage finalResponse; UtlString responseToAddress; UtlString protocol; int responseToPort; int seqNum; UtlString method; UtlString contactField; int expires; static int retrySeqNum = 0; UtlString callId; message.getCallIdField(&callId); message.getContactField(0, contactField); message.getExpiresField(&expires); message.getCSeqField(&seqNum, &method); message.getFromAddress(&responseToAddress, &responseToPort, &protocol); finalResponse.setContactField(contactField); finalResponse.setExpiresField(expires); finalResponse.setFromField("sip:127.0.0.1:5070", 5070); finalResponse.setSendAddress(contactField, responseToPort); finalResponse.setToField(contactField, responseToPort, protocol); finalResponse.setUserAgentField("TestRegistrar"); // finalResponse.setRegisterData(responseToAddress, contactField, "127.0.0.1", contactField, callId, seqNum); if (contactField.contains("anon")) // anonymous user doesnt need authentication, just say ok { finalResponse.setResponseData(&message, 200, "OK"); } else if (contactField.contains("mike")) // mike requires registration, say 401 { UtlString realm; UtlString requestUser; UtlString requestRealm; UtlString requestNonce; UtlString uriParam; // TBD - 25-jan-2010 work might be needed if these tests are re-enabled message.getDigestAuthorizationData( &requestUser, &requestRealm, &requestNonce, NULL, NULL, &uriParam, NULL, // TBD cnonce NULL, // TBD nonceCount NULL, // TBD qop HttpMessage::SERVER, 0); if (seqNum == retrySeqNum) // if this is a retry response { // if they've sent any auth field, just accept it. // TODO: figure out if a username and password has been encrypted and sent. finalResponse.setCSeqField(++seqNum, SIP_REGISTER_METHOD); finalResponse.setResponseData(&message, 200, "OK"); } else { message.getCSeqField(&seqNum, &method); finalResponse.setCSeqField(++seqNum, method); retrySeqNum = seqNum; #ifdef _WIN32 finalResponse.setAuthenticateData("md5", "TestRegistrar", NULL, NULL, NULL, HttpMessage::HttpEndpointEnum::SERVER ); #else finalResponse.setAuthenticateData("md5", "TestRegistrar", NULL, NULL, NULL, HttpMessage::SERVER ); #endif finalResponse.setResponseData(&message, 401, "Not authorized"); } } else if (contactField.contains("xyzzy")) { // this is our special username that will cause a response // to be echoed back with the 3 digit value after xyzzy. // for instance, the contact xyzzy401 will cause a 401 response int pos = contactField.first("xyzzy"); char szCode[4]; szCode[0] = contactField[pos + 5]; szCode[1] = contactField[pos + 6]; szCode[2] = contactField[pos + 7]; szCode[3] = '\0'; finalResponse.setResponseData(&message, atoi(szCode), "OK"); } mpUserAgent->send(finalResponse); return messageProcessed; }
void testHandleAlarm() { OsSysLog::add(FAC_ALARM, PRI_DEBUG, "AlarmServerTest::testHandleAlarm"); UtlString localhost("localhost"); UtlString alarmId("NO_LOG"); UtlString alarmParam("testing"); UtlSList alarmParams; alarmParams.append(&alarmParam); UtlString oldLastString; tail(mAlarmFile, oldLastString); OsSysLog::add(FAC_ALARM, PRI_DEBUG, "oldLastString %s", oldLastString.data()); bool rc=cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams); OsTask::delay(500); CPPUNIT_ASSERT_MESSAGE("handleAlarm('NO_LOG') failed", rc==true); UtlString newLastString; tail(mAlarmFile, newLastString); OsSysLog::add(FAC_ALARM, PRI_DEBUG, "newLastString %s", newLastString.data()); CPPUNIT_ASSERT_MESSAGE("alarm with 'NO_LOG' was logged", !oldLastString.compareTo(newLastString)); alarmId = "TEST_LOG"; alarmParam = "single parameter"; alarmParams.removeAll(); alarmParams.append(&alarmParam); OsSysLog::add(FAC_ALARM, PRI_DEBUG, "Test TEST_LOG"); cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams); OsTask::delay(DELAY); UtlString actualString; UtlString expectedString = "This is a test of the log function. Single parameter should be here: single parameter, and that's all that is required"; tail(mAlarmFile, actualString); char msg[1000]; sprintf(msg, "incorrect message was logged: actualString '%s' expected '%s'", actualString.data(), expectedString.data()); CPPUNIT_ASSERT_MESSAGE(msg, actualString.contains(expectedString)); // test that non-existant alarm returns false alarmId = "NONEXISTANT_ID"; rc=cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams); CPPUNIT_ASSERT_MESSAGE("handleAlarm('NONEXISTANT_ID') did not fail, and should have", rc!=true); // test that alarm with min_threshold is only logged after n attempts alarmId = "MIN_THRESHOLD"; alarmParam = "one"; alarmParams.removeAll(); alarmParams.append(&alarmParam); tail(mAlarmFile, oldLastString); OsSysLog::add(FAC_ALARM, PRI_DEBUG, "oldLastString %s", oldLastString.data()); cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams); OsTask::delay(DELAY); tail(mAlarmFile, newLastString); OsSysLog::add(FAC_ALARM, PRI_DEBUG, "newLastString %s", newLastString.data()); CPPUNIT_ASSERT_MESSAGE("first instance of alarm with 'min_threshold' was logged", !oldLastString.compareTo(newLastString)); alarmParam = "two"; alarmParams.append(&alarmParam); cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams); OsTask::delay(DELAY); tail(mAlarmFile, actualString); expectedString = "This should only be logged the second time"; sprintf(msg, "incorrect message was logged: actualString '%s' expected '%s'", actualString.data(), expectedString.data()); CPPUNIT_ASSERT_MESSAGE(msg, actualString.contains(expectedString)); }
OsStatus NotificationHelper::send ( const UtlString& rMailboxIdentity, const UtlString& rSMTPServer, const Url& mailboxServiceUrl, const UtlString& rContact, const UtlString& rFrom, const UtlString& rReplyTo, const UtlString& rDate, const UtlString& rDurationMSecs, const UtlString& wavFileName, const char* pAudioData, const int& rAudioDatasize, const UtlBoolean& rAttachmentEnabled) const { OsStatus status = OS_SUCCESS; // For forwarded messages, duration = aggregate of duration of different // messages that make up the forwarded message. // Skip duration for forwarded messages in this release (1.1). UtlString durationText = "" ; if( !wavFileName.contains("-FW") ) { durationText += "Duration " ; int iDuration = atoi(rDurationMSecs); if( iDuration > 0 ) { // Convert to seconds iDuration = iDuration / 1000; char temp[10]; if( iDuration >= 3600 ) { // Retrieve the hour. int hours = iDuration / 3600 ; iDuration = iDuration - (hours * 3600); sprintf( temp, "%02d", hours ); durationText = UtlString( temp ) + ":" ; } if( iDuration >= 60 ) { // Retrieve the hour. int mins = iDuration / 60 ; iDuration = iDuration - (mins * 60); sprintf( temp, "%02d", mins ); durationText += UtlString( temp ) + ":" ; } else { durationText += "00:" ; } // append the seconds sprintf( temp, "%02d", iDuration ); durationText += temp; } else { durationText = UtlString("00:00") ; } } UtlString strFrom = "Unknown" ; if( !rFrom.isNull() && rFrom.length() > 0) strFrom = rFrom ; UtlString subject = "New Voicemail from " + strFrom ; UtlString rawMessageId = wavFileName(0, wavFileName.first('-')); UtlString userId = rMailboxIdentity(0, rMailboxIdentity.first('@')); UtlString plainBodyText, htmlBodyText; MailMessage message ( "Voicemail Notification Service", rReplyTo, rSMTPServer ); UtlString baseMailboxLink = mailboxServiceUrl.toString(); baseMailboxLink.append("/").append(userId).append("/inbox"); UtlString playMessageLink = baseMailboxLink; playMessageLink.append("/").append(rawMessageId); UtlString deleteMessageLink = baseMailboxLink; deleteMessageLink.append("/").append(rawMessageId).append("/delete"); UtlString showMailboxLink = baseMailboxLink; plainBodyText += "On " + rDate + ", " + strFrom + " left new voicemail. " + durationText + "\n"; plainBodyText += "Listen to message " + playMessageLink + "\n"; plainBodyText += "Show Voicemail Inbox " + showMailboxLink + "\n"; plainBodyText += "Delete message " + deleteMessageLink + "\n"; UtlString playMessageLinkXml ; UtlString deleteMessageLinkXml; UtlString showMailboxLinkXml; XmlEscape(playMessageLinkXml, playMessageLink) ; XmlEscape(deleteMessageLinkXml, deleteMessageLink) ; XmlEscape(showMailboxLinkXml, showMailboxLink) ; // Format the html text if supported by the browser htmlBodyText = (UtlString)"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n" + " \"http://www.w3.org/TR/html4/strict.dtd\">\n" + "<HTML>\n" + "<HEAD>\n" + "<TITLE>Voicemail Notification</TITLE>\n" + "</HEAD>\n<BODY>\n"; htmlBodyText += "<p>On " + rDate + ", " + strFrom + " left new voicemail. " + durationText + "</p>\n"; htmlBodyText += "<p><a href=\"" + playMessageLinkXml + "\">Listen to message</a></p>\n"; htmlBodyText += "<p><a href=\"" + showMailboxLinkXml + "\">Show Voicemail Inbox</a></p>\n"; htmlBodyText += "<p><a href=\"" + deleteMessageLinkXml + "\">Delete message</a></p>\n"; htmlBodyText += (UtlString)"</BODY>\n" + "</HTML>\n"; if ( rAttachmentEnabled == TRUE ) { unsigned char* unsignedAudioData = (unsigned char*) pAudioData; message.Attach( unsignedAudioData, rAudioDatasize, wavFileName); } message.Body( plainBodyText , htmlBodyText ); message.Subject( subject ); message.To( rContact, rContact ); UtlString response = message.Send(); if ( !response.isNull() ) { if( response.length() > 0 ) { OsSysLog::add(FAC_MEDIASERVER_CGI, PRI_ERR, "NotificationHelper: " "Error sending e-mail to '%s' via SMTP server '%s'\n %s", rContact.data(), rSMTPServer.data(), response.data()); OsSysLog::flush(); } } return status; }
/// Process an incoming NOTIFY from an Appearance. Always sends a response. void AppearanceGroup::handleNotifyRequest(const UtlString* dialogHandle, const SipMessage* msg) { SipMessage response; Appearance* pThisAppearance = findAppearance(*dialogHandle); if ( !pThisAppearance ) { UtlString swappedDialogHandle; mAppearanceGroupSet->swapTags(*dialogHandle, swappedDialogHandle); pThisAppearance = findAppearance(swappedDialogHandle); if ( !pThisAppearance ) { // should never happen, since the NOTIFY was sent straight to the Appearance Os::Logger::instance().log(FAC_SAA, PRI_WARNING, "AppearanceGroup::handleNotifyRequest: ignoring NOTIFY from unknown subscription, dialogHandle %s", dialogHandle->data()); response.setInterfaceIpPort(msg->getInterfaceIp(), msg->getInterfacePort()); response.setResponseData(msg, 481, "Subscription does not exist"); getAppearanceAgent()->getServerUserAgent().send(response); return; } } UtlString contactUri = pThisAppearance->getUri()->data(); // check that event type is supported UtlString eventType; msg->getEventField(eventType); if (eventType != SLA_EVENT_TYPE) { Os::Logger::instance().log(FAC_SAA, PRI_INFO, "AppearanceGroup::handleNotifyRequest: ignoring NOTIFY(%s): not an SLA event", eventType.data()); response.setOkResponseData(msg, NULL); getAppearanceAgent()->getServerUserAgent().send(response); return; } // Get the NOTIFY content. const char* content; ssize_t l; const HttpBody* body = msg->getBody(); if (body) { body->getBytes(&content, &l); } else { Os::Logger::instance().log(FAC_SAA, PRI_WARNING, "AppearanceGroup::handleNotifyRequest: could not get NOTIFY content, dialogHandle %s", dialogHandle->data()); response.setInterfaceIpPort(msg->getInterfaceIp(), msg->getInterfacePort()); response.setResponseData(msg, 493, "Undecipherable"); getAppearanceAgent()->getServerUserAgent().send(response); return; } SipDialogEvent* lContent = new SipDialogEvent(content); UtlString state; UtlString entity; lContent->getState(state); lContent->getEntity(entity); UtlString dialogState = STATE_TERMINATED; UtlString event; UtlString code; UtlString appearanceId; if (state == STATE_TERMINATED) { // probably not needed now that SipSubscribeClient checks for NOTIFY with terminated state // our subscription to this Appearance has terminated. Os::Logger::instance().log(FAC_SAA, PRI_DEBUG, "AppearanceGroup::handleNotifyRequest: subscription to %s has been terminated", contactUri.data()); // terminate any non-held dialogs? or all dialogs? } Os::Logger::instance().log(FAC_SAA, PRI_DEBUG, "AppearanceGroup::handleNotifyRequest: %s update from %s", state.data(), contactUri.data()); // Assign each dialog a globally-unique ID, if not done yet UtlSListIterator* itor = lContent->getDialogIterator(); Dialog* pDialog; while ( (pDialog = dynamic_cast <Dialog*> ((*itor)())) ) { UtlString dialogId; UtlString uniqueDialogId; UtlString rendering; pDialog->getDialogId(dialogId); pDialog->getLocalParameter("x-line-id", appearanceId); pDialog->getLocalParameter("+sip.rendering", rendering); pDialog->getState(dialogState, event, code); // Ignore calls with no appearanceId - these are considered "exclusive". // (e.g. MoH calls are private to the set involved) // These dialogs are not forwarded on to other sets in either partial or full updates. if ( appearanceId == "" ) { Os::Logger::instance().log(FAC_SAA, PRI_DEBUG, "AppearanceGroup::handleNotifyRequest skipping call with no appearance info"); delete lContent->removeDialog(pDialog); continue; } if ( dialogId.contains("@@") ) { // this is one of our identifiers already uniqueDialogId = dialogId; } else { // make a guaranteed unique dialog id, by // prepending to each id value the call-id of the subscription // from which the dialog event was obtained, with "@@" as a separator msg->getCallIdField(&uniqueDialogId); uniqueDialogId.append("@@"); uniqueDialogId.append(dialogId); pDialog->setDialogId(uniqueDialogId); } Os::Logger::instance().log(FAC_SAA, PRI_INFO, "AppearanceGroup::handleNotifyRequest: " "%s update from %s: dialogId %s, x-line-id %s, state %s(%s)", state.data(), contactUri.data(), uniqueDialogId.data(), appearanceId.data(), dialogState.data(), rendering.data()); } delete itor; // Check to see if this appearance (of the Appearance) is available bool okToProceed = true; if ( state == "partial" && dialogState == "trying" ) { UtlHashMapIterator appitor(mAppearances); UtlString* handle; while ( okToProceed && (handle = dynamic_cast <UtlString*> (appitor()))) { Appearance* inst = dynamic_cast <Appearance*> (appitor.value()); okToProceed = !inst->appearanceIdIsSeized(appearanceId); } } bool bSendPartialContent = false; bool bSendFullContent = false; // Send the response. if (okToProceed) { response.setOkResponseData(msg, NULL); } else { Os::Logger::instance().log(FAC_SAA, PRI_DEBUG, "AppearanceGroup::handleNotifyRequest '%s' appearanceId %s is busy", entity.data(), appearanceId.data()); response.setInterfaceIpPort(msg->getInterfaceIp(), msg->getInterfacePort()); response.setResponseData(msg, 409, "Conflict"); } getAppearanceAgent()->getServerUserAgent().send(response); if (okToProceed) { if (lContent) { // Send the content to the proper Appearance instance, so it can // save these dialogs, and set flag to indicate whether they should be sent in partial update bSendPartialContent = pThisAppearance->updateState(lContent, bSendFullContent); } // Publish full and partial updates to the SipPublishContentMgr publish(bSendFullContent, bSendPartialContent, lContent); } // Adjust the expiration of the subscription if the set has the line "seized" // and return it to the longer default if it does not. UtlHashMapIterator appitor(mAppearances); UtlString* handle; while ( (handle = dynamic_cast <UtlString*> (appitor()))) { Appearance* inst = dynamic_cast <Appearance*> (appitor.value()); // if set has line seized, use short subscription timer if ( inst->appearanceIsBusy() ) { inst->setResubscribeInterval(true); } else { inst->setResubscribeInterval(false); } } if (lContent) { delete lContent; } }