/*
   * This method handles:
   * - Setting up the UINICQSubType for Sending messages
   * (the actual message is sent by the caller -
   *  dependent on whether it is going direct/thru server)
   */
  UINICQSubType* MessageHandler::handleOutgoing(MessageEvent *ev)
  {
    UINICQSubType *icq = EventToUINICQSubType(ev);

    /* our status is sent in packets */
    icq->setStatus( Contact::MapStatusToICQStatus(m_self_contact->getStatus(), m_self_contact->isInvisible() ) );
    icq->setDestination( ev->getContact()->getUIN() );
    icq->setSource( m_self_contact->getUIN() );

    return icq;
  }
Beispiel #2
0
  ICQSubType* ICQSubType::ParseICQSubType(Buffer& b, bool adv, bool ack) {
    unsigned char type, flags;
    b >> type
      >> flags;
    
    bool multi = (flags & MSG_Flag_Multi);

    ICQSubType *ist;
    switch(type) {
    case MSG_Type_Normal:
      ist = new NormalICQSubType(multi);
      break;
    case MSG_Type_URL:
      ist = new URLICQSubType();
      break;
    case MSG_Type_SMS:
      ist = new SMSICQSubType();
      break;
    case MSG_Type_AuthReq:
      ist = new AuthReqICQSubType();
      break;
    case MSG_Type_AuthRej:
      ist = new AuthRejICQSubType();
      break;
    case MSG_Type_AuthAcc:
      ist = new AuthAccICQSubType();
      break;
    case MSG_Type_EmailEx:
      ist = new EmailExICQSubType();
      break;
    case MSG_Type_WebPager:
      ist = new WebPagerICQSubType();
      break;
    case MSG_Type_UserAdd:
      ist = new UserAddICQSubType();
      break;
    case MSG_Type_AutoReq_Away:
    case MSG_Type_AutoReq_Occ:
    case MSG_Type_AutoReq_NA:
    case MSG_Type_AutoReq_DND:
    case MSG_Type_AutoReq_FFC:
      ist = new AwayMsgSubType(type);
      break;
    default:
      {
	ostringstream ostr;
	ostr << "Unknown ICQ Subtype: 0x" << std::hex << (int) type;
	throw ParseException(ostr.str());
      }
    }

    if (dynamic_cast<UINICQSubType*>(ist) != NULL) {
      UINICQSubType *ust = dynamic_cast<UINICQSubType*>(ist);
      ust->setAdvanced(adv);
      ust->setACK(ack);
      /* There is nothing in the encoding of the ICQ subtype that
	 distinguishes whether it is an ack or not - this is implied
	 by the protocol layer above this. As such it has to be passed
	 as an argument and set body the rest of parsing continues */
    }
    ist->setFlags(flags);
    ist->ParseBody(b);

    return ist;
  }
  /**
   * Convert a MessageEvent into a UINICQSubType
   */
  UINICQSubType* MessageHandler::EventToUINICQSubType(MessageEvent *ev)
  {
    ContactRef c = ev->getContact();
    UINICQSubType *ist = NULL;

    if (ev->getType() == MessageEvent::Normal) {

      NormalMessageEvent *nv = static_cast<NormalMessageEvent*>(ev);
      ist = new NormalICQSubType( m_translator->client_to_server( nv->getMessage(), ENCODING_CONTACT_LOCALE, c ) );
	  ( static_cast<NormalICQSubType*>(ist))->setTextEncoding( (static_cast<NormalMessageEvent*>(ev))->getTextEncoding() );

    } else if (ev->getType() == MessageEvent::URL) {

      URLMessageEvent *uv = static_cast<URLMessageEvent*>(ev);
      ist = new URLICQSubType( m_translator->client_to_server( uv->getMessage(), ENCODING_CONTACT_LOCALE, c ),
			       m_translator->client_to_server( uv->getURL(),     ENCODING_CONTACT_LOCALE, c ));

    } else if (ev->getType() == MessageEvent::FileTransfer) {

      FileTransferEvent *uv = static_cast<FileTransferEvent*>(ev);
      ist = new FTICQSubType( m_translator->client_to_server( uv->getMessage(), ENCODING_CONTACT_LOCALE, c ),
						m_translator->client_to_server( uv->getDescription(),     ENCODING_CONTACT_LOCALE, c ), uv->getTotalSize());
					    
   
    } else if (ev->getType() == MessageEvent::AwayMessage) {

      ist = new AwayMsgSubType( c->getStatus() );

    } else if (ev->getType() == MessageEvent::AuthReq) {

      AuthReqEvent *uv = static_cast<AuthReqEvent*>(ev);
      ist = new AuthReqICQSubType( m_translator->client_to_server( m_self_contact->getAlias(),     ENCODING_CONTACT_LOCALE, c ),
				   m_translator->client_to_server( m_self_contact->getFirstName(), ENCODING_CONTACT_LOCALE, c ),
				   m_translator->client_to_server( m_self_contact->getLastName(),  ENCODING_CONTACT_LOCALE, c ),
				   m_translator->client_to_server( m_self_contact->getEmail(),     ENCODING_CONTACT_LOCALE, c ),
				   m_self_contact->getAuthReq(),
				   m_translator->client_to_server( uv->getMessage(),               ENCODING_CONTACT_LOCALE, c ));

    }
    else if (ev->getType() == MessageEvent::AuthAck)
    {

      AuthAckEvent *uv = static_cast<AuthAckEvent*>(ev);
      if(uv->isGranted())
        ist = new AuthAccICQSubType();
      else
        ist = new AuthRejICQSubType( m_translator->client_to_server( uv->getMessage(), ENCODING_CONTACT_LOCALE, c ) );
      
    }
    else if (ev->getType() == MessageEvent::UserAdd)
    {
      ist = new UserAddICQSubType( m_translator->client_to_server( m_self_contact->getAlias(),     ENCODING_CONTACT_LOCALE, c ),
				   m_translator->client_to_server( m_self_contact->getFirstName(), ENCODING_CONTACT_LOCALE, c ),
				   m_translator->client_to_server( m_self_contact->getLastName(),  ENCODING_CONTACT_LOCALE, c ),
				   m_translator->client_to_server( m_self_contact->getEmail(),     ENCODING_CONTACT_LOCALE, c ),
				   m_self_contact->getAuthReq() );
    }
    else if (ev->getType() == MessageEvent::Contacts)
    {
      ContactMessageEvent *cv = static_cast<ContactMessageEvent*>(ev);
      ist = new ContactICQSubType(cv->getContacts());
    }
    
    ICQMessageEvent *iev;
    if (ist != NULL && (iev = dynamic_cast<ICQMessageEvent*>(ev)) != NULL) {
      ist->setUrgent( iev->isUrgent() );
      ist->setToContactList( iev->isToContactList() );
    }
    
    return ist;
  }
  /*
   * This method handles:
   * - Receiving incoming messages
   * - Signalling the message
   * - Setting up the UINICQSubType for the ACK
   * (the actual ACK is sent in the caller - dependent on whether it
   *  was direct/thru server)
   */
  bool MessageHandler::handleIncoming(ICQSubType *ist, time_t t)
  {
    ContactRef contact;
    bool advanced, ack = false;

    if (ist->getType() == MSG_Type_FT)
    {
      ostringstream ostr;
      ostr << "FileTransfer request through server." <<endl;
      SignalLog( LogEvent::WARN, ostr.str() );
      //handleIncomingFT(static_cast<FTICQSubType*>(ist));
      return false;
    }
    
    UINICQSubType *uist = dynamic_cast<UINICQSubType*>(ist);
    MessageEvent *ev = ICQSubTypeToEvent(ist, contact, advanced);
    ICQMessageEvent *mev = dynamic_cast<ICQMessageEvent*>(ev);

    Status st = m_self_contact->getStatus();

    if (!advanced) {
      /* mark all non-advanced (ICQ) messages when in Occupied/DND as 'to
       * contact list', so they can be guaranteed to arrive, as they should
       * never be turned down (no ack is sent back) */
      if (mev != NULL && (st == STATUS_OCCUPIED || st == STATUS_DND))
	mev->setToContactList(true);
    }
    
    if (t == 0) t = ev->getTime();
    else ev->setTime(t);

    ev->setDelivered(true);
    // default to true - for clients that ignore this functionality

    if (ev->getType() != MessageEvent::AwayMessage) {
      messaged.emit(ev);
      contact->set_last_message_time( t );
    } else {
      contact->set_last_away_msg_check_time( t );

      ostringstream ostr;
      ostr << "Away_msg respons to: " << contact->getAlias() << endl;
      SignalLog( LogEvent::INFO, ostr.str() );
    }

    if (advanced) {
      /* All these operations only apply to advanced messages -
       * UINICQSubType messages, those that are associated to a UIN and
       * that were sent as an advanced message (through server or
       * direct, NOT offline), and consequently will the ack'ed.
       */

      /* request away message if we are not online */
      if (st != STATUS_ONLINE && advanced)
      {
	want_auto_resp.emit(mev);
	uist->setAwayMessage( m_translator->client_to_server(mev->getAwayMessage(), ENCODING_CONTACT_LOCALE, contact ) );
      }
      else
      {
	uist->setAwayMessage( "" );
      }

      /* update the UINICQSubType */
	
      uist->setACK(true);
      ack = true;
      
      if (ev->isDelivered())
      {
	/* set accept-status of ACK */
	switch(st) {
	case STATUS_ONLINE:
	  uist->setStatus(AcceptStatus_Online);
	  break;
	case STATUS_AWAY:
	  uist->setStatus(AcceptStatus_Away);
	  break;
	case STATUS_NA:
	  uist->setStatus(AcceptStatus_NA);
	  break;
	case STATUS_OCCUPIED:
	  uist->setStatus(AcceptStatus_Occ_Accept);
	  break;
	default:
	  uist->setStatus(AcceptStatus_Online);
	}
      } else {
	MessageEvent::DeliveryFailureReason r = ev->getDeliveryFailureReason();
	/* set accept-status of ACK */
	switch(r) {
	case MessageEvent::Failed_Denied:
	  uist->setStatus(AcceptStatus_Denied);
	  break;
	case MessageEvent::Failed_Occupied:
	  uist->setStatus(AcceptStatus_Occupied);
	  break;
	case MessageEvent::Failed_DND:
	  uist->setStatus(AcceptStatus_DND);
	  break;
	case MessageEvent::Failed_Ignored:
	  ack = false;
	  break;
	default:
	  uist->setStatus(AcceptStatus_Denied);
	}
      }

    }

    // delete the temporary event
    delete ev;

    // whether the message needs ack'ing
    return ack;
  }
  /**
   *  Convert an ICQSubType into a MessageEvent
   */
  MessageEvent* MessageHandler::ICQSubTypeToEvent(ICQSubType *st, ContactRef& contact, bool& adv)
  {
    MessageEvent *e = NULL;

    adv = false;

    switch(st->getType()) {
    case MSG_Type_Normal:
    case MSG_Type_URL:
    case MSG_Type_AuthReq:
    case MSG_Type_AuthRej:
    case MSG_Type_AuthAcc:
    case MSG_Type_AutoReq_Away:
    case MSG_Type_AutoReq_Occ:
    case MSG_Type_AutoReq_NA:
    case MSG_Type_AutoReq_DND:
    case MSG_Type_AutoReq_FFC:
    case MSG_Type_UserAdd:
    case MSG_Type_FT:
    case MSG_Type_Contact:
    {
      UINICQSubType *ist = static_cast<UINICQSubType*>(st);
      adv = ist->isAdvanced();
      contact = lookupUIN( ist->getSource() );
      e = UINICQSubTypeToEvent(ist, contact);
      break;
    }

    case MSG_Type_EmailEx:
    {
      // these come from 'magic' UIN 10
      EmailExICQSubType *subtype = static_cast<EmailExICQSubType*>(st);
      std::string email = m_translator->server_to_client( subtype->getEmail(), ENCODING_ISO_8859_1, contact );
      contact = lookupEmail( email, subtype->getSender() );
      e = new EmailExEvent(contact,
			   email,
			   m_translator->server_to_client( subtype->getSender(), ENCODING_ISO_8859_1, contact ),
			   m_translator->server_to_client( subtype->getMessage(), ENCODING_ISO_8859_1, contact ));
      break;
    }

    case MSG_Type_WebPager:
    {
      WebPagerICQSubType *subtype = static_cast<WebPagerICQSubType*>(st);
      std::string email = m_translator->server_to_client( subtype->getEmail(), ENCODING_ISO_8859_1, contact );
      contact = lookupEmail( email, subtype->getSender() );
      e = new WebPagerEvent(contact,
			    email,
			    m_translator->server_to_client( subtype->getEmail(), ENCODING_ISO_8859_1, contact ),
			    m_translator->server_to_client( subtype->getMessage(), ENCODING_ISO_8859_1, contact ));
      break;
    }

    case MSG_Type_SMS:
    {
      /* TODO: Encoding!?! Someone told me once SMSs are UTF-8 encoded.. need to verify! */
      SMSICQSubType *sst = static_cast<SMSICQSubType*>(st);
      if (sst->getSMSType() == SMSICQSubType::SMS) {
	contact = lookupMobile(sst->getSender());
	e = new SMSMessageEvent(contact, sst->getMessage(),
				sst->getSource(),sst->getSenders_network(),
				sst->getTime());
      } else if (sst->getSMSType() == SMSICQSubType::SMS_Receipt) {
	contact = lookupMobile(sst->getDestination());
	e = new SMSReceiptEvent(contact, sst->getMessage(),
				sst->getMessageId(), sst->getSubmissionTime(),
				sst->getDeliveryTime(), sst->delivered());
      }
      break;
    }
    
    default:
      break;

    } // end of switch
    
    return e;
  }