/* * Copyright (C) 2005 Luca Veltri - University of Parma - Italy * * This source code 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. * * This source code 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 source code; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author(s): * Luca Veltri (luca.veltri@unipr.it) */ package local.ua; import org.zoolu.sip.address.*; import org.zoolu.sip.authentication.DigestAuthentication; import org.zoolu.sip.provider.*; import org.zoolu.sip.transaction.*; import org.zoolu.sip.header.AuthorizationHeader; import org.zoolu.sip.header.ContactHeader; import org.zoolu.sip.header.RequestLine; import org.zoolu.sip.header.StatusLine; import org.zoolu.sip.header.WwwAuthenticateHeader; import org.zoolu.sip.message.*; import org.zoolu.tools.Log; import org.zoolu.tools.LogLevel; import java.io.*; /** Simple Message Agent (MA). * It allows a user to send and receive short messages. */ //public class MessageAgent implements SipProviderListener, TransactionClientListener public class MessageAgent implements SipInterfaceListener, TransactionClientListener { /** Event logger. */ protected Log log; /** UserProfile */ protected UserAgentProfile user_profile; /** SipProvider */ protected SipProvider sip_provider; /** SipInterface to message MESSAGE. */ protected SipInterface sip_interface; /** Message listener */ protected MessageAgentListener listener; protected String qop; /** Costructs a new MessageAgent. */ public MessageAgent(SipProvider sip_provider, UserAgentProfile user_profile, MessageAgentListener listener) { this.sip_provider = sip_provider; this.log = sip_provider.getLog(); this.sip_interface = null; this.listener = listener; this.user_profile = user_profile; // if no contact_url and/or from_url has been set, create it now user_profile.initContactAddress(sip_provider); } /** Sends a new text message. */ public void send(String recipient, String subject, String content) { send(recipient, subject, "text/html", content); } public void send(String recipient, String subject, String content, boolean idialMessage) { if(idialMessage) send(recipient, subject, "idial/InstantMessage", content); else send(recipient, subject, "text/html", content); } public void send(String recipient, String subject, String content, boolean idialMessage, String displayname) { if(idialMessage) send(recipient, subject, "idial/InstantMessage", content, displayname); else send(recipient, subject, "text/html", content, displayname); } /** Sends a new message. */ public void send(String recipient, String subject, String content_type, String content) { NameAddress to_url = new NameAddress(recipient); NameAddress from_url = new NameAddress(user_profile.from_url); MessageFactory msgf = new MessageFactory(); Message req = msgf.createMessageRequest(sip_provider, to_url, from_url, subject, content_type, content); TransactionClient t = new TransactionClient(sip_provider, req, this); t.request(); } /** Sends a new message. */ public void send(String recipient, String subject, String content_type, String content, String displayname) { NameAddress to_url = new NameAddress(recipient); NameAddress from_url = new NameAddress(user_profile.from_url); from_url.setDisplayName(displayname); MessageFactory msgf = new MessageFactory(); Message req = msgf.createMessageRequest(sip_provider, to_url, from_url, subject, content_type, content); TransactionClient t = new TransactionClient(sip_provider, req, this); t.request(); } /** Waits for incoming message. */ public void receive() { //sip_provider.addSipProviderListener(new MethodIdentifier(SipMethods.MESSAGE),this); sip_interface = new SipInterface(sip_provider, new MethodIdentifier(SipMethods.MESSAGE), this); } /** Stops receiving messages. */ public void halt() { //sip_provider.removeSipProviderListener(new MethodIdentifier(SipMethods.MESSAGE)); sip_interface.close(); } // ******************* Callback functions implementation ******************** /** When a new Message is received by the SipProvider. */ /*public void onReceivedMessage(SipProvider provider, Message msg) { //printLog("Message received: "+msg.getFirstLine().substring(0,msg.toString().indexOf('\r'))); if (msg.isRequest() && msg.isMessage()) { (new TransactionServer(sip_provider,msg,null)).respondWith(MessageFactory.createResponse(msg,200,"OK",null,"")); NameAddress sender=msg.getFromHeader().getNameAddress(); NameAddress recipient=msg.getToHeader().getNameAddress(); String subject=null; if (msg.hasSubjectHeader()) subject=msg.getSubjectHeader().getSubject(); String content_type=msg.getContentTypeHeader().getContentType(); String content=msg.getBody(); if (listener!=null) listener.onMaReceivedMessage(this,sender,recipient,subject,content_type,content); } }*/ /** When a new Message is received by the SipInterface. */ public void onReceivedMessage(SipInterface sip, Message msg) { //printLog("Message received: "+msg.getFirstLine().substring(0,msg.toString().indexOf('\r'))); if(msg.isRequest()) { (new TransactionServer(sip_provider, msg, null)).respondWith(MessageFactory.createResponse(msg, 200, SipResponses.reasonOf(200), null)); NameAddress sender = msg.getFromHeader().getNameAddress(); NameAddress recipient = msg.getToHeader().getNameAddress(); String subject = null; if(msg.hasSubjectHeader()) subject = msg.getSubjectHeader().getSubject(); String content_type = msg.getContentTypeHeader().getContentType(); String content = msg.getBody(); if(listener != null) listener.onMaReceivedMessage(this, sender, recipient, subject, content_type, content); } } /** When the TransactionClient goes into the "Completed" state receiving a 2xx response */ public void onTransSuccessResponse(TransactionClient tc, Message resp) { onDeliverySuccess(tc, resp.getStatusLine().getReason()); } /** When the TransactionClient goes into the "Completed" state receiving a 300-699 response */ public void onTransFailureResponse(TransactionClient tc, Message msg) { // SESCA // Autentikointi String method = tc.getTransactionMethod(); StatusLine status_line = msg.getStatusLine(); int code = status_line.getCode(); // AUTHENTICATION-BEGIN if((code == 401 && msg.hasWwwAuthenticateHeader() && msg.getWwwAuthenticateHeader().getRealmParam().equalsIgnoreCase(user_profile.realm)) || (code == 407 && msg.hasProxyAuthenticateHeader() && msg.getProxyAuthenticateHeader().getRealmParam().equalsIgnoreCase(user_profile.realm))) { // req:ssa on cseq:ua kasvatettu Message req = tc.getRequestMessage(); req.setCSeqHeader(req.getCSeqHeader().incSequenceNumber()); WwwAuthenticateHeader wah; if(code == 401) wah = msg.getWwwAuthenticateHeader(); else wah = msg.getProxyAuthenticateHeader(); String qop_options = wah.getQopOptionsParam(); qop = (qop_options != null) ? "auth" : null; RequestLine rl = req.getRequestLine(); // SESCA // BUGI client ei saa lähettää qop:ia //DigestAuthentication digest=new DigestAuthentication(rl.getMethod(),rl.getAddress().toString(),wah,qop,null,username,passwd); DigestAuthentication digest = new DigestAuthentication(rl.getMethod(), rl.getAddress().toString(), wah, null, null, user_profile.authID, user_profile.passwd); AuthorizationHeader ah; if(code == 401) ah = digest.getAuthorizationHeader(); else ah = digest.getProxyAuthorizationHeader(); req.setAuthorizationHeader(ah); // transactions.remove(tc.getTransactionId()); // SESCA // BUGI // Päivitetään invite_req:uun uusin invite-viesti. // Lähetämme uuden inviten, joten teemme uuden invitetransactionclientin, eikä transaction clientia // if (method.equals(SipMethods.INVITE)) { // invite_req = req; // tc=new InviteTransactionClient(sip_provider,req,this); tc = new TransactionClient(sip_provider, req, this); // tc=new TransactionClient(sip_provider,req,this); // } // else { // tc=new TransactionClient(sip_provider,req,this); // } // transactions.put(tc.getTransactionId(),tc); tc.request(); } // AUTHENTICATION-END else onDeliveryFailure(tc, msg.getStatusLine().getReason()); } /** When the TransactionClient is (or goes) in "Proceeding" state and receives a new 1xx provisional response */ public void onTransProvisionalResponse(TransactionClient tc, Message resp) { // do nothing. } /** When the TransactionClient goes into the "Terminated" state, caused by transaction timeout */ public void onTransTimeout(TransactionClient tc) { onDeliveryFailure(tc, "Timeout"); } /** When the delivery successes. */ private void onDeliverySuccess(TransactionClient tc, String result) { printLog("Message successfully delivered (" + result + ")."); Message req = tc.getRequestMessage(); NameAddress recipient = req.getToHeader().getNameAddress(); String subject = null; if(req.hasSubjectHeader()) subject = req.getSubjectHeader().getSubject(); if(listener != null) listener.onMaDeliverySuccess(this, recipient, subject, result); } /** When the delivery fails. */ private void onDeliveryFailure(TransactionClient tc, String result) { printLog("Message delivery failed (" + result + ")."); Message req = tc.getRequestMessage(); NameAddress recipient = req.getToHeader().getNameAddress(); String subject = null; if(req.hasSubjectHeader()) subject = req.getSubjectHeader().getSubject(); if(listener != null) listener.onMaDeliveryFailure(this, recipient, subject, result); } //**************************** Logs ****************************/ /** Starting log level for this class */ //private static final int LOG_OFFSET=SipStack.LOG_LEVEL_UA; /** Adds a new string to the default Log */ private void printLog(String str) { printLog(str, LogLevel.HIGH); } /** Adds a new string to the default Log */ private void printLog(String str, int level) { if(log != null) log.println("MessageAgent: " + str, level + SipStack.LOG_LEVEL_UA); } }