Exemplo n.º 1
0
void PsiContactListViewDelegate::optionChanged(const QString& option)
{
	if (option == contactListFontOptionPath) {
		delete font_;
		delete fontMetrics_;

		font_ = new QFont();
		font_->fromString(PsiOptions::instance()->getOption(contactListFontOptionPath).toString());
		fontMetrics_ = new QFontMetrics(*font_);
		rowHeight_ = qMax(fontMetrics_->height()+2, 18); // 18 - default row height
		contactList()->viewport()->update();
	}
	else if (option == contactListBackgroundOptionPath) {
		QPalette p = contactList()->palette();
		p.setColor(QPalette::Base, ColorOpt::instance()->color(contactListBackgroundOptionPath));
		const_cast<ContactListView*>(contactList())->setPalette(p);
		contactList()->viewport()->update();
	}
	else if (option == showStatusMessagesOptionPath) {
		showStatusMessages_ = PsiOptions::instance()->getOption(showStatusMessagesOptionPath).toBool();
		contactList()->viewport()->update();
	}
	else if(option == slimGroupsOptionPath) {
		slimGroup_ = PsiOptions::instance()->getOption(slimGroupsOptionPath).toBool();
		contactList()->viewport()->update();
	}
	else if(option == outlinedGroupsOptionPath) {
		outlinedGroup_ = PsiOptions::instance()->getOption(outlinedGroupsOptionPath).toBool();
		contactList()->viewport()->update();
	}
	else if(option == statusSingleOptionPath) {
		statusSingle_ = !PsiOptions::instance()->getOption(statusSingleOptionPath).toBool();
		contactList()->viewport()->update();
	}
}
Exemplo n.º 2
0
void PsiContactListViewDelegate::updateAlerts()
{
	Q_ASSERT(!alertingIndexes_.isEmpty());
	if (!contactList()->isVisible())
		return; // needed?

	QRect contactListRect = contactList()->rect();
	QHashIterator<QModelIndex, bool> it(alertingIndexes_);
	while (it.hasNext()) {
		it.next();
		QRect r = contactList()->visualRect(it.key());
		if (contactListRect.intersects(r)) {
			contactList()->dataChanged(it.key(), it.key());
		}
	}
}
Exemplo n.º 3
0
void ModuleManager::_q_messageReceived(const QString &message)
{
	if (message.startsWith(QLatin1String("arguments: "))) {
		QByteArray data = QByteArray::fromBase64(message.section(QLatin1Char(' '), 1).toLatin1());
		QDataStream s(&data, QIODevice::ReadOnly);
		QStringList args;
		s >> args;
		qDebug() << "Received message with:" << args;
		ServicePointer<QObject> contactList("ContactList");
		if (contactList)
			QMetaObject::invokeMethod(contactList.data(), "show", Qt::QueuedConnection);
	} else if (message.startsWith(QLatin1String("url: "))) {
Exemplo n.º 4
0
void Foam::WetParcel<ParcelType>::readFields(CloudType& c)
{
    if (!c.size())
    {
        return;
    }

    ParcelType::readFields(c);

    IOField<scalar> Vliq(c.fieldIOobject("Vliq", IOobject::MUST_READ));
    c.checkFieldIOobject(c, Vliq);

    IOField<scalarField>  partVliq(c.fieldIOobject("partVliq", IOobject::MUST_READ));
    c.checkFieldIOobject(c, partVliq);

    IOField<vectorField>  liquidPositions(c.fieldIOobject("liquidPositions", IOobject::MUST_READ));
    c.checkFieldIOobject(c, liquidPositions);

    IOField<vectorField>  liquidPositionVectors(c.fieldIOobject("liquidPositionVectors", IOobject::MUST_READ));
    c.checkFieldIOobject(c, liquidPositionVectors);

    IOField<labelField>  contactList(c.fieldIOobject("contactList", IOobject::MUST_READ));
    c.checkFieldIOobject(c, contactList);

    IOField<labelField>  previousContactList(c.fieldIOobject("previousContactList", IOobject::MUST_READ));
    c.checkFieldIOobject(c, previousContactList);


    label i = 0;

    forAllIter(typename CloudType, c, iter)
    {
        WetParcel<ParcelType>& p = iter();

        p.Vliq_ = Vliq[i];
        p.partVliq_ = partVliq[i];
        p.liquidPositions_ = liquidPositions[i];
        p.liquidPositionVectors_ = liquidPositionVectors[i];
        p.contactList_ = contactList[i];
        p.previousContactList_ = previousContactList[i];

        i++;
    }

}
Exemplo n.º 5
0
void PsiContactListViewDelegate::drawGroup(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
	QStyleOptionViewItemV2 o = option;
	o.font = *font_;
	o.fontMetrics = *fontMetrics_;
	QPalette palette = o.palette;
	QColor background = ColorOpt::instance()->color("options.ui.look.colors.contactlist.grouping.header-background");
	QColor foreground = ColorOpt::instance()->color("options.ui.look.colors.contactlist.grouping.header-foreground");
	if (!slimGroup_)
		palette.setColor(QPalette::Base, background);
	palette.setColor(QPalette::Text, foreground);
	o.palette = palette;

	drawBackground(painter, o, index);

	QRect r = option.rect;
	if (!slimGroup_ && outlinedGroup_) {
		painter->setPen(QPen(foreground));
		QRect gr(r);
		gr.setLeft(contactList()->x());
		painter->drawRect(gr);
	}

	const QPixmap& pixmap = index.data(ContactListModel::ExpandedRole).toBool() ?
	                        IconsetFactory::iconPtr("psi/groupOpen")->pixmap() :
	                        IconsetFactory::iconPtr("psi/groupClosed")->pixmap();

	const QSize pixmapSize = pixmap.size();
	QRect pixmapRect = relativeRect(option, pixmapSize, QRect());
	r = relativeRect(option, QSize(), pixmapRect, 3);
	painter->drawPixmap(pixmapRect.topLeft(), pixmap);

	QString text = index.data(Qt::ToolTipRole).toString();
	drawText(painter, o, r, text, index);

	if(slimGroup_ && !(option.state & QStyle::State_Selected)) {
		int h = r.y() + (r.height() / 2);
		int x = r.left() + fontMetrics_->width(text) + 8;
		painter->setPen(QPen(background,2));
		painter->drawLine(x, h, r.right(), h);
	}
}
Exemplo n.º 6
0
void Foam::WetParcel<ParcelType>::writeFields(const CloudType& c)
{
    ParcelType::writeFields(c);

    label np =  c.size();

    IOField<scalar> Vliq(c.fieldIOobject("Vliq", IOobject::NO_READ), np);
    IOField<scalarField>  partVliq(c.fieldIOobject("partVliq", IOobject::NO_READ), np);
    IOField<vectorField>  liquidPositions(c.fieldIOobject("liquidPositions", IOobject::NO_READ), np);
    IOField<vectorField>  liquidPositionVectors(c.fieldIOobject("liquidPositionVectors", IOobject::NO_READ), np);
    IOField<labelField>  contactList(c.fieldIOobject("contactList", IOobject::NO_READ), np);
    IOField<labelField>  previousContactList(c.fieldIOobject("previousContactList", IOobject::NO_READ), np);

    label i = 0;

    forAllConstIter(typename CloudType, c, iter)
    {
        const WetParcel<ParcelType>& p = iter();

        Vliq[i] = p.Vliq();
        partVliq[i] = p.partVliq();
        liquidPositions[i] = p.liquidPositions();
        liquidPositionVectors[i] = p.liquidPositionVectors();
        contactList[i] = p.contactList();
        previousContactList[i] = p.previousContactList();



        i++;
    }

    Vliq.write();
    partVliq.write();
    liquidPositions.write();
    liquidPositionVectors.write();
    contactList.write();
    previousContactList.write();

}
Exemplo n.º 7
0
/**
 * Process a redirection.  The caller sets up our processing, but we
 * carry it through to the generation of the response, queuing of the
 * suspend object, etc.  We send the response if we finish processing.
 *
 * message is the message to be processed.  Its memory is owned by our
 * caller, or is attached to the suspend object.
 *
 * method is the request's SIP method.  Its memory is owned by our caller.
 *
 * seqNo is the sequence number to be used for this request.  (If this
 * request is to be suspended and seqNo == mNextSeqNo, we must increment
 * mNextSeqNo.)
 *
 * suspendObject is the suspend object for this request (if it already
 * exists) or NULL.  It is passed as an argument to avoid attempting to
 * look it up if the caller knows that it does not exist (because this
 * is a first processing attempt).
 */
void SipRedirectServer::processRedirect(const SipMessage* pMessage,
                                        UtlString& method,
                                        RedirectPlugin::RequestSeqNo seqNo,
                                        RedirectSuspend* suspendObject)
{
   ErrorDescriptor errorDescriptor;

   // Extract the request URI.

   // This code is not strictly correct, as the request could have:
   //    Route: <registrar [added by proxy]>,
   //           sip:[user]@[domain],
   //           [more]
   // due to an element Record-Routing with its AOR, but no element seems
   // to do that.
   // If we desire to handle that case, we have to correct the code here
   // to remove/skip any top routes that refer to the Registrar, then examine
   // the topmost remaining route (if any).
   // It would also require changing the code for routing ACKs that we forward
   // to modify the topmost route if present, instead of the request-URI.
   // There may be further complications due to strict routing.
   // All of this would be much like the Proxy forwarding requests.
   // Currently, we trust that all Route values refer to the registrar
   // and blindly remove them from any ACK that we must forward directly.

   UtlString stringUri;
   pMessage->getRequestUri(&stringUri);
   // The requestUri is an addr-spec, not a name-addr.
   Url requestUri(stringUri, TRUE);
   Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                 "SipRedirectServer::processRedirect "
                 "Starting to process request URI '%s'",
                 stringUri.data());

   /*
    * Normalize the port in the Request URI
    *   This is not strictly kosher, but it solves interoperability problems.
    *   Technically, user@foo:5060 != user@foo , but many implementations
    *   insist on including the explicit port even when they should not, and
    *   it causes registration mismatches, so we normalize the URI when inserting
    *   and looking up in the database so that if explicit port is the same as
    *   the proxy listening port, then we remove it.
    *   (Since our proxy has mProxyNormalPort open, no other SIP entity
    *   can use sip:user@domain:mProxyNormalPort, so this normalization
    *   cannot interfere with valid addresses.)
    *
    * For the strict rules, set the configuration parameter
    *   SIP_REGISTRAR_PROXY_PORT : PORT_NONE
    */
   if (   mProxyNormalPort != PORT_NONE
       && requestUri.getHostPort() == mProxyNormalPort
       )
   {
      requestUri.setHostPort(PORT_NONE);
   }

   // Seize the lock that protects the list of suspend objects.
   OsLock lock(mRedirectorMutex);

   // Process with the redirectors.
   // Set to TRUE if any of the redirectors requests suspension.
   UtlBoolean willSuspend = FALSE;
   // Set to TRUE if any of the redirectors requests an error response.
   UtlBoolean willError = FALSE;
   PluginIterator iterator(mRedirectPlugins);
   RedirectPlugin* redirector;
   // Authority level of the last redirector to have modified the contact list.
   ssize_t contactListAuthorityLevel = LOWEST_AUTHORITY_LEVEL;
   ContactList contactList( stringUri );

   int i;                       // Iterator sequence number.
   for (i = 0; (redirector = static_cast <RedirectPlugin*> (iterator.next())) && !willError;
        i++)
   {
      if (mpConfiguredRedirectors[i].bActive)
      {
         // verify if the redirector has a suitable authority level to perform a look-up
         if( mpConfiguredRedirectors[i].authorityLevel >= contactListAuthorityLevel )
         {
            // Place to store the private storage pointer.
            SipRedirectorPrivateStorage* privateStorageP;
            // Initialize it.
            privateStorageP = (suspendObject ?
                               suspendObject->mRedirectors[i].privateStorage :
                               NULL);

            // Call the redirector to process the request.
            contactList.resetWasModifiedFlag();
            RedirectPlugin::LookUpStatus status =
               redirector->lookUp(*pMessage, stringUri, requestUri, method,
                                  contactList, seqNo, i, privateStorageP, errorDescriptor);

            // Create the suspend object if it does not already exist and we need it.
            if (!suspendObject &&
                (status == RedirectPlugin::SEARCH_PENDING || privateStorageP))
            {
               suspendObject = new RedirectSuspend(mRedirectorCount);
               // Insert it into mSuspendList, keyed by seqNo.
               UtlInt* containableSeqNo = new UtlInt(seqNo);
               mSuspendList.insertKeyAndValue(containableSeqNo, suspendObject);
               // Save in it a copy of the message.  (*pMessage is
               // dependent on the OsMsg bringing the message to us, and
               // will be freed when we are done with that OsMsg.)
               suspendObject->mMessage = *pMessage;
               // Use the next sequence number for the next request.
               if (seqNo == mNextSeqNo)
               {
                  // Increment to the next value (and roll over if necessary).
                  mNextSeqNo++;
               }
            }
            // Store the private storage pointer.
            if (suspendObject)
            {
               suspendObject->mRedirectors[i].privateStorage = privateStorageP;
            }

            int statusCode;
            UtlString reasonPhrase;

            // Dispatch on status.
            switch (status)
            {
            case RedirectPlugin::SUCCESS:
               // Processing was successful. If the plug-in modified the Contact list then
               // raise the authority level required to modify the contact list to the
               // authority level of this plug-in.
               if( contactList.wasListModified() )
               {
                  contactListAuthorityLevel = mpConfiguredRedirectors[i].authorityLevel;
               }
               break;

            case RedirectPlugin::ERROR:
               // Processing detected an error.  Log it and set the 'error' flag.
               errorDescriptor.getStatusLineData( statusCode, reasonPhrase );

               Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                             "SipRedirectServer::processRedirect "
                             "ERROR returned by redirector "
                             "'%s' while processing method '%s' URI '%s': "
                             "Status code = %d (%s)",
                             redirector->name().data(), method.data(), stringUri.data(), statusCode, reasonPhrase.data() );
               willError = TRUE;
               break;

            case RedirectPlugin::SEARCH_PENDING:
               Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                             "SipRedirectServer::processRedirect "
                             "SEARCH_PENDING returned by redirector "
                             "'%s' while processing method '%s' URI '%s'",
                             redirector->name().data(), method.data(), stringUri.data());
               willSuspend = TRUE;
               // Mark that this redirector has requested suspension.
               suspendObject->mRedirectors[i].suspended = TRUE;
               suspendObject->mRedirectors[i].needsCancel = TRUE;
               suspendObject->mSuspendCount++;
               break;

            default:
               Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                             "SipRedirectServer::processRedirect "
                             "Invalid status value %d returned by redirector "
                             "'%s' while processing method '%s' URI '%s'",
                             status, redirector->name().data(), method.data(), stringUri.data());
               break;
            }  // end status switch
         } // end authorityLevel >= contactListAuthorityLevel
         else
         {
            // redirector plug-in does not have a suitable authority level to look up the
            // request - it is only allowed to observe it.
            redirector->observe(*pMessage, stringUri, requestUri, method,
                               contactList, seqNo, i);
         }
      }  // end mpConfiguredRedirectors[i]
   }  // end Redirector plug-in iterator

   if (willError || !willSuspend)   // redirector has done all it can
   {
       int numContacts = 0;
       if (method.compareTo(SIP_ACK_METHOD, UtlString::ignoreCase) == 0)
       {
          // See if location server has returned an address to use
          // to forward or just drop the ACK here.
           if (!willError && ((numContacts = contactList.entries()) == 1))
           {
               Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                             "SipRedirectServer::processRedirect "
                             "Forwarding ACK for URI '%s': ",
                             stringUri.data());

               UtlString contactNameAddr;
               UtlString routeEntries;
               int maxForwards;

               // Get the (single) contact.
               contactList.get(0, contactNameAddr);
               // Convert from name-addr format (which is what is in
               // contactList) to addr-spec (which is what is needed
               // for a request-URI.
               Url contactUri(contactNameAddr, Url::NameAddr);
               UtlString contactAddrSpec;
               contactUri.getUri(contactAddrSpec);

               // create the message to forward -
               // change reqUri to located value, add route for debugging info, decrement max-forwards
               // leave last via since we are circling back, not responding
               SipMessage ackCopy(*pMessage);    // copy original ACK
               ackCopy.setRequestFirstHeaderLine(SIP_ACK_METHOD,
                                                 contactAddrSpec,
                                                 SIP_PROTOCOL_VERSION);

               // Remove any existing Route headers.
               // See the comment at the top of this method ("Extract
               // the request URI") for discussion.
               while (ackCopy.removeHeader(SIP_ROUTE_FIELD, 0))
               {
                  // empty
               }

               // Process header parameters in the request URI,
               // especially moving any Route parameters to Route headers.
               ackCopy.applyTargetUriHeaderParams();

               // Put Route to proxy in the first position, so the proxy
               // can see the ACK.
               ackCopy.addRouteUri(mAckRouteToProxy.data());

               // Update or create the Max-Forwards header.
               if (!ackCopy.getMaxForwards(maxForwards))
               {
                   maxForwards = SIP_DEFAULT_MAX_FORWARDS;
               }
               maxForwards--;
               ackCopy.setMaxForwards(maxForwards);

               // get send-to address/port/protocol from top via
               UtlString lastViaAddress;
               int lastViaPort;
               UtlString lastViaProtocol;
               OsSocket::IpProtocolSocketType viaProtocol = OsSocket::UNKNOWN;

               ackCopy.getTopVia(&lastViaAddress, &lastViaPort, &lastViaProtocol);
               SipMessage::convertProtocolStringToEnum(lastViaProtocol.data(), viaProtocol);


               Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                             "SipRedirectServer::processRedirect "
                             "sending ACK to '%s':%d using '%s' "
                             "location service returned '%s', "
                             "converted into '%s'",
                             lastViaAddress.data(),
                             lastViaPort,
                             lastViaProtocol.data(),
                             contactNameAddr.data(),
                             contactAddrSpec.data());

               // This ACK has no matching INVITE, special case
               mpSipUserAgent->sendStatelessAck(ackCopy,            // this will add via
                                                lastViaAddress,
                                                lastViaPort,
                                                viaProtocol);
           }
           else  // locater must return EXACTLY one value to forward
           {
               Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                             "SipRedirectServer::processRedirect "
                             "Cannot redirect ACK for URI '%s', dropping: "
                             "number of contacts=%d  ",
                             stringUri.data(), numContacts);
           }
       }   // end handle ACK redirection
       else     // build and send the proper (error) response
       {
          // The response we will compose and, hopefully, send.
          SipMessage response;

          // Send a response and terminate processing now if an error has
          // been found or if no redirector has requested suspension.
          if (willError)
          {
             buildResponseFromRequestAndErrorDescriptor( response, *pMessage, errorDescriptor );
          }
          else
          {
             // If request processing is finished, construct a response,
             // either 302 or 404.
             if (contactList.entries() > 0)
             {
                // There are contacts, so send a 302 Moved Temporarily.
                Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                              "SipRedirectServer::processRedirect "
                              "Contacts added, sending 302 response");
                response.setResponseData(pMessage,
                                         SIP_TEMPORARY_MOVE_CODE,
                                         SIP_TEMPORARY_MOVE_TEXT);

                // add contacts collected in the contactList to the response
                size_t index;
                size_t numEntries = contactList.entries();

                for( index = 0; index < numEntries; index++ )
                {
                   UtlString contactString;
                   if( contactList.get( index, contactString ) )
                   {
                      response.setContactField(contactString, index );
                   }
                   else
                   {
                      Os::Logger::instance().log(FAC_SIP, PRI_CRIT,
                                    "SipRedirectServer::processRedirect "
                                    "Failed to retrieve contact index %zu", index );
                   }
                }
             }
             else
             {
                // There are no contacts, send back a 404 Not Found.
                Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                              "SipRedirectServer::processRedirect "
                              "No contacts added, sending 404 response");
                response.setResponseData(pMessage,
                                         SIP_NOT_FOUND_CODE,
                                         SIP_NOT_FOUND_TEXT);
             }
          }

          // Identify ourselves in the response
          mpSipUserAgent->setUserAgentHeader(response);

          // Now that we've set the right code into the response, send the
          // response.
          mpSipUserAgent->send(response);
       }    // end sending response to Invite

       // If the suspend object exists, remove it from mSuspendList
       // and delete it.
       if (suspendObject)
       {
          Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                        "SipRedirectServer::processRedirect "
                        "Cleaning up suspense of request %d", seqNo);
          UtlInt containableSeqNo(seqNo);
          cancelRedirect(containableSeqNo, suspendObject);
       }
   }    // end redirector did all it could
   else
   {
      // Request is suspended.
      Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                    "SipRedirectServer::processRedirect "
                    "Suspending request %d", seqNo);
   }
}
Exemplo n.º 8
0
ContactListModel* YaContactListFriendsModel::clone() const
{
	return new YaContactListFriendsModel(contactList());
}
Exemplo n.º 9
0
PsiContactList* PsiContactListModel::psiContactList() const
{
	return static_cast<PsiContactList*>(contactList());
}
Exemplo n.º 10
0
void ContactListUtil::removeContact(PsiContact* contact, QMimeData* _selection, ContactListDragModel* model, QWidget* widget, QObject* obj)
{
	Q_ASSERT(model);
	QModelIndexList indexes = model ? model->indexesFor(contact, _selection) : QModelIndexList();
	if (model && !indexes.isEmpty()) {
		QMimeData* selection = model->mimeData(indexes);
		QString selectionData = confirmationData(contact, _selection, model);

		// WARNING: selection could also contain groups. and when there are groups,
		// all groups' contacts are marked for deletion too
		QList<PsiContact*> contactsLost = model->contactsLostByRemove(selection);
		bool removeConfirmed = contactsLost.isEmpty();
		bool confirmWithoutPrompt = false;

		if (!removeConfirmed) {
			QStringList contactNames = contactNamesFor(contactsLost);

			QString destructiveActionName;
			QString msg;
			bool doPrompt = true;

			// don't prompt when removing single muc or not-in-list contacts
			if(contactsLost.count() == 1 && (contactsLost[0]->isPrivate() || !contactsLost[0]->inList())) {
				doPrompt = false;
			}

			if (!contactNames.isEmpty()) {
				msg = tr("This will permanently remove<br>"
						 "%1"
						 "<br>from your contact list."
                         ).arg(contactNames.join(", ").replace("\\40","@"));
			}

#ifdef YAPSI
			QString complimentaryActionName;
			const char* complimentaryActionSlot = 0;

			ContactListModelSelection contactListSelection(selection);
			if (contactNames.count() > 1 || contactListSelection.groups().count()) {
				QStringList tmp;
				QStringList tmpContactNames = contactNames;
				while (!tmpContactNames.isEmpty()) {
					if (tmp.count() >= 10)
						break;

					tmp << QString("%1. %2").arg(tmp.count() + 1).arg(tmpContactNames.takeFirst());
				}

				QString andNContacts;
				if (!tmpContactNames.isEmpty()) {
					andNContacts = tr("and %n contacts ", 0,
									  tmpContactNames.count());
				}

				if (contactListSelection.groups().count() > 1) {
					msg = tr("This will permanently remove:<br>"
							 "%1"
							 "<br>%2and %n groups from your contact list.",
							 0,
							 contactListSelection.groups().count()
							).arg(tmp.join("<br>"))
							 .arg(andNContacts);
				}
				else if (contactListSelection.groups().count() == 1) {
					msg = tr("This will permanently remove:<br>"
							 "%1"
							 "<br>%2and \"%3\" group from your contact list."
							).arg(tmp.join("<br>"))
							 .arg(andNContacts)
							 .arg(contactListSelection.groups().first().fullName);
				}
				else {
					msg = tr("This will permanently remove:<br>"
							 "%1"
							 "<br>%2from your contact list."
							).arg(tmp.join("<br>"))
							 .arg(andNContacts);
				}
			}

			if (indexes.count() == 1 && model->indexType(indexes.first()) == ContactListModel::GroupType) {
				if (YaContactListContactsModel::virtualUnremovableGroups().contains(contactListSelection.groups().first().fullName)) {
					msg = tr("This is a system group and can't be removed. "
							 "Permanently remove all its contacts from your contact list?");
					destructiveActionName = tr("Clear Group");
				}
				else {
					msg = tr("This will permanently remove<br>"
							 "%1"
							 "<br>group and all its contacts from your contact list.").arg(TextUtil::escape(indexes.first().data().toString()));
				}
			}
			else if (indexes.count() == 1 && model->indexType(indexes.first()) == ContactListModel::ContactType) {
				Q_ASSERT(contactListSelection.contacts().count() == 1);
				ContactListModelSelection::Contact c = contactListSelection.contacts().first();

				PsiAccount* account = contactList()->getAccount(c.account);
				PsiContact* psiContact = account ? account->findContact(c.jid) : 0;
				QStringList contactGroupsLostByRemove;
				if (psiContact) {
					contactGroupsLostByRemove = model->contactGroupsLostByRemove(psiContact, selection);
				}

				if (psiContact && !psiContact->inList() && psiContact->blockAvailable()) {
					msg = tr("This will permanently remove %1 from your contact list. "
							 "You could block it in order to avoid further messages.")
                            .arg(contactNames.join(", ").replace("\\40","@"));
					destructiveActionName = tr("Delete");
					complimentaryActionName = tr("Block");
					complimentaryActionSlot = "blockContactConfirmation";
				}
				else if (psiContact && psiContact->groups().count() > 1 && contactGroupsLostByRemove.count() == 1) {
					// TODO: needs to be translated
					msg = tr("This will remove %1 from \"%2\" group. "
							 "You could also remove it from all groups.")
						  .arg(contactNames.join(", "))
						  .arg(contactGroupsLostByRemove.first());
					destructiveActionName = tr("Delete");
					complimentaryActionName = tr("Delete From All Groups");
					// TODO: needs to be implemented
					complimentaryActionSlot = "removeContactFullyConfirmation";
				}
			}
#endif

			if (!msg.isEmpty()) {
				if (doPrompt) {
#ifdef YAPSI
					if (complimentaryActionSlot) {
						RemoveConfirmationMessageBoxManager::instance()->
							removeConfirmation(selectionData,
											   obj, "removeContactConfirmation",
											   obj, complimentaryActionSlot,
											   tr("Deleting contacts"),
											   msg,
											   widget,
											   destructiveActionName,
											   complimentaryActionName);
					}
#else
					if (false) {
					}
#endif
					else {
						RemoveConfirmationMessageBoxManager::instance()->
							removeConfirmation(selectionData,
											   obj, "removeContactConfirmation",
											   tr("Deleting contacts"),
											   msg,
											   widget,
											   destructiveActionName);
					}

					removeConfirmed = false;
				}
				else {
					confirmWithoutPrompt = true;
				}
			}
		}

		QMetaObject::invokeMethod(obj, "removeContactConfirmation", Qt::DirectConnection,
								  QGenericReturnArgument(),
								  Q_ARG(QString, selectionData), Q_ARG(bool, removeConfirmed));

		if(confirmWithoutPrompt) {
			QMetaObject::invokeMethod(obj, "removeContactConfirmation", Qt::QueuedConnection,
								  QGenericReturnArgument(),
								  Q_ARG(QString, selectionData), Q_ARG(bool, true));
		}

		delete selection;
	}