diff --git a/kopete/config/appearance/layout/TokenPool.cpp b/kopete/config/appearance/layout/TokenPool.cpp index eadb04142..374354afd 100644 --- a/kopete/config/appearance/layout/TokenPool.cpp +++ b/kopete/config/appearance/layout/TokenPool.cpp @@ -1,139 +1,139 @@ /****************************************************************************** * Copyright (C) 2008 Teo Mrnjavac * * 2009 Seb Ruiz * * * * This program 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 program 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 program. If not, see . * ******************************************************************************/ #include "TokenPool.h" #include -#include +#include #include #include TokenPool::TokenPool(QWidget *parent) : QListWidget(parent) { setAcceptDrops(true); } void TokenPool::addToken(Token *token) { QListWidgetItem *item = new QListWidgetItem(token->icon().pixmap(48, 48), token->name()); addItem(item); m_itemTokenMap.insert(item, token); } QString TokenPool::mimeType() const { return m_mimeType; } void TokenPool::setMimeType(const QString &mimeType) { m_mimeType = mimeType; } // Executed on doubleclick of the TokenPool, emits signal onDoubleClick( QString ) // that connects to TokenLayoutWidget::addToken( QString ) void TokenPool::mouseDoubleClickEvent(QMouseEvent *event) { QListWidgetItem *tokenItem = itemAt(event->pos()); if (tokenItem) { emit onDoubleClick(m_itemTokenMap.value(tokenItem)); //token->name() << token->iconName() << token->value() } } //Executed on mouse press, handles start of drag. void TokenPool::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { m_startPos = event->pos(); //store the start position } QListWidget::mousePressEvent(event); //feed it to parent's event } //Executed on mouse move, handles start of drag. void TokenPool::mouseMoveEvent(QMouseEvent *event) { if (event->buttons() & Qt::LeftButton) { int distance = (event->pos() - m_startPos).manhattanLength(); if (distance >= KApplication::startDragDistance()) { performDrag(event); } } QListWidget::mouseMoveEvent(event); } //This doesn't do much since TokenPool doesn't accept objects. void TokenPool::dragEnterEvent(QDragEnterEvent *event) { QWidget *source = qobject_cast(event->source()); if (source && source != this) { event->setDropAction(Qt::MoveAction); event->accept(); } } //Same as above. void TokenPool::dragMoveEvent(QDragMoveEvent *event) //overrides QListWidget's implementation { QWidget *source = qobject_cast(event->source()); if (source && source != this) { event->setDropAction(Qt::MoveAction); event->accept(); } } //Same as above. void TokenPool::dropEvent(QDropEvent *event) { Q_UNUSED(event) //does nothing, I want the item to be deleted and not dragged here } //Handles the creation of a QDrag object that carries the (text-only) QDataStream from an item in TokenPool void TokenPool::performDrag(QMouseEvent *event) { QListWidgetItem *item = currentItem(); if (item) { Token *token = m_itemTokenMap.value(item); QByteArray itemData; QDataStream dataStream(&itemData, QIODevice::WriteOnly); dataStream << token->name() << token->iconName() << token->value() << QPoint(event->pos() - rect().topLeft()); QMimeData *mimeData = new QMimeData(); mimeData->setData(m_mimeType, itemData); QDrag *drag = new QDrag(this); drag->setMimeData(mimeData); //TODO: set a pointer for the drag, like this: drag->setPixmap( QPixmap("foo.png" ) ); drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::CopyAction); } } diff --git a/kopete/config/status/statusmodel.cpp b/kopete/config/status/statusmodel.cpp index 5f3ee8fcc..41f15b0f0 100644 --- a/kopete/config/status/statusmodel.cpp +++ b/kopete/config/status/statusmodel.cpp @@ -1,360 +1,360 @@ /* kopetestatusmodel.cpp - Kopete Status Model Copyright (c) 2008 by Roman Jarosz Kopete (c) 2008 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "statusmodel.h" #include #include #include -#include +#include #include "kopetestatusitems.h" #include "kopetestatusmanager.h" KopeteStatusModel::KopeteStatusModel(Kopete::Status::StatusGroup *rootItem, QObject *parent) : QAbstractItemModel(parent) , mRootItem(rootItem) { } KopeteStatusModel::~KopeteStatusModel() { } QVariant KopeteStatusModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } QVariant result; switch (role) { case Qt::DisplayRole: if (index.column() == 0) { result = getStatusItem(index)->title(); } break; case Qt::DecorationRole: if (index.column() == 0) { result = Kopete::OnlineStatusManager::pixmapForCategory(getStatusItem(index)->category()); } break; case KopeteStatusModel::Group: result = getStatusItem(index)->isGroup(); break; case KopeteStatusModel::Category: result = (int)getStatusItem(index)->category(); break; case KopeteStatusModel::Title: result = getStatusItem(index)->title(); break; case KopeteStatusModel::Message: { Kopete::Status::Status *s = getStatus(getStatusItem(index)); if (s) { result = s->message(); } break; } default: return result; } return result; } bool KopeteStatusModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid()) { return false; } switch (role) { case KopeteStatusModel::Category: getStatusItem(index)->setCategory((Kopete::OnlineStatusManager::Categories)value.toInt()); break; case KopeteStatusModel::Title: getStatusItem(index)->setTitle(value.toString()); break; case KopeteStatusModel::Message: { Kopete::Status::Status *s = getStatus(getStatusItem(index)); if (!s) { return false; } s->setMessage(value.toString()); break; } default: return false; } emit dataChanged(index, index); emit changed(); return true; } Qt::ItemFlags KopeteStatusModel::flags(const QModelIndex &index) const { if (!index.isValid()) { return Qt::ItemIsDropEnabled; } if (getStatusItem(index)->isGroup()) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } else { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled; } } QVariant KopeteStatusModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section == 0) { return i18n("Title"); } return QVariant(); } QModelIndex KopeteStatusModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) { return QModelIndex(); } Kopete::Status::StatusItem *childItem = getStatusItem(parent)->child(row); if (childItem) { return createIndex(row, column, childItem); } else { return QModelIndex(); } } QModelIndex KopeteStatusModel::parent(const QModelIndex &index) const { if (!index.isValid()) { return QModelIndex(); } Kopete::Status::StatusItem *parentItem = getStatusItem(index)->parentGroup(); if (parentItem == mRootItem) { return QModelIndex(); } return createIndex(parentItem->index(), 0, parentItem); } int KopeteStatusModel::rowCount(const QModelIndex &parent) const { if (parent.column() > 0) { return 0; } return getStatusItem(parent)->childCount(); } int KopeteStatusModel::columnCount(const QModelIndex &) const { return 1; } Qt::DropActions KopeteStatusModel::supportedDropActions() const { return Qt::MoveAction; } QModelIndex KopeteStatusModel::insertItem(const QModelIndex &index, Kopete::Status::StatusItem *item) { int row = 0; QModelIndex parentIndex; if (index.isValid()) { // Don't create nasted groups if (getStatusItem(index)->isGroup() && !item->isGroup()) { parentIndex = index; } else { parentIndex = index.parent(); row = index.row() + 1; } } Kopete::Status::StatusGroup *group = getGroup(getStatusItem(parentIndex)); if (!group) { return QModelIndex(); } emit layoutAboutToBeChanged(); beginInsertRows(parentIndex, row, row); group->insertChild(row, item); endInsertRows(); emit layoutChanged(); emit changed(); return this->index(row, 0, parentIndex); } bool KopeteStatusModel::removeRows(int row, int count, const QModelIndex &parent) { if (count == 0) { return false; } Kopete::Status::StatusGroup *group = getGroup(getStatusItem(parent)); if (!group) { return false; } emit layoutAboutToBeChanged(); beginRemoveRows(parent, row, row + count - 1); while ((count--) > 0) { delete group->child(row); } endRemoveRows(); emit layoutChanged(); emit changed(); return true; } QStringList KopeteStatusModel::mimeTypes() const { QStringList types; types << QStringLiteral("application/xml-kopete-status"); return types; } QMimeData *KopeteStatusModel::mimeData(const QModelIndexList &indexes) const { using namespace Kopete; QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); foreach (const QModelIndex &index, indexes) { if (index.isValid() && index.column() == 0) { Status::StatusItem *item = getStatusItem(index); QDomDocument doc(QLatin1String("kopete-status")); doc.appendChild(StatusManager::storeStatusItem(item)); stream << doc.toString(); } } mimeData->setData(QStringLiteral("application/xml-kopete-status"), encodedData); return mimeData; } bool KopeteStatusModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { if (action == Qt::IgnoreAction) { return true; } if (!data->hasFormat(QStringLiteral("application/xml-kopete-status"))) { return false; } if (column > 0) { return false; } int beginRow; if (row != -1) { beginRow = row; } else if (parent.isValid()) { beginRow = parent.row(); } else { beginRow = rowCount(QModelIndex()); } QByteArray encodedData = data->data(QStringLiteral("application/xml-kopete-status")); QDataStream stream(&encodedData, QIODevice::ReadOnly); using namespace Kopete; Status::StatusGroup *parentItem = getGroup(getStatusItem(parent)); if (!parentItem) { return false; } QStringList newItems; int rows = 0; while (!stream.atEnd()) { QString text; stream >> text; newItems << text; ++rows; } emit layoutAboutToBeChanged(); for (int i = 0; i < newItems.size(); ++i) { QDomDocument doc; doc.setContent(newItems.at(i)); if (!doc.isNull()) { Status::StatusItem *item = StatusManager::parseStatusItem(doc.documentElement()); QDomDocument doc2(QLatin1String("kopete-status")); doc2.appendChild(StatusManager::storeStatusItem(item)); // Don't create nasted groups if (item->isGroup() && parentItem != mRootItem) { int parentRow = parent.row(); beginInsertRows(parent.parent(), parentRow, parentRow); parentItem->parentGroup()->insertChild(parentRow, item); endInsertRows(); } else { beginInsertRows(parent, beginRow, beginRow); parentItem->insertChild(beginRow++, item); endInsertRows(); } } } emit layoutChanged(); emit changed(); return true; } Kopete::Status::StatusItem *KopeteStatusModel::getStatusItem(const QModelIndex &index) const { if (!index.isValid()) { return mRootItem; } return static_cast(index.internalPointer()); } Kopete::Status::Status *KopeteStatusModel::getStatus(Kopete::Status::StatusItem *item) const { if (!item) { return 0; } return qobject_cast(item); } Kopete::Status::StatusGroup *KopeteStatusModel::getGroup(Kopete::Status::StatusItem *item) const { if (!item) { return 0; } return qobject_cast(item); } diff --git a/libkopete/kopeteaccount.h b/libkopete/kopeteaccount.h index b3e6fa3ff..44684e935 100644 --- a/libkopete/kopeteaccount.h +++ b/libkopete/kopeteaccount.h @@ -1,636 +1,636 @@ /* kopeteaccount.h - Kopete Account Copyright (c) 2007 by Gustavo Pichorim Boiko Copyright (c) 2003-2005 by Olivier Goffart Copyright (c) 2003-2004 by Martijn Klingens Copyright (c) 2004 by Richard Smith Kopete (c) 2002-2007 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETEACCOUNT_H #define KOPETEACCOUNT_H #include "kopeteonlinestatus.h" #include "kopetestatusmessage.h" #include "libkopete_export.h" -#include +#include #include -#include +#include #include #include #include class KActionMenu; class KConfigGroup; namespace Kopete { class Contact; class Protocol; class MetaContact; class Group; class OnlineStatus; class BlackLister; class StatusMessage; class Identity; class PropertyContainer; /** * The Kopete::Account class handles one account. * Each protocol implementation should subclass this class in its own custom account class. * There are a few pure virtual methods that must be implemented. Examples are: * \li \ref connect() * \li \ref disconnect() * \li \ref createContact() * * The accountId is an @em constant unique id, which represents the login. * The @ref myself() contact is one of the most important contacts, which represents * the user tied to this account. You must create this contact in the contructor of your * account and pass it to @ref setMyself(). * * All account data is saved to @ref KConfig. This includes the accountId, the autoconnect flag and * the color. You can save more data using @ref configGroup() * * When you create a new account, you have to register it with the account manager by calling * @ref AccountManager::registerAccount. * * @author Olivier Goffart */ class LIBKOPETE_EXPORT Account : public QObject { Q_OBJECT Q_ENUMS(AddMode) Q_PROPERTY(QString accountId READ accountId) Q_PROPERTY(bool excludeConnect READ excludeConnect WRITE setExcludeConnect) Q_PROPERTY(QColor color READ color WRITE setColor) Q_PROPERTY(QPixmap accountIcon READ accountIcon) Q_PROPERTY(bool isConnected READ isConnected) Q_PROPERTY(bool isAway READ isAway) Q_PROPERTY(bool suppressStatusNotification READ suppressStatusNotification) Q_PROPERTY(uint priority READ priority WRITE setPriority) public: /** * \brief Describes how the account was disconnected * * Manual means that the disconnection was done by the user and no reconnection * will take place. Any other value will reconnect the account on disconnection. * The case where the password is wrong will be handled differently. * @see @ref disconnected */ enum DisconnectReason { OtherClient = -4, ///< connection went down because another client connected the same account BadPassword = -3, ///< connection failed because password was incorrect BadUserName = -2, ///< connection failed because user name was invalid / unknown InvalidHost = -1, ///< connection failed because host is unreachable Manual = 0, ///< the user disconnected normally ConnectionReset = 1, ///< the connection was lost Unknown = 99 ///< the reason for disconnection is unknown }; /** * \brief Describes what should be done when the contact is added to a metacontact * @sa @ref addContact() */ enum AddMode { ChangeKABC = 0, ///< The KDE Address book may be updated DontChangeKABC = 1, ///< The KDE Address book will not be changed Temporary = 2 ///< The contact will not be added on the contact list }; /** * \brief Describes what should be done when we set new OnlineStatus * @sa @ref setOnlineStatus() */ enum OnlineStatusOption { None = 0x00, ///< Use the online status KeepSpecialFlags = 0x01 ///< Use the online status but keep special flags, e.g. Invisible }; Q_DECLARE_FLAGS(OnlineStatusOptions, OnlineStatusOption) /** * Constructor for the Account object. * * @param parent the protocol for this account. The account is a child object of the * protocol, so it will be automatically deleted when the protocol is. * @param accountID the unique ID of this account. * @param name the name of this QObject. */ Account(Protocol *parent, const QString &accountID); /** * Destroy the Account object. */ ~Account(); /** * \return the Protocol for this account */ Protocol *protocol() const; /** * \return the unique ID of this account used as the login */ QString accountId() const; /** * The label for this account. * * This is used in the GUI. * \return The label of this account */ QString accountLabel() const; /** * \brief Get the priority of this account. * * Used for sorting and determining the preferred account to message a contact. */ uint priority() const; /** * \brief Set the priority of this account. * * @note This method is called by the UI, and should not be called elsewhere. */ void setPriority(uint priority); /** * \brief Set if the account should not log in automatically. * * This function can be used by the EditAccountPage. Kopete handles connection automatically. * @sa @ref excludeConnect */ void setExcludeConnect(bool); /** * \brief Get if the account should not log in. * * @return @c true if the account should not be connected when connectAll at startup, @c false otherwise. */ bool excludeConnect() const; /** * \brief Get the color for this account. * * The color will be used to visually differentiate this account from other accounts on the * same protocol. * * \return the user color for this account */ const QColor color() const; /** * \brief Set the color for this account. * * This is called by Kopete's account config page; you don't have to set the color yourself. * * @sa @ref color() */ void setColor(const QColor &color); /** * \brief Get the icon for this account. * * Generates an image of size @p size representing this account. The result is not cached. * * @param size the size of the icon. If the size is 0, the default size is used. * @return the icon for this account, colored if needed */ QPixmap accountIcon(const int size = 0) const; /* * \brief Get the icon path for this account. * * This is the account icon path. * * @return the icon path for this account. */ QString accountIconPath(const KIconLoader::Group size) const; /** * \brief change the account icon. * by default the icon of an account is the protocol one, but it may be overide it. * Set QString() to go back to the default (the protocol icon) * * this call will emit colorChanged() */ void setCustomIcon(const QString &); /** * \brief return the icon base * This is the custom account icon set with setIcon. if this icon is null, then the protocol icon is used * don't use this function to get the icon that need to be displayed, use accountIcon */ QString customIcon() const; /** * \brief Retrieve the identity this account belongs to * * \return a pointer to the Identity object this account belongs to. * * \see setIdentity(). */ Identity *identity() const; /** * \brief Sets the identity this account belongs to * * Setting the account to a new identity implies it to be removed from the * identity it was previously associated. * * @param ident The identity this account should be associated to * \return @c true if the identity was changed, @c false otherwise * * @note You should call the default implementation from your reimplementation */ virtual bool setIdentity(Kopete::Identity *ident); /** * \brief Retrieve the 'myself' contact. * * \return a pointer to the Contact object for this account * * \see setMyself(). */ Contact *myself() const; /** * @brief Fill the menu with actions for this account * * You have to reimplement this method to add custom actions to the @p actionMenu which will * be shown in the statusbar. It is the caller's responsibility to ensure the menu is deleted. * * The default implementation provides a generic menu, with actions generated from the protocol's * registered statuses, and an action to show the account's settings dialog. * * You should call the default implementation from your reimplementation, and add more actions * you require to the resulting action menu. * * @see OnlineStatusManager::registerOnlineStatus */ virtual void fillActionMenu(KActionMenu *actionMenu); /** * @brief Return true if account has custom status menu. * * You have to reimplement this method and return true if you don't want to have status menu in menu * which will be shown in the statusbar * * The default implementation returns false. */ virtual bool hasCustomStatusMenu() const; /** * @brief Retrieve the list of contacts for this account (except myself contact) * * The list is guaranteed to contain only contacts for this account, * so you can safely use static_cast to your own derived contact class * if needed. */ const QHash &contacts(); /** * Indicates whether or not we should suppress status notifications * for contacts belonging to this account. * * This is used when we just connected or disconnected, and every contact has their initial * status set. * * @return @c true if notifications should not be used, @c false otherwise */ bool suppressStatusNotification() const; /** * \brief Create a contact (creating a new metacontact if necessary) * * If a contact for this account with ID @p contactId is not already on the contact list, * a new contact with that ID is created, and added to a new metacontact. * * If @p mode is @c ChangeKABC, MetaContact::updateKABC will be called on the resulting metacontact. * If @p mode is @c Temporary, MetaContact::setTemporary will be called on the resulting metacontact, * and the metacontact will not be added to @p group. * If @p mode is @c DontChangeKABC, no additional action is carried out. * * @param contactId the @ref Contact::contactId of the contact to create * @param displayName the displayname (alias) of the new metacontact. Leave as QString() if * no alias is known, then by default, the nick will be taken as alias and tracked if changed. * @param group the group to add the created metacontact to, or 0 for the top-level group. * @param mode the mode used to add the contact. Use DontChangeKABC when deserializing. * @return the new created metacontact or 0L if the operation failed */ MetaContact *addContact(const QString &contactId, const QString &displayName = QString(), Group *group = 0, AddMode mode = DontChangeKABC); /** * @brief Create a new contact, adding it to an existing metacontact * * If a contact for this account with ID @p contactId is not already on the contact list, * a new contact with that ID is created, and added to the metacontact @p parent. * * @param contactId the @ref Contact::contactId of the contact to create * @param parent the parent metacontact (must not be 0) * @param mode the mode used to add the contact. See addContact(const QString&,const QString&,Group*,AddMode) for details. * * @return @c true if creation of the contact succeeded or the contact was already in the list, * @c false otherwise. */ bool addContact(const QString &contactId, MetaContact *parent, AddMode mode = DontChangeKABC); /** * @brief Indicate whether the account is connected at all. * * This is a convenience method that calls @ref Contact::isOnline() on @ref myself(). * This function is safe to call if @ref setMyself() has not been called yet. * * @see @ref isConnectedChanged() */ bool isConnected() const; /** * @brief Indicate whether the account is away. * * This is a convenience method that queries @ref Contact::onlineStatus() on @ref myself(). * This function is safe to call if @ref setMyself() has not been called yet. * * @see @ref isBusy() */ bool isAway() const; /** * @brief Indicate whether the account is busy. * * In busy mode all visible and sound events should be disabled. * * This is a convenience method that queries @ref Contact::onlineStatus() on @ref myself(). * This function is safe to call if @ref setMyself() has not been called yet. * * @see @ref isAway() */ bool isBusy() const; /** * Return the @ref KConfigGroup used to write and read special properties * * "Protocol", "AccountId" , "Color", "AutoConnect", "Priority", "Enabled" , "Icon" are reserved keyword * already in use in that group. * * for compatibility, try to not use key that start with a uppercase */ KConfigGroup *configGroup() const; /** * @brief Remove the account from the server. * * Reimplement this if your protocol supports removing the accounts from the server. * This function is called by @ref AccountManager::removeAccount typically when you remove the * account on the account config page. * * You should add a confirmation message box before removing the account. The default * implementation does nothing. * * @return @c false only if the user requested for the account to be deleted, and deleting the * account failed. Returns @c true in all other cases. */ virtual bool removeAccount(); /** * \return a pointer to the blacklist of the account * @todo remove or implement correctly (BlackLister) */ BlackLister *blackLister(); /** * \return @c true if the contact with ID @p contactId is in the blacklist, @c false otherwise. * @todo remove or implement correctly (BlackLister) */ virtual bool isBlocked(const QString &contactId); protected: /** * \brief Set the 'myself' contact. * * This contact must be defined for every account, because it holds the online status * of the account. You must call this function in the constructor of your account. * * The myself contact can't be deleted as long as the account still exists. The myself * contact is used as a member of every ChatSession involving this account. myself's * contactId should be the accountID. The online status of the myself contact represents * the account's status. * * The myself should have the @ref ContactList::myself() as parent metacontact * */ void setMyself(Contact *myself); /** * \brief Create a new contact in the specified metacontact * * You shouldn't ever call this method yourself. To add contacts, use @ref addContact(). * * This method is called by @ref addContact(). In this method, you should create the * new custom @ref Contact, using @p parentContact as the parent. * * If the metacontact is not temporary and the protocol supports it, you can add the * contact to the server. * * @param contactId the ID of the contact to create * @param parentContact the metacontact to add this contact to * @return @c true if creating the contact succeeded, @c false on failure. */ virtual bool createContact(const QString &contactId, MetaContact *parentContact) = 0; /** * \brief Sets the account label * * @param label The label to set */ void setAccountLabel(const QString &label); protected Q_SLOTS: /** * \brief The service has been disconnected * * You have to call this method when you are disconnected. Depending on the value of * @p reason, this function may attempt to reconnect to the server. * * - BadPassword will ask again for the password * - OtherClient will show a message box * * @param reason the reason for the disconnection. */ virtual void disconnected(Kopete::Account::DisconnectReason reason); /** * @brief Sets the online status of all contacts in this account to the same value * * Some protocols do not provide status-changed events for all contacts when an account * becomes connected or disconnected. For such protocols, this function may be useful * to set all contacts offline. * * Calls @ref Kopete::Contact::setOnlineStatus on all contacts of this account (except the * @ref myself() contact), passing @p status as the status. * * @param status the status to set all contacts of this account except @ref myself() to. */ void setAllContactsStatus(const Kopete::OnlineStatus &status); /** * @brief React to network status changes * * @param status the new network status. */ void networkingStatusChanged(const Solid::Networking::Status status); Q_SIGNALS: /** * The color of the account has been changed * * also emitted when the icon change * @todo probably rename to accountIconChanged */ void colorChanged(const QColor &); /** * Emitted when the account is deleted. * @warning emitted in the Account destructor. It is not safe to call any functions on @p account. */ void accountDestroyed(const Kopete::Account *account); /** * Emitted whenever @ref isConnected() changes. */ void isConnectedChanged(); private: /** * @internal * Reads the configuration information of the account from KConfig. */ void readConfig(); public: /** * @internal * Register a new Contact with the account. This should be called @em only from the * @ref Contact constructor, not from anywhere else (not even a derived class). */ bool registerContact(Contact *c); public Q_SLOTS: /** * @brief Go online for this service. * * @param initialStatus is the status to connect with. If it is an invalid status for this * account, the default online for the account should be used. * @todo probably deprecate in favor of setOnlineStatus */ virtual void connect(const Kopete::OnlineStatus &initialStatus = OnlineStatus()) = 0; /** * @brief Go offline for this service. * * If the service is connecting, you should abort the connection. * * You should call the @ref disconnected function from this function. * @todo probably deprecate in favor of setOnlineStatus */ virtual void disconnect() = 0; public Q_SLOTS: /** * Reimplement this function to set the online status * @param status is the new status * @param reason is the status message to set. * @param options specify how the status should be set * @note If needed, you need to connect. if the offline status is given, you should disconnect */ virtual void setOnlineStatus(const Kopete::OnlineStatus &status, const Kopete::StatusMessage &reason = Kopete::StatusMessage(), const OnlineStatusOptions &options = None) = 0; /** * Reimplement this function to set the status message(with metadata). * You should use this method to set the status message instead of using setOnlineStatus. * @param statusMessage is the status message to set. (Use Kopete::StatusMessage). */ virtual void setStatusMessage(const Kopete::StatusMessage &statusMessage) = 0; /** * Disconnects account, required before resume() * Returns false if account is already suspended. */ bool suspend(const Kopete::StatusMessage &reason = Kopete::StatusMessage()); /** * Sets account to the online status that was active when suspend() was called. * Returns false if account has not been suspended or status has changed to something other than Offline in the meantime. */ bool resume(); /** * Display the edit account widget for the account */ void editAccount(QWidget *parent = nullptr); /** * Add a user to the blacklist. The default implementation calls * blackList()->addContact( contactId ) * * @param contactId the contact to be added to the blacklist * @todo remove or implement correctly (BlackLister) */ virtual void block(const QString &contactId); /** * Remove a user from the blacklist. The default implementation calls * blackList()->removeContact( contactId ) * * @param contactId the contact to be removed from the blacklist * @todo remove or implement correctly (BlackLister) */ virtual void unblock(const QString &contactId); private Q_SLOTS: /** * Restore online status and status message on reconnect. */ void reconnect(); /** * Track the deletion of a Contact and clean up */ void contactDestroyed(Kopete::Contact *); /** * The @ref myself() contact's online status changed. */ void slotOnlineStatusChanged(Kopete::Contact *contact, const Kopete::OnlineStatus &newStatus, const Kopete::OnlineStatus &oldStatus); /** * The @ref myself() contact's property changed. */ void slotContactPropertyChanged(Kopete::PropertyContainer *, const QString &, const QVariant &, const QVariant &); /** * Stop the suppression of status notification (connected to a timer) */ void slotStopSuppression(); private: class Private; Private *const d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(Account::OnlineStatusOptions) } //END namespace Kopete #endif diff --git a/libkopete/kopeteaccountmanager.cpp b/libkopete/kopeteaccountmanager.cpp index abcb3b76c..96ab1ee13 100644 --- a/libkopete/kopeteaccountmanager.cpp +++ b/libkopete/kopeteaccountmanager.cpp @@ -1,536 +1,536 @@ /* kopeteaccountmanager.cpp - Kopete Account Manager Copyright (c) 2002-2003 by Martijn Klingens Copyright (c) 2003-2004 by Olivier Goffart Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "kopeteaccountmanager.h" #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include #include #include #include #include "kopeteaccount.h" #include "kopetebehaviorsettings.h" #include "kopeteprotocol.h" #include "kopetecontact.h" #include "kopetecontactlist.h" #include "kopeteidentitymanager.h" #include "kopetepluginmanager.h" #include "kopetestatusitems.h" #include "kopeteonlinestatus.h" #include "kopeteonlinestatusmanager.h" #include "kopetemetacontact.h" #include "kopetegroup.h" #include "kopetestatusmanager.h" namespace Kopete { static int compareAccountsByPriority(Account *a, Account *b) { uint priority1 = a->priority(); uint priority2 = b->priority(); if (a == b) { //two account are equal only if they are equal :-) return 0; // remember than an account can be only once on the list, but two account may have the same priority when loading } else if (priority1 > priority2) { return 1; } else { return -1; } } class AccountManager::Private { public: QList accounts; QList accountsToBeRemoved; bool suspended; Kopete::StatusMessage suspendedStatusMessage; uint suspendedStatusCategory; }; AccountManager *AccountManager::s_self = nullptr; AccountManager *AccountManager::self() { if (!s_self) { s_self = new AccountManager; } return s_self; } AccountManager::AccountManager() : QObject(qApp) , d(new Private()) { setObjectName(QStringLiteral("KopeteAccountManager")); connect(Solid::Networking::notifier(), SIGNAL(shouldConnect()), this, SLOT(networkConnected())); connect(Solid::Networking::notifier(), SIGNAL(shouldDisconnect()), this, SLOT(networkDisconnected())); connect(Solid::PowerManagement::notifier(), SIGNAL(resumingFromSuspend()), this, SLOT(resume())); #ifdef __GNUC__ #warning TODO: Switch to a org.kde.Solid.PowerManagement Sleeping/Suspending signal when available. #endif QDBusConnection::systemBus().connect(QStringLiteral("org.freedesktop.UPower"), QStringLiteral("/org/freedesktop/UPower"), QLatin1String(""), QStringLiteral("Sleeping"), this, SLOT(suspend())); d->suspended = false; } AccountManager::~AccountManager() { s_self = nullptr; delete d; } bool AccountManager::isAnyAccountConnected() const { foreach (Account *a, d->accounts) { if (a->isConnected()) { return true; } } return false; } void AccountManager::setOnlineStatus(uint category, const Kopete::StatusMessage &statusMessage, uint flags, bool forced) { qCDebug(LIBKOPETE_LOG) << "category: " << category << "status title: " << statusMessage.title() << "status message: " << statusMessage.message(); OnlineStatusManager::Categories categories = (OnlineStatusManager::Categories)category; const bool onlyChangeConnectedAccounts = (!forced && isAnyAccountConnected()); d->suspended = false; foreach (Account *account, d->accounts) { Kopete::OnlineStatus status = OnlineStatusManager::self()->onlineStatus(account->protocol(), categories); // Going offline is always respected if (category & Kopete::OnlineStatusManager::Offline) { account->setOnlineStatus(status, statusMessage); continue; } if (onlyChangeConnectedAccounts) { //If global status is offline, change all account to new status if (account->isConnected() || (((flags & ConnectIfOffline) || Kopete::StatusManager::self()->globalStatusCategory() == Kopete::OnlineStatusManager::Offline) && !account->excludeConnect())) { account->setOnlineStatus(status, statusMessage); } } else { if (!account->excludeConnect()) { account->setOnlineStatus(status, statusMessage); } } } // mark ourselves as globally away if appropriate Kopete::StatusManager::self()->setGlobalStatus(category, statusMessage); } void AccountManager::setOnlineStatus(uint category, const Kopete::StatusMessage &statusMessage, uint flags) { setOnlineStatus(category, statusMessage, flags, false); } void AccountManager::setStatusMessage(const QString &message) { foreach (Account *account, d->accounts) { account->setStatusMessage(message); } } void AccountManager::suspend() { if (d->suspended) { return; } d->suspended = true; d->suspendedStatusMessage = Kopete::StatusManager::self()->globalStatusMessage(); d->suspendedStatusCategory = Kopete::StatusManager::self()->globalStatusCategory(); Kopete::StatusMessage statusMessage(i18n("Offline"), QLatin1String("")); QList statusList = Kopete::StatusManager::self()->getRootGroup()->childList(); //find first Status for OffineStatus for (QList ::ConstIterator it = statusList.constBegin(); it != statusList.constEnd(); ++it) { if (!(*it)->isGroup() && (*it)->category() == Kopete::OnlineStatusManager::Offline) { QString message, title; title = (*it)->title(); message = (static_cast (*it))->message(); //if it is not group, it's status statusMessage.setTitle(title); statusMessage.setMessage(message); break; } } foreach (Account *account, d->accounts) { account->suspend(statusMessage); } Kopete::StatusManager::self()->setGlobalStatus(Kopete::OnlineStatusManager::Offline, statusMessage); } bool AccountManager::resume() { bool networkAvailable = (Solid::Networking::status() == Solid::Networking::Unknown || Solid::Networking::status() == Solid::Networking::Connected); if (!d->suspended || !networkAvailable) { return false; } foreach (Account *account, d->accounts) { account->resume(); } Kopete::StatusManager::self()->setGlobalStatus(d->suspendedStatusCategory, d->suspendedStatusMessage); d->suspended = false; return true; } QColor AccountManager::guessColor(Protocol *protocol) const { // In a perfect wold, we should check if the color is actually not used by the account. // Anyway, this is not really required, It would be a difficult job for about nothing more. // -- Olivier int protocolCount = 0; for (QListIterator it(d->accounts); it.hasNext();) { Account *a = it.next(); if (a->protocol()->pluginId() == protocol->pluginId()) { protocolCount++; } } // let's figure a color QColor color; switch (protocolCount % 7) { case 0: color = QColor(); break; case 1: color = Qt::red; break; case 2: color = Qt::green; break; case 3: color = Qt::blue; break; case 4: color = Qt::yellow; break; case 5: color = Qt::magenta; break; case 6: color = Qt::cyan; break; } return color; } Account *AccountManager::registerAccount(Account *account) { if (!account || d->accounts.contains(account)) { return account; } if (account->accountId().isEmpty()) { account->deleteLater(); return nullptr; } // If this account already exists, do nothing QListIterator it(d->accounts); while (it.hasNext()) { Account *curracc = it.next(); if ((account->protocol() == curracc->protocol()) && (account->accountId() == curracc->accountId())) { account->deleteLater(); return nullptr; } } d->accounts.append(account); qSort(d->accounts.begin(), d->accounts.end(), compareAccountsByPriority); // Connect to the account's status changed signal connect(account->myself(), SIGNAL(onlineStatusChanged(Kopete::Contact *, const Kopete::OnlineStatus&,const Kopete::OnlineStatus&)), this, SLOT(slotAccountOnlineStatusChanged(Kopete::Contact *, const Kopete::OnlineStatus&,const Kopete::OnlineStatus&))); connect(account, SIGNAL(accountDestroyed(const Kopete::Account *)), this, SLOT(unregisterAccount(const Kopete::Account *))); if (!account->identity()) { // the account's Identity must be set here instead of in the Kopete::Account ctor, because there the // identity cannot pick up any state set in the derived Account ctor Identity *identity = Kopete::IdentityManager::self()->findIdentity(account->configGroup()->readEntry("Identity", QString())); // if the identity was not found, use the default one which will for sure exist // FIXME: get rid of this, the account's identity should always exist at this point if (!identity) { qCWarning(LIBKOPETE_LOG) << "No identity for account " << account->accountId() << ": falling back to default"; identity = Kopete::IdentityManager::self()->defaultIdentity(); } account->setIdentity(identity); } emit accountRegistered(account); return account; } void AccountManager::unregisterAccount(const Account *account) { qCDebug(LIBKOPETE_LOG) << "Unregistering account " << account->accountId(); d->accounts.removeAll(const_cast(account)); emit accountUnregistered(account); } const QList &AccountManager::accounts() const { return d->accounts; } QList AccountManager::accounts(Protocol *protocol) const { QList protocolAccounts; foreach (Account *acct, d->accounts) { if (acct->protocol() == protocol) { protocolAccounts.append(acct); } } return protocolAccounts; } Account *AccountManager::findAccount(const QString &protocolId, const QString &accountId) { for (QListIterator it(d->accounts); it.hasNext();) { Account *a = it.next(); if (a->protocol()->pluginId() == protocolId && a->accountId() == accountId) { return a; } } return nullptr; } void AccountManager::removeAccount(Account *account) { if (!account->removeAccount()) { return; } if (!account->isConnected()) { d->accountsToBeRemoved.append(account); QTimer::singleShot(0, this, SLOT(removeAccountInternal())); } else { qCDebug(LIBKOPETE_LOG) << account->accountId() << " is still connected, disconnecting..."; connect(account, SIGNAL(isConnectedChanged()), this, SLOT(removeAccountConnectedChanged())); account->disconnect(); } } void AccountManager::save() { //qCDebug(LIBKOPETE_LOG) ; qSort(d->accounts.begin(), d->accounts.end(), compareAccountsByPriority); for (QListIterator it(d->accounts); it.hasNext();) { Account *a = it.next(); KConfigGroup *config = a->configGroup(); config->writeEntry("Protocol", a->protocol()->pluginId()); config->writeEntry("AccountId", a->accountId()); } KSharedConfig::openConfig()->sync(); } void AccountManager::load() { connect(PluginManager::self(), SIGNAL(pluginLoaded(Kopete::Plugin *)), this, SLOT(slotPluginLoaded(Kopete::Plugin *))); // Iterate over all groups that start with "Account_" as those are accounts // and load the required protocols if the account is enabled. // Don't try to optimize duplicate calls out, the plugin queue is smart enough // (and fast enough) to handle that without adding complexity here KSharedConfig::Ptr config = KSharedConfig::openConfig(); QStringList accountGroups = config->groupList().filter(QRegExp(QLatin1String("^Account_"))); for (QStringList::Iterator it = accountGroups.begin(); it != accountGroups.end(); ++it) { KConfigGroup cg(config, *it); KConfigGroup pluginConfig(config, QStringLiteral("Plugins")); QString protocol = cg.readEntry("Protocol", QString()); if (protocol.endsWith(QLatin1String("Protocol"))) { protocol = QLatin1String("kopete_") + protocol.toLower().remove(QStringLiteral("protocol")); } if (cg.readEntry("Enabled", true) && pluginConfig.readEntry(protocol + QLatin1String("Enabled"), true)) { PluginManager::self()->loadPlugin(protocol, PluginManager::LoadAsync); } } } void AccountManager::slotPluginLoaded(Plugin *plugin) { Protocol *protocol = dynamic_cast(plugin); if (!protocol) { return; } // Iterate over all groups that start with "Account_" as those are accounts // and parse them if they are from this protocol KSharedConfig::Ptr config = KSharedConfig::openConfig(); const QStringList accountGroups = config->groupList().filter(QRegExp(QLatin1String("^Account_"))); for (QStringList::ConstIterator it = accountGroups.constBegin(); it != accountGroups.constEnd(); ++it) { KConfigGroup cg(config, *it); if (cg.readEntry("Protocol") != protocol->pluginId()) { continue; } // There's no GUI for this, but developers may want to disable an account. if (!cg.readEntry("Enabled", true)) { continue; } QString accountId = cg.readEntry("AccountId", QString()); if (accountId.isEmpty()) { qCWarning(LIBKOPETE_LOG) <<"Not creating account for empty accountId." << endl; continue; } qCDebug(LIBKOPETE_LOG) <<"Creating account for '" << accountId << "'" << endl; Account *account = nullptr; account = registerAccount(protocol->createNewAccount(accountId)); if (!account) { qCWarning(LIBKOPETE_LOG) <<"Failed to create account for '" << accountId << "'" << endl; continue; } } } void AccountManager::slotAccountOnlineStatusChanged(Contact *c, const OnlineStatus &oldStatus, const OnlineStatus &newStatus) { Account *account = c->account(); if (!account) { return; } //qCDebug(LIBKOPETE_LOG) ; emit accountOnlineStatusChanged(account, oldStatus, newStatus); } void AccountManager::networkConnected() { if (!resume()) { setOnlineStatus(Kopete::StatusManager::self()->globalStatusCategory(), Kopete::StatusManager::self()->globalStatusMessage(), 0, true); } } void AccountManager::networkDisconnected() { suspend(); } void AccountManager::removeAccountConnectedChanged() { Account *account = qobject_cast(sender()); Q_ASSERT(account); if (!account->isConnected()) { disconnect(account, SIGNAL(isConnectedChanged()), this, SLOT(removeAccountConnectedChanged())); // Use singleShot so we don't delete the account when we use it. d->accountsToBeRemoved.append(account); QTimer::singleShot(0, this, SLOT(removeAccountInternal())); } } void AccountManager::removeAccountInternal() { if (d->accountsToBeRemoved.isEmpty()) { return; } Account *account = d->accountsToBeRemoved.takeFirst(); if (account->isConnected()) { qCWarning(LIBKOPETE_LOG) << "Error, trying to remove connected account " << account->accountId(); return; } Protocol *protocol = account->protocol(); KConfigGroup *configgroup = account->configGroup(); // Clean up the contact list const QHash contactList = account->contacts(); QHash::ConstIterator it, itEnd = contactList.constEnd(); for (it = contactList.constBegin(); it != itEnd; ++it) { Contact *c = it.value(); if (!c) { continue; } MetaContact *mc = c->metaContact(); mc->removeContact(c); c->deleteLater(); if (mc->contacts().count() == 0) { //we can delete the metacontact //get the first group and it's members Group *group = mc->groups().first(); MetaContact::List groupMembers = group->members(); ContactList::self()->removeMetaContact(mc); if (groupMembers.count() == 1 && groupMembers.indexOf(mc) != -1) { ContactList::self()->removeGroup(group); } } } // Clean up the account list d->accounts.removeAll(account); // Clean up configuration configgroup->deleteGroup(); configgroup->sync(); delete account; foreach (Account *account, d->accounts) { if (account->protocol() == protocol) { return; } } //there is nomore account from the protocol, we can unload it // FIXME: pluginId() should return the internal name and not the class name, so // we can get rid of this hack - Olivier/Martijn QString protocolName = protocol->pluginId().remove(QStringLiteral("Protocol")).toLower(); PluginManager::self()->setPluginEnabled(protocolName, false); PluginManager::self()->unloadPlugin(protocolName); } } //END namespace Kopete // vim: set noet ts=4 sts=4 sw=4: // kate: tab-width 4; indent-mode csands; diff --git a/libkopete/kopeteaccountmanager.h b/libkopete/kopeteaccountmanager.h index a7767ffde..eb3bb934f 100644 --- a/libkopete/kopeteaccountmanager.h +++ b/libkopete/kopeteaccountmanager.h @@ -1,236 +1,236 @@ /* kopeteaccountmanager.h - Kopete Account Manager Copyright (c) 2002-2003 by Martijn Klingens Copyright (c) 2003-2005 by Olivier Goffart Kopete (c) 2002-2007 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETEACCOUNTMANAGER_H #define KOPETEACCOUNTMANAGER_H -#include +#include #include #include "libkopete_export.h" #include "libkopete_debug.h" #include "kopetestatusmessage.h" namespace Kopete { class Account; class Plugin; class Protocol; class Contact; class OnlineStatus; class StatusMessage; /** * AccountManager manages all defined accounts in Kopete. You can * query them and globally set them all online or offline from here. * * AccountManager is a singleton, you may uses it with @ref AccountManager::self() * * @author Martijn Klingens * @author Olivier Goffart */ class LIBKOPETE_EXPORT AccountManager : public QObject { Q_OBJECT public: /** * \brief Retrieve the instance of AccountManager. * * The account manager is a singleton class of which only a single * instance will exist. If no manager exists yet this function will * create one for you. * * \return the instance of the AccountManager */ static AccountManager *self(); ~AccountManager(); /** * \brief Retrieve the list of accounts * \return a list of all the accounts */ const QList &accounts() const; /** * \brief Retrieve a list of accounts per protocol * * Provides a list of accounts for a certain protocol. If there are * no accounts for that protocol then the list is empty. * \param protocol the protocol to get accounts for * \return the list of accounts that belong to the @p protocol protocol */ QList accounts(Kopete::Protocol *protocol) const; /** * \brief Return the account asked * \param protocolId is the ID for the protocol * \param accountId is the ID for the account you want * \return the Account object found or NULL if no account was found */ Account *findAccount(const QString &protocolId, const QString &accountId); /** * \brief Delete the account and clean the config data * * This is praticaly called by the account config page when you remove the account. */ void removeAccount(Account *account); /** * \brief Guess the color for a new account * * Guesses a color for the next account of a given protocol based on the already registered colors * \return the color guessed for the account */ QColor guessColor(Protocol *protocol) const; /** * @brief Register the account. * * This adds the account in the manager's account list. * It will check no accounts already exist with the same ID, if any, the account is deleted. and not added * * @return @p account, or 0L if the account was deleted because id collision */ Account *registerAccount(Account *account); /** * \brief Check if there is at least one account connected. * \return true if there at least one account connected, false otherwise. */ bool isAnyAccountConnected() const; /** * Flag to be used in setOnlineStatus * * @c ConnectIfOffline : if set, this will connect offlines account with the status. */ enum SetOnlineStatusFlag { ConnectIfOffline = 0x01 }; public Q_SLOTS: /** * @brief Set all accounts a status in the specified category * * Account that are offline will not be connected, unless the ConnectIfOffline flag is set. * * @param category is one of the Kopete::OnlineStatusManager::Categories * @param statusMessage is the new status message * @param flags is a bitmask of SetOnlineStatusFlag * @param forced is a boolean indicating that all accounts are required to change status * * @note KDE5: Merge these two setOnlineStatus functions (default value for forced is false) */ void setOnlineStatus(/*Kopete::OnlineStatusManager::Categories*/ uint category, const Kopete::StatusMessage &statusMessage, uint flags, bool forced); void setOnlineStatus(/*Kopete::OnlineStatusManager::Categories*/ uint category, const Kopete::StatusMessage &statusMessage = Kopete::StatusMessage(), uint flags = 0); /** * @brief Set the given status message for all online accounts * * @param message Status message to set */ void setStatusMessage(const QString &message); /** * Suspends all accounts. */ void suspend(); /** * Resumes all accounts. * Returns false if network is not available. */ bool resume(); /** * \internal * Save the account data to KConfig */ void save(); /** * \internal * Load the account data from KConfig */ void load(); Q_SIGNALS: /** * \brief Signals when an account is ready for use */ void accountRegistered(Kopete::Account *account); /** * \brief Signals when an account has been unregistered * * At this state, we are already in the Account destructor. */ void accountUnregistered(const Kopete::Account *account); /** * \brief An account has changed its onlinestatus * Technically this monitors Account::myself() onlinestatus changes * \param account Account which changed its onlinestatus * \param oldStatus The online status before the change * \param newStatus The new online status */ void accountOnlineStatusChanged(Kopete::Account *account, const Kopete::OnlineStatus &oldStatus, const Kopete::OnlineStatus &newStatus); private: /** * Private constructor, because we're a singleton */ AccountManager(); private Q_SLOTS: /** * Try to connect every account that should be connected automatically */ void networkConnected(); /** * Disconnect everything */ void networkDisconnected(); void slotPluginLoaded(Kopete::Plugin *plugin); void slotAccountOnlineStatusChanged(Kopete::Contact *c, const Kopete::OnlineStatus &oldStatus, const Kopete::OnlineStatus &newStatus); /** * \internal * Unregister the account. */ void unregisterAccount(const Kopete::Account *account); void removeAccountConnectedChanged(); /** * Remove account and its contacts. */ void removeAccountInternal(); private: static AccountManager *s_self; class Private; Private *const d; }; } //END namespace Kopete #endif diff --git a/libkopete/kopeteavatarmanager.h b/libkopete/kopeteavatarmanager.h index 37f720e94..ca74a1291 100644 --- a/libkopete/kopeteavatarmanager.h +++ b/libkopete/kopeteavatarmanager.h @@ -1,280 +1,280 @@ /* kopeteavatarmanager.h - Global avatar manager Copyright (c) 2007 by MichaĂ«l Larouche Kopete (c) 2002-2007 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETE_AVATARMANAGER_H #define KOPETE_AVATARMANAGER_H -#include -#include +#include +#include #include #include #include "libkopete_export.h" #include "libkopete_debug.h" class QImage; namespace Kopete { class Contact; /** * @brief Manage the avatar storage * * AvatarManager is a class that manage avatar storage. * It can manage the user defined avatar and avatar received * from contacts. * * It can also list the available avatars and filter it * on the categery, like User or Contact. * * @section avatar_dirlayout Avatar Directory Layout * AvatarManager use Kopete user application directory * to actually store avatars on disk. * * The directory is in $KDEHOME/share/apps/kopete/avatars/ * * Sub-directory User store user defined avatars. * It keep track of each avatar change so you can go back to a * previous avatar you had. * * Sub-directory Contacts store avatar received from contacts. * Avatars are managed by account to avoid conflict of avatars between * multiple contacts having the same ID. * For example, an user can have the same ID for MSN and Jabber but * use a different avatar for each account. * * @section avatar_management Avatar management * * @subsection avatar_management_list Listing avatar * If you want to list only an avatar category, * use Kopete::AvatarQueryJob * * @subsection avatar_management_add Adding an avatar * Use the add() method to add an new avatar. For an avatar received from a contact, you * should use the contactId for the name. You can either specify a image path or a QImage. * AvatarManager will save the QImage on disk. When adding an avatar for Contact category, * the "contact" entry need to be filled with a pointer to a Kopete::Contact instance. * * @code Kopete::AvatarManager::AvatarEntry newEntry; newEntry.name = "A new avatar" newEntry.image = avatarImage; newEntry.contact = this; newEntry.category = Kopete::AvatarManager::Contact; Kopete::AvatarManager::self()->add(newEntry); * @endcode * * If the operation has failed, the resulting AvatarEntry path will be empty. * The following code is a good way to test the success of add() method: * @code if( !resultEntry.path.isEmpty() ) { // Set avatar on server } * @endcode * * @subsection avatar_management_delete Removing an avatar * To remove an avatar, create a new AvatarEntry struct and pass the avatar path * to the struct, it will be used to identify which avatar to remove. * * Then just use the remove() method. * @code Kopete::AvatarManager::AvatarEntry entryToRemove; entryToRemove.path = imagePath; Kopete::AvatarManager::self()->remove(entryToRemove); * @endcode * * @subsection avatar_management_update Updating an avatar * Adding an avatar with the same name will update the previous avatar. * * @author MichaĂ«l Larouche */ class LIBKOPETE_EXPORT AvatarManager : public QObject { Q_OBJECT public: /** * Available avatar category. */ enum AvatarCategoryType { User = 1, ///< User defined avatar Contact, ///< Avatar from a contact. All = User | Contact ///< Only used to list all category. }; Q_DECLARE_FLAGS(AvatarCategory, AvatarCategoryType) /** * @brief A single entry in AvatarManager. * * @author MichaĂ«l Larouche * @sa Kopete::AvatarManager */ typedef struct AvatarEntry { QString name; ///< name is a friendly name to identity the avatar QString path; ///< path is the full path to the image on disk QImage image; ///< image is used when adding a new avatar, AvatarManager will write the image on disk. QByteArray data; ///< original data used to construct the image QString dataPath; ///< path is the full path to the data on disk Kopete::Contact *contact; ///< contact is used when adding a new contact avatar. AvatarManager use it to create the final url. AvatarManager::AvatarCategory category; ///< category in which the avatar belong } AvatarEntry; public: /** * @internal * Destructor */ ~AvatarManager(); /** * Get the only instance of AvatarManager * @return AvatarManager single instance */ static AvatarManager *self(); Q_SIGNALS: /** * @brief An avatar was added into the storage * * Listen to this signal if you want to get notified of * new avatar added to the storage. It is used to update * the AvatarSelectorWidget lists. * * @param newEntry new avatar added into the storage. */ void avatarAdded(Kopete::AvatarManager::AvatarEntry newEntry); /** * @brief An avatar was removed from storage * * Listen to this signal if you want to get notified of * avatar being removed from storage. It is used to update * the AvatarSelectorWidget lists. * * @param entryRemoved avatar being remove from storage. */ void avatarRemoved(Kopete::AvatarManager::AvatarEntry entryRemoved); public Q_SLOTS: /** * @brief Add an new avatar to the storage * * No need to scale the image, add() will do it for you. * * @param newEntry New avatar entry * @return a new AvatarEntry struct. If the adding failed, the path is null. */ Kopete::AvatarManager::AvatarEntry add(Kopete::AvatarManager::AvatarEntry newEntry); /** * @brief Remove an avatar from the storage * @param entryToRemove Avatar entry to remove */ bool remove(Kopete::AvatarManager::AvatarEntry entryToRemove); /** * @brief Check if an avatar exists * @param entryToCheck Avatar entry to check */ bool exists(Kopete::AvatarManager::AvatarEntry avatarToCheck); /** * @brief Check if an avatar exists by his name * @param avatarName Avatar entry to check */ bool exists(const QString &avatarName); private: /** * @internal * Constructor is private because the class is a singleton * @param parent QObject parent, not really used */ AvatarManager(QObject *parent = nullptr); private: static AvatarManager *s_self; class Private; Private *const d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(Kopete::AvatarManager::AvatarCategory) /** * @brief Job to query avatar on disk. * * First create the job: * @code Kopete::AvatarQueryJob *queryJob = new Kopete::AvatarQueryJob(parent); queryJob->setQueryFilter(Kopete::AvatarManager::User); connect(queryJob, SIGNAL(result(KJob*)), this, SLOT(queryResult(KJob*))); queryJob->start(); * @endcode * * Then get the avatar list in the resulting slot: * @code void SwallowAndCoconut::queryResult(KJob* job) { Kopete::AvatarQueryJob *queryJob = static_cast(job); if(queryJob && !queryJob->error()) { QList list = queryJob->avatarList(); // Iterate over list } } * @endcode * * @author MichaĂ«l Larouche * @sa Kopete::AvatarManager */ // TODO: Use new Kopete::Task or KCompositeJob class LIBKOPETE_EXPORT AvatarQueryJob : public KJob { Q_OBJECT public: AvatarQueryJob(QObject *parent = nullptr); ~AvatarQueryJob(); /** * @brief Set the filter for the avatar job. * * This is used to only list the user defined avatars or contact avatar. */ void setQueryFilter(Kopete::AvatarManager::AvatarCategory category); /** * @copydoc KJob::start() */ void start() Q_DECL_OVERRIDE; /** * @brief Get the avatar list based on the query * @return List of AvatarManager::AvatarEntry */ QList avatarList() const; private: class Private; Private *const d; }; } #endif diff --git a/libkopete/kopeteblacklister.h b/libkopete/kopeteblacklister.h index bafcb956e..47b9a81c9 100644 --- a/libkopete/kopeteblacklister.h +++ b/libkopete/kopeteblacklister.h @@ -1,123 +1,123 @@ /* kopeteblacklister.h - Kopete BlackLister Copyright (c) 2004 by Roie Kerstein ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETEBLACKLISTER_H #define KOPETEBLACKLISTER_H -#include +#include #include "libkopete_debug.h" namespace Kopete { class Contact; /** * @brief Manages the list of blacklisted contacts for an account * * This class manages the list of contacts the user wishes * to ignore permanently. In order to use the this class, there is no need to * create an instance. Use the @ref Kopete::Account::blackLister() instead. * * Keep in mind that this class does not discard messages from blocked * users - It only manages the list. It is the up to the protocol to * check whether a user is blocked, and act accordingly. A protocol may * re-implement @ref Kopete::Account::block() and @ref Kopete::Account::unblock() * and use @ref Kopete::Account::blackLister() as a persistent list manager * only, or connect the signals @ref contactAdded() and @ref contactRemoved() * to its slots. * * @sa Kopete::Account::block() Kopete::Account::unblock() * * @author Roie Kerstein */ class BlackLister : public QObject { Q_OBJECT public: /** * Create an instance, and read the blacklist from disk if it exists. * @param protocolId is the ID of the protocol owning accountId * @param accountId is the ID of the owning Account. * @param parent The QObject parent for this class. * @param name The QObject name for this class. */ BlackLister(const QString &protocolId, const QString &accountId, QObject *parent = nullptr); ~BlackLister(); /** * \return @c true if @p contact is blocked, @c false otherwise. */ bool isBlocked(Contact *contact); /** * \return @c true if the contact with ID @p contactId is blocked, @c false otherwise. */ bool isBlocked(const QString &contactId); public Q_SLOTS: /** * Add a contact to the blacklist. * * This function emits the @ref contactAdded() signal. * @param contactId is the ID of the contact to be added to the list. */ void addContact(const QString &contactId); /** * @overload */ void addContact(Contact *contact); /** * \brief Remove a contact from the blacklist. * * Removes the contact from the blacklist. * This function emits the @ref contactRemoved() signal. * @param contact is the contact to be removed from the list. */ void removeContact(Contact *contact); /** * @overload */ void removeContact(const QString &contactId); Q_SIGNALS: /** * \brief A new contact has been added to the list * * Connect to this signal if you want to perform additional actions, * and you prefer not to derive from this class. */ void contactAdded(const QString &contactId); /** * \brief A contact has been removed from the list * * Connect to this signal if you want to perform additional actions, * and you prefer not to derive from this class. */ void contactRemoved(const QString &contactId); private: void saveToDisk(); class Private; Private *const d; }; } #endif diff --git a/libkopete/kopetechatsession.h b/libkopete/kopetechatsession.h index b1a4b6d8c..24439f339 100644 --- a/libkopete/kopetechatsession.h +++ b/libkopete/kopetechatsession.h @@ -1,498 +1,498 @@ /* kopetechatsession.h - Manages all chats Copyright (c) 2002 by Duncan Mac-Vicar Prett Copyright (c) 2002 by Daniel Stone Copyright (c) 2002-2003 by Martijn Klingens Copyright (c) 2002-2004 by Olivier Goffart Copyright (c) 2003 by Jason Keirstead Copyright (c) 2005 by MichaĂ«l Larouche Copyright (c) 2009 by Fabian Rami Kopete (c) 2002-2003 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETECHATSESSION_H #define KOPETECHATSESSION_H -#include +#include #include #include "libkopete_export.h" #include "libkopete_debug.h" // FIXME: get rid of these includes #include "kopetemessage.h" #include "kopetemessagehandlerchain.h" class KMMPrivate; class KopeteView; namespace Kopete { class Contact; class Message; class Protocol; class OnlineStatus; class Account; class ChatSessionManager; class PropertyContainer; class MessageHandlerChain; class TemporaryKMMCallbackAppendMessageHandler; typedef QList ContactPtrList; typedef QList MessageList; /** * @author Duncan Mac-Vicar Prett * @author Daniel Stone * @author Martijn Klingens * @author Olivier Goffart * @author Jason Keirstead * * The Kopete::ChatSession manages a single chat. * It is an interface between the protocol, and the chatwindow. * The protocol can connect to @ref messageSent() signals to send the message, and can * append received message with @ref messageReceived() * * The KMM inherits from KXMLGUIClient, this client is merged with the chatwindow's ui * so plugins can add childClients of this client to add their own actions in the * chatwindow. */ class LIBKOPETE_EXPORT ChatSession : public QObject, public KXMLGUIClient { // friend class so the object factory can access the protected constructor friend class ChatSessionManager; Q_OBJECT public: /** * Describes the form of this chat session */ enum Form { Small, /**< The chat is a small group or 1:1 chat */ Chatroom/** Chat with many members and high traffic */ }; /** * Delete a chat manager instance * You shouldn't delete the KMM yourself. it will be deleted when the chatwindow is closed * see also @ref setCanBeDeleted() , @ref deref() */ ~ChatSession(); /** * @brief Get a list of all contacts in the session */ const ContactPtrList &members() const; /** * @brief Get the local user in the session * @return the local user in the session, same as account()->myself() * @note Can be 0 if local user was already deleted during account destruction */ const Contact *myself() const; /** * @brief Get the protocol being used. * @return the protocol */ Protocol *protocol() const; /** * @brief get the account * @return the account * @note Can be 0 if account was already deleted */ Account *account() const; /** * @brief The caption of the chat * * Used for named chats */ const QString displayName(); /** * sets lastUrl for current ChatSession */ void setLastUrl(const QString &verylastUrl); /** * returns lastUrl for current ChatSession * can be empty */ const QString lastUrl(); /** * @brief change the displayname * * change the display name of the chat */ void setDisplayName(const QString &displayName); /** * @brief set a specified KOS for specified contact in this KMM * * Set a special icon for a contact in this kmm only. * by default, all contact have their own status */ void setContactOnlineStatus(const Contact *contact, const OnlineStatus &newStatus); /** * @brief get the status of a contact. * * see @ref setContactOnlineStatus() */ const OnlineStatus contactOnlineStatus(const Contact *contact) const; /** * @brief the manager's view * * Return the view for the supplied Kopete::ChatSession. If it already * exists, it will be returned, otherwise, 0L will be returned or a new one * if canCreate=true * @param canCreate create a new one if it does not exist * @param requestedPlugin Specifies the view plugin to use if we have to create one. */ // FIXME: canCreate should definitely be an enum and not a bool - Martijn KopeteView *view(bool canCreate = false, const QString &requestedPlugin = QString()); /** * says if you may invite contact from the same account to this chat with @ref inviteContact * @see setMayInvite * @return true if it is possible to invite contact to this chat. */ bool mayInvite() const; /** * this method is called when a contact is dragged to the contact list. * @p contactId is the id of the contact. the contact is supposed to be of the same account as * the @ref account() but we can't be sure the Kopete::Contact is really on the contact list * * It is possible to drag contact only if @ref mayInvite return true * * the default implementaiton do nothing */ virtual void inviteContact(const QString &contactId); /** * Returns the message handler chain for the message direction @p dir. */ MessageHandlerChain::Ptr chainForDirection(Message::MessageDirection dir); /** * Get the form of this chatsession. This is a hint to the UI so it can present the chat * appropriately */ Form form() const; /** * say if kopete show warning message, when you closing window of group chat * @see setWarnGroupChat() * @return true if kopete show warning message */ bool warnGroupChat() const; /** * finds proper file with lasturls for current * contact ChatSession->members().first() * then sets lasturl for current ChatSession * if there is no file, lasturl will be set to empty string */ QString initLastUrl(const Kopete::Contact *c); /** * returns file name where urls for this contact supposed to be */ static QString getUrlsFileName(const Kopete::Contact *); /** * prosesses every sent/appended message * looks for urls, if found: sets current lastUrl and save it to proper file */ void urlSearch(const Kopete::Message &msg); /** * finds all urls in the current message (if there are many) * sorts them as they are in the meassage QStringList[0] - is the earliest */ QStringList findUrls(const Kopete::Message &msg); Q_SIGNALS: /** * @brief the KMM will be deleted * Used by a Kopete::ChatSession to signal that it is closing. */ void closing(Kopete::ChatSession *kmm); /** * a message will be soon shown in the chatwindow. * See @ref Kopete::ChatSessionManager::aboutToDisplay() signal */ void messageAppended(Kopete::Message &msg, Kopete::ChatSession *kmm = nullptr); /** * a message will be soon received * See @ref Kopete::ChatSessionManager::aboutToReceive() signal */ void messageReceived(Kopete::Message &msg, Kopete::ChatSession *kmm = nullptr); /** * @brief a message is going to be sent * * The message is going to be sent. * protocols can connect to this signal to send the message ro the network. * the protocol have also to call @ref appendMessage() and @ref messageSucceeded() * See also @ref Kopete::ChatSessionManager::aboutToSend() signal */ void messageSent(Kopete::Message &msg, Kopete::ChatSession *kmm = nullptr); /** * The last message has finaly successfully been sent */ void messageSuccess(); /** * @brief a new contact is now in the chat */ // FIXME: What's 'suppress'? Shouldn't this be an enum? - Martijn void contactAdded(const Kopete::Contact *contact, bool suppress); /** * @brief a contact is no longer in this chat */ void contactRemoved(const Kopete::Contact *contact, const QString &reason, Qt::TextFormat format = Qt::PlainText, bool suppressNotification = false); /** * @brief a contact in this chat has changed his status */ void onlineStatusChanged(Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus &); /** * @brief a contact in this chat has changed his status message */ void statusMessageChanged(Kopete::Contact *); /** * @brief a contact in this chat has changed his display name (previously nickname) */ void nickNameChanged(Kopete::Contact *, const QString &); /** * @brief The name of the chat is changed */ void displayNameChanged(); /** * @brief emitting a typing notification * * The user is typing a message, or just stopped typing * the protocol should connect to this signal to signal to others * that the user is typing if the protocol supports this * @param isTyping say if the user is typing or not */ void myselfTyping(bool isTyping); /** * Signals that a remote user is typing a message. * the chatwindow connects to this signal to update the statusbar */ void remoteTyping(const Kopete::Contact *contact, bool isTyping); /** * Signals that a an event has to be displayed in the statusbar. * The chatwindow connects to this signal to update the statusbar. */ void eventNotification(const QString ¬ificationText); /** * Signals that view for that chat session was activated */ void viewActivated(KopeteView *view); /** * Signals that a message has changed its state. * The chat window connects to this signal to update the message in chat view. */ void messageStateChanged(uint messageId, Kopete::Message::MessageState state); /** * @brief A contact within the chat session changed his photo. * Used to update the contacts photo in chat window. */ void photoChanged(); /** * does nothing */ void toggleGraphicOverride(bool enable); public Q_SLOTS: /** * @brief Got a typing notification from a user */ void receivedTypingMsg(const Kopete::Contact *contact, bool isTyping = true); /** * Got a typing notification from a user. This is a convenience version * of the above method that takes a QString contactId instead of a full * Kopete::Contact */ void receivedTypingMsg(const QString &contactId, bool isTyping = true); /** * @brief Got an event notification from a user. * It will emit the signal eventNotification(). Use this slot in your protocols * and plugins to change chatwindow statusBar text. */ void receivedEventNotification(const QString ¬ificationText); /** * @brief Change state of message. * It will emit the signal messageStateChanged(). Use this slot in your protocols * and plugins to change message state. */ void receivedMessageState(uint messageId, Kopete::Message::MessageState state); /** * Show a message to the chatwindow, or append it to the queue. * This is the function protocols HAVE TO call for both incoming and outgoing messages * if the message must be showed in the chatwindow */ void appendMessage(Kopete::Message &msg); /** * Add a contact to the session * @param c is the contact * @param suppress mean the there will be no automatic notifications in the chatwindow. * (note that i don't like the param suppress at all. it is used in irc to show a different notification (with an info text) * a QStringinfo would be more interesting, but it is also used to don't show the notification when entering in a channel) */ void addContact(const Kopete::Contact *c, bool suppress = false); /** * Add a contact to the session with a pre-set initial status * @param c is the contact * @param initialStatus The initial contactOnlineStatus of the contact * @param suppress mean the there will be no automatic notifications in the chatwindow. * (note that i don't like the param suppress at all. it is used in irc to show a different notification (with an info text) * a QStringinfo would be more interesting, but it is also used to don't show the notification when entering in a channel) * @see contactOnlineStatus */ void addContact(const Kopete::Contact *c, const Kopete::OnlineStatus &initialStatus, bool suppress = false); /** * Remove a contact from the session * @param contact is the contact * @param reason is the optional raison message showed in the chatwindow * @param format The format of the message * @param suppressNotification prevents a notification of the removal in the chat view. See note in @ref addContact */ void removeContact(const Kopete::Contact *contact, const QString &reason = QString(), Qt::TextFormat format = Qt::PlainText, bool suppressNotification = false); /** * Set if the KMM will be deleted when the chatwindow is deleted. It is useful if you want * to keep the KMM alive even if the chatwindow is closed. * Warning: if you set it to false, please keep in mind that you have to reset it to true * later to delete it. In many case, you should never delete yourself the KMM, just call this * this method. * default is true. * If there are no chatwindow when setting it to true, the kmm will be deleted. * * @deprecated use ref and deref */ void setCanBeDeleted(bool canBeDeleted); /** * reference count the chat session. * the chat session may be deleted only if the count reach 0 * if you ref, don't forget to deref * @see deref() */ void ref(); /** * dereference count the chat session * if the reference counter reach 0 and there is no chat window open, the chat session will be deleted. */ void deref(); /** * Send a message to the user */ void sendMessage(Kopete::Message &message); /** * Tell the KMM that the user is typing * This method should be called only by a chatwindow. It emits @ref myselfTyping signal */ void typing(bool t); /** * Protocols have to call this method when the last message sent has been correctly sent * This will emit @ref messageSuccess signal. and allow the email window to get closed */ void messageSucceeded(); /** * Protocols have to call this method if they want to emit a notification when a nudge/buzz is received. */ void emitNudgeNotification(); /** * Raise the chat window and give him the focus * It's used when the user wanted to activated (by clicking on the "view" button of a popup) */ void raiseView(); private Q_SLOTS: void clearChains(); void slotUpdateDisplayName(); void slotViewDestroyed(); void slotOnlineStatusChanged(Kopete::Contact *c, const Kopete::OnlineStatus &status, const Kopete::OnlineStatus &oldStatus); void slotContactDestroyed(Kopete::Contact *contact); void slotMyselfDestroyed(Kopete::Contact *contact); void slotDisplayNameChanged(const QString &oldName, const QString &newName); protected: /** * Create a message manager. This constructor is private, because the * static factory method createSession() creates the object. You may * not create instances yourself directly! */ ChatSession(const Contact *user, ContactPtrList others, Protocol *protocol, Form form = Small); /** * Set whether or not contact from this account may be invited in this chat. * By default, it is set to false * @see inviteContact() * @see mayInvite() */ void setMayInvite(bool); /** * set if kopete show warning message, when you closing window of group chat * By default, it is set to true * @see warnGroupChat() */ void setWarnGroupChat(bool); private: KMMPrivate *d; // FIXME: remove friend class TemporaryKMMCallbackAppendMessageHandler; }; } #endif // vim: set noet ts=4 sts=4 sw=4: diff --git a/libkopete/kopetechatsessionmanager.h b/libkopete/kopetechatsessionmanager.h index 7667119db..19bfc3642 100644 --- a/libkopete/kopetechatsessionmanager.h +++ b/libkopete/kopetechatsessionmanager.h @@ -1,183 +1,183 @@ /* kopetechatsessionmanager.h - Creates chat sessions Copyright (c) 2002-2003 by Duncan Mac-Vicar Prett Kopete (c) 2002-2003 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETECHATSESSIONMANAGER_H #define KOPETECHATSESSIONMANAGER_H -#include -#include +#include +#include #include "kopetechatsession.h" #include "kopetemessage.h" #include "libkopete_debug.h" #include "libkopete_export.h" class KopeteView; namespace Kopete { class Contact; class Protocol; class MessageEvent; typedef QList ContactPtrList; typedef QList MessageList; /** * @author Duncan Mac-Vicar Prett * * Kopete::ChatSessionManager is responsible for creating and tracking Kopete::ChatSession * instances for each chat. */ class LIBKOPETE_EXPORT ChatSessionManager : public QObject { Q_OBJECT public: static ChatSessionManager *self(); ~ChatSessionManager(); /** * Create a new chat session. Provided is the initial list of contacts in * the session. If a session with exactly these contacts already exists, * it will be reused. Otherwise a new session is created. * @param user The local user in the session. * @param chatContacts The list of contacts taking part in the chat. * @param protocol The protocol that the chat is using. * @return A pointer to a new or reused Kopete::ChatSession. */ Kopete::ChatSession *create(const Kopete::Contact *user, Kopete::ContactPtrList chatContacts, Kopete::Protocol *protocol, Kopete::ChatSession::Form form = Kopete::ChatSession::Small); /** * Find a chat session, if one exists, that matches the given list of contacts. * @param user The local user in the session. * @param chatContacts The list of contacts taking part in the chat. * @param protocol The protocol that the chat is using. * @return A pointer to an existing Kopete::ChatSession, or 0L if none was found. */ Kopete::ChatSession *findChatSession(const Kopete::Contact *user, Kopete::ContactPtrList chatContacts, Kopete::Protocol *protocol); /** * Registers a Kopete::ChatSession (or subclass thereof) with the Kopete::ChatSessionManager */ void registerChatSession(Kopete::ChatSession *); /** * Get a list of all open sessions. */ QList sessions(); /** * @internal * called by the kmm itself when it gets deleted */ void removeSession(Kopete::ChatSession *session); /** * create a new view for the manager. * only the manager should call this function */ KopeteView *createView(Kopete::ChatSession *, const QString &requestedPlugin = QString()); /** * Post a new event. this will emit the @ref newEvent signal */ void postNewEvent(Kopete::MessageEvent *); /** * Returns the current active Kopete view */ KopeteView *activeView(); Q_SIGNALS: /** * This signal is emitted whenever a message * is about to be displayed by the KopeteChatWindow. * Please remember that both messages sent and * messages received will emit this signal! * Plugins may connect to this signal to change * the message contents before it's going to be displayed. */ void aboutToDisplay(Kopete::Message &message); /** * Plugins may connect to this signal * to manipulate the contents of the * message that is being sent. */ void aboutToSend(Kopete::Message &message); /** * Plugins may connect to this signal * to manipulate the contents of the * message that is being received. * * This signal is emitted before @ref aboutToDisplay() */ void aboutToReceive(Kopete::Message &message); /** * A new view has been created */ void viewCreated(KopeteView *); /** * A view as been activated(manually only?). */ void viewActivated(KopeteView *view); /* * A view is about to close. */ void viewClosing(KopeteView *view); /** * a new KMM has been created */ void chatSessionCreated(Kopete::ChatSession *); /** * the message is ready to be displayed */ void display(Kopete::Message &message, Kopete::ChatSession *); /** * A new event has been posted. */ void newEvent(Kopete::MessageEvent *); /** * The global shortcut for sending message has been used */ void readMessage(); public Q_SLOTS: void slotReadMessage(); private: ChatSessionManager(QObject *parent = nullptr); class Private; Private *const d; static ChatSessionManager *s_self; }; } #endif // KOPETECHATSESSIONMANAGER_H // vim: set noet ts=4 sts=4 sw=4: diff --git a/libkopete/kopetecommand.h b/libkopete/kopetecommand.h index 4714b0d47..eeb87a738 100644 --- a/libkopete/kopetecommand.h +++ b/libkopete/kopetecommand.h @@ -1,132 +1,132 @@ /* kopetecommand.h - Command Copyright (c) 2003 by Jason Keirstead Copyright (c) 2005 by Michel Hermier Kopete (c) 2002-2005 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETECOMMAND_H #define KOPETECOMMAND_H -#include +#include #include #include "kopetecommandhandler.h" #include "libkopete_debug.h" namespace Kopete { class ChatSession; class Command : public QAction { Q_OBJECT public: /** * an enum defining the type of a command */ typedef enum Type { Normal = 0, System = 1 << 1, // Not removable command Alias = 1 << 2 // Is an alias // Undefined } Type; Q_DECLARE_FLAGS(Types, Type) /** * Creates a Kopete::Command object * * @param parent The plugin who owns this command * @param command The command we want to handle, not including the '/' * @param handlerSlot The slot used to handle the command. This slot must * accept two parameters, a QString of arguments, and a Kopete::ChatSession * pointer to the Manager under which the command was sent. * @param help An optional help string to be shown when the user uses * /help command * @param type If this command is an alias, and what type * @param formatString The formatString of the alias if any * @param minArgs Minimum number of arguments * @param maxArgs Maximum number of arguments * @param cut The shortcut for the command * @param pix The icon to use for the command */ Command(QObject *parent, const QString &command, const char *handlerSlot, const QString &help = QString(), CommandHandler::CommandType type = CommandHandler::Normal, const QString &formatString = QString(), uint minArgs = 0, int maxArgs = -1, const QKeySequence &cut = QKeySequence(), const QString &pix = QString()); ~Command(); /** * Process this command */ void processCommand(const QString &args, ChatSession *manager, bool gui = false); /** * Returns the command this object handles */ const QString &command() const { return m_command; } /** * Returns the help string for this command */ const QString &help() const { return m_help; } /** * Returns the type of the command */ CommandHandler::CommandType type() const { return m_type; } Q_SIGNALS: /** * Emitted whenever a command is handled by this object. When a command * has been handled, all processing on it stops by the command handler * (a command cannot be handled twice) */ void handleCommand(const QString &args, Kopete::ChatSession *manager); private Q_SLOTS: /** * Connected to our activated() signal */ void slotAction(); private: void init(const QString &command, const char *slot, const QString &help, CommandHandler::CommandType type, const QString &formatString, uint minArgs, int maxArgs); void printError(const QString &error, ChatSession *manager, bool gui = false) const; QString m_command; QString m_help; QString m_formatString; int m_minArgs; int m_maxArgs; bool m_processing; CommandHandler::CommandType m_type; class Private; Private *const d; }; } Q_DECLARE_OPERATORS_FOR_FLAGS(Kopete::Command::Types) #endif diff --git a/libkopete/kopetecommandhandler.h b/libkopete/kopetecommandhandler.h index da78440d1..ac3dfa55c 100644 --- a/libkopete/kopetecommandhandler.h +++ b/libkopete/kopetecommandhandler.h @@ -1,220 +1,220 @@ /* kopetecommandhandler.h - Command Handler Copyright (c) 2003 by Jason Keirstead Kopete (c) 2002-2003 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETECOMMANDHANDLER_H #define KOPETECOMMANDHANDLER_H -#include +#include #include #include #include "kopetemessage.h" #include "libkopete_export.h" #include "libkopete_debug.h" struct CommandHandlerPrivate; class KopeteView; class KopeteCommandGUIClient; namespace Kopete { class ChatSession; class Plugin; class Protocol; class Command; typedef QMultiHash CommandList; /** * @author Jason Keirstead * * The Kopete::CommandHandler can handle /action like messages */ class LIBKOPETE_EXPORT CommandHandler : public QObject { friend class ::KopeteCommandGUIClient; Q_OBJECT public: /** * an enum defining the type of a command */ enum CommandType { Normal, SystemAlias, UserAlias, Undefined }; /** * Returns a pointer to the command handler */ static CommandHandler *commandHandler(); /** * \brief Register a command with the command handler. * * Command matching is case insensitive. All commands are registered, * regardless of whether or not they are already handled by another * handler. This is so that if the first plugin is unloaded, the next * handler in the sequence will handle the command. However, there are * certain commands which are reserved (internally handled by the * Kopete::CommandHandler). These commands can also be overridden by * registering a new duplicate command. * * @param parent The plugin who owns this command * @param command The command we want to handle, not including the '/' * @param handlerSlot The slot used to handle the command. This slot must * accept two parameters, a QString of arguments, and a Kopete::ChatSession * pointer to the manager under which the command was sent. * @param help An optional help string to be shown when the user uses * /help \ * @param minArgs the minimum number of arguments for this command * @param maxArgs the maximum number of arguments this command takes * @param cut a default keyboard shortcut * @param pix icon name, the icon will be shown in menus */ void registerCommand(QObject *parent, const QString &command, const char *handlerSlot, const QString &help = QString(), uint minArgs = 0, int maxArgs = -1, const QKeySequence &cut = QKeySequence(), const QString &pix = QString()); /** * \brief Register a command alias. * * @param parent The plugin who owns this alias * @param alias The command for the alias * @param formatString This is the string that will be transformed into another * command. The formatString should begin with an already existing command, * followed by any other arguments. The variables %1, %2... %9 will be substituted * with the arguments passed into the alias. The variable %s will be substituted with * the entire argument string * @param help An optional help string to be shown when the user uses * /help \ * @param minArgs the minimum number of arguments for this command * @param maxArgs the maximum number of arguments this command takes * @param cut a default keyboard shortcut * @param pix icon name, the icon will be shown in menus */ void registerAlias(QObject *parent, const QString &alias, const QString &formatString, const QString &help = QString(), CommandType = SystemAlias, uint minArgs = 0, int maxArgs = -1, const QKeySequence &cut = QKeySequence(), const QString &pix = QString()); /** * \brief Unregister a command. * * When a plugin unloads, all commands are automaticlly unregistered and deleted. * This function should only be called in the case of a plugin which loads and * unloads commands dynamically. * * @param parent The plugin who owns this command * @param command The command to unload */ void unregisterCommand(QObject *parent, const QString &command); /** * \brief Unregister an alias. * * \see unregisterCommand( QObject *parent, const QString &command ) * @param parent The plugin who owns this alias * @param alias The alais to unload */ void unregisterAlias(QObject *parent, const QString &alias); /** * \brief Process a message to see if any commands should be handled * * @param msg The message to process * @param manager The manager who owns this message * @return True if the command was handled, false if not */ bool processMessage(Message &msg, ChatSession *manager); /** * \brief Process a message to see if any commands should be handled * * \see processMessage( Kopete::Message &msg, Kopete::ChatSession *manager) * \param msg A QString contain the message * \param manager the Kopete::ChatSession who will own the message * \return true if the command was handled, false if the command was not handled. */ bool processMessage(const QString &msg, ChatSession *manager); /** * Parses a string of command arguments into a QStringList. Quoted * blocks within the arguments string are treated as one argument. */ static QStringList parseArguments(const QString &args); /** * \brief Check if a command is already handled * * @param command The command to check * @return True if the command is already being handled, False if not */ bool commandHandled(const QString &command); /** * \brief Check if a command is already handled by a spesific protocol * * @param command The command to check * @param protocol The protocol to check * @return True if the command is already being handled, False if not */ bool commandHandledByProtocol(const QString &command, Protocol *protocol); private Q_SLOTS: void slotPluginLoaded(Kopete::Plugin *); void slotPluginDestroyed(QObject *); void slotExecError(QProcess::ProcessError error); void slotExecFinished(); void slotExecSendMessage(KProcess *proc, const QString &buffer); void slotViewCreated(KopeteView *view); void slotHelpCommand(const QString &args, Kopete::ChatSession *manager); void slotClearCommand(const QString &args, Kopete::ChatSession *manager); void slotPartCommand(const QString &args, Kopete::ChatSession *manager); void slotCloseCommand(const QString &args, Kopete::ChatSession *manager); void slotOpenLastUrl(const QString &args, Kopete::ChatSession *manager); //void slotMeCommand( const QString & args, Kopete::ChatSession *manager ); void slotExecCommand(const QString &args, Kopete::ChatSession *manager); void slotAwayCommand(const QString &args, Kopete::ChatSession *manager); void slotAwayAllCommand(const QString &args, Kopete::ChatSession *manager); void slotSayCommand(const QString &args, Kopete::ChatSession *manager); private: /** * Helper function. Returns all the commands that can be used by a KMM of this protocol * (all non-protocol commands, plus this protocols commands) */ CommandList commands(Protocol *); /** * Helper function for commands() */ void addCommands(CommandList &from, CommandList &to, CommandType type = Undefined); CommandHandler(); ~CommandHandler(); static CommandHandlerPrivate *p; }; } #endif diff --git a/libkopete/kopetecontactlist.cpp b/libkopete/kopetecontactlist.cpp index d1f2fae65..8ce5714a1 100644 --- a/libkopete/kopetecontactlist.cpp +++ b/libkopete/kopetecontactlist.cpp @@ -1,434 +1,434 @@ /* kopetecontactlist.cpp - Kopete's Contact List backend Copyright (c) 2005-2007 by Michael Larouche Copyright (c) 2002-2003 by Martijn Klingens Copyright (c) 2002-2004 by Olivier Goffart Copyright (c) 2002 by Duncan Mac-Vicar Prett Copyright (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "kopetecontactlist.h" // Qt includes -#include -#include -#include -#include +#include +#include +#include +#include // KDE includes //#include #include #include "libkopete_debug.h" // Kopete includes #include "kopeteaccount.h" #include "kopeteaccountmanager.h" #include "kopetechatsession.h" #include "kopetecontact.h" #include "kopetedeletecontacttask.h" #include "kopetegroup.h" #include "kopetemetacontact.h" #include "kopetepicture.h" #include "kopetepluginmanager.h" #include "kopeteprotocol.h" #include "xmlcontactstorage.h" namespace Kopete { class ContactList::Private { public: /** Flag: do not save the contact list until she is completely loaded */ bool loaded; bool terminated; QList contacts; QList groups; QList selectedMetaContacts; QList selectedGroups; QTimer *saveTimer; MetaContact *myself; }; ContactList *ContactList::s_self = nullptr; ContactList *ContactList::self() { if (!s_self) { s_self = new ContactList; } return s_self; } ContactList::ContactList() : QObject(kapp) , d(new Private()) { setObjectName(QStringLiteral("KopeteContactList")); //the myself metacontact can't be created now, because it will use //ContactList::self() as parent which will call this constructor -> infinite loop d->myself = nullptr; //no contact list loaded yet, don't save them d->loaded = false; d->terminated = false; // automatically save on changes to the list d->saveTimer = new QTimer(this); d->saveTimer->setObjectName(QStringLiteral("saveTimer")); d->saveTimer->setSingleShot(true); connect(d->saveTimer, SIGNAL(timeout()), SLOT(save())); connect(this, SIGNAL(metaContactAdded(Kopete::MetaContact *)), SLOT(slotSaveLater())); connect(this, SIGNAL(metaContactRemoved(Kopete::MetaContact *)), SLOT(slotSaveLater())); connect(this, SIGNAL(groupAdded(Kopete::Group *)), SLOT(slotSaveLater())); connect(this, SIGNAL(groupRemoved(Kopete::Group *)), SLOT(slotSaveLater())); connect(this, SIGNAL(groupRenamed(Kopete::Group *,QString)), SLOT(slotSaveLater())); } ContactList::~ContactList() { s_self = nullptr; delete d->myself; delete d; } QList ContactList::metaContacts() const { return d->contacts; } QList ContactList::groups() const { return d->groups; } MetaContact *ContactList::metaContact(const QString &metaContactId) const { QListIterator it(d->contacts); while (it.hasNext()) { MetaContact *mc = it.next(); if (mc->metaContactId() == QUuid(metaContactId)) { return mc; } } return nullptr; } Group *ContactList::group(unsigned int groupId) const { if (groupId == Group::topLevel()->groupId()) { return Group::topLevel(); } QListIterator it(d->groups); while (it.hasNext()) { Group *curr = it.next(); if (curr->groupId() == groupId) { return curr; } } return nullptr; } Contact *ContactList::findContact(const QString &protocolId, const QString &accountId, const QString &contactId) const { //Browsing metacontacts is too slow, better to uses the Dict of the account. Account *i = AccountManager::self()->findAccount(protocolId, accountId); if (!i) { qCDebug(LIBKOPETE_LOG) << "Account not found"; return nullptr; } return i->contacts().value(contactId); } MetaContact *ContactList::findMetaContactByDisplayName(const QString &displayName) const { foreach (Kopete::MetaContact *contact, d->contacts) { if (contact->displayName() == displayName) { return contact; } } return 0; } MetaContact *ContactList::findMetaContactByContactId(const QString &contactId) const { QListIterator it(Kopete::AccountManager::self()->accounts()); Kopete::Account *a; while (it.hasNext()) { a = it.next(); Contact *c = a->contacts().value(contactId); if (c && c->metaContact()) { return c->metaContact(); } } return nullptr; } Group *ContactList::findGroup(const QString &displayName, int type) { if (type == Group::Temporary) { return Group::temporary(); } else if (type == Group::TopLevel) { return Group::topLevel(); } else if (type == Group::Offline) { return Group::offline(); } QListIterator it(d->groups); while (it.hasNext()) { Group *curr = it.next(); if (curr->type() == type && curr->displayName() == displayName) { return curr; } } Group *newGroup = new Group(displayName); addGroup(newGroup); return newGroup; } QList ContactList::selectedMetaContacts() const { return d->selectedMetaContacts; } QList ContactList::selectedGroups() const { return d->selectedGroups; } void ContactList::addMetaContacts(QList metaContacts) { foreach (MetaContact *mc, metaContacts) { addMetaContact(mc); } } void ContactList::addMetaContact(MetaContact *mc) { if (d->contacts.contains(mc)) { return; } d->contacts.append(mc); emit metaContactAdded(mc); connect(mc, SIGNAL(persistentDataChanged()), SLOT(slotSaveLater())); connect(mc, SIGNAL(addedToGroup(Kopete::MetaContact *,Kopete::Group *)), SIGNAL(metaContactAddedToGroup(Kopete::MetaContact *,Kopete::Group *))); connect(mc, SIGNAL(removedFromGroup(Kopete::MetaContact *,Kopete::Group *)), SIGNAL(metaContactRemovedFromGroup(Kopete::MetaContact *,Kopete::Group *))); connect(mc, SIGNAL(movedToGroup(Kopete::MetaContact *,Kopete::Group *,Kopete::Group *)), SIGNAL(metaContactMovedToGroup(Kopete::MetaContact *,Kopete::Group *,Kopete::Group *))); } void ContactList::removeMetaContact(MetaContact *m) { if (!d->contacts.contains(m)) { qCDebug(LIBKOPETE_LOG) << "Trying to remove a not listed MetaContact."; return; } if (d->selectedMetaContacts.contains(m)) { d->selectedMetaContacts.removeAll(m); setSelectedItems(d->selectedMetaContacts, d->selectedGroups); } //removes subcontact from server here and now. Kopete::Contact *contactToDelete = 0; foreach (contactToDelete, m->contacts()) { // TODO: Check for good execution of task Kopete::DeleteContactTask *deleteTask = new Kopete::DeleteContactTask(contactToDelete); deleteTask->start(); } d->contacts.removeAll(m); emit metaContactRemoved(m); m->deleteLater(); } void ContactList::mergeMetaContacts(QList src, Kopete::MetaContact *dst) { // merge all metacontacts from src into dst // Note: there is no need to remove the src metacontacts, they are going to be // removed when the last contact is moved to the new metacontact // TODO: add a confirmation dialog asking if this is really wanted // TODO: add a Undo option for this foreach (Kopete::MetaContact *mc, src) { foreach (Kopete::Contact *c, mc->contacts()) { c->setMetaContact(dst); } } } void ContactList::addGroups(QList groups) { foreach (Group *g, groups) { addGroup(g); } } void ContactList::addGroup(Group *g) { if (!d->groups.contains(g)) { d->groups.append(g); emit groupAdded(g); connect(g, SIGNAL(displayNameChanged(Kopete::Group *,QString)), this, SIGNAL(groupRenamed(Kopete::Group *,QString))); } } void ContactList::removeGroup(Group *g) { if (g == Group::topLevel()) { return; } if (d->selectedGroups.contains(g)) { d->selectedGroups.removeAll(g); setSelectedItems(d->selectedMetaContacts, d->selectedGroups); } // Remove metaContacts from group or delete the metaContact if it isn't in any other group foreach (MetaContact *metaContact, g->members()) { const QList mcGroups = metaContact->groups(); if ((mcGroups.count() == 1 && mcGroups.contains(g)) || mcGroups.isEmpty()) { removeMetaContact(metaContact); } else { metaContact->removeFromGroup(g); } } d->groups.removeAll(g); emit groupRemoved(g); g->deleteLater(); } void ContactList::setSelectedItems(QList metaContacts, QList groups) { qCDebug(LIBKOPETE_LOG) << metaContacts.count() << " metacontacts, " << groups.count() << " groups selected"; d->selectedMetaContacts = metaContacts; d->selectedGroups = groups; emit metaContactSelected(groups.isEmpty() && metaContacts.count() == 1); emit selectionChanged(); } MetaContact *ContactList::myself() { if (!d->myself) { d->myself = new MetaContact(); } return d->myself; } /////////////////////////////////////////////////////////////////////////////////////////////// void ContactList::load() { // don't save when we're in the middle of this... d->loaded = false; Kopete::ContactListStorage *storage = new Kopete::XmlContactStorage(); storage->load(); if (!storage->isValid()) { qCDebug(LIBKOPETE_LOG) << "Contact list storage failed. Reason: " << storage->errorMessage(); } else { addGroups(storage->groups()); addMetaContacts(storage->contacts()); } d->loaded = true; delete storage; emit contactListLoaded(); } bool Kopete::ContactList::loaded() const { return d->loaded; } void Kopete::ContactList::save() { if (d->terminated) { qCWarning(LIBKOPETE_LOG) << "Contact list terminated, abort saving"; return; } if (!d->loaded) { qCDebug(LIBKOPETE_LOG) << "Contact list not loaded, abort saving"; return; } Kopete::ContactListStorage *storage = new Kopete::XmlContactStorage(); storage->save(); if (!storage->isValid()) { qCDebug(LIBKOPETE_LOG) << "Contact list storage failed. Reason: " << storage->errorMessage(); // Saving the contact list failed. retry every minute until it works. // single-shot: will get restarted by us next time if it's still failing d->saveTimer->setSingleShot(true); d->saveTimer->start(60000); delete storage; return; } // cancel any scheduled saves d->saveTimer->stop(); delete storage; } void ContactList::shutdown() { if (!d->terminated) { save(); d->terminated = true; d->saveTimer->stop(); } } void ContactList::slotSaveLater() { if (d->terminated) { return; } // if we already have a save scheduled, it will be cancelled. either way, // start a timer to save the contact list a bit later. d->saveTimer->start(17100 /* 17,1 seconds */); } void ContactList::slotKABCChanged() { // TODO: react to changes in KABC, replacing this function, post 3.4 (Will) // call syncWithKABC on each metacontact to check if its associated kabc entry has changed. /* for ( MetaContact * mc = d->contacts.first(); mc; mc = d->contacts.next() ) mc->syncWithKABC();*/ } } //END namespace Kopete // vim: set noet ts=4 sts=4 sw=4: diff --git a/libkopete/kopetecontactlist.h b/libkopete/kopetecontactlist.h index b10c138ad..0bdb61ecc 100644 --- a/libkopete/kopetecontactlist.h +++ b/libkopete/kopetecontactlist.h @@ -1,280 +1,280 @@ /* kopetecontactlist.h - Kopete's Contact List backend Copyright (c) 2002 by Martijn Klingens Copyright (c) 2002-2004 by Olivier Goffart Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETECONTACTLIST_H__ #define KOPETECONTACTLIST_H__ -#include -#include +#include +#include #include "libkopete_export.h" namespace Kopete { class MetaContact; class Group; class Contact; /** * @brief manage contacts and metacontact * * The contactList is a singleton you can uses with @ref ContactList::self() * * it let you get a list of metacontact with metaContacts() * Only metacontact which are on the contact list are returned. * * @author Martijn Klingens * @author Olivier Goffart */ class LIBKOPETE_EXPORT ContactList : public QObject { Q_OBJECT public: /** * The contact list is a singleton object. Use this method to retrieve * the instance. */ static ContactList *self(); ~ContactList(); /** * @brief return a list of all metacontact of the contact list * Retrieve the list of all available meta contacts. * The returned QPtrList is not the internally used variable, so changes * to it won't propagate into the actual contact list. This can be * useful if you need a subset of the contact list, because you can * simply filter the result set as you wish without worrying about * side effects. * The contained MetaContacts are obviously _not_ duplicates, so * changing those *will* have the expected result :-) */ QList metaContacts() const; /** * @return all groups */ QList groups() const; /** * Return the metacontact referenced by the given id. is none is found, return 0L * @sa MetaContact::metaContactId() */ MetaContact *metaContact(const QString &metaContactId) const; /** * return the group with the given unique id. if none is found return 0L */ Group *group(unsigned int groupId) const; /** * @brief find a contact in the contact list. * Browse in each metacontact of the list to find the contact with the given ID. * @param protocolId the @ref Plugin::pluginId() of the protocol ("MSNProtocol") * @param accountId the @ref Account::accountId() * @param contactId the @ref Contact::contactId() * @return the contact with the parameters, or 0L if not found. */ Contact *findContact(const QString &protocolId, const QString &accountId, const QString &contactId) const; /** * Find a contact by display name. Returns the first match. */ MetaContact *findMetaContactByDisplayName(const QString &displayName) const; /** * Find a meta contact by its contact id. Returns the first match. */ MetaContact *findMetaContactByContactId(const QString &contactId) const; /** * @brief find a group with his displayName * If a group already exists with the given name and the given type, the existing group will be returned. * Otherwise, a new group will be created. * @param displayName is the display name to search * @param type is the Group::GroupType to search, the default value is group::Normal * @return always a valid Group */ Group *findGroup(const QString &displayName, int type = 0 /*Group::Normal*/); /** * return the list of metacontact actually selected in the contact list UI */ QList selectedMetaContacts() const; /** * return the list of groups actualy selected in the contact list UI */ QList selectedGroups() const; /** * return the metacontact that represent the user itself. * This metacontact should be the parent of every Kopete::Account::myself() contacts. * * This metacontact is not in the contact list. */ MetaContact *myself(); public Q_SLOTS: /** * Add metacontacts into the contact list * When calling this method, contacts have to be already placed in the correct group. * If contacts are not in a group, they will be added to the top-level group. * It is also better if the MetaContacts could also be completely created, i.e: all contacts already in it */ void addMetaContacts(QList metaContacts); /** * Add the metacontact into the contact list * When calling this method, the contact has to be already placed in the correct group. * If the contact is not in a group, it will be added to the top-level group. * It is also better if the MetaContact could also be completely created, i.e: all contacts already in it */ void addMetaContact(Kopete::MetaContact *c); /** * Remove a metacontact from the contact list. * This method delete itself the metacontact. */ void removeMetaContact(Kopete::MetaContact *contact); /** * Merge one or more metacontacts into another one */ void mergeMetaContacts(QList src, Kopete::MetaContact *dst); /** * Add groups * each group must be added on the list after his creation. */ void addGroups(QList groups); /** * Add a group * each group must be added on the list after his creation. */ void addGroup(Kopete::Group *); /** * Remove a group * this method delete the group */ void removeGroup(Kopete::Group *); /** * Set which items are selected in the ContactList GUI. * This method has to be called by the contact list UI side. * it stores the selected items, and emits signals */ void setSelectedItems(QList metaContacts, QList groups); /** * @internal * Load the contact list */ void load(); bool loaded() const; void save(); /** * @internal * Save and shutdown the contact list */ void shutdown(); Q_SIGNALS: /** * A meta contact was added to the contact list. Interested classes * ( like the listview widgets ) can connect to this signal to receive * the newly added contacts. */ void metaContactAdded(Kopete::MetaContact *mc); /** * A metacontact has just been removed. and will be soon deleted */ void metaContactRemoved(Kopete::MetaContact *mc); /** * A group has just been added */ void groupAdded(Kopete::Group *); /** * A group has just been removed */ void groupRemoved(Kopete::Group *); /** * A group has just been renamed */ void groupRenamed(Kopete::Group *, const QString &oldname); /** * A contact has been added to a group */ void metaContactAddedToGroup(Kopete::MetaContact *mc, Kopete::Group *to); /** * A contact has been removed from a group */ void metaContactRemovedFromGroup(Kopete::MetaContact *mc, Kopete::Group *from); /** * A contact has been moved from one group to another */ void metaContactMovedToGroup(Kopete::MetaContact *mc, Kopete::Group *from, Kopete::Group *to); /** * This signal is emit when the selection has changed, it is emitted after the following slot * Warning: Do not delete any contacts in slots connected to this signal. (it is the warning in the QListView::selectionChanged() doc) */ void selectionChanged(); /** * This signal is emitted each time the selection has changed. the bool is set to true if only one meta contact has been selected, * and set to false if none, or several contacts are selected * you can connect this signal to QAction::setEnabled if you have an action which is applied to only one contact */ void metaContactSelected(bool); void contactListLoaded(); private Q_SLOTS: /** * Called when the contact list changes. Flags the list dirty and schedules a save for a little while later. */ void slotSaveLater(); /** * Called on contact list load or when KABC has changed, to check if we need to update our contact list from there. */ void slotKABCChanged(); private: /** * Private constructor: we are a singleton */ ContactList(); static ContactList *s_self; class Private; Private *const d; }; } //END namespace Kopete #endif diff --git a/libkopete/kopetecontactlistelement.h b/libkopete/kopetecontactlistelement.h index 3733ee164..b5c3298c4 100644 --- a/libkopete/kopetecontactlistelement.h +++ b/libkopete/kopetecontactlistelement.h @@ -1,217 +1,217 @@ /* kopeteplugindataobject.h - Kopete Plugin Data Object Copyright (c) 2003-2005 by Olivier Goffart Copyright (c) 2003 by Martijn Klingens Copyright (c) 2004 by Richard Smith Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETECONTACTLISTELEMENT_H #define KOPETECONTACTLISTELEMENT_H -#include -#include +#include +#include #include "libkopete_export.h" #include "kopetepropertycontainer.h" namespace Kopete { class Plugin; /** * @author Olivier Goffart * * This is the base class for base elements of the contact list. * His purpose is to share the code between @ref Group and @ref MetaContact * * It handle the saving and loading of plugin data from the contact list. * Plugins may set custom data to metaocntacts or groups by calling @ref setPluginData * and may retrieve them with @ref pluginData * * It also allow to store an icon for this element. */ class LIBKOPETE_EXPORT ContactListElement : public PropertyContainer { Q_OBJECT protected: ContactListElement(QObject *parent = nullptr); ~ContactListElement(); public: /** * @brief Set if we are in loading stage. */ void setLoading(bool value); /** * @brief Check if we are in loading stage. * * @return true if we are in loading stage. */ bool loading() const; /** * Set the plugin-specific data. * The data in the provided QMap is a set of key/value pairs. * Note that protocol plugins usually shouldn't use this method, but * reimplement @ref Contact::serialize() instead. This method * is called by @ref Protocol for those classes. * * WARNING: This erases all old data stored for this object! * You may want to consider the @ref setPluginData() overload * that takes a single field as parameter. */ void setPluginData(Plugin *plugin, const QMap &value); void setPluginData(const QString &pluginId, const QMap &pluginData); /** * Convenience method to store or change only a single field of the * plugin data. As with the other @ref setPluginData() method, protocols * are advised not to use this method and reimplement * @ref Contact::serialize() instead. * * Note that you should save the file after adding data or it will get lost. */ void setPluginData(Plugin *plugin, const QString &key, const QString &value); /** * Get the settings as stored previously by calls to @ref setPluginData() * * Note that calling this method for protocol plugins that use the * @ref Contact::serialize() API may yield unexpected results. */ QMap pluginData(Plugin *plugin) const; /** * Convenience method to retrieve only a single field from the plugin * data. See @ref setPluginData(). * * Note that plugin data is accessible only after it has been loaded * from the XML file. Don't call this method before then (e.g. in * constructors). */ QString pluginData(Plugin *plugin, const QString &key) const; typedef QMap > PluginDataMap; typedef QMap ContactData; typedef QList ContactDataList; /** * Get the settings as stored previously by calls to @ref setPluginContactData() * Note that plugins shouldn't use this method */ QMap pluginContactData() const; /** * Get the settings as stored previously by calls to @ref setPluginContactData() for a @p plugin * Note that plugins shouldn't use this method */ ContactDataList pluginContactData(Plugin *plugin) const; /** * Clear all plugin specific data. * Note that plugins shouldn't use this method */ void clearPluginContactData(); /** * Set plugin specific data for each contact. * Note that plugins shouldn't use this method */ void setPluginContactData(Plugin *plugin, const ContactDataList &dataList); /** * Convenience method to append plugin specific data for single contact * Note that plugins shouldn't use this method */ void appendPluginContactData(const QString &pluginId, const ContactData &data); /** * return plugin-specific data for all plugins */ const PluginDataMap pluginData() const; /** * The various icon states. Some state are reserved for Groups, * other for metacontact. * 'None' is the default icon. */ enum IconState { None, Open, Closed, Online, Away, Offline, Unknown }; typedef QMap IconMap; /** * return all registered icons */ const IconMap icons() const; /** * return the icon for this object, in the given state. * if there is no icon registered for this state, the None icon is used * if available */ QString icon(IconState state = None) const; /** * Set the icon in the given state * To clear an entry, set a QString() */ void setIcon(const QString &icon, IconState = None); /** * return if yes or no the user wants to display some custom icon. * you can use @ref icon() to know the icons to uses */ bool useCustomIcon() const; /** * set if the user want to show custom icon he set with @ref setIcon * this does not clear icons string if you set false */ void setUseCustomIcon(bool useCustomIcon); Q_SIGNALS: /** * The plugin data was changed (by a plugin) */ void pluginDataChanged(); /** * The icon to use for some state has changed */ void iconChanged(Kopete::ContactListElement::IconState, const QString &); /** * The visual appearance of some of our icons has changed */ void iconAppearanceChanged(); /** * The useCustomIcon property has changed */ void useCustomIconChanged(bool useCustomIcon); private: class Private; Private *const d; }; } //END namespace Kopete #endif // KOPETECONTACTLISTELEMENT_H // vim: set noet ts=4 sts=4 sw=4: diff --git a/libkopete/kopeteglobal.cpp b/libkopete/kopeteglobal.cpp index 72eb01131..28aab3d58 100644 --- a/libkopete/kopeteglobal.cpp +++ b/libkopete/kopeteglobal.cpp @@ -1,238 +1,238 @@ /* kopeteglobal.cpp - Kopete Globals Copyright (c) 2004 by Richard Smith Kopete (c) 2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "kopeteglobal.h" #include "kopeteuiglobal.h" -#include +#include #include "libkopete_debug.h" #include #include #include #include #include #include #include namespace Kopete { namespace Global { class PropertiesPrivate { public: PropertyTmpl::Map mTemplates; }; Properties *Properties::mSelf = nullptr; Properties *Properties::self() { if (!mSelf) { //qCDebug(LIBKOPETE_LOG) ; mSelf = new Properties(); // create the templates mSelf->fullName(); mSelf->idleTime(); mSelf->onlineSince(); mSelf->lastSeen(); mSelf->statusMessage(); mSelf->firstName(); mSelf->lastName(); mSelf->emailAddress(); mSelf->privatePhone(); mSelf->privateMobilePhone(); mSelf->workPhone(); mSelf->workMobilePhone(); mSelf->nickName(); mSelf->customName(); mSelf->photo(); } return mSelf; } Properties::Properties() { qCDebug(LIBKOPETE_LOG); d = new PropertiesPrivate(); } Properties::~Properties() { qCDebug(LIBKOPETE_LOG); mSelf = nullptr; delete d; } const PropertyTmpl &Properties::tmpl(const QString &key) const { if (d->mTemplates.contains(key)) { /*qCDebug(LIBKOPETE_LOG) << "Found template for key = '" << key << "'" << endl;*/ return d->mTemplates[key]; } else { return PropertyTmpl::null; } } bool Properties::registerTemplate(const QString &key, const PropertyTmpl &tmpl) { if (d->mTemplates.contains(key)) { qCDebug(LIBKOPETE_LOG) <<"Called for EXISTING key = '" << key << "'" << endl; return false; } else { d->mTemplates.insert(key, tmpl); return true; } } void Properties::unregisterTemplate(const QString &key) { qCDebug(LIBKOPETE_LOG) << "called for key: '" << key << "'"; d->mTemplates.remove(key); } bool Properties::isRegistered(const QString &key) { return d->mTemplates.contains(key); } const PropertyTmpl &Properties::fullName() const { return createProp(QStringLiteral("FormattedName"), i18n("Full Name")); } const PropertyTmpl &Properties::idleTime() const { return createProp(QStringLiteral("idleTime"), i18n("Idle Time")); } const PropertyTmpl &Properties::onlineSince() const { return createProp(QStringLiteral("onlineSince"), i18n("Online Since")); } const PropertyTmpl &Properties::lastSeen() const { return createProp(QStringLiteral("lastSeen"), i18n("Last Seen"), QString(), true); } const PropertyTmpl &Properties::statusTitle() const { return createProp(QStringLiteral("statusTitle"), i18n("Status Title")); } const PropertyTmpl &Properties::statusMessage() const { return createProp(QStringLiteral("statusMessage"), i18n("Status Message")); } const PropertyTmpl &Properties::firstName() const { return createProp(QStringLiteral("firstName"), i18n("First Name"), QString(), true); } const PropertyTmpl &Properties::lastName() const { return createProp(QStringLiteral("lastName"), i18n("Last Name"), QString(), true); } const PropertyTmpl &Properties::privatePhone() const { return createProp(QStringLiteral("privatePhoneNumber"), i18n("Private Phone"), QString(), true); } const PropertyTmpl &Properties::privateMobilePhone() const { return createProp(QStringLiteral("privateMobilePhoneNumber"), i18n("Private Mobile Phone"), QString(), true); } const PropertyTmpl &Properties::workPhone() const { return createProp(QStringLiteral("workPhoneNumber"), i18n("Work Phone"), QString(), true); } const PropertyTmpl &Properties::workMobilePhone() const { return createProp(QStringLiteral("workMobilePhoneNumber"), i18n("Work Mobile Phone"), QString(), true); } const PropertyTmpl &Properties::emailAddress() const { return createProp(QStringLiteral("emailAddress"), i18n("Email Address"), QStringLiteral("mail"), true); } const PropertyTmpl &Properties::nickName() const { return createProp(QStringLiteral("nickName"), i18n("Nick Name"), QString(), true); } const PropertyTmpl &Properties::customName() const { return createProp(QStringLiteral("customName"), i18n("Custom Name"), QString(), true); } const PropertyTmpl &Properties::isAlwaysVisible() const { return createProp(QStringLiteral("isAlwaysVisible"), i18n("Shown even if offline"), QString(), true); } const PropertyTmpl &Properties::photo() const { return createProp(QStringLiteral("photo"), i18n("Photo"), QString(), true); } const PropertyTmpl &Properties::createProp(const QString &key, const QString &label, const QString &icon, bool persistent) const { /*qCDebug(LIBKOPETE_LOG) << "key = " << key << ", label = " << label << endl;*/ if (!d->mTemplates.contains(key)) { /* qCDebug(LIBKOPETE_LOG) << "CREATING NEW PropertyTmpl WITH key = " << key << ", label = " << label << ", persisten = " << persistent << endl;*/ d->mTemplates.insert(key, PropertyTmpl(key, label, icon, persistent ? PropertyTmpl::PersistentProperty : PropertyTmpl::NoProperty)); } return tmpl(key); } const PropertyTmpl::Map &Properties::templateMap() const { return d->mTemplates; } } // END namespace Global } // END namespace Kopete // vim: set noet ts=4 sts=4 sw=4: diff --git a/libkopete/kopetegroup.h b/libkopete/kopetegroup.h index b77ff4bdf..1365246da 100644 --- a/libkopete/kopetegroup.h +++ b/libkopete/kopetegroup.h @@ -1,179 +1,179 @@ /* kopetegroup.h - Kopete (Meta)Contact Group Copyright (c) 2002-2005 by Olivier Goffart Copyright (c) 2003 by Martijn Klingens Kopete (c) 2002-2005 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETEGROUP_H #define KOPETEGROUP_H -#include +#include #include "kopetecontactlistelement.h" #include "libkopete_export.h" namespace Kopete { class MetaContact; class Message; /** * Class which represents the Group. * * A Group is a ConstacListElement which means plugin can save data. * * some static group are availavle from this class: topLevel and temporary * * @author Olivier Goffart */ class LIBKOPETE_EXPORT Group : public ContactListElement { Q_PROPERTY(QString displayName READ displayName WRITE setDisplayName) Q_PROPERTY(uint groupId READ groupId) Q_PROPERTY(bool expanded READ isExpanded WRITE setExpanded) Q_OBJECT public: typedef QList List; /** Kinds of groups. */ enum GroupType { Normal = 0, Temporary, TopLevel, Offline }; /** * \brief Create an empty group * * Note that the constructor will not add the group automatically to the contact list. * Use @ref ContactList::addGroup() to add it */ Group(); /** * \brief Create a group of the specified type * * Overloaded constructor to create a group with a display name and Normal type. */ explicit Group(const QString &displayName); ~Group(); /** * \brief Return the group's display name * * \return the display name of the group */ QString displayName() const; /** * \brief Rename the group */ void setDisplayName(const QString &newName); /** * \return the group type */ GroupType type() const; /** * \return the unique id for this group */ uint groupId() const; /** * @brief child metacontact * This function is not very efficient - it searches through all the metacontacts in the contact list * \return the members of this group */ QList members() const; /** * \brief Set if the group is expanded. */ void setExpanded(bool expanded); /** * * \return true if the group is expanded. * \return false otherwise */ bool isExpanded() const; /** * \return a Group pointer to the toplevel group */ static Group *topLevel(); /** * \return a Group pointer to the temporary group */ static Group *temporary(); /** * \return a Group pointer to the offline group */ static Group *offline(); /** * @internal */ void setGroupId(uint groupId); /** * @internal */ uint uniqueGroupId() const; /** * @internal */ void setUniqueGroupId(uint uniqueGroupId); public Q_SLOTS: /** * Send a message to all contacts in the group */ void sendMessage(); Q_SIGNALS: /** * \brief Emitted when the group has been renamed */ void displayNameChanged(Kopete::Group *group, const QString &oldName); private Q_SLOTS: void sendMessage(Kopete::Message &); private: /** * \brief Create a group of the specified type */ Group(const QString &displayName, GroupType type); static Group *s_topLevel; static Group *s_temporary; static Group *s_offline; class Private; Private *const d; /** * @internal used to get reachabe contact to send message to thom. */ QList onlineMembers() const; }; } //END namespace Kopete #endif diff --git a/libkopete/kopeteidentitymanager.h b/libkopete/kopeteidentitymanager.h index 1d0b6b5ef..8b0f90462 100644 --- a/libkopete/kopeteidentitymanager.h +++ b/libkopete/kopeteidentitymanager.h @@ -1,171 +1,171 @@ /* kopeteidentitymanager.h - Kopete Identity Manager Copyright (c) 2007 by Gustavo Pichorim Boiko Kopete (c) 2002-2007 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef __kopeteidentitymanager_h__ #define __kopeteidentitymanager_h__ -#include +#include #include "libkopete_debug.h" #include "libkopete_export.h" #include "kopeteonlinestatus.h" #include "kopeteidentity.h" #include "kopetestatusmessage.h" namespace Kopete { /** * IdentityManager manages all defined identities in Kopete. You can * query them and globally set them all online or offline from here. * * IdentityManager is a singleton, you may uses it with @ref IdentityManager::self() * * @author Gustavo Pichorim Boiko */ class LIBKOPETE_EXPORT IdentityManager : public QObject { Q_OBJECT public: /** * \brief Retrieve the instance of IdentityManager. * * The identity manager is a singleton class of which only a single * instance will exist. If no manager exists yet this function will * create one for you. * * \return the instance of the IdentityManager */ static IdentityManager *self(); ~IdentityManager(); /** * \brief Retrieve the list of identities * \return a list of all the identities */ const Identity::List &identities() const; /** * \brief Return the identity asked * \param identityId is the ID for the identity * \return the Identity object found or NULL if no identity was found */ Identity *findIdentity(const QString &identityId); /** * \brief Returs the default identity to be used * * This is the default identity configured in kopete. If no identity was created * yet, this function will create a new identity, set it as the default identity * and return it. * If there are identities already created, but none of them was set as the default, * it will return the first identity of the list. * @return the default identity */ Identity *defaultIdentity(); /** * @brief Sets a new default identity * * By changing the default identity, you do NOT change the accounts' identity * association. They are kept as if nothing has changed */ void setDefaultIdentity(Identity *ident); /** * \brief Delete the identity and clean the config data * * This will mostly be called when no account is assigned to an identity */ void removeIdentity(Identity *identity); /** * @brief Register the identity. * * This adds the identity in the manager's identity list. * It will check no identities already exist with the same ID, if any, the identity is deleted. and not added * * @return @p identity, or 0L if the identity was deleted because id collision */ Identity *registerIdentity(Identity *identity); public Q_SLOTS: /** * @brief Set all identities a status in the specified category * * @param category is one of the Kopete::OnlineStatusManager::Categories * @param statusMessage is the new status message * @param flags is a bitmask of SetOnlineStatusFlag */ void setOnlineStatus(/*Kopete::OnlineStatusManager::Categories*/ uint category, const Kopete::StatusMessage &statusMessage = Kopete::StatusMessage(), uint flags = 0); /** * \internal * Save the identity data to KConfig */ void save(); /** * \internal * Load the identity data from KConfig */ void load(); Q_SIGNALS: /** * \brief Signals when an identity is ready for use */ void identityRegistered(Kopete::Identity *identity); /** * \brief Signals when an identity has been unregistered * * At this state, we are already in the Identity destructor. */ void identityUnregistered(const Kopete::Identity *identity); /** * \brief Signals when the default identity has changed */ void defaultIdentityChanged(Kopete::Identity *identity); void identityOnlineStatusChanged(Kopete::Identity *identity); private: /** * Private constructor, because we're a singleton */ IdentityManager(); private Q_SLOTS: void slotIdentityOnlineStatusChanged(Kopete::Identity *i); /** * \internal * Unregister the identity. */ void unregisterIdentity(const Kopete::Identity *identity); private: static IdentityManager *s_self; class Private; Private *const d; }; } //END namespace Kopete #endif diff --git a/libkopete/kopeteidletimer.h b/libkopete/kopeteidletimer.h index 30a63a1a6..e14507477 100644 --- a/libkopete/kopeteidletimer.h +++ b/libkopete/kopeteidletimer.h @@ -1,77 +1,77 @@ /* kopeteidletimer.h - Kopete Idle Timer Copyright (c) 2002 by Hendrik vom Lehn Copyright (c) 2003 by Olivier Goffart Copyright (c) 2008 by Roman Jarosz Kopete (c) 2002-2008 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETEIDLETIMER_H #define KOPETEIDLETIMER_H -#include +#include #include "libkopete_export.h" namespace Kopete { /** * IdleTimer handles global idle time and allows to register idle timeout notifications * * IdleTimer is a singleton, you may uses it with @ref IdleTimer::self() */ class LIBKOPETE_EXPORT IdleTimer : public QObject { Q_OBJECT public: /** * Get the only instance of IdleTimer * @return IdleTimer single instance */ static IdleTimer *self(); ~IdleTimer(); /** * @brief Time in seconds the user has been idle */ int idleTime(); public Q_SLOTS: /** * @brief Register new timeout notification * \param idleSeconds the idle notification time period * \param receiver the object that receives the timeout notification. * \param memberActive the slot that is called when user has changed its state from idle to active. * \param memberIdle the slot that is called when user was idle for @param idleSeconds seconds. */ void registerTimeout(int idleSeconds, QObject *receiver, const char *memberActive, const char *memberIdle); /** * removes all registered timeout notifications for this object */ void unregisterTimeout(QObject *receiver); private Q_SLOTS: void updateIdleTime(); private: IdleTimer(); static IdleTimer *instance; class Private; Private *const d; }; } #endif diff --git a/libkopete/kopetemessage.cpp b/libkopete/kopetemessage.cpp index 705a95836..460661176 100644 --- a/libkopete/kopetemessage.cpp +++ b/libkopete/kopetemessage.cpp @@ -1,833 +1,833 @@ /* kopetemessage.cpp - Base class for Kopete messages Copyright (c) 2002-2003 by Martijn Klingens Copyright (c) 2002-2006 by Olivier Goffart Copyright (c) 2006-2007 by Charles Connell Copyright (c) 2007 by MichaĂ«l Larouche Copyright (c) 2008 by Roman Jarosz Kopete (c) 2002-2008 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "kopetemessage.h" #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include "libkopete_debug.h" #include #include "kopetemetacontact.h" #include "kopeteprotocol.h" #include "kopetechatsession.h" #include "kopetecontact.h" #include "kopeteemoticons.h" namespace Kopete { class Message::Private : public QSharedData { public: Private() //assign next message id, it can't be changed later : id(nextId++) , direction(Internal) , format(Qt::PlainText) , type(TypeNormal) , importance(Normal) , state(StateUnknown) , delayed(false) , formattingOverride(false) , forceHtml(false) , isRightToLeft(false) , timeStamp(QDateTime::currentDateTime()) , body(new QTextDocument) , parsedBodyDirty(true) , escapedBodyDirty(true) , fileTransfer(0) { } Private (const Private &other); ~Private(); const uint id; QPointer from; ContactPtrList to; QPointer manager; MessageDirection direction; Qt::TextFormat format; MessageType type; QString requestedPlugin; MessageImportance importance; MessageState state; bool delayed; bool formattingOverride, forceHtml; bool isRightToLeft; QDateTime timeStamp; QFont font; QStringList classes; QColor foregroundColor; QColor backgroundColor; QString subject; QTextDocument *body; mutable QString parsedBody; mutable bool parsedBodyDirty; mutable QString escapedBody; mutable bool escapedBodyDirty; class FileTransferInfo { public: FileTransferInfo() : disabled(false) , fileSize(0) { } bool disabled; QString fileName; unsigned long fileSize; QPixmap filePreview; }; FileTransferInfo *fileTransfer; static uint nextId; }; // Start with 1 as 0 is reserved for invalid id; uint Message::Private::nextId = 1; Message::Private::Private (const Message::Private &other) : QSharedData(other) , id(other.id) { from = other.from; to = other.to; manager = other.manager; direction = other.direction; format = other.format; type = other.type; requestedPlugin = other.requestedPlugin; importance = other.importance; state = other.state; delayed = other.delayed; formattingOverride = other.formattingOverride; isRightToLeft = other.isRightToLeft; timeStamp = other.timeStamp; font = other.font; classes = other.classes; foregroundColor = other.foregroundColor; backgroundColor = other.backgroundColor; subject = other.subject; body = other.body->clone(); parsedBody = other.parsedBody; parsedBodyDirty = other.parsedBodyDirty; escapedBody = other.escapedBody; escapedBodyDirty = other.escapedBodyDirty; if (other.fileTransfer) { fileTransfer = new FileTransferInfo(*other.fileTransfer); } else { fileTransfer = 0; } } Message::Private::~Private () { delete fileTransfer; delete body; } Message::Message() : d(new Private) { } Message::Message(const Contact *fromKC, const Contact *toKC) : d(new Private) { d->from = const_cast(fromKC); QList contacts; contacts << const_cast(toKC); d->to = contacts; } Message::Message(const Contact *fromKC, const QList &toKC) : d(new Private) { d->from = const_cast(fromKC); d->to = toKC; } Message::Message(const Message &other) : d(other.d) { } Message &Message::operator=(const Message &other) { d = other.d; return *this; } Message::~Message() { } uint Message::id() const { return d->id; } uint Message::nextId() { return Message::Private::nextId++; } void Message::setBackgroundOverride(bool enabled) { setFormattingOverride(enabled); } void Message::setForegroundOverride(bool enabled) { setFormattingOverride(enabled); } void Message::setRichTextOverride(bool enabled) { setFormattingOverride(enabled); } void Message::setFormattingOverride(bool enabled) { d->formattingOverride = enabled; d->parsedBodyDirty = true; d->escapedBodyDirty = true; } void Message::setForegroundColor(const QColor &color) { d->foregroundColor = color; } void Message::setBackgroundColor(const QColor &color) { d->backgroundColor = color; } void Message::setFont(const QFont &font) { d->font = font; } void Message::setPlainBody(const QString &body) { doSetBody(body, Qt::PlainText); } void Message::setHtmlBody(const QString &body) { doSetBody(body, Qt::RichText); } void Message::setForcedHtmlBody(const QString &body) { setHtmlBody(body); d->forceHtml = true; } void Message::doSetBody(QString body, Qt::TextFormat f) { // Remove ObjectReplacementCharacter because otherwise html text will be empty if (body.contains(QChar(QChar::ObjectReplacementCharacter))) { body.replace(QChar(QChar::ObjectReplacementCharacter), QChar(' ')); } if (f == Qt::PlainText) { d->body->setPlainText(body); } else { d->body->setHtml(body); } d->format = f; d->isRightToLeft = d->body->toPlainText().isRightToLeft(); d->escapedBodyDirty = true; d->parsedBodyDirty = true; } void Message::setBody(const QTextDocument *_body) { doSetBody(_body, Qt::RichText); } void Message::doSetBody(const QTextDocument *body, Qt::TextFormat f) { delete d->body; d->body = body->clone(); // delete the old body and replace it with a *copy* of the new one d->format = f; d->isRightToLeft = d->body->toPlainText().isRightToLeft(); d->escapedBodyDirty = true; d->parsedBodyDirty = true; } void Message::setImportance(Message::MessageImportance i) { d->importance = i; } QString Message::unescape(const QString &xml) { QString data = xml; // Remove linebreak and multiple spaces. First return nbsp's to normal spaces :) data = data.simplified(); int pos; while ((pos = data.indexOf('<')) != -1) { int endPos = data.indexOf('>', pos + 1); if (endPos == -1) { break; // No more complete elements left } // Take the part between < and >, and extract the element name from that int matchWidth = endPos - pos + 1; const QString match = data.mid(pos + 1, matchWidth - 2).simplified(); int elemEndPos = match.indexOf(' '); const QString elem = (elemEndPos == -1 ? match.toLower() : match.left(elemEndPos).toLower()); if (elem == QLatin1String("img")) { // Replace smileys with their original text' const QString attrTitle = QStringLiteral("title=\""); int titlePos = match.indexOf(attrTitle, elemEndPos); int titleEndPos = match.indexOf('"', titlePos + attrTitle.length()); if (titlePos == -1 || titleEndPos == -1) { // Not a smiley but a normal // Don't update pos, we restart at this position :) data.remove(pos, matchWidth); } else { QString orig = match.mid(titlePos + attrTitle.length(), titleEndPos - titlePos - attrTitle.length()); data.replace(pos, matchWidth, orig); pos += orig.length(); } } else if (elem == QLatin1String("/p") || elem == QLatin1String("/div") || elem == QLatin1String("br")) { // Replace paragraph, div and line breaks with a newline data.replace(pos, matchWidth, '\n'); pos++; } else { // Remove all other elements entirely // Don't update pos, we restart at this position :) data.remove(pos, matchWidth); } } // Replace stuff starting with '&' data.replace(QLatin1String(">"), QLatin1String(">")); data.replace(QLatin1String("<"), QLatin1String("<")); data.replace(QLatin1String("""), QLatin1String("\"")); data.replace(QLatin1String(" "), QLatin1String(" ")); data.replace(QLatin1String("&"), QLatin1String("&")); data.replace(QLatin1String(" "), QLatin1String(" ")); //this one is used in jabber: note, we should escape all &#xx; return data; } QString Message::escape(const QString &text) { QString html = text.toHtmlEscaped(); //Replace carriage returns inside the text html.replace(QLatin1Char('\n'), QLatin1String("
")); //Replace a tab with 4 spaces html.replace(QLatin1Char('\t'), QLatin1String("    ")); //Replace multiple spaces with   //do not replace every space so we break the linebreak html.replace(QRegExp(QLatin1String("\\s\\s")), QStringLiteral("  ")); return html; } QString Message::plainBody() const { // Remove ObjectReplacementCharacter which can be there if html text contains img tag. QString plainText = d->body->toPlainText(); plainText.replace(QChar(QChar::ObjectReplacementCharacter), QChar(' ')); return plainText; } QString Message::escapedBody() const { // qCDebug(LIBKOPETE_LOG) << escapedBody() << " " << d->richTextOverride; // the escaped body is cached because QRegExp is very expensive, so it shouldn't be used any more than necessary if (!d->escapedBodyDirty) { return d->escapedBody; } else { QString html; if (d->format == Qt::PlainText || (d->formattingOverride && !d->forceHtml)) { html = Qt::convertFromPlainText(d->body->toPlainText(), Qt::WhiteSpaceNormal); } else { html = d->body->toHtml(); } // all this regex business is to take off the outer HTML document provided by QTextDocument // remove the head QRegExp badStuff("]*>|]*>.*]*>|]*>|]*>"); html = html.remove(badStuff); // remove newlines that may be present, since they end up being displayed in the chat window. real newlines are represented with
, so we know \n's are meaningless html = html.remove('\n'); d->escapedBody = html; d->escapedBodyDirty = false; return html; } } QString Message::parsedBody() const { //qCDebug(LIBKOPETE_LOG) << "messageformat: " << d->format; if (!d->parsedBodyDirty) { return d->parsedBody; } d->parsedBody = Kopete::Emoticons::parseEmoticons(parseLinks(escapedBody(), Qt::RichText)); d->parsedBodyDirty = false; return d->parsedBody; } static QString makeRegExp(const char *pattern) { const QString urlChar = QStringLiteral("\\+\\-\\w\\./#@&;:=\\?~%_,\\!\\$\\*\\(\\)"); const QString boundaryStart = QStringLiteral("(^|[^%1])(").arg(urlChar); const QString boundaryEnd = QStringLiteral(")([^%1]|$)").arg(urlChar); return boundaryStart + QLatin1String(pattern) + boundaryEnd; } const QStringList Message::regexpPatterns() { const QString name = QStringLiteral("[\\w\\+\\-=_\\.]+"); const QString userAndPassword = QStringLiteral("(?:%1(?::%1)?\\@)").arg(name); const QString urlChar = QStringLiteral("\\+\\-\\w\\./#@&;:=\\?~%_,\\!\\$\\*\\(\\)"); const QString urlSection = QStringLiteral("[%1]+").arg(urlChar); const QString domain = QStringLiteral("[\\-\\w_]+(?:\\.[\\-\\w_]+)+"); QStringList patternList; patternList << makeRegExp("\\w+://%1?\\w%2").arg(userAndPassword, urlSection) << makeRegExp("%1?www\\.%2%3").arg(userAndPassword, domain, urlSection) << makeRegExp("%1@%2").arg(name, domain); return patternList; } QString Message::parseLinks(const QString &message, Qt::TextFormat format) { if (format & Qt::RichText) { // < in HTML *always* means start-of-tag QStringList entries = message.split(QChar('<'), QString::KeepEmptyParts); QStringList::Iterator it = entries.begin(); // first one is different: it doesn't start with an HTML tag. if (it != entries.end()) { *it = parseLinks(*it, Qt::PlainText); ++it; } for (; it != entries.end(); ++it) { QString curr = *it; // > in HTML means start-of-tag if and only if it's the first one after a < int tagclose = curr.indexOf(QChar('>')); // no >: the HTML is broken, but we can cope if (tagclose == -1) { continue; } QString tag = curr.left(tagclose + 1); QString body = curr.mid(tagclose + 1); *it = tag + parseLinks(body, Qt::PlainText); } return entries.join(QLatin1String("<")); } QString result = message; // common subpatterns - may not contain matching parens! const QString name = QStringLiteral("[\\w\\+\\-=_\\.]+"); const QString userAndPassword = QStringLiteral("(?:%1(?::%1)?\\@)").arg(name); const QString urlChar = QStringLiteral("\\+\\-\\w\\./#@&;:=\\?~%_,\\!\\$\\*\\(\\)"); const QString urlSection = QStringLiteral("[%1]+").arg(urlChar); const QString domain = QStringLiteral("[\\-\\w_]+(?:\\.[\\-\\w_]+)+"); //Replace http/https/ftp links: // Replace (stuff)://[user:password@](linkstuff) with a link result.replace( QRegExp(makeRegExp("\\w+://%1?\\w%2").arg(userAndPassword, urlSection)), QStringLiteral("\\1\\2\\3")); // Replace www.X.Y(linkstuff) with a http: link result.replace( QRegExp(makeRegExp("%1?www\\.%2%3").arg(userAndPassword, domain, urlSection)), QStringLiteral("\\1\\2\\3")); //Replace Email Links // Replace user@domain with a mailto: link result.replace( QRegExp(makeRegExp("%1@%2").arg(name, domain)), QStringLiteral("\\1\\2\\3")); //Workaround for Bug 85061: Highlighted URLs adds a ' ' after the URL itself // the trailing   is included in the url. result.replace(QRegExp(QLatin1String("(timeStamp; } void Message::setTimestamp(const QDateTime ×tamp) { d->timeStamp = timestamp; } const Contact *Message::from() const { return d->from; } QList Message::to() const { return d->to; } Message::MessageType Message::type() const { return d->type; } void Message::setType(MessageType type) { d->type = type; } QString Message::requestedPlugin() const { return d->requestedPlugin; } void Message::setRequestedPlugin(const QString &requestedPlugin) { d->requestedPlugin = requestedPlugin; } QColor Message::foregroundColor() const { return d->foregroundColor; } QColor Message::backgroundColor() const { return d->backgroundColor; } bool Message::isRightToLeft() const { return d->isRightToLeft; } QFont Message::font() const { return d->font; } QString Message::subject() const { return d->subject; } void Message::setSubject(const QString &subject) { d->subject = subject; } const QTextDocument *Message::body() const { return d->body; } Qt::TextFormat Message::format() const { return d->format; } Message::MessageDirection Message::direction() const { return d->direction; } void Message::setDirection(MessageDirection direction) { d->direction = direction; } Message::MessageImportance Message::importance() const { return d->importance; } Message::MessageState Message::state() const { return d->state; } void Message::setState(MessageState state) { d->state = state; } ChatSession *Message::manager() const { return d->manager; } void Message::setManager(ChatSession *kmm) { d->manager = kmm; } QString Message::getHtmlStyleAttribute() const { QString styleAttribute; styleAttribute = QStringLiteral("style=\""); if (!d->formattingOverride) { // Affect foreground(color) and background color to message. // we only do this if the formatting won't get stripped anyway if (d->foregroundColor.isValid()) { styleAttribute += QStringLiteral("color: %1; ").arg(d->foregroundColor.name()); } if (d->backgroundColor.isValid()) { styleAttribute += QStringLiteral("background-color: %1; ").arg(d->backgroundColor.name()); } // Affect font parameters. if (d->font != QFont()) { QString fontstr; if (!d->font.family().isNull()) { fontstr += QLatin1String("font-family: ")+d->font.family()+QLatin1String("; "); } if (d->font.italic()) { fontstr += QLatin1String("font-style: italic; "); } if (d->font.strikeOut()) { fontstr += QLatin1String("text-decoration: line-through; "); } if (d->font.underline()) { fontstr += QLatin1String("text-decoration: underline; "); } if (d->font.bold()) { fontstr += QLatin1String("font-weight: bold;"); } styleAttribute += fontstr; } } styleAttribute += QLatin1String("\""); return styleAttribute; } void Message::setFileTransferDisabled(bool disabled) { if (!d->fileTransfer) { d->fileTransfer = new Message::Private::FileTransferInfo(); } d->fileTransfer->disabled = disabled; } bool Message::fileTransferDisabled() const { return (d->fileTransfer) ? d->fileTransfer->disabled : false; } void Message::setFileName(const QString &fileName) { if (!d->fileTransfer) { d->fileTransfer = new Message::Private::FileTransferInfo(); } d->fileTransfer->fileName = fileName; } QString Message::fileName() const { return (d->fileTransfer) ? d->fileTransfer->fileName : QString(); } void Message::setFileSize(unsigned long size) { if (!d->fileTransfer) { d->fileTransfer = new Message::Private::FileTransferInfo(); } d->fileTransfer->fileSize = size; } unsigned long Message::fileSize() const { return (d->fileTransfer) ? d->fileTransfer->fileSize : 0; } void Message::setFilePreview(const QPixmap &preview) { if (!d->fileTransfer) { d->fileTransfer = new Message::Private::FileTransferInfo(); } d->fileTransfer->filePreview = preview; } QPixmap Message::filePreview() const { return (d->fileTransfer) ? d->fileTransfer->filePreview : QPixmap(); } // prime candidate for removal #if 0 QString Message::decodeString(const QByteArray &message, const QTextCodec *providedCodec, bool *success) { /* Note to everyone. This function is not the most efficient, that is for sure. However, it *is* the only way we can be guaranteed that a given string is decoded properly. */ if (success) { *success = true; } // Avoid heavy codec tests on empty message. if (message.isEmpty()) { return QString::fromAscii(message); } //Check first 128 chars int charsToCheck = message.length(); charsToCheck = 128 > charsToCheck ? charsToCheck : 128; #ifdef __GNUC__ #warning Rewrite the following code: heuristicContentMatch() do not existe anymore. #endif //They are providing a possible codec. Check if it is valid // if( providedCodec && providedCodec->heuristicContentMatch( message, charsToCheck ) >= charsToCheck ) { //All chars decodable. return providedCodec->toUnicode(message); } //NOTE see KEncodingDetector@kdecore //Check if it is UTF if (KStringHandler::isUtf8(message)) { //We have a UTF string almost for sure. At least we know it will be decoded. return QString::fromUtf8(message); } /* //Try codecForContent - exact match QTextCodec *testCodec = QTextCodec::codecForContent(message, charsToCheck); if( testCodec && testCodec->heuristicContentMatch( message, charsToCheck ) >= charsToCheck ) { //All chars decodable. return testCodec->toUnicode( message ); } kWarning(14000) << "Unable to decode string using provided codec(s), taking best guesses!"; if( success ) *success = false; //We don't have any clues here. //Try local codec testCodec = QTextCodec::codecForLocale(); if( testCodec && testCodec->heuristicContentMatch( message, charsToCheck ) >= charsToCheck ) { //All chars decodable. qCDebug(LIBKOPETE_LOG) << "Using locale's codec"; return testCodec->toUnicode( message ); } //Try latin1 codec testCodec = QTextCodec::codecForMib(4); if( testCodec && testCodec->heuristicContentMatch( message, charsToCheck ) >= charsToCheck ) { //All chars decodable. qCDebug(LIBKOPETE_LOG) << "Using latin1"; return testCodec->toUnicode( message ); } qCDebug(LIBKOPETE_LOG) << "Using latin1 and cleaning string"; //No codec decoded. Just decode latin1, and clean out any junk. QString result = QLatin1String( message ); const uint length = message.length(); for( uint i = 0; i < length; ++i ) { if( !result[i].isPrint() ) result[i] = '?'; } return result; */ return QString(); } #endif QStringList Message::classes() const { return d->classes; } void Message::addClass(const QString &classe) { d->classes.append(classe); } void Message::setClasses(const QStringList &classes) { d->classes = classes; } } bool Kopete::Message::delayed() const { return d->delayed; } void Kopete::Message::setDelayed(bool delay) { d->delayed = delay; } diff --git a/libkopete/kopetemessage.h b/libkopete/kopetemessage.h index b5ed06683..e2eaa69e9 100644 --- a/libkopete/kopetemessage.h +++ b/libkopete/kopetemessage.h @@ -1,579 +1,579 @@ /* kopetemessage.h - Base class for Kopete messages Copyright (c) 2002-2003 by Martijn Klingens Copyright (c) 2002-2004 by Olivier Goffart Copyright (c) 2006-2007 by Charles Connell Copyright (c) 2007 by MichaĂ«l Larouche Copyright (c) 2008 by Roman Jarosz Kopete (c) 2002-2008 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETEMESSAGE_H #define KOPETEMESSAGE_H -#include -#include -#include +#include +#include +#include #include "libkopete_export.h" class QByteArray; class QColor; class QDateTime; class QFont; class QTextCodec; class QTextDocument; class QStringList; class QPixmap; namespace Kopete { class ChatSession; class Contact; /** * @brief Representation of a message in Kopete * * @author Martijn Klingens * @author Olivier Goffart * @author Charles Connell * @author MichaĂ«l Larouche * * Message represents any kind of messages shown on a chat view. * The message may contain a simple plain text string, or a rich text HTML * message. Also, Message can use a QTextDocument to structure the message. * * Message in plain text can however have a color or a specific font. You can * set color with setForegroundColor() and setBackgroundColor() and change the font * with setFont() * * Message have a direction from where the message come from. By default, the direction * is Internal but it is strongly advised to set the direction explicitly. * * @section plainMessage Creating a plain text message * @code Kopete::Message newMessage(sourceContact, destionationContact); newMessage.setPlainBody( QString("A plain text message") ); newMessage.setDirection( Kopete::Message::Inbound ); * @endcode * * @section richTextMessage Creating a complete rich text message * @code Kopete::Message richTextMessage(sourceContact, destinationContactList); richTextMessage.setTimestamp( QDateTime::currentDateTime() ); richTextMessage.setDirection( Kopete::Message::Outbound ); richTextMessage.setSubject( QString("Kopete API documentation thread") ); richTextMessage.setHtmlBody( QString("A bold text") ); * @endcode */ class LIBKOPETE_EXPORT Message { public: /** * Direction of a message. */ enum MessageDirection { Inbound = 0, ///< Message is from the chat partner Outbound = 1, ///< Message sent by the user Internal = 2 ///< (Default) Message which are not sent via the network. This is just a notification a plugin can show in a chat view }; /** * Specifies the type of the message. */ enum MessageType { TypeNormal, ///< A typical message TypeAction, ///< An IRC-style action. TypeFileTransferRequest, ///< A incoming file transfer request message TypeVoiceClipRequest ///< A incoming voice clip message }; /** * Specifies the type of notification that will be sent with this message */ enum MessageImportance { Low = 0, ///< almost no notifications. automatically used in groupChat Normal = 1, ///< Default notification, for normal message Highlight = 2 ///< Highlight notification, for most important messages, which require particular attentions. }; enum MessageState { StateUnknown = 0, ///< state of message isn't known (e.g. protocol doesn't support message acknowledgment) StateSending = 1, ///< message was sent but not yet delivered. StateSent = 2, ///< message was delivered StateError = 3 ///< message has not been delivered }; /** * Constructs a new empty message */ explicit Message(); /** * Deref and clean private object if refcount == 0 */ ~Message(); /** * @brief Constructs a new message with a from and to contact * * This constructor is a convience of the constructor who * take a list of contacts for destination * @param fromKC Contact who send the message * @param toKC Contact which the message is destined. */ explicit Message(const Contact *fromKC, const Contact *toKC); /** * @brief Constructs a new message with many contacts as the destination. * @param fromKC Contact who send the message * @param contacts List of Contact to send the message */ explicit Message(const Contact *fromKC, const QList &contacts); /** * Copy constructor. * Just adds a reference, doesn't actually copy. */ Message(const Message &other); /** * Assignment operator * Just like the copy constructor it just refs and doesn't copy. */ Message &operator=(const Message &other); /** * @brief Get unique message id. * @return message id */ uint id() const; /** * @brief Get next unique message id. * @return next id */ static uint nextId(); /** * @brief Accessor method for the timestamp of the message * @return The message's timestamp */ QDateTime timestamp() const; /** * @brief Set the message timestamp * @param timestamp timestamp as QDateTime. By default the current date and time. */ void setTimestamp(const QDateTime ×tamp); /** * @brief Accessor method for the "delayed" attribute of the message * @return true if the message was delayed (for example because it has * been stored on a server while the intended recipient was offline or * because the message is contained in the history of a group chat room). */ bool delayed() const; /** * @brief Set the "delayed" attribute of the message * @param delay whether the message was delayed, see delayed() */ void setDelayed(bool delay); /** * @brief Accessor method for the Contact that sent this message * @return The Contact who sent this message */ const Contact *from() const; /** * @brief Accessor method for the Contacts that this message was sent to * @return Pointer list of the Contacts this message was sent to */ QList to() const; /** * @brief Accessor method for the message type * @return The type of the message * @see MessageType */ MessageType type() const; /** * @brief Set message type * @param type The type of the message * @see MessageType */ void setType(MessageType type); /** * @brief Accessor method for the preferred plugin * If null, Kopete will use the user's preferred plugin. * @return The preferred plugin */ QString requestedPlugin() const; /** * @brief Set a view plugin which will display the message * * This is used mostly by Jabber plugin to select between * the email window or the chat window depending of the * type of message. * @param requesedPlugin View plugin name */ void setRequestedPlugin(const QString &requestedPlugin); /** * @brief Accessor method for the foreground color * @return The message's foreground color */ QColor foregroundColor() const; /** * @brief Accessor method for the background color of the message * @return The message's background color */ QColor backgroundColor() const; /** * @brief Accesssor method for the direction of the text based on what language it is in * @return The message text's direction */ bool isRightToLeft() const; /** * returns QStringList with regexp patterns * will be used to look for links in the message */ const QStringList regexpPatterns(); /** * @brief Accessor method for the font of the message * @return The message's font */ QFont font() const; /** * @brief Accessor method for the subject of the message * @return The message subject */ QString subject() const; /** * @brief Set message subject * @param subject Message's subject */ void setSubject(const QString &subject); /** * @brief Accessor method for the body of the message * This is used internaly, to modify it make a copy of it with QTextDocument::clone() * @return The message body */ const QTextDocument *body() const; /** * @brief Accessor method for the format of the message * @return The message format */ Qt::TextFormat format() const; /** * @brief Accessor method for the direction of the message * @return The message direction */ MessageDirection direction() const; /** * @brief Set the message direction * @param direction The message direction * @see MessageDirection */ void setDirection(MessageDirection direction); /** * @brief Accessor method for the importance * @see setImportance * @return The message importance (low/normal/highlight) */ MessageImportance importance() const; /** * @brief Set the importance. * @see importance and @see MessageImportance * @param importance The message importance to set */ void setImportance(MessageImportance importance); /** * @brief Accessor method for the state * @return The message state (unknown/sending/sent/error) */ MessageState state() const; /** * @brief Set the state of message. * @see MessageState * @param state The message state to set */ void setState(MessageState state); /** * @brief Sets the foreground color for the message * @see foregroundColor * @param color The color */ void setForegroundColor(const QColor &color); /** * @brief Sets the background color for the message * @see backgroundColor * @param color The color */ void setBackgroundColor(const QColor &color); /** * @brief Sets the font for the message * @see font * @param font The font */ void setFont(const QFont &font); /** * @brief Sets the body of the message * * @param body The body, intpreted as plain text */ void setPlainBody(const QString &body); /** * @brief Sets the body of the message * * @param body The body, interpreted as HTML */ void setHtmlBody(const QString &body); /** * @brief Sets the body of the message, which is used even if formatting is overridden * * @param body The body, interpreted as HTML */ void setForcedHtmlBody(const QString &body); /** * @brief Sets the body of the message * The format is changed to RichText automatically * @param body The body */ void setBody(const QTextDocument *body); /** * @brief Get the message body back as plain text * @return The message body as plain text */ QString plainBody() const; /** * @brief Get the message body as escaped (X)HTML format. * That means every HTML special char (\>, \<, \&, ...) is escaped to the HTML entity (\<, \>, ...) * and newlines (\\n) are converted to \
* Just because you set an HTML body doesn't mean you'll get the same string back here, but it will * be equivalent in meaning * @return The message body as escaped text */ QString escapedBody() const; /** * @brief Get the message body as parsed HTML with Emoticons, and URL parsed * This should be ready to be shown in the chatwindow. * @return The HTML and Emoticon parsed message body */ QString parsedBody() const; /** * Get the related message manager. * If it is not set, returns 0L. * * The @ref ChatSession is only set if the message is already passed by the manager. * We should trust this only in aboutToSend/aboutToReceive signals */ ChatSession *manager() const; /** * @brief Set the messagemanager for this message. * Should be only used by the manager itself. @see manager * @param manager The chat session */ void setManager(ChatSession *manager); /** * @brief Does nothing */ void LIBKOPETE_DEPRECATED setBackgroundOverride(bool enable); /** * @brief Does nothing */ void LIBKOPETE_DEPRECATED setForegroundOverride(bool enable); /** * @brief Does nothing */ void LIBKOPETE_DEPRECATED setRichTextOverride(bool enable); /** * @brief Ignores peer's formatting */ void setFormattingOverride(bool enable); /** * @brief Return HTML style attribute for this message. * @return A string formatted like this: "style=attr" */ QString getHtmlStyleAttribute() const; /** * @brief Set the state of incoming file transfer * @param disabled flag to indicate if the file transfer request should be enabled or disabled. */ void setFileTransferDisabled(bool disabled); /** * @brief Accessor method for the file transfer state * @return if file transfer request should be enable or disable */ bool fileTransferDisabled() const; /** * @brief Set file name of incoming file transfer * @param fileName file name */ void setFileName(const QString &fileName); /** * @brief Accessor method for the file name of incoming file transfer * @return file name of incoming file transfer */ QString fileName() const; /** * @brief Set file transfer size * @param size file transfer size */ void setFileSize(unsigned long size); /** * @brief Accessor method for the file transfer size * @return file transfer size */ unsigned long fileSize() const; /** * @brief Set file preview icon for file transfer * @param preview file preview icon */ void setFilePreview(const QPixmap &preview); /** * @brief Accessor method for the file preview icon * @return file preview icon */ QPixmap filePreview() const; /** * @return The list of classes * Class are used to give different notification on a message. They are also used in the chatwindow as an HTML class */ QStringList classes() const; /** * @brief Add a class * @see classes * @param class class to add */ void addClass(const QString &classe); /** * @brief Set the classes * @see classes * @param classes The new classes */ void setClasses(const QStringList &classes); public: /* static helpers */ /** * Unescapes a string, removing XML entity references and returns a plain text. * * Note that this method is *VERY* expensive when called on rich text bodies, * use with care! * */ static QString unescape(const QString &xml); /** * @brief Transform a plaintext message into HTML. * it escape main entity like > < add some <br /> or &nbsp; */ static QString escape(const QString &); #if 0 //candidate for removal! /** * Helper function to decode a string. Whatever returned here is *nearly guaranteed* to * be parseable by the XML engine. * * @param message The string you are trying to decode * @param providedCodec A codec you want to try to decode with * @param success Optional pointer to a bool you want updated on success. "Success" * is defined as a successful decoding using either UTF8 or the codec you * provided. If a guess has to be taken, success will be false. * @return The decoded string */ static QString decodeString(const QByteArray &message, const QTextCodec *providedCodec = nullptr, bool *success = nullptr); #endif private: class Private; QSharedDataPointer d; /** * Called internally by @ref setBody() and the constructor * Basically @ref setBody() without detach * @internal */ void doSetBody(QString body, Qt::TextFormat format = Qt::PlainText); /** * Called internally by @ref setBody() and the constructor * Basically @ref setBody() without detach * @internal */ void doSetBody(const QTextDocument *body, Qt::TextFormat format = Qt::PlainText); /** * Called internally in rich text handling * @internal */ static QString parseLinks(const QString &message, Qt::TextFormat format); }; } #endif // vim: set noet ts=4 sts=4 sw=4: diff --git a/libkopete/kopetemessageevent.h b/libkopete/kopetemessageevent.h index 819a4ec6d..c337d248a 100644 --- a/libkopete/kopetemessageevent.h +++ b/libkopete/kopetemessageevent.h @@ -1,126 +1,126 @@ /* kopetemessageevent.h - Kopete Message Event Copyright (c) 2003 by Olivier Goffart Copyright (c) 2002 by Duncan Mac-Vicar Prett Copyright (c) 2002 by Hendrik vom Lehn Copyright (c) 2004 by Richard Smith Kopete (c) 2002 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETEMESSAGEEVENT_H #define KOPETEMESSAGEEVENT_H -#include +#include #include "kopetemessage.h" #include "libkopete_export.h" namespace Kopete { /** * @author Olivier Goffart * @author Richard Smith * * Kopete::MessageEvent is used when a new messages arrives, it is * caught by the UI. It contains just information about * the message, and a signal when it is terminated (i.e. * the message is read **/ class LIBKOPETE_EXPORT MessageEvent : public QObject { Q_OBJECT public: explicit MessageEvent(const Kopete::Message &, QObject *parent = nullptr); /* implicit */ ~MessageEvent(); /** * @return A copy of the message */ Kopete::Message message(); /** * Sets the message contained in this event. * @param message The new value for the message */ void setMessage(const Kopete::Message &message); /** * The state of the event. * - @c Nothing means that the event has not been accepted or ignored * - @c Applied if the event has been applied * - @c Ignored if the event has been ignored */ enum EventState { Nothing, Applied, Ignored }; EventState state(); public Q_SLOTS: /** * @deprecated Use accept() instead to continue the processing of this event once the caller has moved to using MessageHandlers * * execute the event */ void apply(); /** * @deprecated Use discard() instead to destroy this event once the caller has moved to using MessageHandlers * * ignore the event */ void ignore(); /** * @brief Passes the event to the next handler * * Call this when you've finished processing this event */ void accept(); /** * @brief Discards the event * * If this event should not be processed any further, this function * should be called to discard it. */ void discard(); Q_SIGNALS: /** * The event has been processed */ void done(Kopete::MessageEvent *); /** * The event has been discarded. * @param event The event sending the signal. */ void discarded(Kopete::MessageEvent *event); /** * The event has been accepted by its current handler. * @param event The event sending the signal. */ void accepted(Kopete::MessageEvent *event); private: class Private; Private *const d; }; } #endif // vim: set noet ts=4 sts=4 sw=4: diff --git a/libkopete/kopetemessagehandler.h b/libkopete/kopetemessagehandler.h index b9b7fbbd4..668670f46 100644 --- a/libkopete/kopetemessagehandler.h +++ b/libkopete/kopetemessagehandler.h @@ -1,221 +1,221 @@ /* kopetemessagehandler.h - Kopete Message Filtering Copyright (c) 2004 by Richard Smith Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETEMESSAGEHANDLER_H #define KOPETEMESSAGEHANDLER_H -#include -#include +#include +#include #include "libkopete_export.h" //FIXME: Message::MessageDirection could be moved into namespace Kopete // to avoid this being included everywhere #include "kopetemessage.h" namespace Kopete { class MessageEvent; class ChatSession; /** * @author Richard Smith * * An object which sits between the protocol and the chat window which * intercepts and processes messages on their way through. * * This class implements Handler role in the Chain of Responsibility pattern. * The Client role will be filled by the Kopete::MessageHandlerChain class. */ class LIBKOPETE_EXPORT MessageHandler : public QObject { Q_OBJECT public: MessageHandler(); virtual ~MessageHandler() = 0; /** * @return the next handler in the chain */ MessageHandler *next(); // FIXME: remove? void setNext(MessageHandler *next); /** * @brief Gets the rich-text capabilities of this message handling object * * The default implementation returns next()->capabilities(). */ virtual int capabilities(); /** * @brief Performs any processing necessary on the message * * @param event The message event to process. Should not be null. * * Overriders of this handler @em must cause (possibly asynchronously) * one of the following to happen: * - @p event->discard() to be called * - @p event->continue() to be called * - this base class implementation to be called (equivalent to event->continue() but faster) * * The base class implementation passes the event on to the next * handler in the chain. * * @note If you store @p event, be aware that it could be deleted at any time, and either * connect to the discarded(Kopete::MessageEvent*) signal or store it in a QPointer. */ virtual void handleMessage(MessageEvent *event); /** @internal */ void handleMessageInternal(MessageEvent *event); private Q_SLOTS: /** * @internal The message has been accepted. Pass it on to the next handler. */ void messageAccepted(Kopete::MessageEvent *event); private: class Private; Private *const d; }; /** * @author Richard Smith * * A factory for creating MessageHandlers. Instantiate a class derived from MessageHandlerFactory * in order to make your MessageHandler be automatically added to the list of handlers used * when constructing handler chains. * * @note If you construct a handler for an Inbound chain, it may still be asked to process Outbound * messages. This is because when a message is being sent it first passes through the Outbound * chain to the protocol, then (when it has been delivered) it passes back through the Inbound * chain to the chat window to be displayed. */ class LIBKOPETE_EXPORT MessageHandlerFactory { public: /** * Constructs a MessageHandlerFactory, and adds it to the list of factories considered when * creating a MessageHandlerChain for a ChatSession. * * @note Since the factory is added to the list of possible factories before the object is * finished being constructed, it is not safe to call any function from a derived class's * constructor which may cause a MessageHandlerChain to be created. */ MessageHandlerFactory(); /** * Destroys the MessageHandlerFactory and removes it from the list of factories. */ virtual ~MessageHandlerFactory(); typedef QLinkedList FactoryList; /** * @return the list of registered message handler factories */ static FactoryList messageHandlerFactories(); /** * @brief Creates a message handler for a given manager in a given direction. * @param manager The manager whose message handler chain the message handler is for * @param direction The direction of the chain that is being created. * @return the @ref MessageHandler object to put in the chain, or 0 if none is needed. */ virtual MessageHandler *create(ChatSession *manager, Message::MessageDirection direction) = 0; /** * Special stages usable with any message direction */ enum SpecialStage { StageDoNotCreate = -10000, ///< do not create a filter for this stage StageStart = 0, ///< start of processing StageEnd = 10000 ///< end of processing }; /** * Processing stages for handlers in inbound message handler chains */ enum InboundStage { InStageStart = 0, ///< message was just received InStageToSent = 2000, ///< convert from received format to sent format InStageToDesired = 5000, ///< convert to how the user wants the message InStageFormat = 7000, ///< decorate the message without changing the content InStageEnd = 10000 ///< message ready for display }; /** * Processing stages for handlers in outbound message handler chains */ enum OutboundStage { OutStageStart = 0, ///< user just hit Send OutStageParse = 2000, ///< process commands OutStageToDesired = 4000, ///< convert to how the user wanted to send OutStageFormat = 6000, ///< decorate the message without changing the content OutStageToSent = 8000, ///< convert to the format to send in OutStageEnd = 10000 ///< message ready for sending }; /** * Processing stages for handlers in internal message handler chains */ enum InternalStage { IntStageStart = 0, ///< some component just created the message IntStageEnd = 10000 ///< message ready for display }; /** * Offsets within a processing stage. Using these values allows finer * control over where in a chain a message handler will be added. Add * one of these values to values from the various Stage enumerations * to form a filter position. */ enum Offset { OffsetBefore = -90, OffsetVeryEarly = -60, OffsetEarly = -30, OffsetNormal = 0, OffsetLate = 30, OffsetVeryLate = 60, OffsetAfter = 90 }; /** * @brief Returns the position in the message handler chain to put this factory's handlers * @param manager The manager whose message handler chain the message handler is for * @param direction The direction of the chain that is being created. * @return a member of the InboundStage, OutboundStage or InternalStage enumeration, as * appropriate, optionally combined with a member of the Offset enumeration. * @retval StageDoNotCreate No filter should be created for this chain. */ virtual int filterPosition(ChatSession *manager, Message::MessageDirection direction) = 0; private: // noncopyable MessageHandlerFactory(const MessageHandlerFactory &); void operator=(const MessageHandlerFactory &); class Private; Private *const d; }; } #endif // vim: set noet ts=4 sts=4 sw=4: diff --git a/libkopete/kopetemessagehandlerchain.h b/libkopete/kopetemessagehandlerchain.h index 0b49344b6..f247ba5c9 100644 --- a/libkopete/kopetemessagehandlerchain.h +++ b/libkopete/kopetemessagehandlerchain.h @@ -1,99 +1,99 @@ /* kopetefilterchain.h - Kopete Message Filter Chain Copyright (c) 2004 by Richard Smith Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETEMESSAGEHANDLERCHAIN_H #define KOPETEMESSAGEHANDLERCHAIN_H -#include +#include #include #include "kopetemessage.h" #include "kopetetask.h" #include "libkopete_debug.h" namespace Kopete { class MessageEvent; class MessageHandler; class ProcessMessageTask; /** * @brief A chain of message handlers; the processing layer between protocol and chat view * * This class represents a chain of connected message handlers. * * This class is the client of the chain of responsibility formed by the * MessageHandlers, and acts as a facade for that chain, presenting a * more convenient interface. * * @author Richard Smith */ class MessageHandlerChain : public QObject, private QSharedData { Q_OBJECT public: friend class QExplicitlySharedDataPointer; typedef QExplicitlySharedDataPointer Ptr; /** * Create a new MessageHandlerChain object with the appropriate handlers for * processing messages entering @p manager in direction @p direction. */ static Ptr create(ChatSession *manager, Message::MessageDirection direction); ProcessMessageTask *processMessage(const Message &message); int capabilities(); private: MessageHandlerChain(); ~MessageHandlerChain(); friend class ProcessMessageTask; class Private; Private *const d; }; /** * @brief A task for processing a message * @author Richard Smith */ class ProcessMessageTask : public Task { Q_OBJECT public: MessageEvent *event(); public Q_SLOTS: void start() Q_DECL_OVERRIDE; void slotDone(); void kill(bool); protected: // Avoid compiler warning about QObject::event using Task::event; private: ProcessMessageTask(MessageHandlerChain::Ptr, MessageEvent *event); ~ProcessMessageTask(); friend class MessageHandlerChain; class Private; Private *const d; }; } #endif // KOPETEMESSAGEHANDLERCHAIN_H // vim: set noet ts=4 sts=4 sw=4: diff --git a/libkopete/kopetemetacontact.h b/libkopete/kopetemetacontact.h index 420988bef..5cbe7cda4 100644 --- a/libkopete/kopetemetacontact.h +++ b/libkopete/kopetemetacontact.h @@ -1,627 +1,627 @@ /* kopetemetacontact.h - Kopete Meta Contact Copyright (c) 2002-2003 by Martijn Klingens Copyright (c) 2002-2005 by Duncan Mac-Vicar Prett Copyright (c) 2002-2005 by Olivier Goffart Copyright (c) 2003 by Will Stephenson Kopete (c) 2002-2005 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef kopetemetacontact_h__ #define kopetemetacontact_h__ #include "kopetecontactlistelement.h" #include -#include -#include +#include +#include #include "libkopete_export.h" #include "kopeteonlinestatus.h" #include "kopetestatusmessage.h" namespace Kopete { class Plugin; class Group; class Picture; /** * @author Will Stephenson * @author Martijn Klingens * @author Duncan Mac-Vicar Prett * @author Olivier Goffart * * A metacontact represent a person. This is a kind of entry to * the contact list. All information of a contact is contained in * the metacontact. Plugins can store data in it with all * @ref ContactListElement methods */ class LIBKOPETE_EXPORT MetaContact : public ContactListElement { Q_OBJECT Q_PROPERTY(QString displayName READ displayName WRITE setDisplayName) Q_PROPERTY(QString statusString READ statusString) Q_PROPERTY(QString statusIcon READ statusIcon) Q_PROPERTY(bool isOnline READ isOnline) Q_PROPERTY(bool isReachable READ isReachable) Q_PROPERTY(bool isTemporary READ isTemporary) Q_PROPERTY(bool canAcceptFiles READ canAcceptFiles) //Q_PROPERTY( ulong idleTime READ idleTime ) Q_PROPERTY(QUuid metaContactId READ metaContactId WRITE setMetaContactId) Q_PROPERTY(bool photoSyncedWithKABC READ isPhotoSyncedWithKABC WRITE setPhotoSyncedWithKABC) public: typedef QList List; /** * Enumeration of possible sources for a property (which may be * photos, see setPhotoSource() for instance). */ enum PropertySource { SourceContact /**< Data comes from the contact itself. */, SourceKABC /**< Data comes from KABC (addressbook). */, SourceCustom /**< Data comes from somewhere else. */ }; /** * constructor */ MetaContact(); /** * destructor */ ~MetaContact(); /** * @brief Returns this metacontact's ID. * * Every metacontact has a unique id, set when creating the contact, * or reading the contactlist */ QUuid metaContactId() const; /** * @internal * Set the meta contact id for this meta contact to use. It should only * be used by the contact list loading mechanism */ void setMetaContactId(const QUuid &newMetaContactId); /** * @brief Get the KABC id for this metacontact */ QString kabcId() const; /** * @brief Set the KABC id for this metacontact * Use with care! You could create a one to many relationship */ void setKabcId(const QString &newKabcId); /** * @brief Retrieve the list of contacts that are part of the meta contact */ QList contacts() const; /** * @brief The groups the contact is stored in */ QList groups() const; /** * Find the Contact to a given contact. If contact * is not found, a null pointer is returned. * if @p protocolId or @p accountId are null, it is searched over all protocols/accounts */ Contact *findContact(const QString &protocolId, const QString &accountId, const QString &contactId); /** * @brief Set the source of metacontact displayName * * This method selects the display name source for one * of the sources defined in @ref PropertySource * * @see PropertySource */ void setDisplayNameSource(PropertySource source); void setDisplayNameSource(const QString &nameSourcePID, const QString &nameSourceAID, const QString &nameSourceCID); /** * @brief get the source of metacontact display name * * This method obtains the current name source for one * of the sources defined in @ref PropertySource * * @see PropertySource */ PropertySource displayNameSource() const; /** * @brief Set the source of metacontact photo * * This method selects the photo source for one * of the sources defined in @ref PropertySource * * @see PropertySource */ void setPhotoSource(PropertySource source); void setPhotoSource(const QString &photoSourcePID, const QString &photoSourceAID, const QString &photoSourceCID); /** * @brief get the source of metacontact photo * * This method obtains the current photo source for one * of the sources defined in @ref PropertySource * * @see PropertySource */ PropertySource photoSource() const; /** * @brief the display name showed in the contact list window * * The displayname is the name which should be shown almost everywere to * represent the metacontact. (in the contact list, in the chatwindow, ...) * * This is a kind of alias, set by the kopete user, as opposed to a nickname * set by the contact itself. * * If the protocol support alias serverside, the metacontact displayname * should probably be synchronized with the alias on the server. * * This displayName is obtained from the source set with @ref setDisplayNameSource */ QString displayName() const; /** * @brief the photo showed in the contact list window * * Returns a image for the metacontact. If the metacontact photo source is * the KDE addressbook. it will return the picture stored in the addressbook * It can also use a subcontact as the photo source. * * This photo is obtained from the source set with @ref setPhotoSource * @deprecated Use picture().image() instead. */ LIBKOPETE_DEPRECATED QImage photo() const; /** * Return the correct Kopete::Picture object depending of the metacontact photo source. * * This photo is obtained from the source set with @ref setPhotoSource * * KDE4 TODO: Rename this to photo() and use the new object. */ Picture &picture() const; /** * @brief Set the custom displayName. * * This display name is used when name source is Custom * this metohd may emit @ref displayNameChanged signal. * And will call @ref Kopete::Contact::sync * * @see displayName() * @see displayNameSource() */ void setDisplayName(const QString &name); /** * @brief Returns the custom display name * * @see displayName() * @see displayNameSource() */ QString customDisplayName() const; /** * @brief Returns the custom display photo * * @see photo() * @see photoSource() */ QUrl customPhoto() const; /** * @brief Set the custom photo. * * This photo is used when photo source is set toCustom * this metohd may emit @ref photoChanged signal. * * @see photo() * @see photoSource() */ void setPhoto(const QUrl &url); /** * @brief get the subcontact being tracked for its displayname (null if not set) * * The MetaContact will adjust its displayName() every time the * "nameSource" changes its nickname property. */ Contact *displayNameSourceContact() const; /** * @brief set the subcontact whose name is to be tracked (set to null to disable tracking) * @see nameSource */ void setDisplayNameSourceContact(Contact *contact); /** * @brief get the subcontact being tracked for its photo */ Contact *photoSourceContact() const; /** * @brief set the subcontact to use for SourceContact source */ void setPhotoSourceContact(Contact *contact); /** * @return true if when a subcontact change his photo, the photo will be set to the kabc contact. */ bool isPhotoSyncedWithKABC() const; /** * Set if the photo should be synced with the adressbook when the photosource change his photo * * If \p b is true, the photo will be synced immediately if possible */ void setPhotoSyncedWithKABC(bool b); /** * Temporary contacts will not be serialized. * If they are added to the contact list, they appears in a special "Not in your contact list" group. * (the @ref Group::temporary group) */ bool isTemporary() const; /** * @brief Add a contact which has just been deserialised to the meta contact * @param c The Contact being added */ void addContact(Contact *c); /** * @brief remove the contact from this metacontact * * set 'deleted' to true if the Contact is already deleted * * @param c is the contact to remove * @param deleted : if it is false, it will disconnect the old contact, and call some method. */ void removeContact(Contact *c, bool deleted = false); /** * @return the preferred child Contact for communication, or 0 if none is suitable (all unreachable). */ Contact *preferredContact(); /** * @brief The name of the icon associated with the contact's status * @todo improve with OnlineStatus */ QString statusIcon() const; /** * @brief The status string of the contact * * @see @ref status() * @todo improve with OnlineStatus */ QString statusString() const; /** * Returns whether this contact can be reached online for at least one * FIXME: Make that an enum, because status can be unknown for certain * protocols */ bool isOnline() const; /** * Returns whether this contact is visible even if offline */ bool isAlwaysVisible() const; /** * Returns whether this contact can accept files * @return True if the user is online with a file capable protocol, false otherwise */ bool canAcceptFiles() const; /** * Return a more fine-grained status. * Online means at least one sub-contact is online, away means at least * one is away, but nobody is online and offline speaks for itself */ OnlineStatus::StatusType status() const; /** * Like isOnline, but returns true even if the contact is not online, but * can be reached trough offline-messages. * it it return false, you are unable to open a chatwindow * @todo : Here too, use preference order, not append order! * @todo : Here too an enum. */ bool isReachable() const; /** * return the time in second the contact is idle. */ quint32 idleTime() const; /** * Get or set a field for the KDE address book backend. Fields not * registered during the call to Plugin::addressBookFields() * cannot be altered! * * @param p The Plugin by which uses this field * @param app refers to the application id in the libkabc database. * This should be a standardized format to make sense in the address * book in the first place - if you could use "" as application * then probably you should use the plugin data API instead of the * address book fields. * @param key The name of the address book field to get or set * * @todo: In the code the requirement that fields are registered first * is already lifted, but the API needs some review before we * can remove it here too. * Probably it requires once more some rewrites to get it working * properly :( - Martijn */ QString addressBookField(Plugin *p, const QString &app, const QString &key) const; /** * @brief set an address book field * * @see also @ref addressBookField() * @param p The Plugin by which uses this field * @param app The application ID in the KABC database * @param key The name of the address book field to set * @param value The value of the address book field to set */ void setAddressBookField(Plugin *p, const QString &app, const QString &key, const QString &value); /** * @brief The status message of metacontact */ StatusMessage statusMessage() const; public Q_SLOTS: /** * @brief Send a file to this metacontact * * This is the MetaContact level slot for sending files. It may be called through the * "Send File" entry in the GUI, or over DCOP. If the function is called through the GUI, * no parameters are sent and they assume default values. This slot calls the slotSendFile * with identical params of the highest ranked contact capable of sending files (if any) * * @param sourceURL The actual QUrl of the file you are sending * @param altFileName (Optional) An alternate name for the file - what the receiver will see * @param fileSize (Optional) Size of the file being sent. Used when sending a nondeterminate * file size (such as over a socket) * */ void sendFile(const QUrl &sourceURL, const QString &altFileName = QString(), unsigned long fileSize = 0L); /** * Serialize this metaContact * This causes each Kopete::Protocol subclass to serialise its contacts' data into the metacontact's plugin data */ void serialize(); Q_SIGNALS: /** * One of the subcontacts' idle status has changed. As with online status, * this can occur without the metacontact changing idle state */ void contactIdleStateChanged(Kopete::Contact *contact); /** * Status title or message has changed */ void statusMessageChanged(Kopete::MetaContact *metaContact); public Q_SLOTS: /** * @brief Move a contact from one group to another. */ void moveToGroup(Kopete::Group *from, Kopete::Group *to); /** * @brief Remove a contact from one group */ void removeFromGroup(Kopete::Group *from); /** * @brief Add a contact to another group. */ void addToGroup(Kopete::Group *to); /** * @brief Set if this is a temporary contact. (see @ref isTemporary) * * @param b if the contact is or not temporary * @param group if the contact was temporary and b is false, then the contact will be moved to this group. * if group is null, it will be moved to top-level */ void setTemporary(bool b = true, Kopete::Group *group = 0L); /** * @brief Contact another user. * * Depending on the config settings, call sendMessage() or * startChat() * * returns the Contact that was chosen as the preferred */ Contact *execute(); /** * @brief Send a single message, classic ICQ style. * * The actual sending is done by the Contact, but the meta contact * does the GUI side of things. * This is a slot to allow being called easily from e.g. a GUI. * * returns the Contact that was chosen as the preferred */ Contact *sendMessage(); /** * @brief Start a chat in a persistent chat window * * Like sendMessage, but this time a full-blown chat will be opened. * Most protocols can't distinguish between the two and are either * completely session based like MSN or completely message based like * ICQ the only true difference is the GUI shown to the user. * * returns the Contact that was chosen as the preferred */ Contact *startChat(); /** * When all the plugins are loaded, set the Contact Source. */ void slotAllPluginsLoaded(); /** * If a plugin is loaded, maybe data about this plugin are already cached in the metacontact */ void slotPluginLoaded(Kopete::Plugin *plugin); /** * If a protocol is loaded, deserialize cached data */ void slotProtocolLoaded(Kopete::Protocol *p); Q_SIGNALS: /** * @brief The MetaContact online status changed */ void onlineStatusChanged(Kopete::MetaContact *contact, Kopete::OnlineStatus::StatusType status); /** * @brief A contact's online status changed * * this signal differs from @ref onlineStatusChanged because a contact can * change his status without changing MetaContact status. It is mainly used to update the small icons * in the contact list */ void contactStatusChanged(Kopete::Contact *contact, const Kopete::OnlineStatus &status); /** * @brief The meta contact's display name changed */ void displayNameChanged(const QString &oldName, const QString &newName); /** * @brief The meta contact's photo changed */ void photoChanged(); /** * @brief The contact was moved */ void movedToGroup(Kopete::MetaContact *contact, Kopete::Group *from, Kopete::Group *to); /** * @brief The contact was removed from group */ void removedFromGroup(Kopete::MetaContact *contact, Kopete::Group *group); /** * @brief The contact was added to another group */ void addedToGroup(Kopete::MetaContact *contact, Kopete::Group *to); /** * @brief a contact has been added into this metacontact * * This signal is emitted when a contact is added to this metacontact */ void contactAdded(Kopete::Contact *c); /** * @brief a contact has been removed from this metacontact * * This signal is emitted when a contact is removed from this metacontact */ void contactRemoved(Kopete::Contact *c); /** * Some part of this object's persistent data (as returned by toXML) has changed. */ void persistentDataChanged(); private Q_SLOTS: /** * Update the contact's online status and emit onlineStatusChanged * when appropriate */ void updateOnlineStatus(); /** * One of the child contact's online status changed */ void slotContactStatusChanged(Kopete::Contact *c, const Kopete::OnlineStatus &status, const Kopete::OnlineStatus &oldStatus); /** * One of the child contact's property changed */ void slotPropertyChanged(Kopete::PropertyContainer *contact, const QString &key, const QVariant &oldValue, const QVariant &newValue); void slotContactDisplayNameChanged(const QString &oldName, const QString &newName); /** * A child contact was deleted, remove it from the list, if it's still * there */ void slotContactDestroyed(Kopete::Contact *); /** * Update the KABC Picture when the addressbook is changed. */ void slotUpdateAddressBookPicture(); protected: //QImage photoFromContact( Kopete::Contact *c) const; //QImage photoFromKABC( const QString &id ) const; QImage photoFromCustom() const; //QString nameFromContact( Kopete::Contact *c) const; //QString nameFromKABC( const QString &id ) const; void onlineStatusNotification(Kopete::Contact *c); private: class Private; Private *const d; }; // util functions shared with metacontact property dialog LIBKOPETE_EXPORT QImage photoFromContact(Kopete::Contact *c) /*const*/; LIBKOPETE_EXPORT QImage photoFromKABC(const QString &id) /*const*/; LIBKOPETE_EXPORT QString nameFromContact(Kopete::Contact *c) /*const*/; LIBKOPETE_EXPORT QString nameFromKABC(const QString &id) /*const*/; } //END namespace Kopete #endif // vim: set noet ts=4 sts=4 sw=4: diff --git a/libkopete/kopeteonlinestatus.h b/libkopete/kopeteonlinestatus.h index 761627d19..10a0eba24 100644 --- a/libkopete/kopeteonlinestatus.h +++ b/libkopete/kopeteonlinestatus.h @@ -1,468 +1,468 @@ /* kopeteonlinestatus.h - Kopete Online Status Copyright (c) 2003 by Martijn Klingens Copyright (c) 2003 by Duncan Mac-Vicar Prett Copyright (c) 2003 by Will Stephenson Copyright (c) 2004 by Olivier Goffart Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef kopeteonlinestatus_h #define kopeteonlinestatus_h #include "libkopete_export.h" #include #include -#include -#include +#include +#include #include #include "kopeteonlinestatusmanager.h" class QString; class QPixmap; class QColor; namespace Kopete { class OnlineStatusManager; class Identity; class Protocol; class Account; class Contact; /** * @author Martijn Klingens * @author Will Stephenson (icon generating code) * * OnlineStatus is a class that encapsulates all information about the * various online states that a protocol can be in in a single class. The * online status consists of both a 'global' status as it's known to libkopete * and used for going online or away, which non-protocol plugins can use, * and the 'private' status, which is simply an unsigned int and is only * useful for the actual protocol plugin that uses the status. * * This class is passed around by value, but is refcounted to cut down on the * amount of overhead. All in all it should be more than fast enough for * general use. * * Note that ONLY the constructor can set the data, the object is considered * to be const after creation as there really shouldn't be a need to change * a status' characteristics during runtime! */ class LIBKOPETE_EXPORT OnlineStatus { public: /** * The available global states. It is possible that multiple internal * states map to the same global states. For example ICQ's 'Do not disturb' * is handled just like 'Away' by libkopete. Only ICQ itself makes (and * should make) a distinction. * The order is important and is used in the < or > operator */ enum StatusType { /** * Refers to protocols where state cannot be determined. This * applies to SMS contacts (text messages via mobile phones), * since there's no presence information over SMS, but also * to e.g. MSN contacts that are not on your contact list, * since MSN only allows a user to query online state for * users that are formally on the contact list. Lastly, libkopete * itself uses the Unknown state in @ref MetaContact for * meta contacts that have no child contacts at all. */ Unknown = 0, /** * State where you really cannot be contacted. Although * Kopete doesn't oppose any technical limitations it really * doesn't make sense to have more than one status per protocol * that maps to 'Offline', since you're supposed to be * disconnected from the network in this state. */ Offline = 10, /** * State where the user is not available on the network yet * but trying to get onto. Most useful to yourself contact, because * this state means not visible but with network access */ Connecting = 20, /** * State where you are online but none of your contacts can * see that you're online. Useful for all the protocols that support * being invisible. */ Invisible = 30, /** * Refers to a state where you can be technically reached, but * for one reason or another it is often not useful to do so. * This will be because you are not in front of the computer * or because the client detected you don't interact. */ Away = 40, /** * Means that you have other things to do * and don't want to get involved in messaging ('Busy' or 'Do * not Disturb' for example). */ Busy = 45, /** * Refers to a true online state, i.e. you can be contacted by * others both technically and practically. This also applies * to e.g. ICQ's 'Free for Chat' status. */ Online = 50 }; // note than Unknown is first, because the metacontact algorithm to detect // the metacontact status from the contact status starts from Unknown, and // takes a contact only if its status is greater /** * Reserved internal status values * * Any internal status value > 0x80000000 is reserved for internal * libkopete use. This enumeration lists the currently known values. */ enum ReservedInternalStatus { /** * The account this contact belongs to is offline. Used with * the Unknown StatusType. */ AccountOffline = 0x80000001 }; /** * Constructor. * * Creates an empty OnlineStatus object. Since you cannot change * OnlineStatus objects that are already created other than by their * assignment operator, this constructor is only a convenience method * for use in e.g. class members and local variables. */ OnlineStatus(); /** * Constructor. * * Creates a new OnlineStatus object. All fields are mandatory; there * are no default values. Also, you cannot change the object after creation. * * @param status is the global online status as used by libkopete * @param weight is the 'weight' of this status. The contact list is * sorted by status, and by weight within a status. It's not possible to * 'promote' an Away item to a level above Online, since the status field * always takes precedence. Weight is used when the same status is used * more than once. Weight is also used for picking the most important * 'Away' status for a protocol when going Away. * @param protocol is a pointer to the protocol used. This is used when * comparing two online status objects. * @param internalStatus is the status as used internally by the protocol. * This status is usually a lot more fine-grained than the status as used * by libkopete and should be unique per protocol. * @param overlayIcons is a list of QStrings which are the name of status * icons to be used by the KDE icon loader. (Statuses which don't have icons * to overlay like Online and Offline should use QString() as icon * name ). NOTE if the string is a movie ( *.mng ) it must be the first string in the list. * TODO: KDE4 sort out movies and overlay icons. * @param description is a description in e.g. tooltips. */ OnlineStatus(StatusType status, unsigned weight, Protocol *protocol, unsigned internalStatus, const QStringList &overlayIcons, const QString &description); /** * Constructor. * * @p Creates a new OnlineStatus object and registers it with the @ref Kopete::OnlineStatusManager. * Registration allows you to generate a KActionMenu filled with KActions for changing to this OnlineStatus, * using Kopete::Account::accountMenu(). * * @p Note that weight has an additional significance for registered protocols when used for menu generation. * * All fields are mandatory; there * are no default values. Also, you cannot change the object after creation. * * @param status is the global online status as used by libkopete * @param weight is the 'weight' of this status. The contact list is * sorted by status, and by weight within a status. It's not possible to * 'promote' an Away item to a level above Online, since the status field * always takes precedence. Weight is used when the same status is used * more than once. Weight is also used for picking the most important * 'Away' status for a protocol when going Away. Additionally, Weight determinesis also * @param protocol is a pointer to the protocol used. This is used when * comparing two online status objects. * @param internalStatus is the status as used internally by the protocol. * This status is usually a lot more fine-grained than the status as used * by libkopete and should be unique per protocol. * @param overlayIcon is a string returning the name of the status icon to be * used by the KDE icon loader. (Status whiwh doesn't have icon to overlay like * Online and Offline should use QString() as icon string) * @param description is a description in e.g. tooltips. * @param caption is the text of the action in the menu * @param categories the categories this online status is in * @param options the options of this online status * @see Kopete::OnlineStatusManager for more info about the categories and options parameters * * You can set the status to be in the predefined categories. * Ideally, each category should own one status. * A status may be in several categories, or in none. * There shouldn't be more than one status per protocol per categories. */ OnlineStatus(StatusType status, unsigned weight, Protocol *protocol, unsigned internalStatus, const QStringList &overlayIcon, const QString &description, const QString &caption, OnlineStatusManager::Categories categories = 0x0, OnlineStatusManager::Options options = 0x0); /** * Constructor. * * Creates a libkopete builtin status object. Weight, protocol and internal * status are set to zero, the strings and icons are set to the meta contact * strings. */ OnlineStatus(StatusType status); /* implicit */ /** * Copy constructor. * * Just adds a reference to the refcount. Used to copy around the status * objects with very little overhead. */ OnlineStatus(const OnlineStatus &other); /** * Destructor. */ ~OnlineStatus(); /** * \brief Return the status */ StatusType status() const; /** * \brief Return the internal status */ unsigned internalStatus() const; /** * \brief Return the weight */ unsigned weight() const; /** * \brief Return the list of overlay icons */ QStringList overlayIcons() const; /** * \brief Return the description */ QString description() const; /** * \brief Return the protocol this applies to */ Protocol *protocol() const; /** * \brief Return the text for the action in the menu */ QString caption() const; /** * \brief Return the categories this online status is in * * @see Kopete::OnlineStatusManager for more info about the categories */ OnlineStatusManager::Categories categories() const; /** * \brief Return the options of this online status * * @see Kopete::OnlineStatusManager for more info about the options parameters */ OnlineStatusManager::Options options() const; /** * @return @c true if this a contact with this status is definitely online, * @c false if the contact is Offline, Connecting or Unknown. */ bool isDefinitelyOnline() const; /** * \brief Return a status icon generated for the given Contact * * This will draw an overlay representing the online status * of the contact the OnlineStatus applies to * over the base icon. * A cache is employed to reduce CPU and memory usage. * @param contact is the contact the icon should apply to. */ QIcon iconFor(const Contact *contact) const; /** * \brief Return a status icon generated for the given Contact * \overload * \deprecated Use the one that return a QIcon * @param contact is the contact the icon should apply to. * @param size is the size we the icon should be scaled to */ LIBKOPETE_DEPRECATED QPixmap iconFor(const Contact *contact, int size) const { return iconFor(contact).pixmap(size); } /** * \brief Return the mime source for a status icon generated for the given Contact * * This behaves essentially like the method above, except for that * it returns a mime source string that can be used to render the * image in richtext components and the like. The returned key * is only valid until the cache is cleared for the next time, * so no assumptions should be made about long-time availability * of the referenced data. * @param contact is the contact the icon should apply to. * @param size is the size we the icon should be scaled to - 16 is default and so costs nothing */ QString mimeSourceFor(const Contact *contact, int size = 16) const; /** * \brief Return a status icon generated for the given Account * * This will draw an overlay representing the online status * of the account the OnlineStatus applies to * over the base icon. * A cache is employed to reduce CPU and memory usage. * @param account is the account the icon should apply to. * The account's color causes tinting, if it's plain QColor(), no tinting takes place. * @param size is the size we the icon should be scaled to - 16 is default and so costs nothing */ QIcon iconFor(const Account *account) const; /** * \brief Return a status icon generated for the given Account * \overload * \deprecated Use the varient which return a QIcon * * @param account is the account the icon should apply to. * The account's color causes tinting, if it's plain QColor(), no tinting takes place. * @param size is the size we the icon should be scaled to - 16 is default and so costs nothing */ LIBKOPETE_DEPRECATED QPixmap iconFor(const Account *account, int size) const { return iconFor(account).pixmap(size); } /** * \brief Return the mime source for a status icon generated for the given Account * * This behaves essentially like the method above, except for that * it returns a mime source string that can be used to render the * image in richtext components and the like. The returned key * is only valid until the cache is cleared for the next time, * so no assumptions should be made about long-time availability * of the referenced data. * @param account is the account the icon should apply to. * The account's color causes tinting, if it's plain QColor(), no tinting takes place. * @param size is the size we the icon should be scaled to - 16 is default and so costs nothing */ QString mimeSourceFor(const Account *account, int size = 16) const; /** * \brief Return a previously rendered status icon for a mime source key * * You can access icons with this method that have previously been rendered * using mimeSourceFor(). Note that only a cache lookup will be done, so * if the cache has been invalidated due to a change of icon sets between * requesting the key (thus rendering the icon) and trying to access the * icon by key, an invalid pixmap will be returned. */ QPixmap iconFor(const QString &mimeSource) const; /** * \brief Returns the status icon for the protocol. * * A cache is employed to reduce CPU and memory usage. */ QPixmap protocolIcon(const KIconLoader::StdSizes size) const; /** * \brief Returns the status icon for the protocol. * * A cache is employed to reduce CPU and memory usage. */ LIBKOPETE_DEPRECATED QPixmap protocolIcon() const; /** * Assignment operator */ OnlineStatus &operator=(const OnlineStatus &other); /** * Comparison operator * * Returns true if both the protocol and the internal status are * identical. */ bool operator==(const OnlineStatus &other) const; /** * Comparison operator * * This operator works exactly opposite of @ref operator==() */ bool operator!=(const OnlineStatus &other) const; /** * Comparison operator * * Returns true if the status() of this contact is of higher value than the other * contact or if both statuses are equal and weight() is higher for this contact. */ bool operator>(const OnlineStatus &other) const; /** * Comparison operator * * This operator works exactly opposite of @ref operator>() */ bool operator<(const OnlineStatus &other) const; /** * \brief returns a QString from a StatusType * * Static method to convert a Kopete::OnlineStatus::StatusType to a string to avoid * many issues when saving StatusType to disk */ static QString statusTypeToString(OnlineStatus::StatusType status); /** * \brief returns a StatusType from a QString * * Static method to convert a QString representing a StatusType to a StatusType to avoid * many issues when saving StatusType to disk */ static OnlineStatus::StatusType statusStringToType(const QString &string); private: class Private; QExplicitlySharedDataPointer d; QString mimeSource(const QString &icon, int size, QColor color, bool idle) const; }; } //END namespace Kopete #endif diff --git a/libkopete/kopetepassword.h b/libkopete/kopetepassword.h index 4b15ba73b..acb1b6c84 100644 --- a/libkopete/kopetepassword.h +++ b/libkopete/kopetepassword.h @@ -1,205 +1,205 @@ /* kopetepassword.h - Kopete Password Copyright (c) 2004 by Richard Smith Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETEPASSWORD_H #define KOPETEPASSWORD_H -#include +#include #include #include "libkopete_export.h" namespace KWallet { class Wallet; } class QPixmap; /** @internal */ class KopetePasswordGetRequest; /** @internal */ class KopetePasswordSetRequest; /** @internal */ class KopetePasswordClearRequest; namespace Kopete { /** * @author Richard Smith * * The Kopete::Password object is responsible for storing and retrieving a * password for a plugin or account object. * * If the KWallet is active, passwords will be stored in it, otherwise, they * will be stored in the KConfig, in a slightly mangled form. */ class LIBKOPETE_EXPORT Password : public QObject { Q_OBJECT public: /** * Create a new Kopete::Password object. * * @param configGroup The configuration group to save passwords in. * @param allowBlankPassword If this password is allowed to be blank * @param name The name for this object */ explicit Password(const QString &configGroup, bool allowBlankPassword = false); /** * Create a shallow copy of this object */ Password(const Password &other); ~Password(); /** * Assignment operator for passwords: make this object represent a different password */ Password &operator=(Password &other); /** * Returns the preferred size for images passed to the retrieve and request functions. */ static int preferredImageSize(); /** * @brief Returns whether the password currently stored by this object is known to be incorrect. * This flag gets reset whenever the user enters a new password, and is * expected to be set by the user of this class if it is detected that the * password the user entered is wrong. */ bool isWrong(); /** * Flag the password as being incorrect. * @see isWrong */ void setWrong(bool bWrong = true); /** * Type of password request to perform: * FromConfigOrUser : get the password from the config file, or from the user * if no password in config. * FromUser : always ask the user for a password (ie, if last password was * wrong or you know the password has changed). */ enum PasswordSource { FromConfigOrUser, FromUser }; /** * @brief Start an asynchronous call to get the password. * Causes a password entry dialog to appear if the password is not set. Triggers * a provided slot when done, but not until after this function has returned (you * don't need to worry about reentrancy or nested event loops). * * @param receiver The object to notify when the password request finishes * @param slot The slot on receiver to call at the end of the request. The signature * of this function should be slot( const QString &password ). password will * be the password if successful, or QString() if failed. * @param image The icon to display in the dialog when asking for the password * @param prompt The message to display to the user, asking for a * password. Can be any Qt RichText string. * @param source The source the password is taken from if a wrong or * invalid password is entered or the password could not be found in the wallet */ void request(QObject *receiver, const char *slot, const QPixmap &image, const QString &prompt, PasswordSource source = FromConfigOrUser); /** * @brief Start an asynchronous password request without a prompt * * Starts an asynchronous password request. Does not pop up a password entry dialog * if there is no password. * @see request(QObject*,const char*,const QPixmap&,const QString&,bool,unsigned int) * The password given to the provided slot will be NULL if no password could be retrieved for * some reason, such as the user declining to open the wallet, or no password being found. */ void requestWithoutPrompt(QObject *receiver, const char *slot); /** * @return true if the password is remembered, false otherwise. * * If it returns false, calling @ref request() will * pop up an Enter Password window. */ bool remembered(); /** * @return true if you are allowed to have a blank password */ bool allowBlankPassword(); /** * When a password request succeeds, the password is cached. This function * returns the cached password, if there is one, or QString() if there * is not. */ QString cachedValue(); public Q_SLOTS: /** * Set the password for this account. * @param pass If set to QString(), the password is forgotten unless you * specified to allow blank passwords. Otherwise, sets the password to * this value. * * Note: this function is asynchronous; changes will not be instant. */ void set(const QString &pass = QString()); /** * Unconditionally clears the stored password */ void clear(); private: void readConfig(); void writeConfig(); class Private; Private *d; //TODO: can we rearrange things so these aren't friends? friend class ::KopetePasswordGetRequest; friend class ::KopetePasswordSetRequest; friend class ::KopetePasswordClearRequest; }; } /** * This class is an implementation detail of KopetePassword. * @internal * @see KopetePassword */ class KopetePasswordRequestBase : public QObject { Q_OBJECT public: KopetePasswordRequestBase(QObject *parent) : QObject(parent) { } Q_SIGNALS: void requestFinished(const QString &password); public Q_SLOTS: virtual void walletReceived(KWallet::Wallet *wallet) = 0; virtual void gotPassword(const QString &, bool) = 0; virtual void slotCancelPressed() = 0; }; #endif // vim: set noet ts=4 sts=4 sw=4: diff --git a/libkopete/kopetepluginmanager.h b/libkopete/kopetepluginmanager.h index 397018292..24ba63995 100644 --- a/libkopete/kopetepluginmanager.h +++ b/libkopete/kopetepluginmanager.h @@ -1,248 +1,248 @@ /* kopetepluginmanager.h - Kopete Plugin Loader Copyright (c) 2002-2003 by Duncan Mac-Vicar Prett Copyright (c) 2002-2003 by Martijn Klingens Kopete (c) 2002-2003 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETEPLUGINMANAGER_H #define KOPETEPLUGINMANAGER_H -#include -#include +#include +#include #include "libkopete_export.h" class KPluginInfo; namespace Kopete { class Plugin; class Protocol; typedef QList PluginList; class PluginManagerPrivate; /** * @author Duncan Mac-Vicar Prett * @author Martijn Klingens */ class LIBKOPETE_EXPORT PluginManager : public QObject { friend class PluginManagerPrivate; Q_OBJECT Q_ENUMS(PluginLoadMode) public: /** * Retrieve the plugin loader instance. */ static PluginManager *self(); /** * Returns a list of all available plugins for the given category. * Currently there are two categories, "Plugins" and "Protocols", but * you can add your own categories if you want. * * If you pass an empty string you get the complete list of ALL plugins. * * You can query all information on the plugins through the KPluginInfo * interface. */ QList availablePlugins(const QString &category = QString()) const; /** * Returns a list of all plugins that are actually loaded. * If you omit the category you get all, otherwise it's a filtered list. * See also @ref availablePlugins(). */ PluginList loadedPlugins(const QString &category = QString()) const; /** * @brief Search by plugin name. This is the key used as X-KDE-PluginInfo-Name in * the .desktop file, e.g. "kopete_jabber" * * @return The @ref Kopete::Plugin object found by the search, or a null * pointer if the plugin is not loaded. * * If you want to also load the plugin you can better use @ref loadPlugin, which returns * the pointer to the plugin if it's already loaded. */ Plugin *plugin(const QString &pluginName) const; /** * @return the KPluginInfo for the specified plugin */ KPluginInfo pluginInfo(const Kopete::Plugin *plugin) const; /** * Shuts down the plugin manager on Kopete shutdown, but first * unloads all plugins asynchronously. * * After 3 seconds all plugins should be removed; what's still left * by then is unloaded through a hard delete instead. * * Note that this call also derefs the plugin manager from the event * loop, so do NOT call this method when not terminating Kopete! */ void shutdown(); /** * Enable a plugin. * * This marks a plugin as enabled in the config file, so loadAll() * can pick it up later. * * This method does not actually load a plugin, it only edits the * config file. * * @param name is the name of the plugin as it is listed in the .desktop * file in the X-KDE-Library field. * @param enabled sets whether or not the plugin is enabled * * Returns false when no appropriate plugin can be found. */ bool setPluginEnabled(const QString &name, bool enabled = true); /** * This method check if all the plugins are loaded. * @return true if all the plugins are loaded. */ bool isAllPluginsLoaded() const; /** * Plugin loading mode. Used by @ref loadPlugin(). Code that doesn't want to block * the GUI and/or lot a lot of plugins at once should use asynchronous loading (@c LoadAsync). * The default is synchronous loading (@c LoadSync). */ enum PluginLoadMode { LoadSync, LoadAsync }; public Q_SLOTS: /** * @brief Load a single plugin by plugin name. Returns an existing plugin * if one is already loaded in memory. * * If mode is set to Async, the plugin will be queued and loaded in * the background. This method will return a null pointer. To get * the loaded plugin you can track the @ref pluginLoaded() signal. * * See also @ref plugin(). */ Plugin *loadPlugin(const QString &pluginId, PluginLoadMode mode = LoadSync); /** * @brief Unload the plugin specified by @p pluginName */ bool unloadPlugin(const QString &pluginName); /** * @brief Loads all the enabled plugins. Also used to reread the * config file when the configuration has changed. */ void loadAllPlugins(); Q_SIGNALS: /** * @brief Signals a new plugin has just been loaded. */ void pluginLoaded(Kopete::Plugin *plugin); /** * @brief Signals a plugin has just been unloaded. */ void pluginUnloaded(const QString &pluginName); /** * @brief Signals a new protocol has just been loaded. * @note pluginLoaded is also emitted before this signal */ void protocolLoaded(Kopete::Protocol *protocol); /** * @brief All plugins have been loaded by the plugin manager. * * This signal is emitted exactly ONCE, when the plugin manager has emptied * its plugin queue for the first time. This means that if you call an async * loadPlugin() before loadAllPlugins() this signal is probably emitted after * the initial call completes, unless you are quick enough to fill the queue * before it completes, which is a dangerous race you shouldn't count upon :) * * The signal is delayed one event loop iteration through a singleShot timer, * but that is not guaranteed to be enough for account instantiation. You may * need an additional timer for it in the code if you want to programmatically * act on it. * * If you use the signal for enabling/disabling GUI objects there is little * chance a user is able to activate them in the short while that's remaining, * the slow part of the code is over now and the remaining processing time * is neglectable for the user. */ void allPluginsLoaded(); private Q_SLOTS: /** * @brief Cleans up some references if the plugin is destroyed */ void slotPluginDestroyed(QObject *plugin); /** * shutdown() starts a timer, when it fires we force all plugins * to be unloaded here by deref()-ing the event loop to trigger the plugin * manager's destruction */ void slotShutdownTimeout(); /** * Common entry point to deref() the KApplication. Used both by the clean * shutdown and the timeout condition of slotShutdownTimeout() */ void slotShutdownDone(); /** * Emitted by a Kopete::Plugin when it's ready for unload */ void slotPluginReadyForUnload(); /** * Load a plugin from our queue. Does nothing if the queue is empty. * Schedules itself again if more plugins are pending. */ void slotLoadNextPlugin(); private: /** * @internal * * The internal method for loading plugins. * Called by @ref loadPlugin directly or through the queue for async plugin * loading. */ Plugin *loadPluginInternal(const QString &pluginId); /** * @internal * * Find the KPluginInfo structure by key. Reduces some code duplication. * * Returns a null pointer when no plugin info is found. */ KPluginInfo infoForPluginId(const QString &pluginId) const; PluginManager(); ~PluginManager(); }; } #endif // KOPETEPLUGINMANAGER_H // vim: set noet ts=4 sts=4 sw=4: diff --git a/libkopete/kopeteproperty.h b/libkopete/kopeteproperty.h index d6f099a9b..053d89893 100644 --- a/libkopete/kopeteproperty.h +++ b/libkopete/kopeteproperty.h @@ -1,208 +1,208 @@ /* kopeteproperty.h Kopete::Property class Copyright (c) 2007 by Gustavo Pichorim Boiko Copyright (c) 2004 by Stefan Gehn Copyright (c) 2006 by MichaĂ«l Larouche Kopete (c) 2004-2007 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef _KOPETEPROPERTY_H_ #define _KOPETEPROPERTY_H_ -#include -#include +#include +#include #include "libkopete_export.h" namespace Kopete { /** * @author Stefan Gehn * @author MichaĂ«l Larouche * * The template class for registering properties in Kopete * You need to use this if you want to set properties for a * Kopete::Contact **/ class LIBKOPETE_EXPORT PropertyTmpl { public: enum PropertyOption { NoProperty = 0x0, PersistentProperty = 0x1, RichTextProperty = 0x2, PrivateProperty = 0x4 }; Q_DECLARE_FLAGS(PropertyOptions, PropertyOption) /** * Constructor only used for empty PropertyTmpl objects * * Note: Only useful for the null object **/ PropertyTmpl(); /** * Constructor * @param key internal unique key for this template * @param label a label to show for properties based on this template * @param icon name of the icon to show for properties based on this template * @param options set the options for that property. See PropertyOption enum. **/ PropertyTmpl(const QString &key, const QString &label, const QString &icon = QString(), PropertyOptions options = NoProperty); /** * Copy constructor **/ PropertyTmpl(const PropertyTmpl &other); /** Destructor */ ~PropertyTmpl(); PropertyTmpl &operator=(const PropertyTmpl &other); bool operator==(const PropertyTmpl &other) const; bool operator!=(const PropertyTmpl &other) const; /** * Getter for the unique key. Properties based on this template will be * stored with this key **/ const QString &key() const; /** * Getter for i18ned label **/ const QString &label() const; /** * Getter for icon to show aside or instead of @p label() **/ const QString &icon() const; /** * Return the options for that property. */ PropertyOptions options() const; /** * Returns true if properties based on this template should * be saved across Kopete sessions, false otherwise. **/ bool persistent() const; /** * Returns true if properties based on this template are HTML formatted **/ bool isRichText() const; /** * Returns true if properties based on this template are invisible to the user **/ bool isPrivate() const; /** * An empty template, check for it using isNull() */ static PropertyTmpl null; /** * Returns true if this object is an empty template **/ bool isNull() const; /** * A Map of QString and PropertyTmpl objects, based on QMap **/ typedef QMap Map; private: class Private; Private *d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(PropertyTmpl::PropertyOptions) /** * @author Stefan Gehn * * A data container for whatever information Kopete or any of its * plugins want to store for a Kopete::Contact **/ class LIBKOPETE_EXPORT Property { public: /** * Constructor only used for empty Property objects * * Note: you cannot set a label or value later on! **/ Property(); /** * @param tmpl The contact property template this property is based on * @param value The value this Property holds **/ Property(const PropertyTmpl &tmpl, const QVariant &value); /** * Copy constructor **/ Property(const Property &other); /** Destructor **/ ~Property(); Property &operator=(const Property &other); /** * Getter for this properties template **/ const PropertyTmpl &tmpl() const; /** * Getter for this properties value **/ const QVariant &value() const; /** * The null, i.e. empty, Property */ static Property null; /** * Returns true if this object is an empty Property (i.e. it holds no * value), false otherwise. **/ bool isNull() const; /** * Returns true if this property is HTML formatted **/ bool isRichText() const; /** * A map of key,Property items **/ typedef QMap Map; private: class Private; Private *const d; }; } // END namespace Kopete #endif //_KOPETEPROPERTY_H_ diff --git a/libkopete/kopetepropertycontainer.h b/libkopete/kopetepropertycontainer.h index 824cd7ba1..72d78ac79 100644 --- a/libkopete/kopetepropertycontainer.h +++ b/libkopete/kopetepropertycontainer.h @@ -1,121 +1,121 @@ /* kopetepropertycontainer.h - Kopete Property Container Copyright (c) 2007 by Gustavo Pichorim Boiko Copyright (c) 2002-2004 by Duncan Mac-Vicar Prett Copyright (c) 2002-2003 by Martijn Klingens Copyright (c) 2002-2004 by Olivier Goffart Kopete (c) 2002-2007 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETEPROPERTYCONTAINER_H #define KOPETEPROPERTYCONTAINER_H -#include +#include #include "kopeteglobal.h" #include "libkopete_export.h" #include "libkopete_debug.h" namespace Kopete { /** * @author Gustavo Pichorim Boiko * * This class abstracts a generic contact * Use it for inserting contacts in the contact list for example. */ class LIBKOPETE_EXPORT PropertyContainer : public QObject { Q_OBJECT public: /** * @brief A container for properties. * * This class provides an interface for reading and writing properties. */ PropertyContainer(QObject *parent = nullptr); virtual ~PropertyContainer(); /** * @brief Serialize the persistent properties for storage in the contact list. * * Does the same as @ref serialize() does but for KopeteContactProperties * set in this contact with their persistency flag turned on. * In contrary to @ref serialize() this does not need to be reimplemented. * */ void serializeProperties(QMap &serializedData) const; /** * @brief Deserialize the contacts persistent properties */ void deserializeProperties(const QMap &serializedData); /** * @return A QStringList containing all property keys **/ QStringList properties() const; /** * Check for existence of a certain property stored * using "key". * \param key the property to check for **/ bool hasProperty(const QString &key) const; /** * \brief Get the value of a property with key "key". * * If you don't know the type of the returned QVariant, you will need * to check for it. * \return the value of the property **/ const Kopete::Property &property(const QString &key) const; const Kopete::Property &property(const Kopete::PropertyTmpl &tmpl) const; /** * \brief Add or Set a property for this contact. * * @param tmpl The template this property is based on, key, label etc. are * taken from this one * @param value The value to store * * \note Setting a NULL value or an empty QString castable value * removes the property if it already existed. * Don't abuse this for property-removal, instead use * @ref removeProperty() if you want to remove on purpose. * The Removal is done to clean up the list of properties and to purge them * from UI. **/ void setProperty(const Kopete::PropertyTmpl &tmpl, const QVariant &value); /** * \brief Remove a property if it exists * * @param tmpl the template this property is based on **/ void removeProperty(const Kopete::PropertyTmpl &tmpl); Q_SIGNALS: void propertyChanged(Kopete::PropertyContainer *container, const QString &key, const QVariant &oldValue, const QVariant &newValue); private: class Private; Private *const d; }; } //END namespace Kopete #endif diff --git a/libkopete/kopeteprotocol.h b/libkopete/kopeteprotocol.h index 38a50fa43..edeb092f4 100644 --- a/libkopete/kopeteprotocol.h +++ b/libkopete/kopeteprotocol.h @@ -1,310 +1,310 @@ /* kopeteprotocol.h - Kopete Protocol Copyright (c) 2002 by Duncan Mac-Vicar Prett Copyright (c) 2002-2003 by Martijn Klingens Copyright (c) 2002-2005 by Olivier Goffart Copyright (c) 2007 by MichaĂ«l Larouche Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETEPROTOCOL_H #define KOPETEPROTOCOL_H -#include +#include #include "kopeteplugin.h" #include "kopeteonlinestatus.h" #include "libkopete_debug.h" class KopeteEditAccountWidget; class AddContactPage; class KJob; #include "libkopete_export.h" namespace Kopete { class Contact; class MetaContact; class Account; /*namespace UI { class EditAccountWidget; class AddContactPage; }*/ /** * @brief base class of every protocol. * * A protocol is just a particular case of Plugin * * Protocol is an abstract class, you need to reimplement createNewAccount, * createAddContactPage, createEditAccountWidget * * * @author Duncan Mac-Vicar Prett * @author Martijn Klingens * @author Olivier Goffart */ class LIBKOPETE_EXPORT Protocol : public Plugin { Q_OBJECT public: /** * @todo Ideally, the destructor should be protected. but we need it public to allow QPtrList */ virtual ~Protocol(); /** * @brief Create an empty Account * * This method is called during the loading of the config file. * @param accountId - the account ID to create the account with. This is usually * the login name of the account * * you don't need to register the account to the AccountManager in this function. * But if you want to use this function don't forget to call @ref AccountManager::registerAccount * * @return The new @ref Account object created by this function */ virtual Account *createNewAccount(const QString &accountId) = 0; /** * @brief Create a new AddContactPage widget to be shown in the Add Contact Wizard. * * @return A new AddContactPage to be shown in the Add Contact Wizard */ virtual AddContactPage *createAddContactWidget(QWidget *parent, Account *account) = 0; /** * @brief Create a new KopeteEditAccountWidget * * @return A new KopeteEditAccountWidget to be shown in the account part of the configurations. * * @param account is the KopeteAccount to edit. If it's 0L, then we create a new account * @param parent The parent of the 'to be returned' widget */ virtual KopeteEditAccountWidget *createEditAccountWidget(Account *account, QWidget *parent) = 0; /** * @brief Available capabilities * * @ref capabilities() returns an ORed list of these, which * the edit widget interperts to determine what buttons to show */ enum Capability { BaseFgColor = 0x1, ///< Setting the bg color of the whole edit widget / message BaseBgColor = 0x2, ///< Setting the fg color of the whole edit widget / message RichFgColor = 0x4, ///< Setting the fg/bg color of text portions individually RichBgColor = 0x8, ///< Setting the fg/bg color of text portions individually BaseFont = 0x10, ///< Setting the font of the whole edit widget / message RichFont = 0x20, ///< Setting the font of text portions individually /// Setting the formatting of the whole edit widget / message BaseUFormatting = 0x40, BaseIFormatting = 0x80, BaseBFormatting = 0x100, /// Setting the formatting of text portions individually RichUFormatting = 0x200, RichIFormatting = 0x400, RichBFormatting = 0x800, Alignment = 0x1000, ///< Setting the alignment of text portions /// Setting the formatting of the whole edit widget / message BaseFormatting = BaseIFormatting | BaseUFormatting | BaseBFormatting, /// Setting the formatting of text portions individually RichFormatting = RichIFormatting | RichUFormatting | RichBFormatting, RichColor = RichBgColor | RichFgColor, BaseColor = BaseBgColor | BaseFgColor, //Shortcut for All of the above - full HTML FullRTF = RichFormatting | Alignment | RichFont | RichFgColor | RichBgColor, CanSendOffline = 0x10000 ///< If it's possible to send offline messages }; Q_DECLARE_FLAGS(Capabilities, Capability) /** * @brief a bitmask of the capabilities of this protocol * @sa @ref setCapabilities */ Capabilities capabilities() const; /** * @brief true if account can add own contact into a contact list */ bool canAddMyself() const; /** * @brief Returns the status used for contacts when accounts of this protocol are offline */ Kopete::OnlineStatus accountOfflineStatus() const; protected: /** * @brief Constructor for Protocol * * @param instance The protocol's instance, every plugin needs to have a KAboutData of its own * @param parent The protocol's parent object * @param name The protocol's name */ Protocol(QObject *parent, bool canAddMyself = false); /** * @brief Sets the capabilities of this protcol. * * The subclass contructor is a good place for calling it. * @sa @ref capabilities() */ void setCapabilities(Capabilities); public: /** * Reimplemented from Kopete::Plugin. * * This method disconnects all accounts and deletes them, after which it * will emit readyForUnload. * * Note that this is an asynchronous operation that may take some time * with active chats. It's no longer immediate as it used to be in * Kopete 0.7.x and before. This also means that you can do a clean * shutdown. * @note The method is not private to allow subclasses to reimplement * it even more, but if you need to do this please explain why * on the list first. It might make more sense to add another * virtual for protocols that's called instead, but for now I * actually think protocols don't need their own implementation * at all, so I left out the necessary hooks on purpose. * - Martijn */ void aboutToUnload() Q_DECL_OVERRIDE; private Q_SLOTS: /** * @internal * The account changed online status. Used while unloading the protocol. */ void slotAccountOnlineStatusChanged(Kopete::Contact *self); /** * @internal * The account is destroyed. When it's the last account we emit the * readyForUnload signal. Used while unloading the protocol. */ void slotAccountDestroyed(); public: /** * @brief Deserialize the plugin data for a meta contact. * * This method splits up the data into the independent Kopete::Contact objects * and calls @ref deserializeContact() for each contact. * * Note that you can still reimplement this method if you prefer, but you are * strongly recommended to use this version of the method instead, unless you * want to do _VERY_ special things with the data... * * @todo we probably should think to another way to save the contacltist. */ void deserialize(MetaContact *metaContact, const QMap &serializedData) Q_DECL_OVERRIDE; /** * @brief Deserialize the plugin data for a meta contact's contacts. */ virtual void deserializeContactList(MetaContact *metaContact, const QList< QMap > &dataList); /** * @brief Deserialize a single contact. * * This method is called by @ref deserialize() for each separate contact, * so you don't need to add your own hooks for multiple contacts in a single * meta contact yourself. @p serializedData and @p addressBookData will be * the data the contact provided in Kopete::Contact::serialize. * * The default implementation does nothing. * * @return The contact created from the data * @sa Contact::serialize * * @todo we probably should think to another way to save the contacltist. */ virtual Contact *deserializeContact(MetaContact *metaContact, const QMap &serializedData, const QMap &addressBookData); /** * @brief Factory method to create a protocol Task * * Protocols Task are tasks needed for executing specific * commands for the given protocol. This method creates the * required task for the given task type. * * If a task type is not available in the protocol, just return * a null pointer, like the default implementation. * * Example of a implementation of createProtocolTask() * @code KJob* JabberProtocol::createProtocolTask(const QString &taskType) { if( taskType == QLatin1String("DeleteContactTask") ) { return new JabberDeleteContactTask(); } if( taskType == QLatin1String("AddContactTask") ) { return new JabberAddContactTask(); } return 0; } * @endcode * * @param taskType a task type as a string. Check each task for name. */ virtual KJob *createProtocolTask(const QString &taskType); /** * Check whether a password is valid for this protocol. The default implementation * validates every password * @param password The password to check */ virtual bool validatePassword(const QString &password) const; public: /** * Serialize meta contact into the metacontact's plugin data * Call serialize() for all contained contacts for this protocol. * @internal * it's public because for example, Contact::setMetaContact uses it. * @todo we probably should think to another way to save the contacltist. */ void serialize(Kopete::MetaContact *metaContact); private: class Private; Private *const d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(Protocol::Capabilities) } //END namespace kopete #endif diff --git a/libkopete/kopetestatusitems.cpp b/libkopete/kopetestatusitems.cpp index 739cba1fc..a278fb131 100644 --- a/libkopete/kopetestatusitems.cpp +++ b/libkopete/kopetestatusitems.cpp @@ -1,143 +1,143 @@ /* kopetestatusitems.cpp - Kopete Status Items Copyright (c) 2008 by Roman Jarosz Kopete (c) 2008 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "kopetestatusitems.h" -#include +#include namespace Kopete { namespace Status { StatusItem::StatusItem() : QObject() , mParentItem(0) { mUid = QUuid::createUuid().toString(); } StatusItem::StatusItem(const QString &uid) : mParentItem(0) { mUid = uid; } void StatusItem::setCategory(OnlineStatusManager::Categories category) { mCategory = category; emit changed(); } void StatusItem::setTitle(const QString &title) { mTitle = title; emit changed(); } StatusGroup *StatusItem::parentGroup() const { return qobject_cast(parent()); } int StatusItem::index() const { if (parent()) { return parentGroup()->indexOf(const_cast(this)); } return 0; } /****************************************************/ /****************************************************/ StatusGroup::StatusGroup() : StatusItem() { } StatusGroup::StatusGroup(const QString &uid) : StatusItem(uid) { } void StatusGroup::insertChild(int i, StatusItem *item) { item->setParent(this); connect(item, SIGNAL(destroyed(QObject *)), this, SLOT(childDestroyed(QObject *))); mChildItems.insert(i, item); emit childInserted(i, item); } void StatusGroup::appendChild(Kopete::Status::StatusItem *item) { insertChild(mChildItems.size(), item); } void StatusGroup::removeChild(Kopete::Status::StatusItem *item) { item->setParent(0); disconnect(item, 0, this, 0); mChildItems.removeAll(item); emit childRemoved(item); } StatusItem *StatusGroup::copy() const { StatusGroup *newGroup = new StatusGroup(uid()); newGroup->setTitle(title()); newGroup->setCategory(category()); foreach (StatusItem *item, mChildItems) { newGroup->appendChild(item->copy()); } return newGroup; } void StatusGroup::childDestroyed(QObject *object) { StatusItem *item = static_cast(object); mChildItems.removeAll(item); emit childRemoved(item); } /****************************************************/ /****************************************************/ Status::Status() : StatusItem() { } Status::Status(const QString &uid) : StatusItem(uid) { } void Status::setMessage(const QString &message) { mMessage = message; emit changed(); } StatusItem *Status::copy() const { Status *newStatus = new Status(uid()); newStatus->setTitle(title()); newStatus->setCategory(category()); newStatus->setMessage(message()); return newStatus; } } } diff --git a/libkopete/kopetestatusitems.h b/libkopete/kopetestatusitems.h index e0a9aa89f..082fabbc6 100644 --- a/libkopete/kopetestatusitems.h +++ b/libkopete/kopetestatusitems.h @@ -1,298 +1,298 @@ /* kopetestatusitems.h - Kopete Status Items Copyright (c) 2008 by Roman Jarosz Kopete (c) 2008 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETESTATUSITEMS_H #define KOPETESTATUSITEMS_H -#include -#include -#include +#include +#include +#include #include "libkopete_export.h" #include "kopeteonlinestatusmanager.h" namespace Kopete { namespace Status { class StatusGroup; /** * StatusItem is a base class for all status items. The items store * values that are needed to build status menu. * * The items are stored in StatusManager. * * IdentityManager is a singleton, you may uses it with @ref IdentityManager::self() * *@author Roman Jarosz */ class LIBKOPETE_EXPORT StatusItem : public QObject { Q_OBJECT public: /** * StatusItem constructor **/ StatusItem(); StatusItem(const QString &uid); /** * Sets category **/ void setCategory(OnlineStatusManager::Categories category); /** * Returns category **/ OnlineStatusManager::Categories category() const { return mCategory; } /** * Sets title **/ void setTitle(const QString &title); /** * Returns title **/ QString title() const { return mTitle; } /** * Returns unique identifier **/ QString uid() const { return mUid; } /** * Returns true if StatusItem is group **/ virtual bool isGroup() const = 0; /** * Returns number of childes **/ virtual int childCount() const = 0; /** * Returns a StatusItem at given @p index or 0 if there is no item at given @p index **/ virtual StatusItem *child(int /*index*/) const = 0; /** * Returns index of this Item in parent group **/ int index() const; /** * Returns StatusGroup this Item belongs to **/ StatusGroup *parentGroup() const; /** * Creates a copy of StatusItem * * @note this copies also uid so it should only be used when we know * that the original or copy object will be destroyed **/ virtual StatusItem *copy() const = 0; Q_SIGNALS: /** * This signal is emitted whenever the item's content changes **/ void changed(); private: OnlineStatusManager::Categories mCategory; QString mTitle; QString mUid; StatusGroup *mParentItem; Q_DISABLE_COPY(StatusItem) }; /** * StatusGroup represents a group that can contain other StatusItems * *@author Roman Jarosz */ class LIBKOPETE_EXPORT StatusGroup : public StatusItem { Q_OBJECT public: /** * StatusGroup constructor **/ StatusGroup(); StatusGroup(const QString &uid); /** * Returns true if StatusItem is group * @note for StatusGroup it always returns true; **/ bool isGroup() const Q_DECL_OVERRIDE { return true; } /** * Returns number of childes **/ int childCount() const Q_DECL_OVERRIDE { return mChildItems.count(); } /** * Returns a StatusItem at given @p index or 0 if there is no item at given @p index **/ StatusItem *child(int index) const Q_DECL_OVERRIDE { return mChildItems.value(index, 0); } /** * Returns list of all childes **/ QList childList() const { return mChildItems; } /** * Returns index for given StatusItem **/ int indexOf(StatusItem *child) const { return mChildItems.indexOf(child); } /** * Inserts @p child at given @p index **/ void insertChild(int index, StatusItem *child); /** * Inserts @p child at the end **/ void appendChild(Kopete::Status::StatusItem *child); /** * Removes @p child **/ void removeChild(Kopete::Status::StatusItem *child); /** * Creates a copy of this object * * @note this copies also uid so it should only be used when we know * that the original or copy object will be destroyed **/ StatusItem *copy() const Q_DECL_OVERRIDE; Q_SIGNALS: /** * This signal is emitted after new child was inserted is inserted at position @p index **/ void childInserted(int index, Kopete::Status::StatusItem *child); /** * This signal is emitted after child was removed **/ void childRemoved(Kopete::Status::StatusItem *child); private Q_SLOTS: void childDestroyed(QObject *object); private: QList mChildItems; }; /** * Status represents a status which has title, message and category. * Values from this class are used to create status action with which user can change status. * *@author Roman Jarosz */ class LIBKOPETE_EXPORT Status : public StatusItem { Q_OBJECT public: /** * Status constructor **/ Status(); Status(const QString &uid); /** * Returns true if the item is group * @note for Status it always returns false; **/ bool isGroup() const Q_DECL_OVERRIDE { return false; } /** * Returns number of childes * @note for Status it always returns 0; **/ int childCount() const Q_DECL_OVERRIDE { return 0; } /** * Returns the item at given @p index or 0 if there is no item at given @p index * @note for Status it always returns 0; **/ StatusItem *child(int) const Q_DECL_OVERRIDE { return 0; } /** * Set message **/ void setMessage(const QString &message); /** * Returns message **/ QString message() const { return mMessage; } /** * Creates a copy of this object * * @note this copies also uid so it should only be used when we know * that the original or copy object will be destroyed **/ StatusItem *copy() const Q_DECL_OVERRIDE; private: QString mMessage; }; } } #endif diff --git a/libkopete/kopetestatusmanager.h b/libkopete/kopetestatusmanager.h index 3596d48f9..0bf95bcb3 100644 --- a/libkopete/kopetestatusmanager.h +++ b/libkopete/kopetestatusmanager.h @@ -1,175 +1,175 @@ /* kopetestatusmanager.h - Kopete Status Manager Copyright (c) 2008 by Roman Jarosz Kopete (c) 2008 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETESTATUSMANAGER_H #define KOPETESTATUSMANAGER_H -#include +#include #include "libkopete_export.h" #include "kopetestatusmessage.h" class QDomElement; namespace Kopete { class Account; class OnlineStatus; namespace Status { class StatusGroup; class StatusItem; } /** * StatusManager manages status items that are used to build status menu. * It also stores current status message and sets auto away status. * * StatusManager is a singleton, you may uses it with @ref StatusManager::self() * * @author Roman Jarosz */ class LIBKOPETE_EXPORT StatusManager : public QObject { Q_OBJECT public: /** * Get the only instance of StatusManager * @return StatusManager single instance */ static StatusManager *self(); ~StatusManager(); /** * Save status data tree into XML file */ void saveXML(); /** * Load status data tree into XML file */ void loadXML(); /** * Set new status data tree */ void setRootGroup(Status::StatusGroup *rootGroup); /** * Get current status data tree */ Status::StatusGroup *getRootGroup() const; /** * Copy current status data tree */ Status::StatusGroup *copyRootGroup() const; /** * Find status item for given uid */ const Status::StatusItem *itemForUid(const QString &uid) const; /** * Convert status item to XML structure * * @note it's public because it's also used for drag&drop */ static QDomElement storeStatusItem(const Status::StatusItem *item); /** * Restore status item from XML structure * * @note it's public because it's also used for drag&drop */ static Status::StatusItem *parseStatusItem(QDomElement element); /** * Remember current global status */ void setGlobalStatus(uint category, const Kopete::StatusMessage &statusMessage = Kopete::StatusMessage()); /** * Remember current global status message */ void setGlobalStatusMessage(const Kopete::StatusMessage &statusMessage = Kopete::StatusMessage()); /** * Get current global status message */ Kopete::StatusMessage globalStatusMessage() const; /** * Get current global status category */ uint globalStatusCategory() const; /** * Returns true if auto away status was set */ bool autoAway(); /** * Returns true if global away status was set */ bool globalAway(); public Q_SLOTS: /** * Undo auto away */ void setActive(); /** * Confirm with the user, then set auto away */ void askAndSetActive(); /** * Set all online account to auto away status */ void setAutoAway(); Q_SIGNALS: /** * This signal is emitted when root item of status data tree has changed. */ void changed(); /** * This signal is emitted when global status has changed. */ void globalStatusChanged(); private Q_SLOTS: void accountUnregistered(const Kopete::Account *account); void checkIdleTimer(); void loadSettings(); void loadBehaviorSettings(); private: StatusManager(); void updateUidHash(Status::StatusItem *item); Status::StatusGroup *defaultStatuses() const; static StatusManager *instance; class Private; Private *const d; }; } #endif diff --git a/libkopete/kopetestatusmessage.h b/libkopete/kopetestatusmessage.h index a90501566..32c5c66f5 100644 --- a/libkopete/kopetestatusmessage.h +++ b/libkopete/kopetestatusmessage.h @@ -1,142 +1,142 @@ /* kopetestatusmessage.h - Describle a status message and it's metadata. Copyright (c) 2006 by MichaĂ«l Larouche Kopete (c) 2002-2006 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef KOPETESTATUSMESSAGE_H #define KOPETESTATUSMESSAGE_H -#include +#include #include #include "libkopete_export.h" namespace Kopete { /** * @brief This class encapsulate a status message. * A status message to today(as 2006) standards is more than a simple text. * It can be used to show the current listening song, current playing game, show our mood etc.. * So this class allows to add metadata to the status message where protocols will be able to use properly. * * @code * // Create a new status message. * Kopete::StatusMessage message; * message.setMessage( QString("Writing APIDOX") ); * message.addMetaData( "musicPlayer", "amaroK" ); * message.addMetaData( "artist", "Liquid Tension Experiment" ); * message.addMetaData( "title", "Acid Rain" ); * message.addMetaData( "album", "Liquid Tension Experiment 2" ); * * account->setStatusMessage(message); * @endcode * This class is implicit shared. * @author MichaĂ«l Larouche */ class LIBKOPETE_EXPORT StatusMessage { public: /** * Create a empty status message. */ StatusMessage(); /** * Create a new status message with the specified status message. * This constructor is not explicit so it's allow implicit QString * conversation to this class. * @param statusMessage the status message. */ StatusMessage(const QString &statusMessage); /* implicit */ /** * Create a new status message with the specified status message and title. * @param statusTitle the status title. * @param statusMessage the status message. */ StatusMessage(const QString &statusTitle, const QString &statusMessage); /** * StatusMessage copy constructor. * Very cheap because the class is implicit shared. */ StatusMessage(const StatusMessage ©); /** * StatusMessage destructor */ ~StatusMessage(); /** * StatusMessage copy-assignment operator. * Very cheap because the class is implicit shared. */ StatusMessage &operator=(const StatusMessage &other); /** * Verify if the status message is empty. * @return true if the status message is empty. */ bool isEmpty() const; /** * Add a metadata to the status message. * @param key Key to identity the metadata. * @param value Value for the metadata. */ void addMetaData(const QString &key, const QVariant &value); /** * Add a hash of metadata to the status message. * If a key already exists, it gets replaced (it doesn't use QHash::unite).; * @param otherHash The hash to add. */ void addMetaData(const QHash &otherHash); /** * Check if the status message has the specified metadata. * @param key Key of the metadata. * @return true if the metadata is present. */ bool hasMetaData(const QString &key) const; /** * Retrieve the specified metadata. * @param key Key of the metadata * @return The medata value */ QVariant metaData(const QString &key) const; /** * Set a new status message. * @param message New status message. */ void setMessage(const QString &message); /** * Return the current status message. * @return The current status message. */ QString message() const; /** * Set a new status title. * @param title New status title. */ void setTitle(const QString &title); /** * Return the current status title. * @return The current status title. */ QString title() const; private: class Private; QExplicitlySharedDataPointer d; }; } #endif diff --git a/libkopete/kopetetransfermanager.cpp b/libkopete/kopetetransfermanager.cpp index cc296c847..04f355051 100644 --- a/libkopete/kopetetransfermanager.cpp +++ b/libkopete/kopetetransfermanager.cpp @@ -1,613 +1,613 @@ /* kopetetransfermanager.cpp Copyright (c) 2002-2003 by Nick Betcher Copyright (c) 2002-2003 by Richard Smith Copyright (c) 2008 by Roman Jarosz Kopete (c) 2002-2008 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "kopetetransfermanager.h" #include -#include +#include #include #include #include #include #include #include #include #include #include #include #include "kopetemetacontact.h" #include "kopetecontact.h" #include "kopetemessage.h" #include "kopetechatsession.h" #include "kopeteuiglobal.h" /*************************** * Kopete::FileTransferInfo * ***************************/ Kopete::FileTransferInfo::FileTransferInfo() { mId = 0; mContact = 0; mSize = 0; mSaveToDirectory = false; } Kopete::FileTransferInfo::FileTransferInfo(Kopete::Contact *contact, const QStringList &files, const unsigned long size, const QString &recipient, KopeteTransferDirection di, const unsigned int id, QString internalId, const QPixmap &preview, bool saveToDirectory) { mContact = contact; mFiles = files; mId = id; mSize = size; mRecipient = recipient; m_intId = internalId; mDirection = di; mPreview = preview; mSaveToDirectory = saveToDirectory; } /*************************** * Kopete::Transfer * ***************************/ static const int TransferRateWindowLength = 10; static const int TransferRateTimerDelay = 1000; class Kopete::Transfer::Private { public: Private(const Kopete::FileTransferInfo &ftInfo) : info(ftInfo) , transferRateTimer(0) { memset(transferRate, 0, sizeof(transferRate)); } FileTransferInfo info; QUrl target; //if ft has one file then localUrl is file otherwise it's directory QUrl localUrl; int transferRate[TransferRateWindowLength]; int transferRateTimer; }; Kopete::Transfer::Transfer(const Kopete::FileTransferInfo &kfti, const QString &localFile, bool showProgressInfo) : KIO::Job() , d(new Private(kfti)) { connect(kfti.contact(), SIGNAL(destroyed(QObject *)), this, SLOT(slotContactDestroyed())); this->setUiDelegate(new KIO::JobUiDelegate()); if (showProgressInfo) { KIO::getJobTracker()->registerJob(this); } QUrl targ; targ.setPath(localFile); d->localUrl = targ; init(targ, showProgressInfo); } Kopete::Transfer::Transfer(const Kopete::FileTransferInfo &kfti, bool showProgressInfo) : KIO::Job() , d(new Private(kfti)) { connect(kfti.contact(), SIGNAL(destroyed(QObject *)), this, SLOT(slotContactDestroyed())); this->setUiDelegate(new KIO::JobUiDelegate()); if (showProgressInfo) { KIO::getJobTracker()->registerJob(this); } // TODO: use mInfo.url().fileName() after move to protocol-aware filetransfers QUrl targ; targ.setPath(d->info.file()); init(displayURL(d->info.contact(), targ.fileName()), showProgressInfo); } void Kopete::Transfer::init(const QUrl &target, bool showProgressInfo) { d->target = target; setTotalAmount(KJob::Files, d->info.files().count()); setTotalAmount(KJob::Bytes, d->info.size()); if (showProgressInfo) { emitCopying(sourceURL(), destinationURL()); } connect(this, SIGNAL(result(KJob *)), SLOT(slotResultEmitted())); ui()->setAutoErrorHandlingEnabled(false); } Kopete::Transfer::~Transfer() { stopTransferRateTimer(); delete d; } const Kopete::FileTransferInfo &Kopete::Transfer::info() const { return d->info; } QUrl Kopete::Transfer::displayURL(const Kopete::Contact *contact, const QString &file) { QUrl url; url.setScheme(QStringLiteral("kopete")); QString host; if (!contact) { host = QStringLiteral("unknown origin"); } else if (contact->metaContact()) { host = contact->metaContact()->displayName(); } else { host = contact->contactId(); } url.setHost(host); // url.setPath( contact->protocol()->displayName() ); url = url.adjusted(QUrl::RemoveFilename); url.setPath(url.path() + file); return url; } void Kopete::Transfer::slotNextFile(const QString &sourceFile, const QString &destinationFile) { QUrl src; QUrl dest; //qCDebug(LIBKOPETE_LOG) << "source: " << sourceFile << " destination: " << destinationFile; if (d->info.direction() == Kopete::FileTransferInfo::Incoming) { QUrl url(sourceFile); src = displayURL(d->info.contact(), url.fileName()); dest.setPath(destinationFile); } else { src.setPath(sourceFile); QUrl url(destinationFile); dest = displayURL(d->info.contact(), url.fileName()); } setProcessedAmount(KJob::Files, processedAmount(KJob::Files) + 1); emit description(this, i18n("Copying"), qMakePair(i18n("Source"), src.toDisplayString()), qMakePair(i18n("Destination"), dest.toDisplayString())); } // TODO: add possibility of network file transfers; // call mInfo->url() not file() QUrl Kopete::Transfer::sourceURL() { if (d->info.direction() == Kopete::FileTransferInfo::Incoming) { return displayURL(d->info.contact(), d->info.file()); } else { QUrl url; url.setPath(d->info.file()); return url; } } QUrl Kopete::Transfer::destinationURL() { return d->target; } void Kopete::Transfer::emitCopying(const QUrl &src, const QUrl &dest) { emit description(this, i18n("Copying"), qMakePair(i18n("Source"), src.toDisplayString()), qMakePair(i18n("Destination"), dest.toDisplayString())); } void Kopete::Transfer::slotProcessed(unsigned int bytes) { if (!d->transferRateTimer) { d->transferRateTimer = startTimer(TransferRateTimerDelay); } d->transferRate[0] += (bytes - processedAmount(KJob::Bytes)); setProcessedAmount(KJob::Bytes, bytes); emitPercent(bytes, d->info.size()); } void Kopete::Transfer::timerEvent(QTimerEvent *event) { if (event->timerId() != d->transferRateTimer) { KIO::Job::timerEvent(event); return; } // Calculate average transferRate qint64 bytesPerSecond = 0; for (int i = 0; i < TransferRateWindowLength; ++i) { bytesPerSecond += d->transferRate[i]; } bytesPerSecond /= qint64(TransferRateWindowLength); for (int i = TransferRateWindowLength - 2; i >= 0; --i) { d->transferRate[i + 1] = d->transferRate[i]; } d->transferRate[0] = 0; emitSpeed(bytesPerSecond); // Stop the timer if there is no activity. if (bytesPerSecond == 0) { stopTransferRateTimer(); } } void Kopete::Transfer::slotComplete() { stopTransferRateTimer(); setError(KJob::NoError); showHtmlMessage(i18n("File transfer %1 completed.", fileForMessage())); emitResult(); } void Kopete::Transfer::slotError(int error, const QString &errorText) { stopTransferRateTimer(); setError(error); setErrorText(errorText); showHtmlMessage(i18n("File transfer %1 failed.", fileForMessage())); emitResult(); } void Kopete::Transfer::slotResultEmitted() { if (error() == KIO::ERR_USER_CANCELED) { stopTransferRateTimer(); showHtmlMessage(i18n("You cancelled file transfer %1", fileForMessage())); emit transferCanceled(); } } void Kopete::Transfer::slotContactDestroyed() { setError(KIO::ERR_USER_CANCELED); emitResult(); } void Kopete::Transfer::slotCancelled() { stopTransferRateTimer(); // If cancel button was pressed suppress notification because it was show already in slotResultEmitted() if (error() != KIO::ERR_USER_CANCELED) { showHtmlMessage(i18n("File transfer %1 cancelled.", fileForMessage())); emitResult(); } } bool Kopete::Transfer::showMessage(QString text) const { Kopete::ChatSession *cs = chatSession(); if (!cs) { return false; } Kopete::Message msg; msg.setPlainBody(text); cs->appendMessage(msg); return true; } bool Kopete::Transfer::showHtmlMessage(QString text) const { Kopete::ChatSession *cs = chatSession(); if (!cs) { return false; } Kopete::Message msg; msg.setHtmlBody(text); cs->appendMessage(msg); return true; } QString Kopete::Transfer::fileForMessage() const { if (d->info.direction() == Kopete::FileTransferInfo::Incoming) { return QStringLiteral("
%2").arg(d->localUrl.url(), d->localUrl.toLocalFile().toHtmlEscaped()); } else { return d->info.file().toHtmlEscaped(); } } void Kopete::Transfer::stopTransferRateTimer() { if (d->transferRateTimer) { killTimer(d->transferRateTimer); d->transferRateTimer = 0; } } Kopete::ChatSession *Kopete::Transfer::chatSession() const { Kopete::Contact *c = d->info.contact(); return (c) ? c->manager() : 0; } /*************************** * Kopete::TransferManager * ***************************/ Kopete::TransferManager *Kopete::TransferManager::transferManager() { static TransferManager s(nullptr); return &s; } Kopete::TransferManager::TransferManager(QObject *parent) : QObject(parent) { } Kopete::Transfer *Kopete::TransferManager::addTransfer(Kopete::Contact *contact, const QString &file, const unsigned long size, const QString &recipient, Kopete::FileTransferInfo::KopeteTransferDirection di) { return addTransfer(contact, QStringList(file), size, recipient, di); } Kopete::Transfer *Kopete::TransferManager::addTransfer(Kopete::Contact *contact, const QStringList &files, const unsigned long size, const QString &recipient, Kopete::FileTransferInfo::KopeteTransferDirection di) { // Use message id to make file transfer id unique because we already use it for incoming file transfer. uint id = Kopete::Message::nextId(); Kopete::FileTransferInfo info(contact, files, size, recipient, di, id); Kopete::Transfer *trans = new Kopete::Transfer(info); connect(trans, SIGNAL(result(KJob *)), this, SLOT(slotComplete(KJob *))); mTransfersMap.insert(id, trans); return trans; } unsigned int Kopete::TransferManager::askIncomingTransfer(Kopete::Contact *contact, const QString &file, const unsigned long size, const QString &description, QString internalId, const QPixmap &preview) { return askIncomingTransfer(contact, QStringList(file), size, description, internalId, preview); } unsigned int Kopete::TransferManager::askIncomingTransfer(Kopete::Contact *contact, const QStringList &files, const unsigned long size, const QString &description, QString internalId, const QPixmap &preview) { Kopete::ChatSession *cs = contact->manager(Kopete::Contact::CanCreate); if (!cs) { return 0; } const QString dn = contact->metaContact() ? contact->metaContact()->displayName() : contact->contactId(); QString msgFileName; foreach (const QString &file, files) { QString trimmedFile = file.trimmed(); if (!trimmedFile.isEmpty()) { msgFileName += trimmedFile + ", "; } } // Remove ", " from end if (msgFileName.size() >= 2) { msgFileName = msgFileName.left(msgFileName.size() - 2); } Kopete::Message msg(contact, cs->myself()); msg.setType(Kopete::Message::TypeFileTransferRequest); msg.setDirection(Kopete::Message::Inbound); msg.setPlainBody(description); msg.setFileName(msgFileName); msg.setFileSize(size); msg.setFilePreview(preview); Kopete::FileTransferInfo info(contact, files, size, dn, Kopete::FileTransferInfo::Incoming, msg.id(), internalId, preview, (files.count() > 1)); mTransferRequestInfoMap.insert(msg.id(), info); cs->appendMessage(msg); return msg.id(); } void Kopete::TransferManager::saveIncomingTransfer(unsigned int id) { Kopete::FileTransferInfo info = mTransferRequestInfoMap.value(id); if (!info.isValid()) { return; } KConfigGroup cg(KSharedConfig::openConfig(), "File Transfer"); const QString defaultPath = cg.readEntry("defaultPath", QDir::homePath()); QUrl url = QString(defaultPath + QLatin1String("/") + info.file()); if (info.saveToDirectory()) { url = getSaveDir(url); } else { url = getSaveFile(url); } if (url.isEmpty()) { return; } if (!url.isValid()) { emit askIncomingDone(id); emit refused(info); mTransferRequestInfoMap.remove(id); return; } const QString directory = (info.saveToDirectory()) ? url.toLocalFile() : url.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path(); if (!directory.isEmpty()) { cg.writeEntry("defaultPath", directory); } Kopete::Transfer *trans = new Kopete::Transfer(info, url.toLocalFile()); connect(trans, SIGNAL(result(KJob *)), this, SLOT(slotComplete(KJob *))); mTransfersMap.insert(info.transferId(), trans); emit askIncomingDone(id); emit accepted(trans, url.toLocalFile()); mTransferRequestInfoMap.remove(id); } void Kopete::TransferManager::cancelIncomingTransfer(unsigned int id) { Kopete::FileTransferInfo info = mTransferRequestInfoMap.value(id); if (!info.isValid()) { return; } emit askIncomingDone(id); emit refused(info); mTransferRequestInfoMap.remove(id); } void Kopete::TransferManager::slotComplete(KJob *job) { Kopete::Transfer *transfer = dynamic_cast(job); if (!transfer) { return; } emit done(transfer); for (QMap::Iterator it = mTransfersMap.begin(); it != mTransfersMap.end(); ++it) { if (it.value() == transfer) { removeTransfer(it.key()); break; } } } void Kopete::TransferManager::sendFile(const QUrl &file, const QString &fname, unsigned long sz, bool mustBeLocal, QObject *sendTo, const char *slot) { QUrl url = file; QString filename; unsigned int size = 0; //If the file location is null, then get it from a file open dialog if (!url.isValid()) { url = QFileDialog::getOpenFileUrl(0l, i18n("Kopete File Transfer"), QString(), QStringLiteral("*")); } else { filename = fname; size = sz; } if (filename.isEmpty()) { filename = url.fileName(); } if (size == 0) { KFileItem finfo(KFileItem::Unknown, KFileItem::Unknown, url); size = (unsigned long)finfo.size(); } if (!url.isEmpty()) { if (mustBeLocal && !url.isLocalFile()) { KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(), KMessageBox::Sorry, i18n("Sorry, sending files which are not stored locally is not yet supported by this protocol.\n" "Please copy this file to your computer and try again.")); } else { connect(this, SIGNAL(sendFile(QUrl,QString,uint)), sendTo, slot); emit sendFile(url, filename, size); disconnect(this, SIGNAL(sendFile(QUrl,QString,uint)), sendTo, slot); } } } void Kopete::TransferManager::removeTransfer(unsigned int id) { mTransfersMap.remove(id); //we don't need to delete the job, the job get deleted itself } QUrl Kopete::TransferManager::getSaveFile(const QUrl &startDir) const { QUrl url = startDir; for (;;) { url = QFileDialog::getSaveFileUrl(nullptr, i18n("File Transfer"), url, QStringLiteral("*")); if (!url.isValid()) { return url; } if (!url.isLocalFile()) { KMessageBox::messageBox(0, KMessageBox::Sorry, i18n("You must provide a valid local filename")); continue; } QFileInfo fileInfo(url.toLocalFile()); if (fileInfo.exists()) { if (!fileInfo.isWritable()) { KMessageBox::messageBox(0, KMessageBox::Sorry, i18n("You do not have permission to write to selected file")); continue; } int ret = KMessageBox::warningContinueCancel(0, i18n("The file '%1' already exists.\nDo you want to overwrite it ?", url.toLocalFile()), i18n("Overwrite File"), KStandardGuiItem::save()); if (ret == KMessageBox::Cancel) { continue; } } else { QFileInfo dirInfo(url.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path()); if (!dirInfo.isDir() || !dirInfo.exists()) { KMessageBox::messageBox(0, KMessageBox::Sorry, i18n("The directory %1 does not exist", dirInfo.fileName())); continue; } else if (!dirInfo.isWritable()) { KMessageBox::messageBox(0, KMessageBox::Sorry, i18n("You do not have permission to write to selected directory")); continue; } } break; } return url; } QUrl Kopete::TransferManager::getSaveDir(const QUrl &startDir) const { QUrl url = startDir; for (;;) { url = QFileDialog::getExistingDirectoryUrl(nullptr,i18n("File Transfer"), url); if (!url.isValid()) { return url; } if (!url.isLocalFile()) { KMessageBox::messageBox(0, KMessageBox::Sorry, i18n("You must provide a valid local directory")); continue; } QFileInfo dirInfo(url.toLocalFile()); if (!dirInfo.isDir() || !dirInfo.exists()) { KMessageBox::messageBox(0, KMessageBox::Sorry, i18n("The directory %1 does not exist", dirInfo.filePath())); continue; } else if (!dirInfo.isWritable()) { KMessageBox::messageBox(0, KMessageBox::Sorry, i18n("You do not have permission to write to selected directory")); continue; } break; } return url; } diff --git a/libkopete/private/kopeteviewmanager.h b/libkopete/private/kopeteviewmanager.h index 82199654d..3c7f65d39 100644 --- a/libkopete/private/kopeteviewmanager.h +++ b/libkopete/private/kopeteviewmanager.h @@ -1,111 +1,111 @@ /* kopeteviewmanager.h - View Manager Copyright (c) 2003 by Jason Keirstead Kopete (c) 2002-2003 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef KOPETEVIEWMANAGER_H #define KOPETEVIEWMANAGER_H -#include +#include #include "kopetemessage.h" #include "libkopete_export.h" namespace Kopete { class ChatSession; class MessageEvent; } class KopeteView; struct KopeteViewManagerPrivate; /** * Relates an actual chat to the means used to view it. */ class LIBKOPETE_EXPORT KopeteViewManager : public QObject { Q_OBJECT public: /** * This is a singleton class. Call this method to get a pointer to * a KopeteViewManager. */ static KopeteViewManager *viewManager(); KopeteViewManager(); ~KopeteViewManager(); /** * Return a view for the supplied Kopete::ChatSession. If one already * exists, it will be returned, otherwise, a new view is created. * @param session The Kopete::ChatSession we are viewing. * @param requestedPlugin Specifies the view plugin to use. */ KopeteView *view(Kopete::ChatSession *session, const QString &requestedPlugin = QString()); /** * Provide access to the list of KopeteChatWindow the class maintains. */ KopeteView *activeView() const; /** * Returns unread messages for the given contact * @param contact Message sender */ QList pendingMessages(Kopete::Contact *contact); public Q_SLOTS: /** * Make a view visible and on top. * @param manager The originating Kopete::ChatSession. * @param isOutboundMessage Whether the message is inbound or outbound. * * @todo Document @p activate */ void readMessages(Kopete::ChatSession *manager, bool isOutboundMessage, bool activate = false); /** * Called when a new message has been appended to the given * Kopete::ChatSession. Procures a view for the message, and generates * any notification events or displays messages, as appropriate. * @param msg The new message * @param manager The originating Kopete::ChatSession */ void messageAppended(Kopete::Message &msg, Kopete::ChatSession *manager); void nextEvent(); private Q_SLOTS: void slotViewDestroyed(KopeteView *); void slotChatSessionDestroyed(Kopete::ChatSession *); public Q_SLOTS: /** * An event has been deleted. */ void slotEventDeleted(Kopete::MessageEvent *); void slotPrefsChanged(); void slotViewActivated(KopeteView *); private: void createNotification(Kopete::Message &msg, const QString &unchangedMessage, Kopete::ChatSession *session, Kopete::MessageEvent *event, QWidget *viewWidget, bool isActiveWindow, bool isViewOnCurrentDesktop); KopeteViewManagerPrivate *d; static KopeteViewManager *s_viewManager; }; #endif diff --git a/libkopete/tasks/kopetecontacttaskbase.cpp b/libkopete/tasks/kopetecontacttaskbase.cpp index ac3fb9dc8..e296c267c 100644 --- a/libkopete/tasks/kopetecontacttaskbase.cpp +++ b/libkopete/tasks/kopetecontacttaskbase.cpp @@ -1,63 +1,63 @@ /* kopetecontacttaskbase.cpp - Base task for all contact tasks Copyright (c) 2007 by MichaĂ«l Larouche Kopete (c) 2002-2007 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "kopetecontacttaskbase.h" // Qt includes -#include +#include // KDE includes #include "libkopete_debug.h" // Kopete includes #include #include namespace Kopete { class ContactTaskBase::Private { public: QPointer contact; }; ContactTaskBase::ContactTaskBase(QObject *parent) : Kopete::Task(parent) , d(new Private) { } ContactTaskBase::~ContactTaskBase() { delete d; } void ContactTaskBase::setContact(Kopete::Contact *contact) { d->contact = contact; // Add the children tasks for DeleteContactTask from the rptocol KJob *subTask = d->contact->protocol()->createProtocolTask(taskType()); if (subTask) { qCDebug(LIBKOPETE_LOG) << "Adding protocol subtask for " << taskType(); addSubTask(subTask); } } Kopete::Contact *ContactTaskBase::contact() { return d->contact; } } // end namespace Kopete diff --git a/plugins/history/historydialog.h b/plugins/history/historydialog.h index 52e7f8bd3..0a5d519e9 100644 --- a/plugins/history/historydialog.h +++ b/plugins/history/historydialog.h @@ -1,177 +1,177 @@ /* kopetehistorydialog.h - Kopete History Dialog Copyright (c) 2002 by Richard Stellingwerff Copyright (c) 2004 by Stefan Gehn Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef HISTORYDIALOG_H #define HISTORYDIALOG_H -#include +#include #include #include #include #include "kopetemessage.h" class QTreeWidgetItem; class QAction; class KHTMLView; class KHTMLPart; namespace KParts { class BrowserArguments; class OpenUrlArguments; class Part; } namespace Kopete { class MetaContact; } namespace Kopete { class Contact; } namespace Kopete { class XSLT; } namespace Ui { class HistoryViewer; } class DMPair { public: DMPair() { md = QDate(0, 0, 0); mc = 0; } DMPair(QDate d, Kopete::MetaContact *c) { md = d; mc = c; } QDate date() const { return md; } Kopete::MetaContact *metaContact() const { return mc; } bool operator==(const DMPair p1) const { return p1.date() == this->date() && p1.metaContact() == this->metaContact(); } private: QDate md; Kopete::MetaContact *mc; }; /** * @author Richard Stellingwerff * @author Stefan Gehn */ class HistoryDialog : public QDialog { Q_OBJECT public: explicit HistoryDialog(Kopete::MetaContact *mc, QWidget *parent = nullptr); ~HistoryDialog(); /** * Calls init(Kopete::Contact *c) for each subcontact of the metacontact */ signals: void closing(); private slots: void slotOpenURLRequest(const QUrl &url, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &); // Called when a date is selected in the treeview void dateSelected(QTreeWidgetItem *); void slotSearch(); void searchFinished(); void slotSearchTextChanged(const QString &txt); // To enable/disable search button void slotContactChanged(int index); void slotFilterChanged(int index); void init(); void slotLoadDays(); void slotRightClick(const QString &url, const QPoint &point); void slotCopy(); void slotCopyURL(); void slotImportHistory(); private: enum Disabled { Prev = 1, Next = 2 }; void refreshEnabled(/*Disabled*/ uint disabled); void initProgressBar(const QString &text, int nbSteps); void doneProgressBar(); void init(Kopete::MetaContact *mc); void init(Kopete::Contact *c); /** * Show the messages in the HTML View */ void setMessages(QList m); void treeWidgetHideElements(bool s); QString highlight(const QString &htmlText, const QString &highlight) const; QString escapeXMLText(const QString &text) const; /** * We show history dialog to look at the log for a metacontact. Here is this metacontact. */ Kopete::MetaContact *mMetaContact; QList mMetaContactList; // History View KHTMLView *mHtmlView; KHTMLPart *mHtmlPart; Ui::HistoryViewer *mMainWidget; Kopete::XSLT *mXsltParser; struct Init { QList dateMCList; // mc for MetaContact } mInit; bool mSearching; QAction *mCopyAct; QAction *mCopyURLAct; QString mURL; }; #endif diff --git a/plugins/history/historyguiclient.h b/plugins/history/historyguiclient.h index 0f61081b5..2b718301e 100644 --- a/plugins/history/historyguiclient.h +++ b/plugins/history/historyguiclient.h @@ -1,66 +1,66 @@ /* historyguiclient.h Copyright (c) 2003 by Olivier Goffart Kopete (c) 2003 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef HISTORYGUICLIENT_H #define HISTORYGUICLIENT_H -#include +#include #include class QAction; namespace Kopete { class ChatSession; } class HistoryLogger; /** *@author Olivier Goffart */ class HistoryGUIClient : public QObject, public KXMLGUIClient { Q_OBJECT public: HistoryGUIClient(Kopete::ChatSession *parent = 0); ~HistoryGUIClient(); HistoryLogger *logger() const { return m_logger; } private slots: void slotPrevious(); void slotLast(); void slotNext(); void slotQuote(); void slotViewHistory(); private: HistoryLogger *m_logger; Kopete::ChatSession *m_manager; //bool m_autoChatWindow; //int m_nbAutoChatWindow; //unsigned int m_nbChatWindow; QAction *actionPrev; QAction *actionNext; QAction *actionLast; }; #endif diff --git a/plugins/history/historyimport.h b/plugins/history/historyimport.h index 5f4074f32..b9132b03e 100644 --- a/plugins/history/historyimport.h +++ b/plugins/history/historyimport.h @@ -1,158 +1,158 @@ /* historylogger.cpp Copyright (c) 2008 by Timo Schluessler Kopete (c) 2008 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef HISTORYIMPORT_H #define HISTORYIMPORT_H -#include +#include #include #include class QDir; class QStandardItem; class QTreeView; class QTextEdit; class QCheckBox; class QModelIndex; class QFile; namespace Kopete { class Contact; } /** * @author Timo Schluessler */ class HistoryImport : public KDialog { Q_OBJECT public: HistoryImport(QWidget *parent); ~HistoryImport(); private: /** * Used for internal storage of a message. */ struct Message { bool incoming; QString text; QDateTime timestamp; }; /** * Holds the messages sent and received between two specified contacts. */ struct Log { Kopete::Contact *me; Kopete::Contact *other; QList messages; /** * Comparison between the Message lists is not necessary because we need this operator * only in displayLog() to get the index of this log in logs. */ bool operator==(const struct Log &cmp) { if (cmp.me == me && cmp.other == other /* && other.messages == messages*/) { return true; } else { return false; } } }; /** * Parses @param file and appends the found messages to @param log. */ void parsePidginXml(QFile &file, struct Log *log, QDate date); /** * Parses @param file and appends the found messages to @param log. */ void parsePidginTxt(QFile &file, struct Log *log, QDate date); /** * Inserts @param log into treeView and prepares to display it when clicking on it. */ void displayLog(struct Log *log); /** * Looks up if an item with @param text exists already as child of @param parent. * If not, it creates one. */ QStandardItem *findItem(const QString &text, QStandardItem *parent); /** * @return the number of files found in @param depth th subdir of @param dir. */ int countLogs(QDir dir, int depth); /** * Tries to extract the time from @param string using formats specified in timeFormats. * @param ref is used when @param string doesn't contain a date or to adjust a found date. * @param ref is taken from the filename of the log. */ QDateTime extractTime(const QString &string, QDate ref); QStringList timeFormats; QTreeView *treeView; QTextEdit *display; /** * Used for adding details to the details widget. */ QTextCursor detailsCursor; /** * Enables/disables auto search for log dirs. */ QCheckBox *selectByHand; /** * Contains all already parsed logs. */ QList logs; /** * Used for mapping nickname to account. See isNickIncoming(). */ QHash knownNicks; /** * To warn the user when importing logs twice */ bool pidginImported; int amount; bool cancel; private slots: /** * Starts parsing history from pidgin. * Default path is ~/.purple/logs. */ void importPidgin(void); void save(void); void itemClicked(const QModelIndex &index); }; #endif diff --git a/plugins/history/historylogger.h b/plugins/history/historylogger.h index ad6089610..54d355d71 100644 --- a/plugins/history/historylogger.h +++ b/plugins/history/historylogger.h @@ -1,224 +1,224 @@ /* historylogger.cpp Copyright (c) 2003-2004 by Olivier Goffart Kopete (c) 2003-2004 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef HISTORYLOGGER_H #define HISTORYLOGGER_H -#include -#include -#include -#include +#include +#include +#include +#include class QDate; class QTimer; namespace Kopete { class Message; } namespace Kopete { class Contact; } namespace Kopete { class MetaContact; } /** * One hinstance of this class is opened for every Kopete::ChatSession, * or for the history dialog * * @author Olivier Goffart */ class HistoryLogger : public QObject { Q_OBJECT public: /** * - Chronological: messages are read from the first to the last, in the time order * - AntiChronological: messages are read from the last to the first, in the time reversed order */ enum Sens { Default, Chronological, AntiChronological }; /** * Constructor, takes the contact, and the color of messages */ explicit HistoryLogger(Kopete::MetaContact *m, QObject *parent = 0); explicit HistoryLogger(Kopete::Contact *c, QObject *parent = 0); ~HistoryLogger(); /** * return or setif yes or no outgoing message are hidden (and not parsed) */ bool hideOutgoing() const { return m_hideOutgoing; } void setHideOutgoing(bool); /** * set a searching filter * @param filter is the string to search * @param caseSensitive say if the case is important * @param isRegExp say if the filter is a QRegExp, or a simle string */ void setFilter(const QString &filter, bool caseSensitive = false, bool isRegExp = false); QString filter() const; bool filterCaseSensitive() const; bool filterRegExp() const; //---------------------------------- /** * log a message * @param c add a presision to the contact to use, if null, autodetect. */ void appendMessage(const Kopete::Message &msg, const Kopete::Contact *c = 0L); /** * read @param lines message from the current position * from Kopete::Contact @param c in the given @param sens */ QList readMessages(int lines, const Kopete::Contact *c = 0, Sens sens = Default, bool reverseOrder = false, bool colorize = true); /** * Same as the following, but for one date. I did'nt reuse the above function * because its structure is really different. * Read all the messages for the given @param date */ QList readMessages(QDate date); /** * The pausition is set to the last message */ void setPositionToLast(); /** * The position is set to the first message */ void setPositionToFirst(); /** * Set the current month (in number of month since the actual month) */ void setCurrentMonth(int month); /** * @return The list of the days for which there is a log for m_metaContact for month of * @param date (don't care of the day) */ QList getDaysForMonth(QDate date); /** * Get the filename of the xml file which contains the history from the * contact in the specified @param date. Specify @param date in order to get the filename for * the given date.year() date.month(). */ static QString getFileName(const Kopete::Contact *, QDate date); private: bool m_hideOutgoing; Qt::CaseSensitivity m_filterCaseSensitive; bool m_filterRegExp; QString m_filter; /* *contais all QDomDocument, for a KC, for a specified Month */ QMap > m_documents; /** * Contains the current message. * in fact, this is the next, still not showed */ QMap m_currentElements; /** * Get the document, open it is @param canload is true, contain is set to false if the document * is not already contained */ QDomDocument getDocument(const Kopete::Contact *c, unsigned int month, bool canLoad = true, bool *contain = 0L); QDomDocument getDocument(const Kopete::Contact *c, const QDate date, bool canLoad = true, bool *contain = 0L); /** * look over files to get the last month for this contact */ unsigned int getFirstMonth(const Kopete::Contact *c); unsigned int getFirstMonth(); /* * the current month */ unsigned int m_currentMonth; /* * the cached getFirstMonth */ int m_cachedMonth; /* * the metacontact we are using */ Kopete::MetaContact *m_metaContact; /* * keep the old position in memory, so if we change the sens, we can begin here */ QMap m_oldElements; unsigned int m_oldMonth; Sens m_oldSens; /** * the timer used to save the file */ QTimer *m_saveTimer; QDomDocument m_toSaveDocument; QString m_toSaveFileName; unsigned int m_saveTimerTime; //time in ms between each save /** * workaround for the 31 midnight bug. * it contains the number of the current month. */ int m_realMonth; /* * FIXME: * WORKAROUND * due to a bug in QT, i have to keep the document element in the memory to * prevent crashes */ QList workaround; private slots: /** * the metacontact has been deleted */ void slotMCDeleted(); /** * save the current month's document on the disk. * connected to the m_saveTimer signal */ void saveToDisk(); }; #endif diff --git a/plugins/history/historyplugin.h b/plugins/history/historyplugin.h index 975117c87..4d2867fce 100644 --- a/plugins/history/historyplugin.h +++ b/plugins/history/historyplugin.h @@ -1,104 +1,104 @@ /* historyplugin.h Copyright (c) 2003-2005 by Olivier Goffart (c) 2003 by Stefan Gehn Kopete (c) 2003-2004 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef HISTORYPLUGIN_H #define HISTORYPLUGIN_H -#include -#include +#include +#include #include "kopeteplugin.h" #include "kopetemessagehandler.h" class KopeteView; namespace Kopete { class ChatSession; } class HistoryGUIClient; class HistoryPlugin; /** * @author Richard Smith */ class HistoryMessageLogger : public Kopete::MessageHandler { QPointer history; public: HistoryMessageLogger(HistoryPlugin *history) : history(history) { } void handleMessage(Kopete::MessageEvent *event); }; class HistoryMessageLoggerFactory : public Kopete::MessageHandlerFactory { HistoryPlugin *history; public: explicit HistoryMessageLoggerFactory(HistoryPlugin *history) : history(history) { } Kopete::MessageHandler *create(Kopete::ChatSession * /*manager*/, Kopete::Message::MessageDirection direction) { if (direction != Kopete::Message::Inbound) { return 0; } return new HistoryMessageLogger(history); } int filterPosition(Kopete::ChatSession *, Kopete::Message::MessageDirection) { return Kopete::MessageHandlerFactory::InStageToSent+5; } }; /** * @author Olivier Goffart */ class HistoryPlugin : public Kopete::Plugin { Q_OBJECT public: HistoryPlugin(QObject *parent, const QVariantList &args); ~HistoryPlugin(); /** * convert the Kopete 0.6 / 0.5 history to the new format */ static void convertOldHistory(); /** * return true if an old history has been detected, and no new ones */ static bool detectOldHistory(); void messageDisplayed(const Kopete::Message &msg); private slots: void slotViewCreated(KopeteView *); void slotViewHistory(); void slotKMMClosed(Kopete::ChatSession *); void slotSettingsChanged(); private: HistoryMessageLoggerFactory m_loggerFactory; QMap m_loggers; Kopete::Message m_lastmessage; }; #endif diff --git a/plugins/history2/history2dialog.h b/plugins/history2/history2dialog.h index 82ade2dc3..b12795e25 100644 --- a/plugins/history2/history2dialog.h +++ b/plugins/history2/history2dialog.h @@ -1,173 +1,173 @@ /* kopetehistory2dialog.h - Kopete History2 Dialog Copyright (c) 2002 by Richard Stellingwerff Copyright (c) 2004 by Stefan Gehn Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef HISTORYDIALOG_H #define HISTORYDIALOG_H -#include +#include #include #include #include "kopetemessage.h" class QTreeWidgetItem; class QAction; class KHTMLView; class KHTMLPart; namespace KParts { class BrowserArguments; class OpenUrlArguments; class Part; } namespace Kopete { class MetaContact; } namespace Kopete { class Contact; } namespace Kopete { class XSLT; } namespace Ui { class History2Viewer; } class DMPair { public: DMPair() { md = QDate(0, 0, 0); mc = 0; } DMPair(QDate d, Kopete::MetaContact *c) { md = d; mc = c; } QDate date() const { return md; } Kopete::MetaContact *metaContact() const { return mc; } bool operator==(const DMPair p1) const { return p1.date() == this->date() && p1.metaContact() == this->metaContact(); } private: QDate md; Kopete::MetaContact *mc; }; /** * @author Richard Stellingwerff * @author Stefan Gehn */ class History2Dialog : public KDialog { Q_OBJECT public: explicit History2Dialog(Kopete::MetaContact *mc, QWidget *parent = nullptr); ~History2Dialog(); /** * Calls init(Kopete::Contact *c) for each subcontact of the metacontact */ signals: void closing(); private slots: void slotOpenURLRequest(const KUrl &url, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &); // Called when a date is selected in the treeview void dateSelected(QTreeWidgetItem *); void slotSearch(); void searchFinished(); void slotSearchTextChanged(const QString &txt); // To enable/disable search button void slotContactChanged(int index); void slotFilterChanged(int index); void init(QString s); void slotRightClick(const QString &url, const QPoint &point); void slotCopy(); void slotCopyURL(); void slotImportHistory2(); private: enum Disabled { Prev = 1, Next = 2 }; void refreshEnabled(/*Disabled*/ uint disabled); void initProgressBar(const QString &text, int nbSteps); void doneProgressBar(); /** * Show the messages in the HTML View */ void setMessages(QList m); void treeWidgetHideElements(bool s); QString highlight(const QString &htmlText, const QString &highlight) const; QString escapeXMLText(const QString &text) const; /** * We show history2 dialog to look at the log for a metacontact. Here is this metacontact. */ Kopete::MetaContact *mMetaContact; QList mMetaContactList; // History2 View KHTMLView *mHtmlView; KHTMLPart *mHtmlPart; Ui::History2Viewer *mMainWidget; Kopete::XSLT *mXsltParser; struct Init { QList dateMCList; // mc for MetaContact } mInit; bool mSearching; QAction *mCopyAct; QAction *mCopyURLAct; QString mURL; }; #endif diff --git a/plugins/history2/history2guiclient.h b/plugins/history2/history2guiclient.h index bcad6fa8c..eae5c1278 100644 --- a/plugins/history2/history2guiclient.h +++ b/plugins/history2/history2guiclient.h @@ -1,62 +1,62 @@ /* history2guiclient.h Copyright (c) 2003 by Olivier Goffart Kopete (c) 2003 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef HISTORYGUICLIENT_H #define HISTORYGUICLIENT_H -#include +#include #include class QAction; namespace Kopete { class ChatSession; } /** *@author Olivier Goffart */ class History2GUIClient : public QObject, public KXMLGUIClient { Q_OBJECT public: History2GUIClient(Kopete::ChatSession *parent = 0); ~History2GUIClient(); private slots: void slotPrevious(); void slotLast(); void slotNext(); void slotQuote(); void slotViewHistory2(); private: Kopete::ChatSession *m_manager; //bool m_autoChatWindow; //int m_nbAutoChatWindow; //unsigned int m_nbChatWindow; QAction *actionPrev; QAction *actionNext; QAction *actionLast; int offset; }; #endif diff --git a/plugins/history2/history2import.h b/plugins/history2/history2import.h index cd404ba7c..b99d80e68 100644 --- a/plugins/history2/history2import.h +++ b/plugins/history2/history2import.h @@ -1,156 +1,156 @@ /* history2logger.cpp Copyright (c) 2008 by Timo Schluessler Kopete (c) 2008 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef HISTORYIMPORT_H #define HISTORYIMPORT_H -#include +#include #include #include class QDir; class QStandardItem; class QTreeView; class QTextEdit; class QCheckBox; class QModelIndex; class QFile; namespace Kopete { class Contact; class Message; } /** * @author Timo Schluessler */ class History2Import : public KDialog { Q_OBJECT public: History2Import(QWidget *parent); ~History2Import(); private: /** * Used for internal storage of a message. */ struct Message { bool incoming; QString text; QDateTime timestamp; }; /** * Holds the messages sent and received between two specified contacts. */ struct Log { Kopete::Contact *me; Kopete::Contact *other; QList messages; }; /** * Parses @param file and appends the found messages to @param log. */ void parsePidginXml(QFile &file, struct Log *log, QDate date); /** * Parses @param file and appends the found messages to @param log. */ void parsePidginTxt(QFile &file, struct Log *log, QDate date); QString getKopeteHistory2FileName(const Kopete::Contact *c, QDate date); void readKopeteMessages(QString protocol, QString account, QString file, struct Log *log); /** * Inserts @param log into treeView and prepares to display it when clicking on it. */ void displayLog(struct Log *log); /** * Looks up if an item with @param text exists already as child of @param parent. * If not, it creates one. */ QStandardItem *findItem(const QString &text, QStandardItem *parent); /** * @return the number of files found in @param depth th subdir of @param dir. */ int countLogs(QDir dir, int depth); /** * Tries to extract the time from @param string using formats specified in timeFormats. * @param ref is used when @param string doesn't contain a date or to adjust a found date. * @param ref is taken from the filename of the log. */ QDateTime extractTime(const QString &string, QDate ref); QStringList timeFormats; QTreeView *treeView; QTextEdit *display; /** * Used for adding details to the details widget. */ QTextCursor detailsCursor; /** * Enables/disables auto search for log dirs. */ QCheckBox *selectByHand; /** * Contains all already parsed logs. */ QList logs; /** * Used for mapping nickname to account. See isNickIncoming(). */ QHash knownNicks; QList cache; Kopete::Contact *cacheContact; /** * To warn the user when importing logs twice */ bool pidginImported; int amount; bool cancel; private slots: /** * Starts parsing history2 from pidgin. * Default path is ~/.purple/logs. */ void importPidgin(void); void importKopete(); void save(void); void itemClicked(const QModelIndex &index); }; #endif diff --git a/plugins/history2/history2logger.h b/plugins/history2/history2logger.h index d43195351..f18af5903 100644 --- a/plugins/history2/history2logger.h +++ b/plugins/history2/history2logger.h @@ -1,118 +1,118 @@ /* history2logger.cpp Copyright (c) 2003-2004 by Olivier Goffart Kopete (c) 2003-2004 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef HISTORYLOGGER_H #define HISTORYLOGGER_H -#include -#include -#include -#include +#include +#include +#include +#include #include #include class QDate; class DMPair; namespace Kopete { class Message; class Contact; class MetaContact; } /** * One hinstance of this class is opened for every Kopete::ChatSession, * or for the history2 dialog * * @author Olivier Goffart */ class History2Logger : public QObject { Q_OBJECT public: static History2Logger *instance() { static QMutex mutex; if (!m_Instance) { mutex.lock(); if (!m_Instance) { m_Instance = new History2Logger(); } mutex.unlock(); } return m_Instance; } static void drop() { static QMutex mutex; mutex.lock(); delete m_Instance; m_Instance = 0; mutex.unlock(); } /** * @return The list of the days for which there is a log for m_metaContact for month of * @param date (don't care of the day) */ QList getDays(const Kopete::MetaContact *c, QString search = ""); QList getDays(QString search = ""); /** * log a message * @param c add a presision to the contact to use, if null, autodetect. */ void appendMessage(const Kopete::Message &msg, const Kopete::Contact *c = 0L, bool skipDuplicate = false); bool messageExists(const Kopete::Message &msg, const Kopete::Contact *c = 0L); void beginTransaction(); void commitTransaction(); /** * read @param lines message from the current position * from Kopete::Contact @param c in the given @param sens */ QList readMessages(int lines, int offset = 0, const Kopete::MetaContact *c = NULL, bool reverseOrder = true); /** * Same as the following, but for one date. I did'nt reuse the above function * because its structure is really different. * Read all the messages for the given @param date */ QList readMessages(QDate date, const Kopete::MetaContact *c = 0); private: History2Logger(); History2Logger(const History2Logger &); // hide copy constructor History2Logger &operator=(const History2Logger &); // hide assign op ~History2Logger(); static History2Logger *m_Instance; QSqlDatabase m_db; }; #endif diff --git a/plugins/history2/history2plugin.h b/plugins/history2/history2plugin.h index b92a72ddb..4148620d2 100644 --- a/plugins/history2/history2plugin.h +++ b/plugins/history2/history2plugin.h @@ -1,95 +1,95 @@ /* history2plugin.h Copyright (c) 2003-2005 by Olivier Goffart (c) 2003 by Stefan Gehn Kopete (c) 2003-2004 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef HISTORYPLUGIN_H #define HISTORYPLUGIN_H -#include -#include +#include +#include #include "kopeteplugin.h" #include "kopetemessagehandler.h" class KopeteView; namespace Kopete { class ChatSession; } class History2GUIClient; class History2Plugin; /** * @author Richard Smith */ class History2MessageLogger : public Kopete::MessageHandler { QPointer history2; public: History2MessageLogger(History2Plugin *history2) : history2(history2) { } void handleMessage(Kopete::MessageEvent *event); }; class History2MessageLoggerFactory : public Kopete::MessageHandlerFactory { History2Plugin *history2; public: explicit History2MessageLoggerFactory(History2Plugin *history2) : history2(history2) { } Kopete::MessageHandler *create(Kopete::ChatSession * /*manager*/, Kopete::Message::MessageDirection direction) { if (direction != Kopete::Message::Inbound) { return 0; } return new History2MessageLogger(history2); } int filterPosition(Kopete::ChatSession *, Kopete::Message::MessageDirection) { return Kopete::MessageHandlerFactory::InStageToSent+5; } }; /** * @author Olivier Goffart */ class History2Plugin : public Kopete::Plugin { Q_OBJECT public: History2Plugin(QObject *parent, const QStringList &args); ~History2Plugin(); void messageDisplayed(const Kopete::Message &msg); private slots: void slotViewCreated(KopeteView *); void slotViewHistory(); void slotKMMClosed(Kopete::ChatSession *); void slotSettingsChanged(); private: History2MessageLoggerFactory m_loggerFactory; QMap m_loggers; Kopete::Message m_lastmessage; }; #endif diff --git a/plugins/nowlistening/nlamarok.cpp b/plugins/nowlistening/nlamarok.cpp index 3c54d7095..60247c3cb 100644 --- a/plugins/nowlistening/nlamarok.cpp +++ b/plugins/nowlistening/nlamarok.cpp @@ -1,124 +1,124 @@ /* nlamarok.cpp Kopete Now Listening To plugin Copyright (c) 2002,2003,2004 by Will Stephenson Kopete Copyright (c) 2002,2003,2004 by the Kopete developers Purpose: This class abstracts the interface to amaroK by implementing NLMediaPlayer ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #include "nlamarok.h" #include -#include +#include #include "nlmediaplayer.h" // from kvirc mpris interface struct MPRISPlayerStatus { int Play; int Random; int RepeatCurrent; int RepeatPlaylist; }; Q_DECLARE_METATYPE(MPRISPlayerStatus) QDBusArgument &operator<<(QDBusArgument &argument, const MPRISPlayerStatus &status) { argument.beginStructure(); argument << status.Play << status.Random << status.RepeatCurrent << status.RepeatPlaylist; argument.endStructure(); return argument; } const QDBusArgument &operator>>(const QDBusArgument &argument, MPRISPlayerStatus &status) { argument.beginStructure(); argument >> status.Play >> status.Random >> status.RepeatCurrent >> status.RepeatPlaylist; argument.endStructure(); return argument; } NLamaroK::NLamaroK() : NLMediaPlayer() { m_type = Audio; m_name = "amaroK"; m_client = new QDBusInterface("org.mpris.amarok", "/Player", "org.freedesktop.MediaPlayer"); qDBusRegisterMetaType(); } NLamaroK::~NLamaroK() { delete m_client; } void NLamaroK::update() { m_playing = false; m_newTrack = false; QString newTrack; QString result; if (!m_client->isValid()) { delete m_client; m_client = new QDBusInterface("org.mpris.amarok", "/Player", "org.freedesktop.MediaPlayer"); } if (!m_client->isValid()) { return; } // See if amarok is currently playing. QDBusReply statusReply = m_client->call("GetStatus"); if (statusReply.isValid()) { // 0 = playing, 1 = paused, 2 = stopped if (statusReply.value().Play == 0) { m_playing = true; } else { m_playing = false; m_newTrack = true; m_track = ""; m_album = ""; m_artist = ""; return; } } else { m_playing = false; } QDBusReply metaDataReply = m_client->call("GetMetadata"); if (!metaDataReply.isValid()) { return; } const QVariantMap &metaData = metaDataReply.value(); // Fetch title newTrack = metaData["title"].toString(); if (newTrack != m_track) { m_newTrack = true; m_track = newTrack; } // Fetch album m_album = metaData["album"].toString(); // Fetch artist m_artist = metaData["artist"].toString(); } diff --git a/plugins/nowlistening/nlamarok.h b/plugins/nowlistening/nlamarok.h index 80d7b8332..8f9fdad63 100644 --- a/plugins/nowlistening/nlamarok.h +++ b/plugins/nowlistening/nlamarok.h @@ -1,43 +1,43 @@ /* nlamarok.h Kopete Now Listening To plugin Copyright (c) 2002,2003,2004 by Will Stephenson Kopete (c) 2002,2003,2004 by the Kopete developers Purpose: This class abstracts the interface to amaroK by implementing NLMediaPlayer ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef NLAMAROK_H #define NLAMAROK_H -#include +#include #include "nlmediaplayer.h" class QDBusInterface; class NLamaroK : public NLMediaPlayer { public: NLamaroK(); virtual ~NLamaroK(); virtual void update(); private: QDBusInterface *m_client; }; #endif diff --git a/plugins/nowlistening/nljuk.cpp b/plugins/nowlistening/nljuk.cpp index a2cb4db15..bbb997ad4 100644 --- a/plugins/nowlistening/nljuk.cpp +++ b/plugins/nowlistening/nljuk.cpp @@ -1,84 +1,84 @@ /* nljuk.cpp Kopete Now Listening To plugin Copyright (c) 2002,2003,2004 by Will Stephenson Copyright (c) 2003 by Ismail Donmez Copyright (c) 2002,2003 by the Kopete developers Purpose: This class abstracts the interface to JuK by implementing NLMediaPlayer ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #include "nljuk.h" #include -#include +#include #include "nlmediaplayer.h" NLJuk::NLJuk() : NLMediaPlayer() { m_type = Audio; m_name = "JuK"; m_client = new QDBusInterface("org.kde.juk", "/Player"); } NLJuk::~NLJuk() { delete m_client; } void NLJuk::update() { m_playing = false; QString newTrack; if (!m_client->isValid()) { delete m_client; m_client = new QDBusInterface("org.kde.juk", "/Player"); } // see if JuK is registered with DBUS if (m_client->isValid()) { // see if it's playing QDBusReply playingReply = m_client->call("playing"); if (playingReply.isValid()) { m_playing = playingReply.value(); } QDBusReply albumReply = m_client->call("trackProperty", QString("Album")); if (albumReply.isValid()) { m_album = albumReply.value(); } QDBusReply artistReply = m_client->call("trackProperty", QString("Artist")); if (artistReply.isValid()) { m_artist = artistReply.value(); } QDBusReply titleReply = m_client->call("trackProperty", QString("Title")); if (titleReply.isValid()) { newTrack = titleReply.value(); } if (newTrack != m_track) { m_newTrack = true; m_track = newTrack; } else { m_newTrack = false; } } else { kDebug(14307) << "Juk is not running!\n"; } } diff --git a/plugins/nowlistening/nljuk.h b/plugins/nowlistening/nljuk.h index b677ef7bd..ccd638a28 100644 --- a/plugins/nowlistening/nljuk.h +++ b/plugins/nowlistening/nljuk.h @@ -1,45 +1,45 @@ /* nljuk.h Kopete Now Listening To plugin Copyright (c) 2002,2003,2004 by Will Stephenson Copyright (c) 2003 by Ismail Donmez Kopete (c) 2002,2003 by the Kopete developers Purpose: This class abstracts the interface to JuK by implementing NLMediaPlayer ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef NLJUK_H #define NLJUK_H -#include +#include #include "nlmediaplayer.h" class QDBusInterface; class NLJuk : public NLMediaPlayer { public: NLJuk(); virtual ~NLJuk(); virtual void update(); private: QDBusInterface *m_client; }; #endif diff --git a/plugins/nowlistening/nlkaffeine.cpp b/plugins/nowlistening/nlkaffeine.cpp index 3c9f32a15..ed0d5352c 100644 --- a/plugins/nowlistening/nlkaffeine.cpp +++ b/plugins/nowlistening/nlkaffeine.cpp @@ -1,74 +1,74 @@ /* nlkaffeine.cpp Kopete Now Listening To plugin Copyright (c) 2004 by Will Stephenson Kopete Copyright (c) 2002,2003,2004 by the Kopete developers Purpose: This class abstracts the interface to Kaffeine by implementing NLMediaPlayer ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #include "nlkaffeine.h" #include -#include +#include #include "nlmediaplayer.h" NLKaffeine::NLKaffeine() : NLMediaPlayer() { m_client = new QDBusInterface("org.kde.Kaffeine", "/KaffeineIface"); m_type = Video; m_name = "Kaffeine"; } NLKaffeine::~NLKaffeine() { delete m_client; } void NLKaffeine::update() { m_playing = false; m_newTrack = false; QString newTrack; // TODO: Port to Kaffeine D-BUS Interface // see if kaffeine is registered with D-BUS if (!m_client->isValid()) { delete m_client; m_client = new QDBusInterface("org.kde.Kaffeine", "/KaffeineIface"); } if (m_client->isValid()) { QDBusReply isPlayingReply = m_client->call("isPlaying"); if (isPlayingReply.isValid()) { m_playing = isPlayingReply.value(); } QDBusReply getTrackReply = m_client->call("getTrack"); if (getTrackReply.isValid()) { newTrack = getTrackReply.value(); } if (newTrack != m_track) { m_newTrack = true; m_track = newTrack; } } else { kDebug(14307) << "Kaffeine is not running!\n"; } } diff --git a/plugins/nowlistening/nlkaffeine.h b/plugins/nowlistening/nlkaffeine.h index a4d93ef40..7254403ed 100644 --- a/plugins/nowlistening/nlkaffeine.h +++ b/plugins/nowlistening/nlkaffeine.h @@ -1,43 +1,43 @@ /* nlkaffeine.h Kopete Now Listening To plugin Copyright (c) 2002,2003,2004 by Will Stephenson Kopete (c) 2002,2003,2004 by the Kopete developers Purpose: This class abstracts the interface to Kaffeine by implementing NLMediaPlayer ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef NLKAFFEINE_H #define NLKAFFEINE_H -#include +#include #include "nlmediaplayer.h" class QDBusInterface; class NLKaffeine : public NLMediaPlayer { public: NLKaffeine(); virtual ~NLKaffeine(); virtual void update(); private: QDBusInterface *m_client; }; #endif diff --git a/plugins/nowlistening/nlkscd.cpp b/plugins/nowlistening/nlkscd.cpp index 7bf4e2c22..97b118138 100644 --- a/plugins/nowlistening/nlkscd.cpp +++ b/plugins/nowlistening/nlkscd.cpp @@ -1,93 +1,93 @@ /* nlkscd.cpp Kopete Now Listening To plugin Copyright (c) 2002,2003,2004 by Will Stephenson Kopete (c) 2002,2003,2004 by the Kopete developers Purpose: This class abstracts the interface to KsCD by implementing NLMediaPlayer ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #include "nlkscd.h" #include -#include +#include #include "nlmediaplayer.h" NLKscd::NLKscd() : NLMediaPlayer() { m_client = new QDBusInterface("org.kde.kscd", "/CDPlayer"); m_type = Audio; m_name = "KsCD"; } NLKscd::~NLKscd() { delete m_client; } void NLKscd::update() { m_playing = false; QString newTrack; if (!m_client->isValid()) { delete m_client; m_client = new QDBusInterface("org.kde.kscd", "/CDPlayer"); } // see if it's registered with D-BUS if (m_client->isValid()) { // see if it's playing QDBusReply playingReply = m_client->call("playing"); if (playingReply.isValid()) { m_playing = playingReply.value(); } // poll it for its current artist QDBusReply artistReply = m_client->call("currentArtist"); if (artistReply.isValid()) { m_artist = artistReply.value(); } //album QDBusReply albumReply = m_client->call("currentAlbum"); if (albumReply.isValid()) { m_album = albumReply.value(); } // Get the current track title QDBusReply trackReply = m_client->call("currentTrackTitle"); if (trackReply.isValid()) { newTrack = trackReply.value(); } // if the current track title has changed if (newTrack != m_track) { m_newTrack = true; m_track = newTrack; } else { m_newTrack = false; } // kDebug( 14307 ) << "NLKscd::update() - found kscd - " // << m_track << endl; } // else // kDebug( 14307 ) << "NLKscd::update() - kscd not found"; } // vim: set noet ts=4 sts=4 sw=4: diff --git a/plugins/nowlistening/nlkscd.h b/plugins/nowlistening/nlkscd.h index 1e4d17441..d64d12a67 100644 --- a/plugins/nowlistening/nlkscd.h +++ b/plugins/nowlistening/nlkscd.h @@ -1,44 +1,44 @@ /* nlkscd.h Kopete Now Listening To plugin Copyright (c) 2002,2003,2004 by Will Stephenson Kopete (c) 2002,2003,2004 by the Kopete developers Purpose: This class abstracts the interface to Kscd by implementing NLMediaPlayer ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef NLKSCD_H #define NLKSCD_H -#include +#include #include "nlmediaplayer.h" class QDBusInterface; class NLKscd : public NLMediaPlayer { public: NLKscd(); virtual ~NLKscd(); virtual void update(); private: QDBusInterface *m_client; }; #endif // vim: set noet ts=4 sts=4 sw=4: diff --git a/plugins/nowlistening/nlmpris.cpp b/plugins/nowlistening/nlmpris.cpp index a0deac4be..6312e4299 100644 --- a/plugins/nowlistening/nlmpris.cpp +++ b/plugins/nowlistening/nlmpris.cpp @@ -1,147 +1,147 @@ /* nlmpris.cpp Kopete Now Listening To plugin Copyright (c) 2010 by Volker Härtel Kopete (c) 2002,2003 by the Kopete developers Purpose: This class abstracts the interface to mpris by implementing NLMediaPlayer ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #include "nlmpris.h" #include -#include +#include struct mprisPlayerStatus { int state; // 0 = Playing, 1 = Paused, 2 = Stopped. int random; // 0 = Playing linearly, 1 = Playing randomly. int repeat; // 0 = Go to the next element once the current has finished playing, 1 = Repeat the current element int repeatPlayList; // 0 = Stop playing once the last element has been played, 1 = Never give up playing }; Q_DECLARE_METATYPE(mprisPlayerStatus) QDBusArgument &operator <<(QDBusArgument &arg, const mprisPlayerStatus &status) { arg.beginStructure(); arg << status.state; arg << status.random; arg << status.repeat; arg << status.repeatPlayList; arg.endStructure(); return arg; } const QDBusArgument &operator >>(const QDBusArgument &arg, mprisPlayerStatus &status) { arg.beginStructure(); arg >> status.state; arg >> status.random; arg >> status.repeat; arg >> status.repeatPlayList; arg.endStructure(); return arg; } NLmpris::NLmpris() : NLMediaPlayer() { m_type = Audio; m_name = "MPRIS compatible player"; m_client = 0; qDBusRegisterMetaType(); } NLmpris::~NLmpris() { delete m_client; } void NLmpris::update() { m_playing = false; if (m_client == 0 || !m_client->isValid()) { QStringList services; const QDBusConnection &sessionConn(QDBusConnection::sessionBus()); // Check if the connection is successful if (sessionConn.isConnected()) { const QDBusConnectionInterface *bus = sessionConn.interface(); const QDBusReply &reply(bus->registeredServiceNames()); if (reply.isValid()) { // Search for "org.mpris" string services = reply.value().filter("org.mpris."); } } // If no service was found then return false and unlock the mutex if (services.isEmpty()) { return; } // Start the d-bus interface, needed to check the application status and make calls to it if (m_client != 0) { delete m_client; m_client = 0; } m_client = new QDBusInterface(services.at(0), "/Player", "org.freedesktop.MediaPlayer"); QDBusInterface dbusMprisRoot(services.at(0), "/", "org.freedesktop.MediaPlayer"); // See if the application is registered. if (!m_client->isValid()) { return; } if (!dbusMprisRoot.isValid()) { m_name = QString("MPRIS compatible player"); } else { // Identity is part of /, not /Player. QDBusReply playerName = dbusMprisRoot.call("Identity"); m_name = playerName.value(); } } // see if it's playing QDBusReply mprisStatus = m_client->call("GetStatus"); if (mprisStatus.value().state == 0) { m_playing = true; } QDBusReply metaDataReply = m_client->call("GetMetadata"); if (!metaDataReply.isValid()) { return; } const QVariantMap &metaData = metaDataReply.value(); // Fetch title const QString newTrack = metaData["title"].toString(); if (newTrack != m_track) { m_newTrack = true; m_track = newTrack; } // Fetch album m_album = metaData["album"].toString(); // Fetch artist m_artist = metaData["artist"].toString(); } diff --git a/plugins/nowlistening/nlmpris.h b/plugins/nowlistening/nlmpris.h index 0822983a9..0f13c280e 100644 --- a/plugins/nowlistening/nlmpris.h +++ b/plugins/nowlistening/nlmpris.h @@ -1,43 +1,43 @@ /* nlmpris.h Kopete Now Listening To plugin Copyright (c) 2010 by Volker Härtel Kopete (c) 2002,2003,2004 by the Kopete developers Purpose: This class abstracts the interface to audacious by implementing NLMediaPlayer ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef NLMPRIS_H #define NLMPRIS_H -#include +#include #include "nlmediaplayer.h" class QDBusInterface; class NLmpris : public NLMediaPlayer { public: NLmpris(); virtual ~NLmpris(); virtual void update(); private: QDBusInterface *m_client; }; #endif diff --git a/plugins/nowlistening/nlmpris2.cpp b/plugins/nowlistening/nlmpris2.cpp index bd1d20893..616761092 100644 --- a/plugins/nowlistening/nlmpris2.cpp +++ b/plugins/nowlistening/nlmpris2.cpp @@ -1,116 +1,116 @@ /* nlmpris2.cpp Kopete Now Listening To plugin Copyright (c) 2012 by Volker Härtel Kopete (c) 2002,2003 by the Kopete developers Purpose: This class abstracts the interface to mpris by implementing NLMediaPlayer ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #include "nlmpris2.h" #include -#include +#include NLmpris2::NLmpris2() : NLMediaPlayer() { m_type = Audio; m_name = "MPRIS2 compatible player"; m_client = 0; } NLmpris2::~NLmpris2() { delete m_client; } void NLmpris2::update() { m_playing = false; if (m_client == 0 || !m_client->isValid()) { QStringList services; const QDBusConnection &sessionConn(QDBusConnection::sessionBus()); // Check if the connection is successful if (sessionConn.isConnected()) { const QDBusConnectionInterface *bus = sessionConn.interface(); const QDBusReply &reply(bus->registeredServiceNames()); if (reply.isValid()) { // Search for "org.mpris.MediaPlayer2" string services = reply.value().filter("org.mpris.MediaPlayer2"); } } // If no service was found then return false and unlock the mutex if (services.isEmpty()) { return; } // Start the d-bus interface, needed to check the application status and make calls to it if (m_client != 0) { delete m_client; m_client = 0; } m_client = new QDBusInterface(services.at(0), "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties"); QDBusInterface dbusMprisRoot(services.at(0), "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2"); // See if the application is registered. if (!m_client->isValid()) { return; } if (!dbusMprisRoot.isValid()) { m_name = QString("MPRIS2 compatible player"); } else { m_name = dbusMprisRoot.property("Identity").toString(); } } // see if it's playing QDBusReply mprisStatus = m_client->call("Get", "org.mpris.MediaPlayer2.Player", "PlaybackStatus"); if (!mprisStatus.isValid()) { return; } m_playing = (mprisStatus.value().toString() == "Playing"); QDBusReply metaDataReply = m_client->call("Get", "org.mpris.MediaPlayer2.Player", "Metadata"); if (!metaDataReply.isValid()) { return; } if (!metaDataReply.value().canConvert()) { return; } QVariantMap metaData; QDBusArgument arg = metaDataReply.value().value(); arg >> metaData; // Fetch title const QString newTrack = metaData["xesam:title"].toString(); if (newTrack != m_track) { m_newTrack = true; m_track = newTrack; } // Fetch album m_album = metaData["xesam:album"].toString(); // Fetch artist m_artist = metaData["xesam:artist"].toString(); } diff --git a/plugins/nowlistening/nlmpris2.h b/plugins/nowlistening/nlmpris2.h index 758178fc5..4695a28f4 100644 --- a/plugins/nowlistening/nlmpris2.h +++ b/plugins/nowlistening/nlmpris2.h @@ -1,43 +1,43 @@ /* nlmpris2.h Kopete Now Listening To plugin Copyright (c) 2012 by Volker Härtel Kopete (c) 2002,2003,2004 by the Kopete developers Purpose: This class abstracts the interface to audacious by implementing NLMediaPlayer ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef NLMPRIS2_H #define NLMPRIS2_H -#include +#include #include "nlmediaplayer.h" class QDBusInterface; class NLmpris2 : public NLMediaPlayer { public: NLmpris2(); virtual ~NLmpris2(); virtual void update(); private: QDBusInterface *m_client; }; #endif diff --git a/plugins/nowlistening/nlquodlibet.cpp b/plugins/nowlistening/nlquodlibet.cpp index cb7281066..ca4437b2c 100644 --- a/plugins/nowlistening/nlquodlibet.cpp +++ b/plugins/nowlistening/nlquodlibet.cpp @@ -1,130 +1,130 @@ /* nlquodlibet.cpp Kopete Now Listening To plugin Copyright (c) 2006,2007 by Will Stephenson Kopete (c) 2002,2003,2004,2005,2006,2007 by the Kopete developers Purpose: This class abstracts the interface to the Quod Libet music player by implementing NLMediaPlayer ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #include "nlquodlibet.h" #include #include -#include -#include -#include +#include +#include +#include #include #include #include NLQuodLibet::NLQuodLibet() : NLMediaPlayer() { m_name = "Quod Libet"; m_playing = false; m_watch = new KDirWatch(this); connect(m_watch, SIGNAL(created(QString)), SLOT(fileChanged(QString))); connect(m_watch, SIGNAL(deleted(QString)), SLOT(fileChanged(QString))); connect(m_watch, SIGNAL(created(QString)), SLOT(fileChanged(QString))); m_watch->addFile(currentTrackPath()); } NLQuodLibet::~NLQuodLibet() { } void NLQuodLibet::update() { //look for running QL // see if the ~/.quodlibet/current exists // if yes // parse for artist, album, title // m_playing = true; // else // m_playing = false; // assume we have no data m_artist = i18n("Unknown artist"); m_album = i18n("Unknown album"); m_track = i18n("Unknown track"); QString path = currentTrackPath(); QFile currentTrackFile(path); if (currentTrackFile.exists()) { m_playing = true; QFileInfo info(currentTrackFile); m_newTrack = (info.lastModified() > m_timestamp); if (m_newTrack) { m_timestamp = info.lastModified(); } parseFile(currentTrackFile); } else { m_playing = false; } } QString NLQuodLibet::currentTrackPath() const { return QDir::homePath() + QLatin1String("/.quodlibet/current"); } void NLQuodLibet::parseFile(QFile &file) { if (file.open(QIODevice::ReadOnly)) { QTextStream stream(&file); QString line; while (!stream.atEnd()) { line = stream.readLine(); // line of text excluding '\n' parseLine(line); } file.close(); } } void NLQuodLibet::parseLine(const QString &line) { QStringList parts = line.split('=', QString::KeepEmptyParts); if (parts.count() == 2) { if (parts[0] == "album") { kDebug() << "found QL album: " << parts[1]; m_album = parts[1]; } if (parts[0] == "artist") { kDebug() << "found QL artist: " << parts[1]; m_artist = parts[1]; } if (parts[0] == "title") { kDebug() << "found QL track: " << parts[1]; m_track = parts[1]; } } } void NLQuodLibet::fileChanged(const QString &file) { if (file == currentTrackPath()) { update(); } } // vim: set noet ts=4 sts=4 sw=4: diff --git a/plugins/statistics/statisticscontact.h b/plugins/statistics/statisticscontact.h index 7edaf5eb0..69e214138 100644 --- a/plugins/statistics/statisticscontact.h +++ b/plugins/statistics/statisticscontact.h @@ -1,271 +1,271 @@ /* statisticscontact.h Copyright (c) 2003-2004 by Marc Cramdal Copyright (c) 2007 by the Kopete Developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef STATISTICSCONTACT_H #define STATISTICSCONTACT_H #include "kopeteonlinestatus.h" #include "kopetemessage.h" #include "kopetemetacontact.h" -#include -#include -#include +#include +#include +#include class StatisticsDB; class QDateTime; class StatisticsContact { public: StatisticsContact(Kopete::MetaContact *mc, StatisticsDB *db); /** * We save all stats to the database (commonstats) */ ~StatisticsContact(); /* * Access method */ /** \brief Access method * \return m_db */ StatisticsDB *db() { return m_db; } /** \brief Access method * \return m_metaContact */ Kopete::MetaContact *metaContact() { return m_metaContact; } /** \brief Access method * \return m_metaContactId */ QString metaContactId() { return m_metaContactId; } /** \brief Access method * \return m_oldStatus */ Kopete::OnlineStatus::StatusType oldStatus() { return m_oldStatus; } /** \brief Access method * \return m_oldStatusDateTime */ QDateTime oldStatusDateTime() const { return m_oldStatusDateTime; } /** \brief Access method * \return m_messageLength */ int messageLength() const { return m_messageLength; } /** \brief Access method * \return m_timeBetweenTwoMessages */ int timeBetweenTwoMessages() const { return m_timeBetweenTwoMessages; } /** * \brief Access method * \return m_lastTalk */ QDateTime lastTalk() const { return m_lastTalk; } /** * \brief Access method * \return m_lastPresent */ QDateTime lastPresent() const { return m_lastPresent; } /** * \brief sets \p m_isChatWindowOpen to true */ void setIsChatWindowOpen(bool c) { m_isChatWindowOpen = c; } /* * Method performing some useful actions */ /** * \brief update the events database with the new statuss */ void onlineStatusChanged(Kopete::OnlineStatus::StatusType status); /** * \brief update the average time between to messages for this contact * Should be called when a new message is received by this contact */ void newMessageReceived(Kopete::Message &m); /** * \returns true if contact was status at dt, false else. */ bool wasStatus(QDateTime dt, Kopete::OnlineStatus::StatusType status); /** * \returns the status of the contact at dt. Return false if dt is invalid. */ QString statusAt(QDateTime dt); /** * \returns the main (most used) status of the contact at date (not time) dt. return false if dt is invalid. */ QString mainStatusDate(const QDate &date); /* * Prevision methods */ /** // * \brief Give information on when the next event will occur // * // * \param status the status to be checked. // * \retval nextEventDateTime the next event average prevision datetime. // */ // QDateTime nextEvent(const Kopete::OnlineStatus::StatusType& status); // // /** // * \brief Convenience method for nextEvent with Offline status // */ // QDateTime nextOfflineEvent(); // // /** // * \brief Convenience method for nextEvent with Online status // */ // QDateTime nextOnlineEvent(); /** * \brief computes the main "status" events for the contact */ QList mainEvents(const Kopete::OnlineStatus::StatusType &status); /// \brief used by mainEvents() QList computeCentroids(const QList ¢roids, const QList &values); private: /** * \brief Checks if the value name exists in "commonstats" table, if not, add the row. * * \param name the name of the entry to be checked * \param statVar1 retrieve this var from the database. If it doesn't exists, get it from \p defaultValue1 * \param statVar2 retrieve this var from the database. If it doesn't exists, get it from \p defaultValue2 * \param defaultValue1 defaultValue for \p statVar1 * \param defaultValue2 defaultValue for \p statVar2 * \retval statvar1 * \retval statvar2 */ void commonStatsCheck(const QString &name, QString &statVar1, QString &statVar2, const QString &defaultValue1 = QLatin1String(""), const QString &defaultValue2 = QLatin1String("")); /** * @brief Same as commonStatsCheck for integers. * Provided for convenience */ void commonStatsCheck(const QString &name, int &statVar1, int &statVar2, const int defaultValue1 = 0, const int defaultValue2 = -1); /** * @brief Save a value in the "commonstats" table * \param name the name of the entry to be saved * \param statVar1 what we are going to store in the first column for this entry * \param statVar2 the second stat we can save in this table for this entry * \param statVarChanged if this param is true, we save. Else, we don't. Spare some disk usage. */ void commonStatsSave(const QString &name, const QString &statVar1, const QString &statVar2, const bool statVarChanged); /** * Kopete::MetaContact linked to this StatisticsContact * Each StatisticsContact object _has_ to be linked to a metaContact */ QPointer m_metaContact; /** * Id of Kopete::MetaContact */ QString m_metaContactId; /** * Required to be able to write to the database */ StatisticsDB *m_db; /** * The interest of statistics contact is to manage the changes of status * in order to correctly update the database. That's why here we keep the oldStatus */ Kopete::OnlineStatus::StatusType m_oldStatus; /// We keep the old status datetime here QDateTime m_oldStatusDateTime; /** * Average time this user takes between two of his messages * It may be used to compute a "speed" or "availability" for this contact */ int m_timeBetweenTwoMessages; bool m_timeBetweenTwoMessagesChanged; /// Date at which the last message was received. /// Used to compute m_timeBetweenTwoMessages QDateTime m_lastMessageReceived; /// This is the ponderation corresponding to m_timeBetweenTwoMessagesOn int m_timeBetweenTwoMessagesOn; /// We don't count time if a chatwindow isn't open bool m_isChatWindowOpen; /** * Average length of contact's messages */ int m_messageLength; bool m_messageLengthChanged; /// This is the ponderation corresponding to m_messageLength int m_messageLengthOn; /** * Last time user talked with this contact */ QDateTime m_lastTalk; bool m_lastTalkChanged; /** * Last time user was present (=online or away) */ QDateTime m_lastPresent; bool m_lastPresentChanged; }; #endif diff --git a/plugins/webpresence/webpresenceplugin.cpp b/plugins/webpresence/webpresenceplugin.cpp index 654c94ac6..7fc44a6f3 100644 --- a/plugins/webpresence/webpresenceplugin.cpp +++ b/plugins/webpresence/webpresenceplugin.cpp @@ -1,468 +1,468 @@ /* webpresenceplugin.cpp Kopete Web Presence plugin Copyright 2005-2006 by Tommi Rantala Copyright (c) 2002,2003 by Will Stephenson Kopete (c) 2002-2006 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #include "webpresenceplugin.h" -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include "kopetepluginmanager.h" #include "kopeteprotocol.h" #include "kopeteaccountmanager.h" #include "kopeteaccount.h" #include "kopetecontact.h" #include "webpresenceconfig.h" K_PLUGIN_FACTORY(WebPresencePluginFactory, registerPlugin(); ) K_EXPORT_PLUGIN(WebPresencePluginFactory("kopete_webpresence")) WebPresencePlugin::WebPresencePlugin(QObject *parent, const QVariantList & /*args*/) : Kopete::Plugin(parent) , shuttingDown(false) , resultFormatting(WEB_HTML) , m_output(0) { m_writeScheduler = new QTimer(this); connect(m_writeScheduler, SIGNAL(timeout()), this, SLOT(slotWriteFile())); connect(Kopete::AccountManager::self(), SIGNAL(accountRegistered(Kopete::Account *)), this, SLOT(listenToAllAccounts())); connect(Kopete::AccountManager::self(), SIGNAL(accountUnregistered(const Kopete::Account *)), this, SLOT(listenToAllAccounts())); connect(this, SIGNAL(settingsChanged()), this, SLOT(slotSettingsChanged())); slotSettingsChanged(); listenToAllAccounts(); } WebPresencePlugin::~WebPresencePlugin() { delete m_output; } void WebPresencePlugin::slotSettingsChanged() { // Force reading config WebPresenceConfig::self()->load(); resultFormatting = WEB_UNDEFINED; if (WebPresenceConfig::self()->formatHTML()) { resultFormatting = WEB_HTML; } else if (WebPresenceConfig::self()->formatXHTML()) { resultFormatting = WEB_XHTML; } else if (WebPresenceConfig::self()->formatXML()) { resultFormatting = WEB_XML; } else if (WebPresenceConfig::self()->formatStylesheet()) { resultFormatting = WEB_CUSTOM; userStyleSheet = WebPresenceConfig::self()->formatStylesheetURL(); } // Default to HTML, if we don't get anything useful from config file. if (resultFormatting == WEB_UNDEFINED) { resultFormatting = WEB_HTML; } // Update file slotWriteFile(); } void WebPresencePlugin::listenToAllAccounts() { // Connect to signals notifying of all accounts' status changes. ProtocolList protocols = allProtocols(); for (ProtocolList::Iterator it = protocols.begin(); it != protocols.end(); ++it) { QList accounts = Kopete::AccountManager::self()->accounts(*it); foreach (Kopete::Account *account, accounts) { listenToAccount(account); } } slotWaitMoreStatusChanges(); } void WebPresencePlugin::listenToAccount(Kopete::Account *account) { if (account && account->myself()) { // Connect to the account's status changed signal // because we can't know if the account has already connected QObject::disconnect(account->myself(), SIGNAL(onlineStatusChanged(Kopete::Contact *, const Kopete::OnlineStatus&, const Kopete::OnlineStatus&)), this, SLOT(slotWaitMoreStatusChanges())); QObject::connect(account->myself(), SIGNAL(onlineStatusChanged(Kopete::Contact *, const Kopete::OnlineStatus&, const Kopete::OnlineStatus&)), this, SLOT(slotWaitMoreStatusChanges())); } } void WebPresencePlugin::slotWaitMoreStatusChanges() { if (!m_writeScheduler->isActive()) { m_writeScheduler->start(WebPresenceConfig::self()->uploadFrequency() * 1000); } } void WebPresencePlugin::slotWriteFile() { m_writeScheduler->stop(); // generate the (temporary) XML file representing the current contact list const KUrl dest = WebPresenceConfig::self()->uploadURL(); if (dest.isEmpty() || !dest.isValid()) { kDebug(14309) << "url is empty or not valid. NOT UPDATING!"; return; } KTemporaryFile *xml = generateFile(); xml->setAutoRemove(true); switch (resultFormatting) { case WEB_XML: m_output = xml; xml = nullptr; break; case WEB_HTML: case WEB_XHTML: case WEB_CUSTOM: m_output = new KTemporaryFile(); m_output->open(); if (!transform(xml, m_output)) { //TODO: give some error to user, even better if shown only once delete m_output; m_output = nullptr; delete xml; return; } delete xml; // might make debugging harder! break; default: return; } // upload it to the specified URL KUrl src(m_output->fileName()); KIO::FileCopyJob *job = KIO::file_move(src, dest, -1, KIO::Overwrite | KIO::HideProgressInfo); connect(job, SIGNAL(result(KJob *)), SLOT(slotUploadJobResult(KJob *))); } void WebPresencePlugin::slotUploadJobResult(KJob *job) { if (job->error()) { kDebug(14309) << "Error uploading presence info."; KMessageBox::detailedError(0, i18n("An error occurred when uploading your presence page.\nCheck the path and write permissions of the destination."), 0, displayName()); delete m_output; m_output = nullptr; } } KTemporaryFile *WebPresencePlugin::generateFile() { // generate the (temporary) XML file representing the current contact list kDebug(14309); QString notKnown = i18n("Not yet known"); QDomDocument doc; doc.appendChild(doc.createProcessingInstruction(QStringLiteral("xml"), QStringLiteral("version=\"1.0\" encoding=\"UTF-8\""))); QDomElement root = doc.createElement(QStringLiteral("webpresence")); doc.appendChild(root); // insert the current date/time QDomElement date = doc.createElement(QStringLiteral("listdate")); QDomText t = doc.createTextNode( KLocale::global()->formatDateTime(QDateTime::currentDateTime())); date.appendChild(t); root.appendChild(date); // insert the user's name QDomElement name = doc.createElement(QStringLiteral("name")); QDomText nameText; const QString userName = WebPresenceConfig::self()->showThisName(); if (!WebPresenceConfig::self()->showName() && !userName.isEmpty()) { nameText = doc.createTextNode(userName); } else { nameText = doc.createTextNode(notKnown); } name.appendChild(nameText); root.appendChild(name); // insert the list of the user's accounts QDomElement accounts = doc.createElement(QStringLiteral("accounts")); root.appendChild(accounts); QList list = Kopete::AccountManager::self()->accounts(); // If no accounts, stop here if (!list.isEmpty()) { foreach (Kopete::Account *account, list) { QDomElement acc = doc.createElement(QStringLiteral("account")); //output += h.openTag( "account" ); QDomElement protoName = doc.createElement(QStringLiteral("protocol")); QDomText protoNameText = doc.createTextNode( account->protocol()->pluginId()); protoName.appendChild(protoNameText); acc.appendChild(protoName); Kopete::Contact *me = account->myself(); QString displayName = me->displayName(); QDomElement accName = doc.createElement(QStringLiteral("accountname")); QDomText accNameText = doc.createTextNode((me) ? displayName : notKnown); accName.appendChild(accNameText); acc.appendChild(accName); QDomElement accStatus = doc.createElement(QStringLiteral("accountstatus")); QDomText statusText = doc.createTextNode((me) ? statusAsString(me->onlineStatus()) : notKnown); accStatus.appendChild(statusText); // Do not add these if we're shutting down, because the result // would be quite weird. if (!shuttingDown) { // Add away message as an attribute, if one exists. if ((me->onlineStatus().status() == Kopete::OnlineStatus::Away || me->onlineStatus().status() == Kopete::OnlineStatus::Busy) && !me->property(QStringLiteral("awayMessage")).value().toString().isEmpty()) { accStatus.setAttribute(QStringLiteral("awayreason"), me->property(QStringLiteral("awayMessage")).value().toString()); } // Add the online status description as an attribute, if one exits. if (!me->onlineStatus().description().isEmpty()) { accStatus.setAttribute(QStringLiteral("statusdescription"), me->onlineStatus().description()); } } acc.appendChild(accStatus); if (WebPresenceConfig::self()->includeIMAddress()) { QDomElement accAddress = doc.createElement(QStringLiteral("accountaddress")); QDomText addressText = doc.createTextNode((me) ? me->contactId() : notKnown); accAddress.appendChild(addressText); acc.appendChild(accAddress); } accounts.appendChild(acc); } } // write the XML to a temporary file KTemporaryFile *file = new KTemporaryFile(); file->setAutoRemove(false); file->open(); QString buf; QTextStream stream(&buf, QIODevice::WriteOnly); stream.setCodec("UTF-16"); // QtXML works only with UTF-16 doc.documentElement().save(stream, 4); // QDomDocument::save() override stream codec to UTF-8 file->write(buf.toUtf8()); file->flush(); return file; } bool WebPresencePlugin::transform(KTemporaryFile *src, KTemporaryFile *dest) { bool retval = true; xmlSubstituteEntitiesDefault(1); xmlLoadExtDtdDefaultValue = 1; QFile sheet; switch (resultFormatting) { case WEB_XML: // Oops! We tried to call transform() but XML was requested. return false; case WEB_HTML: if (WebPresenceConfig::self()->useImagesHTML()) { sheet.setFileName(QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("/webpresence/webpresence_html_images.xsl"))); } else { sheet.setFileName(QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("/webpresence/webpresence_html.xsl"))); } break; case WEB_XHTML: if (WebPresenceConfig::self()->useImagesHTML()) { sheet.setFileName(QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("/webpresence/webpresence_xhtml_images.xsl"))); } else { sheet.setFileName(QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("/webpresence/webpresence_xhtml.xsl"))); } break; case WEB_CUSTOM: sheet.setFileName(userStyleSheet.path()); break; default: // Shouldn't ever reach here. return false; } // TODO: auto / smart pointers would be useful here xsltStylesheetPtr cur = 0; xmlDocPtr doc = 0; xmlDocPtr res = 0; if (!sheet.exists()) { kDebug(14309) << "ERROR: Style sheet not found"; retval = false; goto end; } // is the cast safe? cur = xsltParseStylesheetFile((const xmlChar *)sheet.fileName().toLatin1().data()); if (!cur) { kDebug(14309) << "ERROR: Style sheet parsing failed"; retval = false; goto end; } doc = xmlParseFile(QFile::encodeName(src->fileName())); if (!doc) { kDebug(14309) << "ERROR: XML parsing failed"; retval = false; goto end; } res = xsltApplyStylesheet(cur, doc, 0); if (!res) { kDebug(14309) << "ERROR: Style sheet apply failed"; retval = false; goto end; } if (xsltSaveResultToFd(dest->handle(), res, cur) == -1) { kDebug(14309) << "ERROR: Style sheet apply failed"; retval = false; goto end; } // then it all worked! end: xsltCleanupGlobals(); xmlCleanupParser(); if (doc) { xmlFreeDoc(doc); } if (res) { xmlFreeDoc(res); } if (cur) { xsltFreeStylesheet(cur); } return retval; } ProtocolList WebPresencePlugin::allProtocols() { kDebug(14309); Kopete::PluginList plugins = Kopete::PluginManager::self()->loadedPlugins(QStringLiteral("Protocols")); Kopete::PluginList::ConstIterator it; ProtocolList result; for (it = plugins.constBegin(); it != plugins.constEnd(); ++it) { result.append(static_cast(*it)); } return result; } QString WebPresencePlugin::statusAsString(const Kopete::OnlineStatus &newStatus) { if (shuttingDown) { return QStringLiteral("OFFLINE"); } QString status; switch (newStatus.status()) { case Kopete::OnlineStatus::Online: status = QStringLiteral("ONLINE"); break; case Kopete::OnlineStatus::Away: status = QStringLiteral("AWAY"); break; case Kopete::OnlineStatus::Busy: status = QStringLiteral("BUSY"); break; case Kopete::OnlineStatus::Offline: case Kopete::OnlineStatus::Invisible: status = QStringLiteral("OFFLINE"); break; default: status = QStringLiteral("UNKNOWN"); } return status; } void WebPresencePlugin::aboutToUnload() { // Stop timer. Do not need it anymore. m_writeScheduler->stop(); // Force statusAsString() report all accounts as OFFLINE. shuttingDown = true; // Do final update of webpresence file. slotWriteFile(); emit readyForUnload(); } // vim: set noet ts=4 sts=4 sw=4: #include "webpresenceplugin.moc" diff --git a/plugins/webpresence/webpresenceplugin.h b/plugins/webpresence/webpresenceplugin.h index 6621505da..4e168fb51 100644 --- a/plugins/webpresence/webpresenceplugin.h +++ b/plugins/webpresence/webpresenceplugin.h @@ -1,126 +1,126 @@ /* webpresenceplugin.h Kopete Web Presence plugin Copyright (c) 2002,2003 by Will Stephenson Kopete (c) 2002,2003 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef WEBPRESENCEPLUGIN_H #define WEBPRESENCEPLUGIN_H -#include +#include #include #include "kopeteplugin.h" class QTimer; class KTemporaryFile; class KJob; namespace Kopete { } namespace Kopete { class Protocol; } namespace Kopete { class Account; } namespace Kopete { class OnlineStatus; } typedef QList ProtocolList; class WebPresencePlugin : public Kopete::Plugin { Q_OBJECT private: KUrl userStyleSheet; // Is set to true when Kopete has notified us // that we're about to be unloaded. bool shuttingDown; enum { WEB_HTML, WEB_XHTML, WEB_XML, WEB_CUSTOM, WEB_UNDEFINED } resultFormatting; public: WebPresencePlugin(QObject *parent, const QVariantList &args); virtual ~WebPresencePlugin(); void aboutToUnload() Q_DECL_OVERRIDE; protected Q_SLOTS: /** * Called when settings were changed */ void slotSettingsChanged(); /** * Write a file to the specified location, */ void slotWriteFile(); /** * Called when an upload finished, displays error if needed */ void slotUploadJobResult(KJob *); /** * Called to schedule a write, after waiting to see if more changes * occur (accounts tend to change status together) */ void slotWaitMoreStatusChanges(); /** * Sets us up to respond to account status changes */ void listenToAllAccounts(); /** * Sets us up to respond to a new account */ void listenToAccount(Kopete::Account *account); protected: /** * Generate the file (HTML, text) to be uploaded */ KTemporaryFile *generateFile(); /** * Apply named stylesheet to get content and presentation */ bool transform(KTemporaryFile *src, KTemporaryFile *dest); /** * Helper method, generates list of all IM protocols */ ProtocolList allProtocols(); /** * Converts numeric status to a string */ QString statusAsString(const Kopete::OnlineStatus &newStatus); /** * Schedules writes */ QTimer *m_writeScheduler; // The file to be uploaded to the WWW KTemporaryFile *m_output; }; #endif // vim: set noet ts=4 sts=4 sw=4: diff --git a/protocols/gadu/gadurichtextformat.h b/protocols/gadu/gadurichtextformat.h index 3fea0c23f..e652d29d4 100644 --- a/protocols/gadu/gadurichtextformat.h +++ b/protocols/gadu/gadurichtextformat.h @@ -1,56 +1,56 @@ // // Copyright (C) 2004 Grzegorz Jaskiewicz // // gadurichtextformat.h // // This program 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 program 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 program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA // 02110-1301, USA. #ifndef GADURICHTEXTFORMAT_H #define GADURICHTEXTFORMAT_H #include -#include +#include class QString; namespace Kopete { class Message; } class KGaduMessage; class GaduRichTextFormat { public: GaduRichTextFormat(); ~GaduRichTextFormat(); QString convertToHtml(const QString &, unsigned int, void *); KGaduMessage *convertToGaduMessage(const Kopete::Message &); private: QString formatOpeningTag(const QString &, const QString & = QString()); QString formatClosingTag(const QString &); bool insertRtf(uint); QString unescapeGaduMessage(QString &); void parseAttributes(const QString, const QString); QString escapeBody(QString &); QColor color; gg_msg_richtext_format rtfs; gg_msg_richtext_color rtcs; gg_msg_richtext *header; QByteArray rtf; }; #endif // GADURICHTEXTFORMAT_H diff --git a/protocols/groupwise/gwaccount.h b/protocols/groupwise/gwaccount.h index e3579aca6..514562efc 100644 --- a/protocols/groupwise/gwaccount.h +++ b/protocols/groupwise/gwaccount.h @@ -1,373 +1,373 @@ /* gwaccount.h - Kopete GroupWise Protocol Copyright (c) 2006,2007 Novell, Inc http://www.opensuse.org Copyright (c) 2004 SUSE Linux AG http://www.suse.com Based on Testbed Copyright (c) 2003-2007 by Will Stephenson Kopete (c) 2002-2007 by the Kopete developers ************************************************************************* * * * This library 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. * * * ************************************************************************* */ #ifndef GW_ACCOUNT_H #define GW_ACCOUNT_H -#include +#include #include #include #include #include #include "gwerror.h" #include class KActionMenu; namespace Kopete { class Group; class MetaContact; } class GroupWiseContact; class GroupWiseChatSession; class GroupWiseProtocol; class KNetworkConnector; namespace QCA { class TLS; } class QCATLSHandler; class ClientStream; namespace GroupWise { class Client; } class GWContactList; using namespace GroupWise; /** * This represents an account on a Novell GroupWise Messenger Server */ class GroupWiseAccount : public Kopete::PasswordedAccount { Q_OBJECT public: GroupWiseAccount( GroupWiseProtocol *parent, const QString& accountID, const char *name = 0 ); ~GroupWiseAccount(); /** * Construct the context menu used for the status bar icon */ void fillActionMenu( KActionMenu *actionMenu ) Q_DECL_OVERRIDE; // DEBUG ONLY void dumpManagers(); // DEBUG ONLY /** * Creates a protocol specific Kopete::Contact subclass and adds it to the supplied * Kopete::MetaContact */ bool createContact(const QString& contactId, Kopete::MetaContact* parentContact) Q_DECL_OVERRIDE; /** * Delete a contact on the server */ void deleteContact( GroupWiseContact * contact ); /** * Called when Kopete is set globally away */ virtual void setAway(bool away, const QString& reason); /** * Utility access to the port given by the user */ int port() const; /** * Utility access to the server given by the user */ const QString server() const; /** * Utility access to our protocol */ GroupWiseProtocol * protocol() const; /** * Utility access to the @ref Client which is the main interface exposed by libgroupwise. * Most protocol actions are carried out using the client's member functions but the possibility exists * to start Tasks directly on the client and respond directly to their signals. */ Client * client() const; /** * Utility to create or access a message manager instance for a given GUID and set of contacts */ GroupWiseChatSession * chatSession( Kopete::ContactPtrList others, const ConferenceGuid & guid, Kopete::Contact::CanCreateFlags canCreate ); /** * Look up a contact given a DN * Returns 0 if none found */ GroupWiseContact * contactForDN( const QString & dn ); /** * Create a conference (start a chat) on the server */ void createConference( const int clientId, const QStringList& invitees ); /** * Send a message */ void sendMessage( const ConferenceGuid & guid, const Kopete::Message & message ); /** * Invite someone to join a conference */ void sendInvitation( const ConferenceGuid & guid, const QString & dn, const QString & message ); /** * Check a contact's blocking status * Only works when connected - otherwise always returns false */ bool isContactBlocked( const QString & m_dn ); /** * Set up a temporary contact (not on our contact list but is messaging us or involved in a conversation that we have been invited to. */ GroupWiseContact * createTemporaryContact( const QString & dn ); /** * Check whether sync is not currently needed */ bool dontSync(); void syncContact( GroupWiseContact * contact ); public Q_SLOTS: void slotTestRTFize(); /* Connects to the server. */ void connectWithPassword ( const QString &password ) Q_DECL_OVERRIDE; /* Disconnects from the server. */ void disconnect() Q_DECL_OVERRIDE; virtual void disconnect( Kopete::Account::DisconnectReason reason ); /** Set the online status for the account. Reimplemented from Kopete::Account */ void setOnlineStatus( const Kopete::OnlineStatus& status , const Kopete::StatusMessage &reason = Kopete::StatusMessage(), const OnlineStatusOptions& options = None ) Q_DECL_OVERRIDE; /** * Set the status message for the account. Reimplemented from Kopete::Account */ void setStatusMessage( const Kopete::StatusMessage &statusMessage ) Q_DECL_OVERRIDE; Q_SIGNALS: void conferenceCreated( const int mmId, const GroupWise::ConferenceGuid & guid ); void conferenceCreationFailed( const int mmId, const int statusCode ); void contactTyping( const ConferenceEvent & ); void contactNotTyping( const ConferenceEvent & ); void privacyChanged( const QString & dn, bool allowed ); protected Q_SLOTS: void slotMessageSendingFailed(); /** * Set an auto reply message for use when the account is away * TODO: Extend Kopete::AwayAction so you can set multiple ones there. */ void slotSetAutoReply(); /** * Manage the user's privacy settings */ void slotPrivacy(); /** * Show a dialog to join a chatroom without first adding it to the contact list */ void slotJoinChatRoom(); /** * Slot informing GroupWise when a group is renamed */ void slotKopeteGroupRenamed( Kopete::Group * ); /** * Slot informing GroupWise when a group is removed */ void slotKopeteGroupRemoved( Kopete::Group * ); // SERVER SIDE CONTACT LIST PROCESSING /** * Called when we receive a FOLDER from the server side contact list * Adds to the Kopete contact list if not already present. */ void receiveFolder( const FolderItem & folder ); /** * Called when we receive a CONTACT from the server side contact list * Adds to a folder in the Kopete contact list. */ void receiveContact( const ContactItem & ); /** * Called when we receive a CONTACT'S METADATA (including initial status) from the server side contact list, * or in response to an explicitly query. This is necessary to handle some events from the server. * These events are queued in the account until the data arrives and then we handle the event. */ void receiveContactUserDetails( const GroupWise::ContactDetails & ); /** * Called after we create a contact on the server */ void receiveContactCreated(); /** * Handles the response to deleting a contact on the server */ void receiveContactDeleted( const ContactItem & instance ); // SLOTS HANDLING PROTOCOL EVENTS /** * Received a message from the server. * Find the conversation that this message belongs to, and display it there. * @param event contains event type, sender, content, flags. Type is used to handle autoreplies, normal messages, and [system] broadcasts. */ void handleIncomingMessage( const ConferenceEvent & ); /** * A contact changed status */ void receiveStatus( const QString &, quint16, const QString & ); /** * Our status changed on the server */ void changeOurStatus( GroupWise::Status, const QString &, const QString & ); /** * Called when we've been disconnected for logging in as this user somewhere else */ void slotConnectedElsewhere(); /** * Called when we've logged in successfully */ void slotLoggedIn(); /** * Called when a login attempt failed */ void slotLoginFailed(); /** * We joined a conference having accepted an invitation, create a message manager */ void receiveConferenceJoin( const GroupWise::ConferenceGuid & guid, const QStringList & participants, const QStringList & invitees ); /** * Someone joined a conference, add them to the appropriate message manager */ void receiveConferenceJoinNotify( const ConferenceEvent & ); /** * Someone left a conference, remove them from the message manager */ void receiveConferenceLeft( const ConferenceEvent & ); /** * The user was invited to join a conference */ void receiveInvitation( const ConferenceEvent & ); /** * Notification that a third party was invited to join conference */ void receiveInviteNotify( const ConferenceEvent & ); /** * Notification that a third party declined an invitation */ void receiveInviteDeclined( const ConferenceEvent & ); /** * A conference was closed by the server because everyone has left or declined invitations * Prevents any further messages to this conference */ // void closeConference(); // SLOTS HANDLING NETWORK EVENTS /** * Update the local user's metadata */ void receiveAccountDetails( const GroupWise::ContactDetails & details ); /** * The TLS handshake has happened, check the result */ void slotTLSHandshaken(); /** The connection is ready for a login */ void slotTLSReady( int secLayerCode ); /** * Called when the clientstream is connected, debug only */ void slotCSConnected(); /** * Performs necessary actions when the client stream has been disconnected */ void slotCSDisconnected(); void slotCSError( int error ); void slotCSWarning( int warning ); // HOUSEKEEPING /** * We listen for the destroyed() signal and leave any conferences we * might have been in, and remove it from our map. */ void slotLeavingConference( GroupWiseChatSession * ); /** Debug slots */ void slotConnError(); void slotConnConnected(); protected: /** * Sends a status message to the server - called by the status specific slotGoAway etc */ //void setStatus( GroupWise::Status status, const QString & reason = QString() ); int handleTLSWarning (QCA::TLS::IdentityResult identityResult, QCA::Validity validityResult, QString server, QString accountId); GroupWiseChatSession * findChatSessionByGuid( const GroupWise::ConferenceGuid & guid ); /** * reconcile any changes to the contact list which happened offline */ void reconcileOfflineChanges(); /** * Memory management */ void cleanup(); private: // action menu and its actions QAction * m_actionAutoReply; QAction * m_actionManagePrivacy; QAction * m_actionJoinChatRoom; // Network code KNetworkConnector * m_connector; QCA::Initializer m_qcaInit; QCA::TLS * m_QCATLS; QCATLSHandler * m_tlsHandler; ClientStream * m_clientStream; // Client, entry point of libgroupwise Client * m_client; QString m_password; QString m_initialReason; QList m_chatSessions; bool m_dontSync; GWContactList * m_serverListModel; }; /** * @internal * An action that selects an OnlineStatus and provides a status message, but not using Kopete::Away, because the status message relates only to this status. */ /*class OnlineStatusMessageAction : public QAction { Q_OBJECT public: OnlineStatusMessageAction ( const Kopete::OnlineStatus& status, const QString &text, const QString &message, const QIcon &pix, QObject *parent=0, const char *name=0); Q_SIGNALS: void activated( const Kopete::OnlineStatus& status, const QString & ); private Q_SLOTS: void slotActivated(); private: Kopete::OnlineStatus m_status; QString m_message; }; */ #endif diff --git a/protocols/groupwise/libgroupwise/tasks/conferencetask.h b/protocols/groupwise/libgroupwise/tasks/conferencetask.h index c4f5d113e..6d2bd5bc2 100644 --- a/protocols/groupwise/libgroupwise/tasks/conferencetask.h +++ b/protocols/groupwise/libgroupwise/tasks/conferencetask.h @@ -1,75 +1,75 @@ /* Kopete Groupwise Protocol conferencetask.h - Event Handling task responsible for all conference related events Copyright (c) 2004 SUSE Linux AG http://www.suse.com Based on Iris, Copyright (C) 2003 Justin Karneges Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef CONFERENCETASK_H #define CONFERENCETASK_H #include "gwerror.h" #include "eventtask.h" -#include +#include /** * This Task is responsible for handling all conference related events, and signalling them up to @ref GroupWiseAccount * Implementation note: It would be fit the model more cleanly to have each of these in their own Task, but the amount * of code they share is quite large, and the differences in the way each event uses it are small * @author SUSE AG */ using namespace GroupWise; class ConferenceTask : public EventTask { Q_OBJECT public: ConferenceTask(Task *parent); ~ConferenceTask(); bool take(Transfer *transfer) Q_DECL_OVERRIDE; Q_SIGNALS: void typing(const ConferenceEvent &); void notTyping(const ConferenceEvent &); void joined(const ConferenceEvent &); void left(const ConferenceEvent &); void invited(const ConferenceEvent &); void otherInvited(const ConferenceEvent &); void invitationDeclined(const ConferenceEvent &); void closed(const ConferenceEvent &); void message(const ConferenceEvent &); void autoReply(const ConferenceEvent &); // GW7 void broadcast(const ConferenceEvent &); void systemBroadcast(const ConferenceEvent &); protected Q_SLOTS: void slotReceiveUserDetails(const GroupWise::ContactDetails &); protected: quint32 readFlags(QDataStream &din); QString readMessage(QDataStream &din); /** * Checks to see if we need more data from the client before we can propagate this event * and queues the event if so * @return whether the event was queued pending more data */ bool queueWhileAwaitingData(const ConferenceEvent &event); void dumpConferenceEvent(ConferenceEvent &evt); private: // A list of events which are waiting for more data from the server before they can be exposed to the client QList< ConferenceEvent > m_pendingEvents; }; #endif diff --git a/protocols/groupwise/libgroupwise/tasks/pollsearchresultstask.cpp b/protocols/groupwise/libgroupwise/tasks/pollsearchresultstask.cpp index 55ca72771..9389049b7 100644 --- a/protocols/groupwise/libgroupwise/tasks/pollsearchresultstask.cpp +++ b/protocols/groupwise/libgroupwise/tasks/pollsearchresultstask.cpp @@ -1,185 +1,185 @@ /* Kopete Groupwise Protocol pollsearchresultstask.cpp - Poll the server to see if it has processed our search yet. Copyright (c) 2006 Novell, Inc http://www.opensuse.org Copyright (c) 2004 SUSE Linux AG http://www.suse.com Based on Iris, Copyright (C) 2003 Justin Karneges Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "pollsearchresultstask.h" #include "gwfield.h" #include "response.h" #include "logintask.h" -#include +#include using namespace GroupWise; PollSearchResultsTask::PollSearchResultsTask(Task *parent) : RequestTask(parent) { } PollSearchResultsTask::~PollSearchResultsTask() { } void PollSearchResultsTask::poll(const QString &queryHandle) { Field::FieldList lst; lst.append(new Field::SingleField(Field::NM_A_SZ_OBJECT_ID, 0, NMFIELD_TYPE_UTF8, queryHandle)); createTransfer(QStringLiteral("getresults"), lst); } bool PollSearchResultsTask::take(Transfer *transfer) { if (!forMe(transfer)) { return false; } Response *response = dynamic_cast(transfer); if (!response) { return false; } if (response->resultCode()) { setError(response->resultCode()); return true; } // look for the status code Field::FieldList responseFields = response->fields(); Field::SingleField *sf = responseFields.findSingleField(Field::NM_A_SZ_STATUS); m_queryStatus = sf->value().toInt(); Field::MultiField *resultsArray = responseFields.findMultiField(Field::NM_A_FA_RESULTS); if (!resultsArray) { setError(Protocol); return true; } Field::FieldList matches = resultsArray->fields(); const Field::FieldListIterator end = matches.end(); for (Field::FieldListIterator it = matches.find(Field::NM_A_FA_CONTACT); it != end; it = matches.find(++it, Field::NM_A_FA_CONTACT)) { Field::MultiField *mf = static_cast(*it); Field::FieldList contact = mf->fields(); GroupWise::ContactDetails cd = extractUserDetails(contact); m_results.append(cd); } // first field: Field::NM_A_SZ_STATUS contains #define SEARCH_PENDING 0 #define SEARCH_INPROGRESS 1 #define SEARCH_COMPLETED 2 #define SEARCH_TIMEOUT 3 #define SEARCH_CANCELLED 4 #define SEARCH_ERROR 5 // set a status code if needed // followed by Field::NM_A_FA_RESULTS, looks like a getdetails // add an accessor to get at the results list of ContactItems, probably if (m_queryStatus != 2) { setError(m_queryStatus); } else { setSuccess(m_queryStatus); } return true; } QList< GroupWise::ContactDetails > PollSearchResultsTask::results() { return m_results; } int PollSearchResultsTask::queryStatus() { return m_queryStatus; } GroupWise::ContactDetails PollSearchResultsTask::extractUserDetails(Field::FieldList &fields) { ContactDetails cd; cd.status = GroupWise::Invalid; cd.archive = false; // read the supplied fields, set metadata and status. Field::SingleField *sf; if ((sf = fields.findSingleField(Field::NM_A_SZ_AUTH_ATTRIBUTE))) { cd.authAttribute = sf->value().toString(); } if ((sf = fields.findSingleField(Field::NM_A_SZ_DN))) { cd.dn = sf->value().toString().toLower(); // HACK: lowercased DN } if ((sf = fields.findSingleField(Field::KOPETE_NM_USER_DETAILS_CN))) { cd.cn = sf->value().toString(); } if ((sf = fields.findSingleField(Field::KOPETE_NM_USER_DETAILS_GIVEN_NAME))) { cd.givenName = sf->value().toString(); } if ((sf = fields.findSingleField(Field::KOPETE_NM_USER_DETAILS_SURNAME))) { cd.surname = sf->value().toString(); } if ((sf = fields.findSingleField(Field::KOPETE_NM_USER_DETAILS_FULL_NAME))) { cd.fullName = sf->value().toString(); } if ((sf = fields.findSingleField(Field::KOPETE_NM_USER_DETAILS_ARCHIVE_FLAG))) { cd.archive = (sf->value().toInt() == 1); } if ((sf = fields.findSingleField(Field::NM_A_SZ_STATUS))) { cd.status = sf->value().toInt(); } if ((sf = fields.findSingleField(Field::NM_A_SZ_MESSAGE_BODY))) { cd.awayMessage = sf->value().toString(); } Field::MultiField *mf; QMap< QString, QVariant > propMap; if ((mf = fields.findMultiField(Field::NM_A_FA_INFO_DISPLAY_ARRAY))) { Field::FieldList fl = mf->fields(); const Field::FieldListIterator end = fl.end(); for (Field::FieldListIterator it = fl.begin(); it != end; ++it) { // assumes each property only present once // check in logintask.cpp and if it's a multi field, // get the value of this instance, check if it's already in the property map and append if found. Field::SingleField *propField = dynamic_cast(*it); if (propField) { QString propName = propField->tag(); QString propValue = propField->value().toString(); propMap.insert(propName, propValue); } else { Field::MultiField *propList = dynamic_cast(*it); if (propList) { QString parentName = propList->tag(); Field::FieldList propFields = propList->fields(); const Field::FieldListIterator end = propFields.end(); for (Field::FieldListIterator it = propFields.begin(); it != end; ++it) { propField = dynamic_cast(*it); if (propField) { QString propValue = propField->value().toString(); QString contents = propMap[ propField->tag() ].toString(); if (!contents.isEmpty()) { contents.append(", "); } contents.append(propField->value().toString()); propMap.insert(propField->tag(), contents); } } } } } } if (!propMap.empty()) { cd.properties = propMap; } return cd; } diff --git a/protocols/groupwise/libgroupwise/tasks/updatecontacttask.cpp b/protocols/groupwise/libgroupwise/tasks/updatecontacttask.cpp index a61e55276..3e21c1e2a 100644 --- a/protocols/groupwise/libgroupwise/tasks/updatecontacttask.cpp +++ b/protocols/groupwise/libgroupwise/tasks/updatecontacttask.cpp @@ -1,75 +1,75 @@ /* Kopete Groupwise Protocol updatecontacttask.cpp - rename a contact on the server Copyright (c) 2004 SUSE Linux AG http://www.suse.com Based on Iris, Copyright (C) 2003 Justin Karneges Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "updatecontacttask.h" #include "gwfield.h" -#include +#include using namespace GroupWise; UpdateContactTask::UpdateContactTask(Task *parent) : UpdateItemTask(parent) { } UpdateContactTask::~UpdateContactTask() { } QString UpdateContactTask::displayName() { return m_name; } void UpdateContactTask::renameContact(const QString &newName, const QList &contactInstances) { m_name = newName; // build a list of delete, add fields that removes each instance on the server and then readds it with the new name Field::FieldList lst; const QList::ConstIterator end = contactInstances.end(); for (QList::ConstIterator it = contactInstances.begin(); it != end; ++it) { Field::FieldList contactFields; contactFields.append(new Field::SingleField(Field::NM_A_SZ_OBJECT_ID, 0, NMFIELD_TYPE_UTF8, (*it).id)); contactFields.append(new Field::SingleField(Field::NM_A_SZ_PARENT_ID, 0, NMFIELD_TYPE_UTF8, (*it).parentId)); contactFields.append(new Field::SingleField(Field::NM_A_SZ_SEQUENCE_NUMBER, 0, NMFIELD_TYPE_UTF8, (*it).sequence)); if (!(*it).dn.isNull()) { contactFields.append(new Field::SingleField(Field::NM_A_SZ_DN, 0, NMFIELD_TYPE_UTF8, (*it).dn)); } if (!(*it).displayName.isNull()) { contactFields.append(new Field::SingleField(Field::NM_A_SZ_DISPLAY_NAME, 0, NMFIELD_TYPE_UTF8, (*it).displayName)); } lst.append( new Field::MultiField(Field::NM_A_FA_CONTACT, NMFIELD_METHOD_DELETE, 0, NMFIELD_TYPE_ARRAY, contactFields)); } for (QList::ConstIterator it = contactInstances.begin(); it != end; ++it) { Field::FieldList contactFields; contactFields.append(new Field::SingleField(Field::NM_A_SZ_OBJECT_ID, 0, NMFIELD_TYPE_UTF8, (*it).id)); contactFields.append(new Field::SingleField(Field::NM_A_SZ_PARENT_ID, 0, NMFIELD_TYPE_UTF8, (*it).parentId)); contactFields.append(new Field::SingleField(Field::NM_A_SZ_SEQUENCE_NUMBER, 0, NMFIELD_TYPE_UTF8, (*it).sequence)); if (!(*it).dn.isNull()) { contactFields.append(new Field::SingleField(Field::NM_A_SZ_DN, 0, NMFIELD_TYPE_UTF8, (*it).dn)); } contactFields.append(new Field::SingleField(Field::NM_A_SZ_DISPLAY_NAME, 0, NMFIELD_TYPE_UTF8, newName)); lst.append( new Field::MultiField(Field::NM_A_FA_CONTACT, NMFIELD_METHOD_ADD, 0, NMFIELD_TYPE_ARRAY, contactFields)); } //lst.dump( true ); UpdateItemTask::item(lst); } diff --git a/protocols/groupwise/libgroupwise/tasks/updatecontacttask.h b/protocols/groupwise/libgroupwise/tasks/updatecontacttask.h index 7d3e2ab7f..ae975d01f 100644 --- a/protocols/groupwise/libgroupwise/tasks/updatecontacttask.h +++ b/protocols/groupwise/libgroupwise/tasks/updatecontacttask.h @@ -1,46 +1,46 @@ /* Kopete Groupwise Protocol updatecontacttask.h - rename a contact on the server Copyright (c) 2004 SUSE Linux AG http://www.suse.com Based on Iris, Copyright (C) 2003 Justin Karneges Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef UPDATECONTACTTASK_H #define UPDATECONTACTTASK_H #include "gwerror.h" #include "libgroupwise_export.h" #include "updateitemtask.h" -#include +#include /** * Renames a contact on the server * @author Kopete Developers */ class LIBGROUPWISE_EXPORT UpdateContactTask : public UpdateItemTask { Q_OBJECT public: UpdateContactTask(Task *parent); ~UpdateContactTask(); void renameContact(const QString &newName, const QList &contactInstances); QString displayName(); private: QString m_name; }; #endif diff --git a/protocols/groupwise/ui/gwprivacydialog.cpp b/protocols/groupwise/ui/gwprivacydialog.cpp index 8dd11f1ab..3cc8154a5 100644 --- a/protocols/groupwise/ui/gwprivacydialog.cpp +++ b/protocols/groupwise/ui/gwprivacydialog.cpp @@ -1,363 +1,363 @@ /* Kopete Groupwise Protocol gwprivacydialog.cpp - dialog summarising, and editing, the user's privacy settings Copyright (c) 2006 Novell, Inc http://www.opensuse.org Copyright (c) 2004 SUSE Linux AG http://www.suse.com Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library 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. * * * ************************************************************************* */ #include "gwprivacydialog.h" #include #include #include -#include -#include +#include +#include #include #include #include #include #include "client.h" #include "gwaccount.h" #include "ui_gwcontactsearch.h" #include "gwprotocol.h" #include "gwsearch.h" #include "privacymanager.h" #include "userdetailsmanager.h" class PrivacyLBI : public QListWidgetItem { public: PrivacyLBI( const QIcon &icon, const QString & text, QListWidget * listWidget, const QString & dn ) : QListWidgetItem( icon, text, listWidget ), m_dn( dn ) { } QString dn() { return m_dn; } private: QString m_dn; }; GroupWisePrivacyDialog::GroupWisePrivacyDialog( GroupWiseAccount * account, QWidget *parent, const char * /*name*/ ) : KDialog( parent) , m_account( account ), m_dirty( false ), m_searchDlg(0) { setCaption(i18nc( "Account specific privacy settings", "Manage Privacy for %1", account->accountId() )); setButtons(KDialog::Ok|KDialog::Apply|KDialog::Cancel); setDefaultButton(Ok); setModal(false); QWidget * wid = new QWidget( this ); m_privacy.setupUi( wid ); setMainWidget( wid ); PrivacyManager * mgr = m_account->client()->privacyManager(); // populate the widget; // admin lock if ( mgr->isPrivacyLocked() ) { m_privacy.status->setText( i18n( "Privacy settings have been administratively locked" ) ); disableWidgets(); } populateWidgets(); m_privacy.allowList->setSelectionMode( QAbstractItemView::ExtendedSelection ); m_privacy.denyList->setSelectionMode( QAbstractItemView::ExtendedSelection ); connect( m_privacy.btnAllow, SIGNAL(clicked(bool)), SLOT(slotAllowClicked()) ); connect( m_privacy.btnBlock, SIGNAL(clicked(bool)), SLOT(slotBlockClicked()) ); connect( m_privacy.btnAdd, SIGNAL(clicked(bool)), SLOT(slotAddClicked()) ); connect( m_privacy.btnRemove, SIGNAL(clicked(bool)), SLOT(slotRemoveClicked()) ); connect( m_privacy.allowList, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(slotAllowListClicked()) ); connect( m_privacy.denyList, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(slotDenyListClicked()) ); connect( mgr, SIGNAL(privacyChanged(QString,bool)), SLOT(slotPrivacyChanged()) ); connect(this,SIGNAL(okClicked()),this,SLOT(slotOk())); connect(this,SIGNAL(applyClicked()),this,SLOT(slotApply())); m_privacy.btnAdd->setEnabled( true ); m_privacy.btnAllow->setEnabled( false ); m_privacy.btnBlock->setEnabled( false ); m_privacy.btnRemove->setEnabled( false ); /* showButtonOK( true ); showButtonApply( true ); showButtonCancel( true ); */ show(); } GroupWisePrivacyDialog::~GroupWisePrivacyDialog() { } void GroupWisePrivacyDialog::populateWidgets() { m_dirty = false; PrivacyManager * mgr = m_account->client()->privacyManager(); // default policy QString defaultPolicyText = i18n( "" ); if ( mgr->defaultAllow() ) m_defaultPolicy = new QListWidgetItem( defaultPolicyText, m_privacy.allowList ); else m_defaultPolicy = new QListWidgetItem( defaultPolicyText, m_privacy.denyList ); QPixmap icon = m_account->protocol()->groupwiseAvailable.iconFor( m_account ).pixmap( 16 ); // allow list QStringList allowList = mgr->allowList(); QStringList::Iterator end = allowList.end(); for ( QStringList::Iterator it = allowList.begin(); it != end; ++it ) { GroupWise::ContactDetails cd = m_account->client()->userDetailsManager()->details( *it ); if ( cd.fullName.isEmpty() ) cd.fullName = cd.givenName + ' ' + cd.surname; new PrivacyLBI( icon, cd.fullName, m_privacy.allowList, *it ); } // deny list QStringList denyList = mgr->denyList(); end = denyList.end(); for ( QStringList::Iterator it = denyList.begin(); it != end; ++it ) { GroupWise::ContactDetails cd = m_account->client()->userDetailsManager()->details( *it ); if ( cd.fullName.isEmpty() ) cd.fullName = cd.givenName + ' ' + cd.surname; new PrivacyLBI( icon, cd.fullName, m_privacy.denyList, *it ); } updateButtonState(); } void GroupWisePrivacyDialog::disableWidgets() { m_privacy.btnAllow->setEnabled( false ); m_privacy.btnBlock->setEnabled( false ); m_privacy.btnAdd->setEnabled( false ); m_privacy.btnRemove->setEnabled( false ); } void GroupWisePrivacyDialog::slotBlockClicked() { // take each selected item from the allow list and add it to the deny list // start at the bottom, as we are changing the contents of the list as we go for( int i = m_privacy.allowList->count() - 1; i >= 0 ; --i ) { if ( m_privacy.allowList->item(i)->isSelected() ) { m_dirty = true; QListWidgetItem * lbi = m_privacy.allowList->item( i ); m_privacy.allowList->takeItem( lbi->listWidget()->row(lbi) ); m_privacy.denyList->addItem( lbi ); delete lbi; } } updateButtonState(); } void GroupWisePrivacyDialog::slotAllowClicked() { // take each selected item from the deny list and add it to the allow list for( int i = m_privacy.denyList->count() - 1; i >= 0 ; --i ) { if ( m_privacy.denyList->item(i)->isSelected() ) { m_dirty = true; QListWidgetItem * lbi = m_privacy.denyList->item( i ); m_privacy.denyList->takeItem( lbi->listWidget()->row(lbi) ); m_privacy.allowList->addItem( lbi ); delete lbi; } } updateButtonState(); } void GroupWisePrivacyDialog::slotAddClicked() { if ( !m_searchDlg ) { m_searchDlg = new KDialog( this); m_searchDlg->setCaption(i18n( "Search for Contact to Block" )); m_searchDlg->setButtons(KDialog::Ok|KDialog::Cancel ); m_searchDlg->setDefaultButton(KDialog::Ok); m_searchDlg->setModal(false); m_search = new GroupWiseContactSearch( m_account, QAbstractItemView::ExtendedSelection, false, m_searchDlg ); m_searchDlg->setMainWidget( m_search ); QObject::connect( m_searchDlg, SIGNAL(okClicked()), SLOT(slotSearchedForUsers()) ); QObject::connect( m_search, SIGNAL(selectionValidates(bool)), m_searchDlg, SLOT(enableButtonOk(bool)) ); m_searchDlg->enableButtonOk( false ); } m_searchDlg->show(); } void GroupWisePrivacyDialog::slotSearchedForUsers() { // create an item for each result, in the block list QList< ContactDetails > selected = m_search->selectedResults(); QList< ContactDetails >::Iterator it = selected.begin(); const QList< ContactDetails >::Iterator end = selected.end(); QPixmap icon = m_account->protocol()->groupwiseAvailable.iconFor( m_account ).pixmap ( 16 ); for ( ; it != end; ++it ) { m_dirty = true; m_account->client()->userDetailsManager()->addDetails( *it ); if ( (*it).fullName.isEmpty() ) (*it).fullName = (*it).givenName + ' ' + (*it).surname; new PrivacyLBI( icon, (*it).fullName, m_privacy.denyList, (*it).dn ); } } void GroupWisePrivacyDialog::slotRemoveClicked() { // remove any selected items from either list, except the default policy for( int i = m_privacy.denyList->count() - 1; i >= 0 ; --i ) { if ( m_privacy.denyList->item(i)->isSelected() ) { m_dirty = true; QListWidgetItem * lbi = m_privacy.denyList->item( i ); // can't remove the default policy if ( lbi == m_defaultPolicy ) continue; QListWidgetItem *itemToBeRemoved = m_privacy.denyList->takeItem(i); delete itemToBeRemoved; } } for( int i = m_privacy.allowList->count() - 1; i >= 0 ; --i ) { if ( m_privacy.allowList->item(i)->isSelected() ) { m_dirty = true; QListWidgetItem * lbi = m_privacy.allowList->item( i ); // can't remove the default policy if ( lbi == m_defaultPolicy ) continue; QListWidgetItem *itemToBeRemoved = m_privacy.allowList->takeItem(i); delete itemToBeRemoved; } } updateButtonState(); } void GroupWisePrivacyDialog::slotAllowListClicked() { // don't get into feedback disconnect( m_privacy.denyList, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(slotDenyListClicked()) ); m_privacy.denyList->clearSelection(); connect( m_privacy.denyList, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(slotDenyListClicked()) ); bool selected = false; for( int i = m_privacy.allowList->count() - 1; i >= 0 ; --i ) { if ( m_privacy.allowList->item(i)->isSelected() ) { selected = true; break; } } m_privacy.btnAllow->setEnabled( false ); m_privacy.btnBlock->setEnabled( selected ); m_privacy.btnRemove->setEnabled( selected ); } void GroupWisePrivacyDialog::slotDenyListClicked() { // don't get into feedback disconnect( m_privacy.allowList, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(slotAllowListClicked()) ); m_privacy.allowList->clearSelection(); connect( m_privacy.allowList, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(slotAllowListClicked()) ); bool selected = false; for( int i = m_privacy.denyList->count() - 1; i >= 0 ; --i ) { if ( m_privacy.denyList->item(i)->isSelected() ) { selected = true; break; } } m_privacy.btnAllow->setEnabled( selected ); m_privacy.btnBlock->setEnabled( false ); m_privacy.btnRemove->setEnabled( selected ); } void GroupWisePrivacyDialog::slotPrivacyChanged() { m_privacy.denyList->clear(); m_privacy.allowList->clear(); populateWidgets(); } void GroupWisePrivacyDialog::updateButtonState() { enableButtonApply( m_dirty ); } void GroupWisePrivacyDialog::slotOk() { if ( m_dirty ) commitChanges(); KDialog::accept(); } void GroupWisePrivacyDialog::slotApply() { if ( m_dirty ) { commitChanges(); m_dirty = false; updateButtonState(); } #ifdef __GNUC__ #warning "kde4: port it" #endif //KDialogBase::slotApply(); } void GroupWisePrivacyDialog::commitChanges() { if ( m_account->isConnected() ) { bool defaultDeny = false; QStringList denyList; QStringList allowList; // pass on our current allow, deny and default policy to the PrivacyManager for( int i = 0; i < (int)m_privacy.denyList->count(); ++i ) { if ( m_privacy.denyList->item( i ) == m_defaultPolicy ) defaultDeny = true; else { PrivacyLBI * lbi = static_cast( m_privacy.denyList->item( i ) ); denyList.append( lbi->dn() ); } } for( int i = 0; i < (int)m_privacy.allowList->count(); ++i ) { if ( m_privacy.allowList->item( i ) == m_defaultPolicy ) defaultDeny = false; else { PrivacyLBI * lbi = static_cast( m_privacy.allowList->item( i ) ); allowList.append( lbi->dn() ); } } PrivacyManager * mgr = m_account->client()->privacyManager(); mgr->setPrivacy( defaultDeny, allowList, denyList ); } else errorNotConnected(); } void GroupWisePrivacyDialog::errorNotConnected() { KMessageBox::information( this, i18n( "You can only change privacy settings while you are logged in to the GroupWise Messenger server." ) , i18n("'%1' Not Logged In", m_account->accountId() ) ); } diff --git a/protocols/groupwise/ui/gwsearch.cpp b/protocols/groupwise/ui/gwsearch.cpp index 50a15730d..7da4f2efb 100644 --- a/protocols/groupwise/ui/gwsearch.cpp +++ b/protocols/groupwise/ui/gwsearch.cpp @@ -1,438 +1,438 @@ /* Kopete Groupwise Protocol gwsearch.cpp - logic for server side search widget Copyright (c) 2006 Novell, Inc http://www.opensuse.org Copyright (c) 2004 SUSE Linux AG http://www.suse.com Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library 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. * * * ************************************************************************* */ #include "gwsearch.h" -#include +#include #include #include #include #include #include #include #include #include #include #include "client.h" #include "gwfield.h" #include "gwaccount.h" #include "gwcontact.h" #include "gwcontactproperties.h" #include "gwprotocol.h" #include "tasks/searchusertask.h" //#include "../modeltest.h" class GroupWiseContactSearchModel : public QAbstractItemModel { public: enum ContactDetailsRole { CnRole = Qt::UserRole+1, DnRole, GivenNameRole, SurnameRole, FullNameRole, AwayMessageRole, AuthAttributeRole, StatusRole, StatusOrderedRole, ArchiveRole, PropertiesRole }; GroupWiseContactSearchModel( QList contents, GroupWiseAccount * account, QObject * parent ) : QAbstractItemModel( parent ), m_account( account ), m_contents( contents ) { } ~GroupWiseContactSearchModel() { } QModelIndex index( int row, int column, const QModelIndex& index ) const Q_DECL_OVERRIDE { if ( row >= 0 && column >= 0 && row < rowCount() && column < columnCount() && !index.isValid() ) { return createIndex( row, column ); } else { return QModelIndex(); } } QModelIndex parent( const QModelIndex & /*index*/ ) const Q_DECL_OVERRIDE { return QModelIndex(); } int columnCount( const QModelIndex & parent = QModelIndex() ) const Q_DECL_OVERRIDE { if ( parent.isValid() ) return 0; else return 4; } int rowCount( const QModelIndex & parent = QModelIndex() ) const Q_DECL_OVERRIDE { if ( parent.isValid() ) return 0; else return m_contents.count(); } QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const Q_DECL_OVERRIDE { if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) { switch ( section ) { case 0: return i18n( "Status" ); break; case 1: return QVariant( i18n( "First Name" ) ); break; case 2: return QVariant( i18n( "Last Name" ) ); break; case 3: return QVariant( i18n( "User ID" ) ); break; } } return QAbstractItemModel::headerData( section, orientation, role ); } Qt::ItemFlags flags( const QModelIndex & index ) const Q_DECL_OVERRIDE { if ( !index.isValid() ) { return 0; } return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const Q_DECL_OVERRIDE { if ( !index.isValid() ) return QVariant(); GroupWise::ContactDetails contactDetails = m_contents.at( index.row() ); switch ( role ) { case Qt::DecorationRole: if ( index.column() == 0 ) { return QVariant( GroupWiseProtocol::protocol()->gwStatusToKOS( contactDetails.status ).iconFor( m_account ) ); } else { return QVariant(); } break; case StatusOrderedRole: int statusOrdered; switch ( contactDetails.status ) { case 0: //unknown statusOrdered = 0; break; case 1: //offline statusOrdered = 1; break; case 2: //online statusOrdered = 5; break; case 3: //busy statusOrdered = 2; break; case 4: // away statusOrdered = 3; break; case 5: //idle statusOrdered = 4; break; default: statusOrdered = 0; break; } return QVariant( statusOrdered ); break; case Qt::DisplayRole: switch ( index.column() ) { case 0: return QVariant( GroupWiseProtocol::protocol()->gwStatusToKOS( contactDetails.status ).description() ); break; case 1: return QVariant( contactDetails.givenName ); case 2: return QVariant( contactDetails.surname ); case 3: return QVariant(GroupWiseProtocol::protocol()->dnToDotted( contactDetails.dn ) ); } return QVariant(); break; case CnRole: return QVariant( contactDetails.cn ); break; case DnRole: return QVariant( contactDetails.dn ); break; case GivenNameRole: return QVariant( contactDetails.givenName ); break; case SurnameRole: return QVariant( contactDetails.surname ); break; case FullNameRole: return QVariant( contactDetails.fullName ); break; case AwayMessageRole: return QVariant( contactDetails.awayMessage ); break; case AuthAttributeRole: return QVariant( contactDetails.authAttribute ); break; case StatusRole: return QVariant( contactDetails.status ); break; case ArchiveRole: return QVariant( contactDetails.archive ); break; case PropertiesRole: return QVariant( contactDetails.properties ); break; default: return QVariant(); } return QVariant(); } GroupWiseAccount * m_account; QList m_contents; }; class GroupWiseContactSearchSortProxyModel : public QSortFilterProxyModel { public: GroupWiseContactSearchSortProxyModel( QObject * parent = 0 ) : QSortFilterProxyModel( parent ) {} bool lessThan( const QModelIndex &left, const QModelIndex &right ) const Q_DECL_OVERRIDE { if ( left.column() == 0 && right.column() == 0 ) { return left.data( GroupWiseContactSearchModel::StatusOrderedRole ).toInt() < right.data( GroupWiseContactSearchModel::StatusOrderedRole ).toInt(); } else { return QSortFilterProxyModel::lessThan( left, right ); } } }; class OnlineOnlyGroupWiseContactSearchSortProxyModel : public GroupWiseContactSearchSortProxyModel { public: OnlineOnlyGroupWiseContactSearchSortProxyModel( QObject * parent = 0 ) : GroupWiseContactSearchSortProxyModel( parent ) {} bool filterAcceptsRow( int source_row, const QModelIndex & source_parent ) const Q_DECL_OVERRIDE { QModelIndex index = sourceModel()->index( source_row, 0, source_parent ); int statusOrdered = sourceModel()->data( index, GroupWiseContactSearchModel::StatusOrderedRole ).toInt(); return ( statusOrdered > 1 ); } }; GroupWiseContactSearch::GroupWiseContactSearch( GroupWiseAccount * account, QAbstractItemView::SelectionMode mode, bool onlineOnly, QWidget *parent ) : QWidget( parent ), m_account( account ) { setupUi( this ); connect( m_details, SIGNAL(clicked()), SLOT(slotShowDetails()) ); connect( m_search, SIGNAL(clicked()), SLOT(slotDoSearch()) ); connect( m_clear, SIGNAL(clicked()), SLOT(slotClear()) ); if ( onlineOnly ) { m_proxyModel = new OnlineOnlyGroupWiseContactSearchSortProxyModel( this ); } else { m_proxyModel = new GroupWiseContactSearchSortProxyModel( this ); } m_proxyModel->setDynamicSortFilter(true); m_results->header()->setClickable( true ); m_results->header()->setSortIndicator( 0, Qt::DescendingOrder ); m_results->header()->setSortIndicatorShown( true ); m_results->setSelectionMode( mode ); m_details->setEnabled( false ); } GroupWiseContactSearch::~GroupWiseContactSearch() { } void GroupWiseContactSearch::slotClear() { m_firstName->clear(); m_lastName->clear(); m_userId->clear(); m_title->clear(); m_dept->clear(); } void GroupWiseContactSearch::slotDoSearch() { // build a query QList< GroupWise::UserSearchQueryTerm > searchTerms; if ( !m_firstName->text().isEmpty() ) { GroupWise::UserSearchQueryTerm arg; arg.argument = m_firstName->text(); arg.field = Field::KOPETE_NM_USER_DETAILS_GIVEN_NAME; arg.operation = searchOperation( m_firstNameOperation->currentIndex() ); searchTerms.append( arg ); } if ( !m_lastName->text().isEmpty() ) { GroupWise::UserSearchQueryTerm arg; arg.argument = m_lastName->text(); arg.field = Field::KOPETE_NM_USER_DETAILS_SURNAME; arg.operation = searchOperation( m_lastNameOperation->currentIndex() ); searchTerms.append( arg ); } if ( !m_userId->text().isEmpty() ) { GroupWise::UserSearchQueryTerm arg; arg.argument = m_userId->text(); arg.field = Field::NM_A_SZ_USERID; arg.operation = searchOperation( m_userIdOperation->currentIndex() ); searchTerms.append( arg ); } if ( !m_title->text().isEmpty() ) { GroupWise::UserSearchQueryTerm arg; arg.argument = m_title->text(); arg.field = Field::NM_A_SZ_TITLE; arg.operation = searchOperation( m_titleOperation->currentIndex() ); searchTerms.append( arg ); } if ( !m_dept->text().isEmpty() ) { GroupWise::UserSearchQueryTerm arg; arg.argument = m_dept->text(); arg.field = Field::NM_A_SZ_DEPARTMENT; arg.operation = searchOperation( m_deptOperation->currentIndex() ); searchTerms.append( arg ); } if ( !searchTerms.isEmpty() ) { // start a search task SearchUserTask * st = new SearchUserTask( m_account->client()->rootTask() ); st->search( searchTerms ); connect( st, SIGNAL(finished()), SLOT(slotGotSearchResults()) ); st->go( true ); m_matchCount->setText( i18n( "Searching" ) ); m_details->setEnabled( false ); emit selectionValidates( false ); } else { qDebug() << "no query to perform!"; } } void GroupWiseContactSearch::slotShowDetails() { qDebug() ; // get the first selected result QModelIndexList selected = m_results->selectionModel()->selectedIndexes(); if ( !selected.empty() ) { // if they are already in our contact list, show that version QModelIndex selectedIndex = selected.first(); QString dn = m_proxyModel->data( selectedIndex, GroupWiseContactSearchModel::DnRole ).toString(); GroupWiseContact * c = m_account->contactForDN( dn ); GroupWiseContactProperties * p; if ( c ) p = new GroupWiseContactProperties( c, this ); else { p = new GroupWiseContactProperties( detailsAtIndex( selectedIndex ), this ); } p->setObjectName( QStringLiteral("gwcontactproperties") ); } } GroupWise::ContactDetails GroupWiseContactSearch::detailsAtIndex( const QModelIndex & index ) const { GroupWise::ContactDetails dt; dt.dn = m_proxyModel->data( index, GroupWiseContactSearchModel::DnRole ).toString(); dt.givenName = m_proxyModel->data( index, GroupWiseContactSearchModel::GivenNameRole ).toString(); dt.surname = m_proxyModel->data( index, GroupWiseContactSearchModel::SurnameRole ).toString(); dt.fullName = m_proxyModel->data( index, GroupWiseContactSearchModel::FullNameRole ).toString(); dt.awayMessage = m_proxyModel->data( index, GroupWiseContactSearchModel::AwayMessageRole ).toString(); dt.authAttribute = m_proxyModel->data( index, GroupWiseContactSearchModel::AuthAttributeRole ).toString(); dt.status = m_proxyModel->data( index, GroupWiseContactSearchModel::StatusRole ).toInt(); dt.archive = m_proxyModel->data( index, GroupWiseContactSearchModel::ArchiveRole ).toBool(); dt.properties = m_proxyModel->data( index, GroupWiseContactSearchModel::PropertiesRole ).toMap(); return dt; } void GroupWiseContactSearch::slotGotSearchResults() { qDebug() ; SearchUserTask * st = ( SearchUserTask * ) sender(); m_lastSearchResults.clear(); m_lastSearchResults = st->results(); m_model = new GroupWiseContactSearchModel( m_lastSearchResults, m_account, this ); //new ModelTest( m_model, this ); m_proxyModel->setSourceModel( m_model ); m_results->setModel( m_proxyModel ); m_results->resizeColumnToContents( 0 ); connect( m_results->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(slotValidateSelection()) ); m_matchCount->setText( i18np( "1 matching user found", "%1 matching users found", m_proxyModel->rowCount() ) ); // if there was only one hit, select it if ( m_lastSearchResults.count() == 1 ) { QItemSelectionModel * selectionModel = m_results->selectionModel(); QItemSelection rowSelection; rowSelection.select( m_proxyModel->index( 0, 0, QModelIndex() ), m_proxyModel->index(0, 3, QModelIndex() ) ); selectionModel->select( rowSelection, QItemSelectionModel::Select ); } m_results->selectionModel()->selectedRows(); } QList< GroupWise::ContactDetails > GroupWiseContactSearch::selectedResults() { QList< GroupWise::ContactDetails> lst; if (m_results->selectionModel()) { foreach( QModelIndex index, m_results->selectionModel()->selectedRows() ) { lst.append( detailsAtIndex( index ) ); } } else { qDebug() << "called when no model was set!"; kBacktrace(); } return lst; } unsigned char GroupWiseContactSearch::searchOperation( int comboIndex ) { switch ( comboIndex ) { case 0: return NMFIELD_METHOD_SEARCH; case 1: return NMFIELD_METHOD_MATCHBEGIN; case 2: return NMFIELD_METHOD_EQUAL; } return NMFIELD_METHOD_IGNORE; } void GroupWiseContactSearch::slotValidateSelection() { int selectedCount = m_results->selectionModel()->selectedRows().count(); m_details->setEnabled( selectedCount == 1 ); emit selectionValidates( selectedCount != 0 ); } diff --git a/protocols/jabber/libjingle.h b/protocols/jabber/libjingle.h index 2bc53a6a9..4f7899ee9 100644 --- a/protocols/jabber/libjingle.h +++ b/protocols/jabber/libjingle.h @@ -1,247 +1,247 @@ /* libjingle.h - libjingle support Copyright (c) 2009-2014 by Pali RohĂ¡r ************************************************************************* * * * This library 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. * * * ************************************************************************* */ #ifndef Libjingle_H #define Libjingle_H -#include +#include #include #include class QTimer; class LibjingleCallDialog; /** * @author Pali RohĂ¡r * @short Class to use libjingle with external apps * This provide support for libjingle client. Now it support voice call using external libjingle example libjingle-call application * @todo Add support for libjingle file transfer * You must have installed "libjingle-call" application in PATH */ class Libjingle : public QObject { Q_OBJECT public: /** * Constructor * It does not login automatically. For login use @see login() * @param jid user name (jabber jid) for jabber account (default none) * @param password password for jabber account (default none) * @param host server host for jabber account (default google's one) * @param port server port for jabber account (default google's one) */ Libjingle(const QString &jid = QString(), const QString &password = QString(), const QString &host = QString(), quint16 port = 0); /** * Destructor */ ~Libjingle(); /** * Set (or change) user name and password for jabber account * Use it if you do not set up in constructor * If you change, first logout @see logout() * @param jid user name (jabber jid) for jabber account (default none) * @param password password for jabber account (default none) */ void setUser(const QString &jid, const QString &password); /** * Set (or change) server host and port for jabber account * Use it if you do not set up in constructor * If you change, first logout @see logout() * @param host server host for jabber account (default google's one) * @param port server port for jabber account (default google's one) */ void setServer(const QString &host, quint16 port); /** * Check if user is online, support libjingle voice call and if no voice call is active * @param user name of contact * @return true if user support voice call */ bool isOnline(const QString &user); /** * Check if we are connected * @return true if we are connected */ bool isConnected(); /** * Set online status * You must be connected @see login() @see connected() * @param status jabber online status (none offline xa away dnd online chat) */ void setStatus(const QString &status); public Q_SLOTS: /** * Start and login to jabber server using libjingle example libjingle-call application for voice call support * Do not forget specify user name and password for jabber account * @see setUser(const QString &jid, const QString &password) @see Libjingle(const QString &jid = QString(), const QString &password = QString()) */ void login(); /** * Logout and quit from jabber server using libjingle example libjingle-call application for voice call support * @param res Resolution why you are going to logout * Resolution is only for signal @see disconnected() */ void logout(const QString &res = QString()); /** * It start voice call to user using external libjingle example libjingle-call application * You must be connected if you want to start voice call @see login() @see connected() * @param user Specify user for voice call */ void makeCall(const QString &user); /** * Accept incoming call */ void acceptCall(); /** * Reject incoming call */ void rejectCall(); /** * Hang up active call */ void hangupCall(); /** * Call both hangupCall() and rejectCall() */ void cancelCall(); /** * Mute or unmute active call * @param b true for mute, false for unmute */ void muteCall(bool b); private: /// libjingle example libjingle-call application process QProcess * callProcess; /// user name (jid) for jabber account QString jid; /// password for jabber account QString password; /// server host for jabber account QString host; /// server port for jabber account quint16 port; /// variable if we are connected bool c; /// variable if we are active voice call bool activeCall; /// variable if libjingle is supported (if libjingle-call exist in PATH) bool support; /// List of all online user, who support voice call QMultiHash usersOnline; /// voice call dialog LibjingleCallDialog * callDialog; /// show voice call dialog void openCallDialog(); /// hide voice call dialog void closeCallDialog(); /// restart timer QTimer * timer; private Q_SLOTS: /// slot for read all available data from libjingle example libjingle-call application void read(); /// slot for write line to libjingle example libjingle-call application void write(const QByteArray &line); /// slot called when libjingle example libjingle-call application failed to start void error(QProcess::ProcessError error); /// slot called when libjingle example libjingle-call application exit or crashed void finished(int, QProcess::ExitStatus exitStatus); /// slot for restart libjingle example libjingle-call application void restart(); Q_SIGNALS: /** * This signal is emitted when we are succesfull login to jabber server */ void connected(); /** * This signal is emitted when we are disconnected or logouted from jabber server * @param res Resolution why we are disconneced */ void disconnected(const QString &res); /** * This signal is emitted when user go online and support voice call * @param user name of who go online * @param resource jabber resource of user */ void userOnline(const QString &user, const QString &resource); /** * This signal is emitted when user go offline or not support voice call * After succesfull login it is all user who are online, but dont support voice call * @param user name of user who go offline * @param resource jabber resource of user */ void userOffline(const QString &user, const QString &resourc); /** * This signal is emitted when user call you * @param user name of user who are call you * @param resource jabber resource of user */ void incomingCall(const QString &user, const QString &resourc); /** * This signal is emitted when you start call, but user from other side does not accept/reject call */ void callingCall(); /** * This signal is emitted when user from other side accept call */ void acceptedCall(); /** * This signal is emitted when user from other side reject call */ void rejectedCall(); /** * This signal is emitted when call is active in all side */ void progressCall(); /** * This signal is emitted when user from other side hang up call */ void hangedupCall(); }; #endif // Libjingle_H diff --git a/protocols/jabber/ui/dlgjabberbookmarkeditor.cpp b/protocols/jabber/ui/dlgjabberbookmarkeditor.cpp index 2e14e59ed..f2e7463e5 100644 --- a/protocols/jabber/ui/dlgjabberbookmarkeditor.cpp +++ b/protocols/jabber/ui/dlgjabberbookmarkeditor.cpp @@ -1,166 +1,166 @@ /* Copyright (c) 2011 by Tobias Koenig ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #include "dlgjabberbookmarkeditor.h" #include -#include +#include class JabberBookmarkModel : public QAbstractListModel { public: enum Role { NameRole = Qt::UserRole, AutoJoinRole }; JabberBookmarkModel( QObject *parent = nullptr ) : QAbstractListModel( parent ) { } void setBookmarks( const JabberBookmark::List &bookmarks ) { beginResetModel(); m_bookmarks = bookmarks; endResetModel(); } JabberBookmark::List bookmarks() const { return m_bookmarks; } int rowCount( const QModelIndex &parent ) const Q_DECL_OVERRIDE { if ( parent.isValid() ) return 0; return m_bookmarks.count(); } QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const Q_DECL_OVERRIDE { if ( index.row() >= m_bookmarks.count() ) return QVariant(); const JabberBookmark bookmark = m_bookmarks.at( index.row() ); switch ( role ) { case Qt::DisplayRole: return QStringLiteral( "%1 (%2)" ).arg( bookmark.fullJId() ).arg( bookmark.name() ); case Qt::DecorationRole: return bookmark.autoJoin() ? QIcon::fromTheme(QStringLiteral("irc-join-channel")) : QVariant(); case NameRole: return bookmark.name(); case AutoJoinRole: return bookmark.autoJoin(); } return QVariant(); } bool setData( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole ) Q_DECL_OVERRIDE { if ( index.row() >= m_bookmarks.count() ) return false; JabberBookmark &bookmark = m_bookmarks[ index.row() ]; if ( role == NameRole ) { bookmark.setName( value.toString() ); emit dataChanged( index, index ); return true; } else if ( role == AutoJoinRole ) { bookmark.setAutoJoin( value.toBool() ); emit dataChanged( index, index ); return true; } return false; } bool removeRows( int row, int count, const QModelIndex &parent = QModelIndex() ) Q_DECL_OVERRIDE { beginRemoveRows( parent, row, row + count - 1 ); for ( int i = 0; i < count; ++i ) m_bookmarks.removeAt( row ); endRemoveRows(); return true; } JabberBookmark::List m_bookmarks; }; DlgJabberBookmarkEditor::DlgJabberBookmarkEditor( const JabberBookmark::List &bookmarks, QWidget *parent ) : KDialog( parent ) { m_ui.setupUi( mainWidget() ); m_model = new JabberBookmarkModel( this ); m_model->setBookmarks( bookmarks ); m_ui.listView->setModel( m_model ); connect( m_ui.renameButton, SIGNAL(clicked()), SLOT(renameBookmark()) ); connect( m_ui.autoJoinButton, SIGNAL(clicked()), SLOT(toggleAutoJoin()) ); connect( m_ui.removeButton, SIGNAL(clicked()), SLOT(removeBookmark()) ); } DlgJabberBookmarkEditor::~DlgJabberBookmarkEditor() { } JabberBookmark::List DlgJabberBookmarkEditor::bookmarks() const { return m_model->bookmarks(); } void DlgJabberBookmarkEditor::renameBookmark() { if ( !m_ui.listView->selectionModel()->hasSelection() ) return; const QModelIndex index = m_ui.listView->selectionModel()->selectedRows().first(); const QString name = QInputDialog::getText( nullptr, i18n( "Group Chat Name" ), i18n( "Enter a name for the group chat:" ), QLineEdit::Normal, index.data( JabberBookmarkModel::NameRole ).toString() ); if ( !name.isEmpty() ) { m_model->setData( index, name, JabberBookmarkModel::NameRole ); } } void DlgJabberBookmarkEditor::toggleAutoJoin() { if ( !m_ui.listView->selectionModel()->hasSelection() ) return; const QModelIndex index = m_ui.listView->selectionModel()->selectedRows().first(); m_model->setData( index, QVariant( !index.data( JabberBookmarkModel::AutoJoinRole ).toBool() ), JabberBookmarkModel::AutoJoinRole ); } void DlgJabberBookmarkEditor::removeBookmark() { if ( !m_ui.listView->selectionModel()->hasSelection() ) return; const QModelIndex index = m_ui.listView->selectionModel()->selectedRows().first(); m_model->removeRow( index.row() ); } diff --git a/protocols/oscar/liboscar/chatroomhandler.h b/protocols/oscar/liboscar/chatroomhandler.h index dc996ad34..de5b25509 100644 --- a/protocols/oscar/liboscar/chatroomhandler.h +++ b/protocols/oscar/liboscar/chatroomhandler.h @@ -1,55 +1,55 @@ /* Kopete Oscar Protocol Chat Room Handler Copyright 2009 Benson Tsai Kopete ( c ) 2002-2009 by the Kopete developers based on filetransferhandler.h and filetransferhandler.cpp ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or ( at your option ) any later version. * * * ************************************************************************* */ #ifndef CHATROOMHANDLER_H #define CHATROOMHANDLER_H -#include +#include #include "oscartypes.h" #include "liboscar_export.h" class ChatRoomTask; class LIBOSCAR_EXPORT ChatRoomHandler : public QObject { Q_OBJECT public: ChatRoomHandler( ChatRoomTask* chatRoomTask ); void send(); QString internalId() const; QString contact() const; QString invite() const; Oscar::WORD exchange() const; QString room() const; public Q_SLOTS: void reject(); void accept(); Q_SIGNALS: void joinChatRoom( const QString& roomName, int exchange ); private: ChatRoomTask* m_chatRoomTask; }; #endif diff --git a/protocols/oscar/liboscar/client.cpp b/protocols/oscar/liboscar/client.cpp index 147b8ca1f..3dfbc8811 100644 --- a/protocols/oscar/liboscar/client.cpp +++ b/protocols/oscar/liboscar/client.cpp @@ -1,1856 +1,1856 @@ /* client.cpp - Kopete Oscar Protocol Copyright (c) 2004-2005 Matt Rogers Copyright (c) 2008 Roman Jarosz Based on code Copyright (c) 2004 SuSE Linux AG Based on Iris, Copyright (C) 2003 Justin Karneges Kopete (c) 2002-2008 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "client.h" #include #include #include #include #include -#include +#include #include //for qDebug() #include #include "filetransfertask.h" #include "buddyicontask.h" #include "clientreadytask.h" #include "connectionhandler.h" #include "chatnavservicetask.h" #include "errortask.h" #include "icquserinfo.h" #include "icquserinfotask.h" #include "logintask.h" #include "connection.h" #include "messagereceivertask.h" #include "messageacktask.h" #include "onlinenotifiertask.h" #include "oscarclientstream.h" #include "oscarsettings.h" #include "oscarutils.h" #include "ownuserinfotask.h" #include "profiletask.h" #include "senddcinfotask.h" #include "sendmessagetask.h" #include "serverredirecttask.h" #include "servicesetuptask.h" #include "contactmanager.h" #include "ssimodifytask.h" #include "ssiauthtask.h" #include "offlinemessagestask.h" #include "task.h" #include "typingnotifytask.h" #include "userinfotask.h" #include "usersearchtask.h" #include "warningtask.h" #include "chatservicetask.h" #include "rateclassmanager.h" #include "icquserinfoupdatetask.h" #include "icqchangepasswordtask.h" #include "oscarmessageplugin.h" #include "xtrazxtraznotify.h" #include "xtrazxawayservice.h" #include "closeconnectiontask.h" #include "icqtlvinforequesttask.h" #include "icqtlvinfoupdatetask.h" #include "filetransferhandler.h" #include "chatroomtask.h" #include "chatroomhandler.h" namespace { class DefaultCodecProvider : public Client::CodecProvider { public: QTextCodec* codecForContact( const QString& ) const Q_DECL_OVERRIDE { return QTextCodec::codecForMib( 4 ); } QTextCodec* codecForAccount() const Q_DECL_OVERRIDE { return QTextCodec::codecForMib( 4 ); } }; DefaultCodecProvider defaultCodecProvider; } namespace Oscar { class Client::ClientPrivate { public: ClientPrivate() {} QString host, user, pass; uint port; bool encrypted; bool encrypted2; QString SSLName; int tzoffset; bool active; enum { StageOne, StageTwo }; int stage; StageOneLoginTask* loginTask; QPointer loginTaskTwo; //Protocol specific data bool isIcq; bool redirectRequested; QList redirectionServices; Oscar::WORD currentRedirect; bool offlineMessagesRequested; QByteArray cookie; Oscar::Settings* settings; //Tasks ErrorTask* errorTask; OnlineNotifierTask* onlineNotifier; OwnUserInfoTask* ownStatusTask; MessageReceiverTask* messageReceiverTask; MessageAckTask* messageAckTask; SSIAuthTask* ssiAuthTask; ICQUserInfoRequestTask* icqInfoTask; ICQTlvInfoRequestTask* icqTlvInfoTask; UserInfoTask* userInfoTask; TypingNotifyTask * typingNotifyTask; SSIModifyTask* ssiModifyTask; //Managers ContactManager* ssiManager; ConnectionHandler connections; //Our Userinfo UserDetails ourDetails; //Infos QList exchanges; struct Status { Oscar::DWORD status; QString message; // for away-,DND-message etc., and for Xtraz status int xtraz; // Xtraz status int mood; // Mood QString title; // Xtraz/Mood title bool sent; } status; //away messages struct AwayMsgRequest { QString contact; ICQStatus contactStatus; }; QList awayMsgRequestQueue; QTimer* awayMsgRequestTimer; CodecProvider* codecProvider; const Oscar::ClientVersion* version; Guid versionCap; }; Client::Client( QObject* parent ) :QObject( parent ) { setObjectName( QStringLiteral("oscarclient") ); d = new ClientPrivate; d->tzoffset = 0; d->active = false; d->isIcq = false; //default to AIM d->redirectRequested = false; d->currentRedirect = 0; d->offlineMessagesRequested = false; d->status.status = 0x0; // default to online d->status.xtraz = -1; // default to no Xtraz d->status.mood = -1; d->status.sent = false; d->ssiManager = new ContactManager( this ); d->settings = new Oscar::Settings(); d->errorTask = nullptr; d->onlineNotifier = nullptr; d->ownStatusTask = nullptr; d->messageReceiverTask = nullptr; d->messageAckTask = nullptr; d->ssiAuthTask = nullptr; d->icqInfoTask = nullptr; d->icqTlvInfoTask = nullptr; d->userInfoTask = nullptr; d->stage = ClientPrivate::StageOne; d->loginTask = nullptr; d->loginTaskTwo = nullptr; d->typingNotifyTask = nullptr; d->ssiModifyTask = nullptr; d->awayMsgRequestTimer = new QTimer(); d->codecProvider = &defaultCodecProvider; connect( this, SIGNAL(redirectionFinished(Oscar::WORD)), this, SLOT(checkRedirectionQueue(Oscar::WORD)) ); connect( d->awayMsgRequestTimer, SIGNAL(timeout()), this, SLOT(nextICQAwayMessageRequest()) ); } Client::~Client() { //delete the connections differently than in deleteConnections() //deleteLater() seems to cause destruction order issues deleteStaticTasks(); delete d->settings; delete d->ssiManager; delete d->awayMsgRequestTimer; delete d; } Oscar::Settings* Client::clientSettings() const { return d->settings; } void Client::connectToServer( const QString& host, quint16 port, bool encrypted, const QString &name ) { ClientStream* cs = createClientStream(); Connection* c = new Connection( cs, "AUTHORIZER" ); c->setClient( this ); d->encrypted2 = encrypted; d->loginTask = new StageOneLoginTask( c->rootTask() ); connect( d->loginTask, SIGNAL(finished()), this, SLOT(lt_loginFinished()) ); connectToServer( c, host, port, encrypted, name ); } void Client::start( const QString &host, const uint port, const QString &userId, const QString &pass ) { Q_UNUSED( host ); Q_UNUSED( port ); // Cleanup client close(); d->user = userId; d->pass = pass; d->stage = ClientPrivate::StageOne; d->active = false; } void Client::close() { QList cList = d->connections.connections(); for ( int i = 0; i < cList.size(); i++ ) { Connection* c = cList.at(i); (new CloseConnectionTask( c->rootTask() ))->go( Task::AutoDelete ); foreach ( Oscar::MessageInfo info, c->messageInfoList() ) emit messageError( info.contact, info.id ); } d->active = false; d->awayMsgRequestTimer->stop(); d->awayMsgRequestQueue.clear(); d->connections.clear(); deleteStaticTasks(); //don't clear the stored status between stage one and two if ( d->stage == ClientPrivate::StageTwo ) { d->status.status = 0x0; d->status.xtraz = -1; d->status.mood = -1; d->status.sent = false; d->status.message.clear(); d->status.title.clear(); } d->exchanges.clear(); d->redirectRequested = false; d->currentRedirect = 0; d->redirectionServices.clear(); d->ssiManager->clear(); d->offlineMessagesRequested = false; } void Client::setStatus( Oscar::DWORD status, const QString &message, int xtraz, const QString &title, int mood ) { kDebug(OSCAR_RAW_DEBUG) << "Setting status message to "<< message; // remember the values to reply with, when requested bool xtrazChanged = (xtraz > -1 || d->status.xtraz != xtraz); bool moodChanged = (mood > -1 || d->status.mood != mood); bool statusInfoChanged = ( !d->status.sent || message != d->status.message || title != d->status.title ); d->status.status = status; d->status.message = message; d->status.xtraz = xtraz; d->status.mood = mood; d->status.title = title; d->status.sent = false; if ( d->active ) { if ( d->isIcq ) { // Set invisible/visible flag Oscar::BYTE privacyByte = ( ( status & 0x0100 ) == 0x0100 ) ? 0x03 : 0x04; setPrivacyTLVs( privacyByte ); } Connection* c = d->connections.connectionForFamily( 0x0002 ); if ( !c ) return; if ( d->isIcq && statusInfoChanged ) { ICQFullInfo info( false ); info.statusDescription.set( title.toUtf8() ); ICQTlvInfoUpdateTask* infoUpdateTask = new ICQTlvInfoUpdateTask( c->rootTask() ); infoUpdateTask->setInfo( info ); infoUpdateTask->go( Task::AutoDelete ); } SendDCInfoTask* sdcit = new SendDCInfoTask( c->rootTask(), status ); if ( d->isIcq && moodChanged ) sdcit->setIcqMood( mood ); if ( d->isIcq && statusInfoChanged ) sdcit->setStatusMessage( title ); if ( !d->isIcq && (status & 0xFF) == 0x00 ) //not icq and status is online sdcit->setStatusMessage( message ); QString msg; // AIM: you're away exactly when your away message isn't empty. // can't use QString() as a message either; ProfileTask // interprets null as "don't change". if ( (status & 0xFF) == 0x00 ) //is status online? { msg = QString::fromAscii(""); } else { if ( message.isEmpty() ) msg = QString::fromAscii(" "); else msg = message; } ProfileTask* pt = new ProfileTask( c->rootTask() ); pt->setAwayMessage( msg ); if ( d->isIcq && xtrazChanged ) pt->setXtrazStatus( xtraz ); pt->go( Task::AutoDelete ); //Has to be sent after ProfileTask otherwise the EA, DND will be wrong sdcit->go( Task::AutoDelete ); d->status.sent = true; } } UserDetails Client::ourInfo() const { return d->ourDetails; } QString Client::host() { return d->host; } int Client::port() { return d->port; } bool Client::encrypted() { return d->encrypted; } QString Client::SSLName() { return d->SSLName; } ContactManager* Client::ssiManager() const { return d->ssiManager; } const Oscar::ClientVersion* Client::version() const { return d->version; } Guid Client::versionCap() const { return d->versionCap; } // SLOTS // void Client::streamConnected() { kDebug(OSCAR_RAW_DEBUG) ; if ( d->loginTaskTwo ) d->loginTaskTwo->go( Task::AutoDelete ); } void Client::lt_loginFinished() { /* Check for stage two login first, since we create the stage two * task when we finish stage one */ if ( d->stage == ClientPrivate::StageTwo ) { //we've finished logging in. start the services setup kDebug(OSCAR_RAW_DEBUG) << "stage two done. setting up services"; initializeStaticTasks(); ServiceSetupTask* ssTask = new ServiceSetupTask( d->connections.defaultConnection()->rootTask() ); connect( ssTask, SIGNAL(finished()), this, SLOT(serviceSetupFinished()) ); ssTask->go( Task::AutoDelete ); //fire and forget } else if ( d->stage == ClientPrivate::StageOne ) { kDebug(OSCAR_RAW_DEBUG) << "stage one login done"; disconnect( d->loginTask, SIGNAL(finished()), this, SLOT(lt_loginFinished()) ); if ( d->loginTask->statusCode() == 0 ) //we can start stage two { kDebug(OSCAR_RAW_DEBUG) << "no errors from stage one. moving to stage two"; //cache these values since they'll be deleted when we close the connections (which deletes the tasks) d->host = d->loginTask->bosServer(); d->port = d->loginTask->bosPort().toUInt(); d->encrypted = d->loginTask->bosEncrypted(); d->SSLName = d->loginTask->bosSSLName(); d->cookie = d->loginTask->loginCookie(); close(); QTimer::singleShot( 100, this, SLOT(startStageTwo()) ); d->stage = ClientPrivate::StageTwo; } else { kDebug(OSCAR_RAW_DEBUG) << "errors reported. not moving to stage two"; close(); //deletes the connections for us } d->loginTask->deleteLater(); d->loginTask = 0; } } void Client::startStageTwo() { //create a new connection and set it up Connection* c = createConnection(); new CloseConnectionTask( c->rootTask() ); //create the new login task d->loginTaskTwo = new StageTwoLoginTask( c->rootTask() ); d->loginTaskTwo->setCookie( d->cookie ); QObject::connect( d->loginTaskTwo, SIGNAL(finished()), this, SLOT(lt_loginFinished()) ); //connect QObject::connect( c, SIGNAL(connected()), this, SLOT(streamConnected()) ); connectToServer( c, d->host, d->port, d->encrypted, d->SSLName ) ; } void Client::serviceSetupFinished() { d->active = true; setStatus( d->status.status, d->status.message, d->status.xtraz, d->status.title, d->status.mood ); d->ownStatusTask->go(); emit haveContactList(); emit loggedIn(); } void Client::receivedIcqInfo( const QString& contact, unsigned int type ) { kDebug(OSCAR_RAW_DEBUG) << "received icq info for " << contact << " of type " << type << endl; if ( type == ICQUserInfoRequestTask::Short ) emit receivedIcqShortInfo( contact ); else emit receivedIcqLongInfo( contact ); } void Client::receivedInfo( Oscar::DWORD sequence ) { UserDetails details = d->userInfoTask->getInfoFor( sequence ); emit receivedUserInfo( details.userId(), details ); } void Client::offlineUser( const QString& user, const UserDetails& ) { emit userIsOffline( user ); } void Client::haveOwnUserInfo() { kDebug( OSCAR_RAW_DEBUG ); UserDetails ud = d->ownStatusTask->getInfo(); d->ourDetails = ud; emit haveOwnInfo(); if ( !d->offlineMessagesRequested && d->active ) { //retrieve offline messages Connection* c = d->connections.connectionForFamily( 0x0004 ); if ( !c ) return; OfflineMessagesTask *offlineMsgTask = new OfflineMessagesTask( c->rootTask() ); offlineMsgTask->go( Task::AutoDelete ); d->offlineMessagesRequested = true; } } void Client::setCodecProvider( Client::CodecProvider* codecProvider ) { d->codecProvider = codecProvider; } void Client::setVersion( const Oscar::ClientVersion* version ) { d->version = version; } void Client::setVersionCap( const QByteArray &cap ) { d->versionCap = Guid( cap ); } // INTERNALS // QString Client::userId() const { return d->user; } QString Client::password() const { return d->pass; } int Client::statusXtraz() const { return d->status.xtraz; } int Client::statusMood() const { return d->status.mood; } QString Client::statusTitle() const { return d->status.title; } QString Client::statusMessage() const { return d->status.message; } void Client::setStatusMessage( const QString &message ) { d->status.message = message; } QByteArray Client::ipAddress() const { //!TODO determine ip address return "127.0.0.1"; } void Client::notifyTaskError( const Oscar::SNAC& s, int errCode, bool fatal ) { emit taskError( s, errCode, fatal ); } void Client::notifySocketError( int errCode, const QString& msg ) { emit socketError( errCode, msg ); } void Client::sendMessage( const Oscar::Message& msg, bool isAuto) { Connection* c = nullptr; if ( msg.channel() == 0x0003 ) { c = d->connections.connectionForChatRoom( msg.exchange(), msg.chatRoom() ); if ( !c ) return; kDebug(OSCAR_RAW_DEBUG) << "sending message to chat room: " << msg.chatRoom() << " on exchange " << msg.exchange(); ChatServiceTask* cst = new ChatServiceTask( c->rootTask(), msg.exchange(), msg.chatRoom() ); cst->setMessage( msg ); cst->setEncoding( d->codecProvider->codecForAccount()->name() ); cst->go( Task::AutoDelete ); } else { c = d->connections.connectionForFamily( 0x0004 ); if ( !c ) return; SendMessageTask *sendMsgTask = new SendMessageTask( c->rootTask() ); // Set whether or not the message is an automated response sendMsgTask->setAutoResponse( isAuto ); sendMsgTask->setMessage( msg ); sendMsgTask->go( Task::AutoDelete ); } } void Client::receivedMessage( const Oscar::Message& msg ) { if ( msg.channel() == 2 && !msg.hasProperty( Oscar::Message::AutoResponse ) ) { // channel 2 message needs an autoresponse, regardless of type Connection* c = d->connections.connectionForFamily( 0x0004 ); if ( !c ) return; Oscar::Message response ( msg ); if ( msg.hasProperty( Oscar::Message::StatusMessageRequest ) ) { kDebug( OSCAR_RAW_DEBUG ) << "Away message request"; QTextCodec* codec = d->codecProvider->codecForContact( msg.sender() ); response.setText( Oscar::Message::UserDefined, statusMessage(), codec ); emit userReadsStatusMessage( msg.sender() ); } else if ( msg.messageType() == Oscar::MessageType::Plugin ) { Oscar::MessagePlugin::Types type = msg.plugin()->type(); Oscar::WORD subType = msg.plugin()->subTypeId(); if ( type == Oscar::MessagePlugin::XtrazScript ) { if ( subType == Oscar::MessagePlugin::SubScriptNotify ) { using namespace Xtraz; XtrazNotify xNotify; xNotify.handle( msg.plugin() ); if ( xNotify.type() == XtrazNotify::Request && xNotify.pluginId() == QLatin1String("srvMng") ) { if ( xNotify.findService( QStringLiteral("cAwaySrv") ) ) { XtrazNotify xNotifyResponse; xNotifyResponse.setSenderUni( userId() ); response.setPlugin( xNotifyResponse.statusResponse( statusXtraz(), statusTitle(), statusMessage() ) ); emit userReadsStatusMessage( msg.sender() ); } } } } else if ( type == Oscar::MessagePlugin::StatusMsgExt ) { Buffer buffer; buffer.addLEDBlock( statusMessage().toUtf8() ); //TODO: Change this to text/x-aolrtf buffer.addLEDBlock( "text/plain" ); msg.plugin()->setData( buffer.buffer() ); emit userReadsStatusMessage( msg.sender() ); } } else { response.setEncoding( Oscar::Message::UserDefined ); response.setTextArray( QByteArray() ); } response.setReceiver( msg.sender() ); response.addProperty( Oscar::Message::AutoResponse ); SendMessageTask *sendMsgTask = new SendMessageTask( c->rootTask() ); sendMsgTask->setMessage( response ); sendMsgTask->go( Task::AutoDelete ); } if ( msg.hasProperty( Oscar::Message::AutoResponse ) ) { if ( msg.hasProperty( Oscar::Message::StatusMessageRequest ) ) { // we got a response to a status message request. QString awayMessage( msg.text( d->codecProvider->codecForContact( msg.sender() ) ) ); kDebug( OSCAR_RAW_DEBUG ) << "Received an away message: " << awayMessage; emit receivedAwayMessage( msg.sender(), awayMessage ); } else if ( msg.messageType() == Oscar::MessageType::Plugin ) { kDebug( OSCAR_RAW_DEBUG ) << "Received an plugin message response."; Oscar::MessagePlugin::Types type = msg.plugin()->type(); Oscar::WORD subType = msg.plugin()->subTypeId(); if ( type == Oscar::MessagePlugin::XtrazScript ) { if ( subType == Oscar::MessagePlugin::SubScriptNotify ) { using namespace Xtraz; XtrazNotify xNotify; xNotify.handle( msg.plugin() ); if ( xNotify.type() == XtrazNotify::Response ) { const Xtraz::XAwayService* service = dynamic_cast(xNotify.findService( QStringLiteral("cAwaySrv") )); if ( service ) emit receivedXStatusMessage( service->senderId(), service->iconIndex(), service->description(), service->message() ); } } } else if ( type == Oscar::MessagePlugin::StatusMsgExt ) { // we got a response to a status message request. Buffer buffer( msg.plugin()->data() ); QString awayMessage = QString::fromUtf8( buffer.getLEDBlock() ); kDebug( OSCAR_RAW_DEBUG ) << "Received an away message: " << awayMessage; emit receivedAwayMessage( msg.sender(), awayMessage ); } } } else { if ( msg.messageType() == Oscar::MessageType::Plugin ) { kDebug( OSCAR_RAW_DEBUG ) << "Received a plugin message."; } else if ( !msg.hasProperty( Oscar::Message::StatusMessageRequest ) ) { // Filter out miranda's invisible check if ( msg.messageType() == 0x0004 && msg.textArray().isEmpty() ) return; // let application handle it kDebug( OSCAR_RAW_DEBUG ) << "Emitting receivedMessage"; emit messageReceived( msg ); } } } void Client::fileMessage( const Oscar::Message& msg ) { Connection* c = d->connections.connectionForFamily( 0x0004 ); if ( !c ) return; kDebug( OSCAR_RAW_DEBUG ) << "internal ip: " << c->localAddress().toString(); kDebug( OSCAR_RAW_DEBUG ) << "external ip: " << ourInfo().dcExternalIp().toString(); SendMessageTask *sendMsgTask = new SendMessageTask( c->rootTask() ); // Set whether or not the message is an automated response sendMsgTask->setAutoResponse( false ); sendMsgTask->setMessage( msg ); sendMsgTask->setIp( c->localAddress().toIPv4Address() ); sendMsgTask->go( Task::AutoDelete ); } void Client::requestAuth( const QString& contactid, const QString& reason ) { Connection* c = d->connections.connectionForFamily( 0x0013 ); if ( !c ) return; d->ssiAuthTask->sendAuthRequest( contactid, reason ); } void Client::sendAuth( const QString& contactid, const QString& reason, bool auth ) { Connection* c = d->connections.connectionForFamily( 0x0013 ); if ( !c ) return; d->ssiAuthTask->sendAuthReply( contactid, reason, auth ); } bool Client::isActive() const { return d->active; } bool Client::isIcq() const { return d->isIcq; } void Client::setIsIcq( bool isIcq ) { d->isIcq = isIcq; } void Client::debug( const QString& str ) { Q_UNUSED(str); // qDebug( "CLIENT: %s", str.toAscii() ); } void Client::initializeStaticTasks() { //set up the extra tasks Connection* c = d->connections.defaultConnection(); if ( !c ) return; d->errorTask = new ErrorTask( c->rootTask() ); d->onlineNotifier = new OnlineNotifierTask( c->rootTask() ); d->ownStatusTask = new OwnUserInfoTask( c->rootTask() ); d->messageReceiverTask = new MessageReceiverTask( c->rootTask() ); d->messageAckTask = new MessageAckTask( c->rootTask() ); d->ssiAuthTask = new SSIAuthTask( c->rootTask() ); d->icqInfoTask = new ICQUserInfoRequestTask( c->rootTask() ); d->icqTlvInfoTask = new ICQTlvInfoRequestTask( c->rootTask() ); d->userInfoTask = new UserInfoTask( c->rootTask() ); d->typingNotifyTask = new TypingNotifyTask( c->rootTask() ); d->ssiModifyTask = new SSIModifyTask( c->rootTask(), true ); connect( d->onlineNotifier, SIGNAL(userIsOnline(QString,UserDetails)), this, SIGNAL(receivedUserInfo(QString,UserDetails)) ); connect( d->onlineNotifier, SIGNAL(userIsOffline(QString,UserDetails)), this, SLOT(offlineUser(QString,UserDetails)) ); connect( d->ownStatusTask, SIGNAL(gotInfo()), this, SLOT(haveOwnUserInfo()) ); connect( d->ownStatusTask, SIGNAL(buddyIconUploadRequested()), this, SIGNAL(iconNeedsUploading()) ); connect( d->messageReceiverTask, SIGNAL(receivedMessage(Oscar::Message)), this, SLOT(receivedMessage(Oscar::Message)) ); connect( d->messageReceiverTask, SIGNAL(fileMessage(int,QString,QByteArray,Buffer)), this, SLOT(gotFileMessage(int,QString,QByteArray,Buffer)) ); connect( d->messageReceiverTask, SIGNAL(chatroomMessage(Oscar::Message,QByteArray)), this, SLOT(gotChatRoomMessage(Oscar::Message,QByteArray)) ); connect( d->messageAckTask, SIGNAL(messageAck(QString,uint)), this, SIGNAL(messageAck(QString,uint)) ); connect( d->errorTask, SIGNAL(messageError(QString,uint)), this, SIGNAL(messageError(QString,uint)) ); connect( d->ssiAuthTask, SIGNAL(authRequested(QString,QString)), this, SIGNAL(authRequestReceived(QString,QString)) ); connect( d->ssiAuthTask, SIGNAL(authReplied(QString,QString,bool)), this, SIGNAL(authReplyReceived(QString,QString,bool)) ); connect( d->icqInfoTask, SIGNAL(receivedInfoFor(QString,uint)), this, SLOT(receivedIcqInfo(QString,uint)) ); connect( d->icqTlvInfoTask, SIGNAL(receivedInfoFor(QString)), this, SIGNAL(receivedIcqTlvInfo(QString)) ); connect( d->userInfoTask, SIGNAL(receivedProfile(QString,QString)), this, SIGNAL(receivedProfile(QString,QString)) ); connect( d->userInfoTask, SIGNAL(receivedAwayMessage(QString,QString)), this, SIGNAL(receivedAwayMessage(QString,QString)) ); connect( d->typingNotifyTask, SIGNAL(typingStarted(QString)), this, SIGNAL(userStartedTyping(QString)) ); connect( d->typingNotifyTask, SIGNAL(typingFinished(QString)), this, SIGNAL(userStoppedTyping(QString)) ); } void Client::removeGroup( const QString& groupName ) { Connection* c = d->connections.connectionForFamily( 0x0013 ); if ( !c ) return; kDebug( OSCAR_RAW_DEBUG ) << "Removing group " << groupName << " from Contact"; SSIModifyTask* ssimt = new SSIModifyTask( c->rootTask() ); if ( ssimt->removeGroup( groupName ) ) ssimt->go( Task::AutoDelete ); else delete ssimt; } void Client::addGroup( const QString& groupName ) { Connection* c = d->connections.connectionForFamily( 0x0013 ); if ( !c ) return; kDebug( OSCAR_RAW_DEBUG ) << "Adding group " << groupName << " to Contact"; SSIModifyTask* ssimt = new SSIModifyTask( c->rootTask() ); if ( ssimt->addGroup( groupName ) ) ssimt->go( Task::AutoDelete ); else delete ssimt; } void Client::addContact( const QString& contactName, const QString& groupName ) { Connection* c = d->connections.connectionForFamily( 0x0013 ); if ( !c ) return; kDebug( OSCAR_RAW_DEBUG ) << "Adding contact " << contactName << " to ssi in group " << groupName; SSIModifyTask* ssimt = new SSIModifyTask( c->rootTask() ); if ( ssimt->addContact( contactName, groupName ) ) ssimt->go( Task::AutoDelete ); else delete ssimt; } void Client::removeContact( const QString& contactName ) { Connection* c = d->connections.connectionForFamily( 0x0013 ); if ( !c ) return; kDebug( OSCAR_RAW_DEBUG ) << "Removing contact " << contactName << " from ssi"; SSIModifyTask* ssimt = new SSIModifyTask( c->rootTask() ); if ( ssimt->removeContact( contactName ) ) ssimt->go( Task::AutoDelete ); else delete ssimt; } void Client::renameGroup( const QString & oldGroupName, const QString & newGroupName ) { Connection* c = d->connections.connectionForFamily( 0x0013 ); if ( !c ) return; kDebug( OSCAR_RAW_DEBUG ) << "Renaming group " << oldGroupName << " to " << newGroupName; SSIModifyTask* ssimt = new SSIModifyTask( c->rootTask() ); if ( ssimt->renameGroup( oldGroupName, newGroupName ) ) ssimt->go( Task::AutoDelete ); else delete ssimt; } void Client::modifyContactItem( const OContact& oldItem, const OContact& newItem ) { int action = 0; //0 modify, 1 add, 2 remove TODO cleanup! Connection* c = d->connections.connectionForFamily( 0x0013 ); if ( !c ) return; if ( !oldItem && newItem ) action = 1; if ( oldItem && !newItem ) action = 2; kDebug(OSCAR_RAW_DEBUG) << "Add/Mod/Del item on server"; SSIModifyTask* ssimt = new SSIModifyTask( c->rootTask() ); switch ( action ) { case 0: if ( ssimt->modifyItem( oldItem, newItem ) ) ssimt->go( Task::AutoDelete ); else delete ssimt; break; case 1: if ( ssimt->addItem( newItem ) ) ssimt->go( Task::AutoDelete ); else delete ssimt; break; case 2: if ( ssimt->removeItem( oldItem ) ) ssimt->go( Task::AutoDelete ); else delete ssimt; break; } } void Client::changeContactGroup( const QString& contact, const QString& newGroupName ) { Connection* c = d->connections.connectionForFamily( 0x0013 ); if ( !c ) return; kDebug(OSCAR_RAW_DEBUG) << "Changing " << contact << "'s group to " << newGroupName << endl; SSIModifyTask* ssimt = new SSIModifyTask( c->rootTask() ); if ( ssimt->changeGroup( contact, newGroupName ) ) ssimt->go( Task::AutoDelete ); else delete ssimt; } void Client::changeContactAlias( const QString& contact, const QString& alias ) { Connection* c = d->connections.connectionForFamily( 0x0013 ); if ( !c ) return; OContact item = ssiManager()->findContact( contact ); if ( item ) { OContact oldItem(item); if ( alias.isEmpty() ) { QList tList( item.tlvList() ); TLV tlv = Oscar::findTLV( tList, 0x0131 ); if ( !tlv ) return; tList.removeAll( tlv ); item.setTLVList( tList ); } else { QList tList; QByteArray data = alias.toUtf8(); tList.append( TLV( 0x0131, data.size(), data ) ); if ( !Oscar::updateTLVs( item, tList ) ) return; } kDebug( OSCAR_RAW_DEBUG ) << "Changing " << contact << "'s alias to " << alias; SSIModifyTask* ssimt = new SSIModifyTask( c->rootTask() ); if ( ssimt->modifyContact( oldItem, item ) ) ssimt->go( Task::AutoDelete ); else delete ssimt; } } void Client::setPrivacyTLVs( Oscar::BYTE privacy, Oscar::DWORD userClasses ) { OContact item = ssiManager()->findItem( QString(), ROSTER_VISIBILITY ); QList tList; tList.append( TLV( 0x00CA, 1, (char *)&privacy ) ); tList.append( TLV( 0x00CB, sizeof(userClasses), (char *)&userClasses ) ); if ( !item ) { kDebug( OSCAR_RAW_DEBUG ) << "Adding new privacy TLV item"; QString empty; OContact s( empty, 0, ssiManager()->nextContactId(), ROSTER_VISIBILITY, tList ); modifyContactItem( item, s ); } else { //found an item OContact s(item); if ( Oscar::updateTLVs( s, tList ) == true ) { kDebug( OSCAR_RAW_DEBUG ) << "Updating privacy TLV item"; modifyContactItem( item, s ); } } } void Client::requestShortTlvInfo( const QString& contactId, const QByteArray &metaInfoId ) { Connection* c = d->connections.connectionForFamily( 0x0015 ); if ( !c ) return; d->icqTlvInfoTask->setUser( Oscar::normalize( contactId ) ); d->icqTlvInfoTask->setMetaInfoId( metaInfoId ); d->icqTlvInfoTask->setType( ICQTlvInfoRequestTask::Short ); d->icqTlvInfoTask->go(); } void Client::requestMediumTlvInfo( const QString& contactId, const QByteArray &metaInfoId ) { Connection* c = d->connections.connectionForFamily( 0x0015 ); if ( !c ) return; d->icqTlvInfoTask->setUser( Oscar::normalize( contactId ) ); d->icqTlvInfoTask->setMetaInfoId( metaInfoId ); d->icqTlvInfoTask->setType( ICQTlvInfoRequestTask::Medium ); d->icqTlvInfoTask->go(); } void Client::requestLongTlvInfo( const QString& contactId, const QByteArray &metaInfoId ) { Connection* c = d->connections.connectionForFamily( 0x0015 ); if ( !c ) return; d->icqTlvInfoTask->setUser( Oscar::normalize( contactId ) ); d->icqTlvInfoTask->setMetaInfoId( metaInfoId ); d->icqTlvInfoTask->setType( ICQTlvInfoRequestTask::Long ); d->icqTlvInfoTask->go(); } void Client::requestFullInfo( const QString& contactId ) { Connection* c = d->connections.connectionForFamily( 0x0015 ); if ( !c ) return; d->icqInfoTask->setUser( contactId ); d->icqInfoTask->setType( ICQUserInfoRequestTask::Long ); d->icqInfoTask->go(); } void Client::requestShortInfo( const QString& contactId ) { Connection* c = d->connections.connectionForFamily( 0x0015 ); if ( !c ) return; d->icqInfoTask->setUser( contactId ); d->icqInfoTask->setType( ICQUserInfoRequestTask::Short ); d->icqInfoTask->go(); } void Client::sendWarning( const QString& contact, bool anonymous ) { Connection* c = d->connections.connectionForFamily( 0x0004 ); if ( !c ) return; WarningTask* warnTask = new WarningTask( c->rootTask() ); warnTask->setContact( contact ); warnTask->setAnonymous( anonymous ); QObject::connect( warnTask, SIGNAL(userWarned(QString,quint16,quint16)), this, SIGNAL(userWarned(QString,quint16,quint16)) ); warnTask->go( Task::AutoDelete ); } bool Client::changeICQPassword( const QString& password ) { Connection* c = d->connections.connectionForFamily( 0x0015 ); if ( !c ) return false; ICQChangePasswordTask* task = new ICQChangePasswordTask( c->rootTask() ); QObject::connect( task, SIGNAL(finished()), this, SLOT(changeICQPasswordFinished()) ); task->setPassword( password ); task->go( Task::AutoDelete ); return true; } void Client::changeICQPasswordFinished() { ICQChangePasswordTask* task = (ICQChangePasswordTask*)sender(); if ( task->success() ) d->pass = task->password(); emit icqPasswordChanged( !task->success() ); } ICQFullInfo Client::getFullInfo( const QString& contact ) { return d->icqTlvInfoTask->fullInfoFor( contact ); } ICQGeneralUserInfo Client::getGeneralInfo( const QString& contact ) { return d->icqInfoTask->generalInfoFor( contact ); } ICQWorkUserInfo Client::getWorkInfo( const QString& contact ) { return d->icqInfoTask->workInfoFor( contact ); } ICQEmailInfo Client::getEmailInfo( const QString& contact ) { return d->icqInfoTask->emailInfoFor( contact ); } ICQNotesInfo Client::getNotesInfo( const QString& contact ) { return d->icqInfoTask->notesInfoFor( contact ); } ICQMoreUserInfo Client::getMoreInfo( const QString& contact ) { return d->icqInfoTask->moreInfoFor( contact ); } ICQInterestInfo Client::getInterestInfo( const QString& contact ) { return d->icqInfoTask->interestInfoFor( contact ); } ICQOrgAffInfo Client::getOrgAffInfo( const QString& contact ) { return d->icqInfoTask->orgAffInfoFor( contact ); } ICQShortInfo Client::getShortInfo( const QString& contact ) { return d->icqInfoTask->shortInfoFor( contact ); } QList Client::chatExchangeList() const { return d->exchanges; } void Client::setChatExchangeList( const QList& exchanges ) { d->exchanges = exchanges; } void Client::requestAIMProfile( const QString& contact ) { d->userInfoTask->requestInfoFor( contact, UserInfoTask::Profile ); } void Client::requestAIMAwayMessage( const QString& contact ) { d->userInfoTask->requestInfoFor( contact, UserInfoTask::AwayMessage ); } void Client::requestICQAwayMessage( const QString& contact, ICQStatus contactStatus ) { kDebug(OSCAR_RAW_DEBUG) << "requesting away message for " << contact; Oscar::Message msg; msg.setChannel( 2 ); msg.setReceiver( contact ); if ( (contactStatus & ICQXStatus) == ICQXStatus ) { Xtraz::XtrazNotify xNotify; xNotify.setSenderUni( userId() ); msg.setMessageType( Oscar::MessageType::Plugin ); // plugin message msg.setPlugin( xNotify.statusRequest() ); } else if ( (contactStatus & ICQPluginStatus) == ICQPluginStatus ) { Oscar::WORD subTypeId = 0xFFFF; QByteArray subTypeText; switch ( contactStatus & ICQStatusMask ) { case ICQOnline: case ICQFreeForChat: case ICQAway: subTypeId = 1; subTypeText = "Away Status Message"; break; case ICQOccupied: case ICQDoNotDisturb: subTypeId = 2; subTypeText = "Busy Status Message"; break; case ICQNotAvailable: subTypeId = 3; subTypeText = "N/A Status Message"; break; default: // may be a good way to deal with possible error and lack of online status message? emit receivedAwayMessage( contact, QStringLiteral("Sorry, this protocol does not support this type of status message") ); return; } Oscar::MessagePlugin *plugin = new Oscar::MessagePlugin(); plugin->setType( Oscar::MessagePlugin::StatusMsgExt ); plugin->setSubTypeId( subTypeId ); plugin->setSubTypeText( subTypeText ); Buffer buffer; buffer.addLEDWord( 0x00000000 ); //TODO: Change this to text/x-aolrtf buffer.addLEDBlock( "text/plain" ); plugin->setData( buffer.buffer() ); msg.setMessageType( Oscar::MessageType::Plugin ); // plugin message msg.setPlugin( plugin ); } else { msg.addProperty( Oscar::Message::StatusMessageRequest ); switch ( contactStatus & ICQStatusMask ) { case ICQAway: msg.setMessageType( Oscar::MessageType::AutoAway ); // away break; case ICQOccupied: msg.setMessageType( Oscar::MessageType::AutoBusy ); // occupied break; case ICQNotAvailable: msg.setMessageType( Oscar::MessageType::AutoNA ); // not awailable break; case ICQDoNotDisturb: msg.setMessageType( Oscar::MessageType::AutoDND ); // do not disturb break; case ICQFreeForChat: msg.setMessageType( Oscar::MessageType::AutoFFC ); // free for chat break; default: // may be a good way to deal with possible error and lack of online status message? emit receivedAwayMessage( contact, QStringLiteral("Sorry, this protocol does not support this type of status message") ); return; } } sendMessage( msg ); } void Client::addICQAwayMessageRequest( const QString& contact, ICQStatus contactStatus ) { kDebug(OSCAR_RAW_DEBUG) << "adding away message request for " << contact << " to queue" << endl; //remove old request if still exists removeICQAwayMessageRequest( contact ); ClientPrivate::AwayMsgRequest amr = { contact, contactStatus }; d->awayMsgRequestQueue.prepend( amr ); if ( !d->awayMsgRequestTimer->isActive() ) d->awayMsgRequestTimer->start( 1000 ); } void Client::removeICQAwayMessageRequest( const QString& contact ) { kDebug(OSCAR_RAW_DEBUG) << "removing away message request for " << contact << " from queue" << endl; QList::iterator it = d->awayMsgRequestQueue.begin(); while ( it != d->awayMsgRequestQueue.end() ) { if ( (*it).contact == contact ) it = d->awayMsgRequestQueue.erase( it ); else it++; } } void Client::nextICQAwayMessageRequest() { kDebug(OSCAR_RAW_DEBUG) << "request queue count " << d->awayMsgRequestQueue.count(); if ( d->awayMsgRequestQueue.empty() ) { d->awayMsgRequestTimer->stop(); return; } else { Connection* c = d->connections.connectionForFamily( 0x0004 ); if ( !c ) return; SNAC s = { 0x0004, 0x0006, 0x0000, 0x00000000 }; //get time needed to restore level to initial //for some reason when we are long under initial level //icq server will start to block our messages int time = c->rateManager()->timeToInitialLevel( s ); if ( time > 0 ) { d->awayMsgRequestTimer->start( time ); return; } else { d->awayMsgRequestTimer->start( 5000 ); } } ClientPrivate::AwayMsgRequest amr; amr = d->awayMsgRequestQueue.back(); d->awayMsgRequestQueue.pop_back(); requestICQAwayMessage( amr.contact, amr.contactStatus ); } void Client::requestStatusInfo( const QString& contact ) { d->userInfoTask->requestInfoFor( contact, UserInfoTask::General ); } void Client::whitePagesSearch( const ICQWPSearchInfo& info ) { Connection* c = d->connections.connectionForFamily( 0x0015 ); if ( !c ) return; UserSearchTask* ust = new UserSearchTask( c->rootTask() ); connect( ust, SIGNAL(foundUser(ICQSearchResult)), this, SIGNAL(gotSearchResults(ICQSearchResult)) ); connect( ust, SIGNAL(searchFinished(int)), this, SIGNAL(endOfSearch(int)) ); ust->go( Task::AutoDelete ); //onGo does nothing in this task. This is just here so autodelete works ust->searchWhitePages( info ); } void Client::uinSearch( const QString& uin ) { Connection* c = d->connections.connectionForFamily( 0x0015 ); if ( !c ) return; UserSearchTask* ust = new UserSearchTask( c->rootTask() ); connect( ust, SIGNAL(foundUser(ICQSearchResult)), this, SIGNAL(gotSearchResults(ICQSearchResult)) ); connect( ust, SIGNAL(searchFinished(int)), this, SIGNAL(endOfSearch(int)) ); ust->go( Task::AutoDelete ); //onGo does nothing in this task. This is just here so autodelete works ust->searchUserByUIN( uin ); } void Client::updateProfile( const QString& profile ) { Connection* c = d->connections.connectionForFamily( 0x0002 ); if ( !c ) return; ProfileTask* pt = new ProfileTask( c->rootTask() ); pt->setProfileText( profile ); pt->go( Task::AutoDelete ); } bool Client::updateProfile( const QList& infoList ) { Connection* c = d->connections.connectionForFamily( 0x0015 ); if ( !c ) return false; ICQUserInfoUpdateTask* ui = new ICQUserInfoUpdateTask( c->rootTask() ); ui->setInfo( infoList ); ui->go( Task::AutoDelete ); return true; } void Client::sendTyping( const QString & contact, bool typing ) { Connection* c = d->connections.connectionForFamily( 0x0004 ); if ( !c || !d->active ) return; d->typingNotifyTask->setParams( contact, ( typing ? TypingNotifyTask::Begin : TypingNotifyTask::Finished ) ); d->typingNotifyTask->go(); // don't delete the task after sending } void Client::connectToIconServer() { Connection* c = d->connections.connectionForFamily( 0x0010 ); if ( c ) return; requestServerRedirect( 0x0010 ); } void Client::setIgnore( const QString& user, bool ignore ) { OContact item = ssiManager()->findItem( user, ROSTER_IGNORE ); if ( item && !ignore ) { kDebug(OSCAR_RAW_DEBUG) << "Removing " << user << " from ignore list"; this->modifyContactItem( item, OContact() ); } else if ( !item && ignore ) { kDebug(OSCAR_RAW_DEBUG) << "Adding " << user << " to ignore list"; OContact s( user, 0, ssiManager()->nextContactId(), ROSTER_IGNORE, QList() ); this->modifyContactItem( OContact(), s ); } } void Client::setVisibleTo( const QString& user, bool visible ) { OContact item = ssiManager()->findItem( user, ROSTER_VISIBLE ); if ( item && !visible ) { kDebug(OSCAR_RAW_DEBUG) << "Removing " << user << " from visible list"; this->modifyContactItem( item, OContact() ); } else if ( !item && visible ) { kDebug(OSCAR_RAW_DEBUG) << "Adding " << user << " to visible list"; OContact s( user, 0, ssiManager()->nextContactId(), ROSTER_VISIBLE, QList() ); this->modifyContactItem( OContact(), s ); } } void Client::setInvisibleTo( const QString& user, bool invisible ) { OContact item = ssiManager()->findItem( user, ROSTER_INVISIBLE ); if ( item && !invisible ) { kDebug(OSCAR_RAW_DEBUG) << "Removing " << user << " from invisible list"; this->modifyContactItem( item, OContact() ); } else if ( !item && invisible ) { kDebug(OSCAR_RAW_DEBUG) << "Adding " << user << " to invisible list"; OContact s( user, 0, ssiManager()->nextContactId(), ROSTER_INVISIBLE, QList() ); this->modifyContactItem( OContact(), s ); } } void Client::requestBuddyIcon( const QString& user, const QByteArray& hash, Oscar::WORD iconType, Oscar::BYTE hashType ) { Connection* c = d->connections.connectionForFamily( 0x0010 ); if ( !c ) return; BuddyIconTask* bit = new BuddyIconTask( c->rootTask() ); connect( bit, SIGNAL(haveIcon(QString,QByteArray)), this, SIGNAL(haveIconForContact(QString,QByteArray)) ); bit->requestIconFor( user ); bit->setIconType( iconType ); bit->setHashType( hashType ); bit->setHash( hash ); bit->go( Task::AutoDelete ); } void Client::requestServerRedirect( Oscar::WORD family, Oscar::WORD exchange, QByteArray cookie, Oscar::WORD instance, const QString& room ) { //making the assumption that family 2 will always be the BOS connection //use it instead since we can't query for family 1 Connection* c = d->connections.connectionForFamily( family ); if ( c && family != 0x000E ) return; //we already have the connection c = d->connections.connectionForFamily( 0x0002 ); if ( !c ) return; if ( d->redirectionServices.indexOf( family ) == -1 ) d->redirectionServices.append( family ); //don't add families twice if ( d->currentRedirect != 0 ) return; //we're already doing one redirection d->currentRedirect = family; //FIXME. this won't work if we have to defer the connection because we're //already connecting to something ServerRedirectTask* srt = new ServerRedirectTask( c->rootTask() ); if ( family == 0x000E ) { srt->setChatParams( exchange, cookie, instance ); srt->setChatRoom( room ); } connect( srt, SIGNAL(haveServer(QString,QByteArray,Oscar::WORD)), this, SLOT(haveServerForRedirect(QString,QByteArray,Oscar::WORD)) ); srt->setService( family ); srt->go( Task::AutoDelete ); } void Client::haveServerForRedirect( const QString& host, const QByteArray& cookie, Oscar::WORD ) { //nasty sender() usage to get the task with chat room info QObject* o = const_cast( sender() ); ServerRedirectTask* srt = dynamic_cast( o ); //create a new connection and set it up int colonPos = host.indexOf(':'); QString realHost; uint realPort; if ( colonPos != -1 ) { realHost = host.left( colonPos ); realPort = host.rightRef(4).toUInt(); //we only need 4 bytes } else { realHost = host; realPort = d->port; } bool encrypted = d->encrypted2; Connection* c = createConnection(); //create the new login task d->loginTaskTwo = new StageTwoLoginTask( c->rootTask() ); d->loginTaskTwo->setCookie( cookie ); QObject::connect( d->loginTaskTwo, SIGNAL(finished()), this, SLOT(serverRedirectFinished()) ); //connect connectToServer( c, realHost, realPort, encrypted, QString() ); QObject::connect( c, SIGNAL(connected()), this, SLOT(streamConnected()) ); if ( srt ) d->connections.addChatInfoForConnection( c, srt->chatExchange(), srt->chatRoomName() ); } void Client::serverRedirectFinished() { StageTwoLoginTask* loginTaskTwo = qobject_cast( sender() ); if ( loginTaskTwo && loginTaskTwo->statusCode() == 0 ) { //stage two was successful Connection* c = d->connections.connectionForFamily( d->currentRedirect ); if ( !c ) return; ClientReadyTask* crt = new ClientReadyTask( c->rootTask() ); crt->setFamilies( c->supportedFamilies() ); crt->go( Task::AutoDelete ); } kDebug(OSCAR_RAW_DEBUG) << "redirection finished for service " << d->currentRedirect << endl; if ( d->currentRedirect == 0x0010 ) emit iconServerConnected(); if ( d->currentRedirect == 0x000D ) { connect( this, SIGNAL(chatNavigationConnected()), this, SLOT(requestChatNavLimits()) ); emit chatNavigationConnected(); } if ( d->currentRedirect == 0x000E ) { //HACK! such abuse! think of a better way if ( !loginTaskTwo ) { kWarning(OSCAR_RAW_DEBUG) << "no login task to get connection from!"; emit redirectionFinished( d->currentRedirect ); return; } Connection* c = loginTaskTwo->client(); QString roomName = d->connections.chatRoomForConnection( c ); Oscar::WORD exchange = d->connections.exchangeForConnection( c ); if ( c ) { kDebug(OSCAR_RAW_DEBUG) << "setting up chat connection"; ChatServiceTask* cst = new ChatServiceTask( c->rootTask(), exchange, roomName ); connect( cst, SIGNAL(userJoinedChat(Oscar::WORD,QString,QString)), this, SIGNAL(userJoinedChat(Oscar::WORD,QString,QString)) ); connect( cst, SIGNAL(userLeftChat(Oscar::WORD,QString,QString)), this, SIGNAL(userLeftChat(Oscar::WORD,QString,QString)) ); connect( cst, SIGNAL(newChatMessage(Oscar::Message)), this, SIGNAL(messageReceived(Oscar::Message)) ); } emit chatRoomConnected( exchange, roomName ); } emit redirectionFinished( d->currentRedirect ); } void Client::checkRedirectionQueue( Oscar::WORD family ) { kDebug(OSCAR_RAW_DEBUG) << "checking redirection queue"; d->redirectionServices.removeAll( family ); d->currentRedirect = 0; if ( !d->redirectionServices.isEmpty() ) { kDebug(OSCAR_RAW_DEBUG) << "scheduling new redirection"; requestServerRedirect( d->redirectionServices.front() ); } } void Client::requestChatNavLimits() { Connection* c = d->connections.connectionForFamily( 0x000D ); if ( !c ) return; kDebug(OSCAR_RAW_DEBUG) << "requesting chat nav service limits"; ChatNavServiceTask* cnst = new ChatNavServiceTask( c->rootTask() ); cnst->setRequestType( ChatNavServiceTask::Limits ); QObject::connect( cnst, SIGNAL(haveChatExchanges(QList)), this, SLOT(setChatExchangeList(QList)) ); cnst->go( Task::AutoDelete ); //autodelete } void Client::determineDisconnection( int code, const QString& string ) { if ( !sender() ) return; //yay for the sender() hack! QObject* obj = const_cast( sender() ); Connection* c = dynamic_cast( obj ); if ( !c ) return; if ( c->isSupported( 0x0002 ) || d->stage == ClientPrivate::StageOne ) //emit on login { emit socketError( code, string ); } foreach ( Oscar::MessageInfo info, c->messageInfoList() ) emit messageError( info.contact, info.id ); //connection is deleted. deleteLater() is used d->connections.remove( c ); c = 0; } void Client::sendBuddyIcon( const QByteArray& iconData ) { Connection* c = d->connections.connectionForFamily( 0x0010 ); if ( !c ) return; kDebug(OSCAR_RAW_DEBUG) << "icon length is " << iconData.size(); BuddyIconTask* bit = new BuddyIconTask( c->rootTask() ); bit->uploadIcon( iconData.size(), iconData ); bit->go( Task::AutoDelete ); } void Client::joinChatRoom( const QString& roomName, int exchange ) { Connection* c = d->connections.connectionForFamily( 0x000D ); if ( !c ) return; kDebug(OSCAR_RAW_DEBUG) << "joining the chat room '" << roomName << "' on exchange " << exchange << endl; ChatNavServiceTask* cnst = new ChatNavServiceTask( c->rootTask() ); connect( cnst, SIGNAL(connectChat(Oscar::WORD,QByteArray,Oscar::WORD,QString)), this, SLOT(setupChatConnection(Oscar::WORD,QByteArray,Oscar::WORD,QString)) ); cnst->createRoom( exchange, roomName ); } void Client::setupChatConnection( Oscar::WORD exchange, QByteArray cookie, Oscar::WORD instance, const QString& room ) { kDebug(OSCAR_RAW_DEBUG) << "cookie is:" << cookie; QByteArray realCookie( cookie ); kDebug(OSCAR_RAW_DEBUG) << "connection to chat room"; requestServerRedirect( 0x000E, exchange, realCookie, instance, room ); } void Client::disconnectChatRoom( Oscar::WORD exchange, const QString& room ) { Connection* c = d->connections.connectionForChatRoom( exchange, room ); if ( !c ) return; d->connections.remove( c ); c = 0; } void Client::connectToServer( Connection* c, const QString& host, quint16 port, bool encrypted, const QString &name ) { d->connections.append( c ); connect( c, SIGNAL(socketError(int,QString)), this, SLOT(determineDisconnection(int,QString)) ); c->connectToServer( host, port, encrypted, name ); } ClientStream* Client::createClientStream() { ClientStream* cs = 0; emit createClientStream( &cs ); if ( !cs ) cs = new ClientStream( new QSslSocket(), 0 ); return cs; } Connection* Client::createConnection() { ClientStream* cs = createClientStream(); cs->setNoopTime( 60000 ); Connection* c = new Connection( cs, "BOS" ); cs->setConnection( c ); c->setClient( this ); return c; } void Client::deleteStaticTasks() { delete d->errorTask; delete d->onlineNotifier; delete d->ownStatusTask; delete d->messageReceiverTask; delete d->messageAckTask; delete d->ssiAuthTask; delete d->icqInfoTask; delete d->icqTlvInfoTask; delete d->userInfoTask; delete d->typingNotifyTask; delete d->ssiModifyTask; d->errorTask = 0; d->onlineNotifier = 0; d->ownStatusTask = 0; d->messageReceiverTask = 0; d->messageAckTask = 0; d->ssiAuthTask = 0; d->icqInfoTask = 0; d->icqTlvInfoTask = 0; d->userInfoTask = 0; d->typingNotifyTask = 0; d->ssiModifyTask = 0; } bool Client::hasIconConnection( ) const { Connection* c = d->connections.connectionForFamily( 0x0010 ); return c; } FileTransferHandler* Client::createFileTransfer( const QString& contact, const QStringList& files ) { Connection* c = d->connections.connectionForFamily( 0x0004 ); if ( !c ) return 0; FileTransferTask *ft = new FileTransferTask( c->rootTask(), contact, ourInfo().userId(), files ); connect( ft, SIGNAL(sendMessage(Oscar::Message)), this, SLOT(fileMessage(Oscar::Message)) ); return new FileTransferHandler(ft); } void Client::inviteToChatRoom( const QString& contact, Oscar::WORD exchange, const QString& room, QString msg) { Connection* c = d->connections.connectionForFamily( 0x0004 ); ChatRoomTask *chatRoomTask = new ChatRoomTask( c->rootTask(), contact, ourInfo().userId(), msg, exchange, room); chatRoomTask->go( Task::AutoDelete ); chatRoomTask->doInvite(); } void Client::gotChatRoomMessage( const Oscar::Message & msg, const QByteArray & cookie ) { Connection* c = d->connections.connectionForFamily( 0x0004 ); if ( msg.requestType() == 0 ) { ChatRoomTask *task = new ChatRoomTask( c->rootTask(), msg.sender(), msg.receiver(), cookie, msg.text( QTextCodec::codecForName( "UTF-8" ) ), msg.exchange(), msg.chatRoom() ); task->go( Task::AutoDelete ); emit chatroomRequest( new ChatRoomHandler( task ) ); } } void Client::gotFileMessage( int type, const QString from, const QByteArray cookie, Buffer buf) { Connection* c = d->connections.connectionForFamily( 0x0004 ); if ( !c ) return; //pass the message to the matching task if we can const QList p = c->rootTask()->findChildren(); foreach( FileTransferTask *t, p) { if ( t->take( type, cookie, buf ) ) { return; } } //maybe it's a new request! if ( type == 0 ) { kDebug(14151) << "new request :)"; FileTransferTask *ft = new FileTransferTask( c->rootTask(), from, ourInfo().userId(), cookie, buf ); connect( ft, SIGNAL(sendMessage(Oscar::Message)), this, SLOT(fileMessage(Oscar::Message)) ); ft->go( Task::AutoDelete ); emit incomingFileTransfer( new FileTransferHandler(ft) ); } kDebug(14151) << "nobody wants it :("; } } diff --git a/protocols/oscar/liboscar/contactmanager.cpp b/protocols/oscar/liboscar/contactmanager.cpp index b42859546..3b70989a9 100644 --- a/protocols/oscar/liboscar/contactmanager.cpp +++ b/protocols/oscar/liboscar/contactmanager.cpp @@ -1,653 +1,653 @@ /* Kopete Oscar Protocol Copyright ( c ) 2004 Gustavo Pichorim Boiko Copyright ( c ) 2004 Matt Rogers Kopete ( c ) 2002-2004 by the Kopete developers based on ssidata.h and ssidata.cpp ( c ) 2002 Tom Linsky ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or ( at your option ) any later version. * * * ************************************************************************* */ #include "contactmanager.h" -#include +#include #include #include "oscarutils.h" // ------------------------------------------------------------------- class ContactManagerPrivate { public: QList contactList; QSet itemIdSet; QSet groupIdSet; bool complete; Oscar::DWORD lastModTime; Oscar::WORD maxContacts; Oscar::WORD maxGroups; Oscar::WORD maxVisible; Oscar::WORD maxInvisible; Oscar::WORD maxIgnore; Oscar::WORD nextContactId; Oscar::WORD nextGroupId; }; ContactManager::ContactManager( QObject *parent ) : QObject(parent) { d = new ContactManagerPrivate; d->complete = false; d->lastModTime = 0; d->nextContactId = 0; d->nextGroupId = 0; d->maxContacts = 999; d->maxGroups = 999; d->maxIgnore = 999; d->maxInvisible = 999; d->maxVisible = 999; } ContactManager::~ContactManager() { clear(); delete d; } void ContactManager::clear() { //delete all Contacts from the list if ( d->contactList.count() > 0 ) { kDebug(OSCAR_RAW_DEBUG) << "Clearing the SSI list"; QList::iterator it = d->contactList.begin(); while ( it != d->contactList.end() && d->contactList.count() > 0 ) it = d->contactList.erase( it ); }; d->itemIdSet.clear(); d->groupIdSet.clear(); d->complete = false; d->lastModTime = 0; d->nextContactId = 0; d->nextGroupId = 0; } Oscar::WORD ContactManager::nextContactId() { if ( d->nextContactId == 0 ) d->nextContactId++; d->nextContactId = findFreeId( d->itemIdSet, d->nextContactId ); if ( d->nextContactId == 0xFFFF ) { kWarning(OSCAR_RAW_DEBUG) << "No free id!"; return 0xFFFF; } d->itemIdSet.insert( d->nextContactId ); return d->nextContactId++; } Oscar::WORD ContactManager::nextGroupId() { if ( d->nextGroupId == 0 ) d->nextGroupId++; d->nextGroupId = findFreeId( d->groupIdSet, d->nextGroupId ); if ( d->nextGroupId == 0xFFFF ) { kWarning(OSCAR_RAW_DEBUG) << "No free group id!"; return 0xFFFF; } d->groupIdSet.insert( d->nextGroupId ); return d->nextGroupId++; } Oscar::WORD ContactManager::numberOfItems() const { return d->contactList.count(); } Oscar::DWORD ContactManager::lastModificationTime() const { return d->lastModTime; } void ContactManager::setLastModificationTime( Oscar::DWORD lastTime ) { d->lastModTime = lastTime; } void ContactManager::setParameters( Oscar::WORD maxContacts, Oscar::WORD maxGroups, Oscar::WORD maxVisible, Oscar::WORD maxInvisible, Oscar::WORD maxIgnore ) { //I'm not using k_funcinfo for these debug statements because of //the function's long signature QString funcName = QStringLiteral( "[void ContactManager::setParameters] " ); kDebug(OSCAR_RAW_DEBUG) << funcName << "Max number of contacts allowed in SSI: " << maxContacts << endl; kDebug(OSCAR_RAW_DEBUG) << funcName << "Max number of groups allowed in SSI: " << maxGroups << endl; kDebug(OSCAR_RAW_DEBUG) << funcName << "Max number of contacts allowed on visible list: " << maxVisible << endl; kDebug(OSCAR_RAW_DEBUG) << funcName << "Max number of contacts allowed on invisible list: " << maxInvisible << endl; kDebug(OSCAR_RAW_DEBUG) << funcName << "Max number of contacts allowed on ignore list: " << maxIgnore << endl; d->maxContacts = maxContacts; d->maxGroups = maxGroups; d->maxInvisible = maxInvisible; d->maxVisible = maxVisible; d->maxIgnore = maxIgnore; } void ContactManager::loadFromExisting( const QList& newList ) { Q_UNUSED( newList ); //FIXME: NOT Implemented! } bool ContactManager::hasItem( const OContact& item ) const { QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it != listEnd; ++it ) { OContact s = ( *it ); if ( s == item ) return true; } return false; } OContact ContactManager::findGroup( const QString &group ) const { QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it != listEnd; ++it ) if ( ( *it ).type() == ROSTER_GROUP && (*it ).name().toLower() == group.toLower() ) return ( *it ); return m_dummyItem; } OContact ContactManager::findGroup( int groupId ) const { QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it != listEnd; ++it ) if ( ( *it ).type() == ROSTER_GROUP && (*it ).gid() == groupId ) return ( *it ); return m_dummyItem; } OContact ContactManager::findContact( const QString &contact, const QString &group ) const { if ( contact.isNull() || group.isNull() ) { kWarning(OSCAR_RAW_DEBUG) << "Passed NULL name or group string, aborting!" << endl; return m_dummyItem; } OContact gr = findGroup( group ); // find the parent group if ( gr.isValid() ) { kDebug(OSCAR_RAW_DEBUG) << "gr->name= " << gr.name() << ", gr->gid= " << gr.gid() << ", gr->bid= " << gr.bid() << ", gr->type= " << gr.type() << endl; QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it != listEnd; ++it ) { if ( ( *it ).type() == ROSTER_CONTACT && (*it ).name() == contact && (*it ).gid() == gr.gid() ) { //we have found our contact kDebug(OSCAR_RAW_DEBUG) << "Found contact " << contact << " in SSI data" << endl; return ( *it ); } } } else { kDebug(OSCAR_RAW_DEBUG) << "ERROR: Group '" << group << "' not found!" << endl; } return m_dummyItem; } OContact ContactManager::findContact( const QString &contact ) const { QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it != listEnd; ++it ) if ( ( *it ).type() == ROSTER_CONTACT && (*it ).name() == contact ) return ( *it ); return m_dummyItem; } OContact ContactManager::findContact( int contactId ) const { QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it!= listEnd; ++it ) if ( ( *it ).type() == ROSTER_CONTACT && ( *it ).bid() == contactId ) return ( *it ); return m_dummyItem; } OContact ContactManager::findItemForIcon( QByteArray iconHash ) const { QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it!= listEnd; ++it ) { if ( ( *it ).type() == ROSTER_BUDDYICONS ) { TLV t = Oscar::findTLV( ( *it ).tlvList(), 0x00D5 ); Buffer b(t.data); b.skipBytes(1); //don't care about flags Oscar::BYTE iconSize = b.getByte(); QByteArray hash( b.getBlock( iconSize ) ); if ( hash == iconHash ) { OContact s = ( *it ); return s; } } } return m_dummyItem; } OContact ContactManager::findItemForIconByRef( int ref ) const { QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it!= listEnd; ++it ) { if ( ( *it ).type() == ROSTER_BUDDYICONS ) { if ( ( *it ).name().toInt() == ref ) { OContact s = ( *it ); return s; } } } return m_dummyItem; } OContact ContactManager::findItem( const QString &contact, int type ) const { QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it!= listEnd; ++it ) if ( ( *it ).type() == type && ( *it ).name() == contact ) return ( *it ); return m_dummyItem; } QList ContactManager::groupList() const { QList list; QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it != listEnd; ++it ) if ( ( *it ).type() == ROSTER_GROUP ) list.append( ( *it ) ); return list; } QList ContactManager::contactList() const { QList list; QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it != listEnd; ++it ) if ( ( *it ).type() == ROSTER_CONTACT ) list.append( ( *it ) ); return list; } QList ContactManager::visibleList() const { QList list; QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it != listEnd; ++it ) if ( ( *it ).type() == ROSTER_VISIBLE ) list.append( ( *it ) ); return list; } QList ContactManager::invisibleList() const { QList list; QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it != listEnd; ++it ) if ( ( *it ).type() == ROSTER_INVISIBLE ) list.append( ( *it ) ); return list; } QList ContactManager::ignoreList() const { QList list; QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it != listEnd; ++it ) if ( ( *it ).type() == ROSTER_IGNORE ) list.append( ( *it ) ); return list; } QList ContactManager::contactsFromGroup( const QString &group ) const { QList list; OContact gr = findGroup( group ); if ( gr.isValid() ) { QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it != listEnd; ++it ) if ( ( *it ).type() == ROSTER_CONTACT && (*it ).gid() == gr.gid() ) list.append( ( *it ) ); } return list; } QList ContactManager::contactsFromGroup( int groupId ) const { QList list; QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it != listEnd; ++it ) if ( ( *it ).type() == ROSTER_CONTACT && (*it ).gid() == groupId ) list.append( ( *it ) ); return list; } OContact ContactManager::visibilityItem() const { OContact item = m_dummyItem; QList::const_iterator it, listEnd = d->contactList.constEnd(); for ( it = d->contactList.constBegin(); it != listEnd; ++it ) { if ( ( *it ).type() == 0x0004 && ( *it ).name().isEmpty() ) { kDebug(OSCAR_RAW_DEBUG) << "Found visibility setting"; item = ( *it ); return item; } } return item; } void ContactManager::setListComplete( bool complete ) { d->complete = complete; } bool ContactManager::listComplete() const { return d->complete; } bool ContactManager::newGroup( const OContact& group ) { //trying to find the group by its ID if ( findGroup( group.name() ).isValid() ) return false; if ( !group.name().isEmpty() ) //avoid the group with gid 0 and bid 0 { // the group is really new kDebug( OSCAR_RAW_DEBUG ) << "Adding group '" << group.name() << "' to SSI list"; addID( group ); d->contactList.append( group ); emit groupAdded( group ); return true; } return false; } bool ContactManager::updateGroup( const OContact& group ) { OContact oldGroup = findGroup( group.name() ); if ( oldGroup.isValid() ) { removeID( oldGroup ); d->contactList.removeAll( oldGroup ); } if ( d->contactList.contains( group ) ) { kDebug(OSCAR_RAW_DEBUG) << "New group is already in list."; return false; } kDebug( OSCAR_RAW_DEBUG ) << "Updating group '" << group.name() << "' in SSI list"; addID( group ); d->contactList.append( group ); emit groupUpdated( group ); return true; } bool ContactManager::removeGroup( const OContact& group ) { QString groupName = group.name(); kDebug(OSCAR_RAW_DEBUG) << "Removing group " << group.name(); removeID( group ); int remcount = d->contactList.removeAll( group ); if ( remcount == 0 ) { kDebug(OSCAR_RAW_DEBUG) << "No groups removed"; return false; } emit groupRemoved( groupName ); return true; } bool ContactManager::removeGroup( const QString &group ) { OContact gr = findGroup( group ); if ( gr.isValid() && removeGroup( gr ) ) { return true; } else kDebug(OSCAR_RAW_DEBUG) << "Group " << group << " not found."; return false; } bool ContactManager::newContact( const OContact& contact ) { if ( d->contactList.contains( contact ) ) { kDebug(OSCAR_RAW_DEBUG) << "New contact is already in list."; return false; } kDebug( OSCAR_RAW_DEBUG ) << "Adding contact '" << contact.name() << "' to SSI list"; addID( contact ); d->contactList.append( contact ); emit contactAdded( contact ); return true; } bool ContactManager::updateContact( const OContact& contact ) { OContact oldContact = findContact( contact.name() ); if ( oldContact.isValid() ) { removeID( oldContact ); d->contactList.removeAll( oldContact ); } if ( d->contactList.contains( contact ) ) { kDebug(OSCAR_RAW_DEBUG) << "New contact is already in list."; return false; } kDebug( OSCAR_RAW_DEBUG ) << "Updating contact '" << contact.name() << "' in SSI list"; addID( contact ); d->contactList.append( contact ); emit contactUpdated( contact ); return true; } bool ContactManager::removeContact( const OContact& contact ) { QString contactName = contact.name(); removeID( contact ); int remcount = d->contactList.removeAll( contact ); if ( remcount == 0 ) { kDebug(OSCAR_RAW_DEBUG) << "No contacts were removed."; return false; } emit contactRemoved( contactName ); return true; } bool ContactManager::removeContact( const QString &contact ) { OContact ct = findContact( contact ); if ( ct.isValid() && removeContact( ct ) ) return true; else kDebug(OSCAR_RAW_DEBUG) << "Contact " << contact << " not found."; return false; } bool ContactManager::newItem( const OContact& item ) { if ( d->contactList.contains( item ) ) { kDebug(OSCAR_RAW_DEBUG) << "Item is already in list."; return false; } kDebug(OSCAR_RAW_DEBUG) << "Adding item " << item.toString(); addID( item ); d->contactList.append( item ); return true; } bool ContactManager::updateItem( const OContact& item ) { OContact oldItem = findItem( item.name(), item.type() ); if ( oldItem.isValid() ) { removeID( oldItem ); d->contactList.removeAll( oldItem ); } if ( d->contactList.contains( item ) ) { kDebug(OSCAR_RAW_DEBUG) << "New item is already in list."; return false; } kDebug( OSCAR_RAW_DEBUG ) << "Updating item in SSI list"; addID( item ); d->contactList.append( item ); return true; } bool ContactManager::removeItem( const OContact& item ) { removeID( item ); int remcount = d->contactList.removeAll( item ); if ( remcount == 0 ) { kDebug(OSCAR_RAW_DEBUG) << "No items were removed."; return false; } return true; } void ContactManager::addID( const OContact& item ) { if ( item.type() == ROSTER_GROUP ) d->groupIdSet.insert( item.gid() ); else d->itemIdSet.insert( item.bid() ); } void ContactManager::removeID( const OContact& item ) { if ( item.type() == ROSTER_GROUP ) { d->groupIdSet.remove( item.gid() ); if ( d->nextGroupId > item.gid() ) d->nextGroupId = item.gid(); } else { d->itemIdSet.remove( item.bid() ); if ( d->nextContactId > item.bid() ) d->nextContactId = item.bid(); } } Oscar::WORD ContactManager::findFreeId( const QSet& idSet, Oscar::WORD fromId ) const { for ( Oscar::WORD id = fromId; id < 0x8000; id++ ) { if ( !idSet.contains( id ) ) return id; } return 0xFFFF; } diff --git a/protocols/oscar/liboscar/filetransferhandler.h b/protocols/oscar/liboscar/filetransferhandler.h index c268dc7b4..1088684b7 100644 --- a/protocols/oscar/liboscar/filetransferhandler.h +++ b/protocols/oscar/liboscar/filetransferhandler.h @@ -1,68 +1,68 @@ /* filetransferhandler.h - File Transfer Handler Copyright (c) 2008 by Roman Jarosz Kopete (c) 2008 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef FILETRANSFERHANDLER_H #define FILETRANSFERHANDLER_H -#include -#include +#include +#include #include "oscartypes.h" #include "liboscar_export.h" class FileTransferTask; class LIBOSCAR_EXPORT FileTransferHandler : public QObject { Q_OBJECT public: FileTransferHandler( FileTransferTask* fileTransferTask ); ~FileTransferHandler(); void send(); QString internalId() const; QString contact() const; QString fileName() const; Oscar::WORD fileCount() const; Oscar::DWORD totalSize() const; QString description() const; public Q_SLOTS: void cancel(); void save( const QString &directory ); void saveAs( const QStringList &fileNames ); Q_SIGNALS: void transferCancelled(); void transferError( int errorCode, const QString &error ); void transferFinished(); void transferProcessed( unsigned int totalSent ); void transferNextFile( const QString& sourceFile, const QString& destinationFile ); void transferNextFile( const QString& fileName, unsigned int fileSize ); void transferFileProcessed(unsigned int bytesSent, unsigned int fileSize ); private Q_SLOTS: void emitTransferCancelled(); void emitTransferError( int errorCode, const QString &error ); void emitTransferFinished(); private: QPointer mFileTransferTask; bool mFileTransferDone; }; #endif diff --git a/protocols/oscar/liboscar/oftmetatransfer.cpp b/protocols/oscar/liboscar/oftmetatransfer.cpp index beba61459..74da7d718 100644 --- a/protocols/oscar/liboscar/oftmetatransfer.cpp +++ b/protocols/oscar/liboscar/oftmetatransfer.cpp @@ -1,590 +1,590 @@ // oftmetatransfer.cpp // Copyright (C) 2006 // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // This library 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 // Lesser General Public License for more details. // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA // 02110-1301 USA #include "oftmetatransfer.h" -#include -#include +#include +#include #include #include "ofttransfer.h" #include "oftprotocol.h" #define BUFFER_SIZE 32768 OftMetaTransfer::OftMetaTransfer( const QByteArray& cookie, const QStringList &files, const QString &dir, QTcpSocket *socket ) : m_file( this ), m_socket( socket ), m_state( SetupReceive ) { //filetransfertask is responsible for hooking us up to the ui //we're responsible for hooking up the socket and timer connect( m_socket, SIGNAL(readyRead()), this, SLOT(socketRead()) ); connect( m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)) ); initOft(); m_oft.cookie = cookie; m_files = files; m_dir = dir; } OftMetaTransfer::OftMetaTransfer( const QByteArray& cookie, const QStringList& files, QTcpSocket *socket ) : m_file( this ), m_socket( socket ), m_state( SetupSend ) { //filetransfertask is responsible for hooking us up to the ui //we're responsible for hooking up the socket and timer connect( m_socket, SIGNAL(readyRead()), this, SLOT(socketRead()) ); connect( m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)) ); initOft(); m_oft.cookie = cookie; for ( int i = 0; i < files.size(); ++i ) { QFileInfo fileInfo( files.at(i) ); m_oft.totalSize += fileInfo.size(); } m_oft.fileCount = files.size(); m_files = files; } void OftMetaTransfer::start() { if ( m_files.count() == 0 ) { doCancel(); return; } //filesLeft is decremented in prompt m_oft.filesLeft = m_oft.fileCount + 1; prompt(); } OftMetaTransfer::~OftMetaTransfer() { if( m_socket ) { m_socket->close(); delete m_socket; m_socket = 0; } kDebug(OSCAR_RAW_DEBUG) << "really done"; } /* bool OftMetaTransfer::validFile() { if ( m_action == Send ) { if ( ! m_file.exists() ) { emit error( KIO::ERR_DOES_NOT_EXIST, m_file.fileName() ); return 0; } if ( m_file.size() == 0 ) { emit error( KIO::ERR_COULD_NOT_READ, i18n("file is empty: ") + m_file.fileName() ); return 0; } if ( ! QFileInfo( m_file ).isReadable() ) { emit error( KIO::ERR_CANNOT_OPEN_FOR_READING, m_file.fileName() ); return 0; } } else //receive { //note: opening for writing clobbers the file if ( m_file.exists() ) { if ( ! QFileInfo( m_file ).isWritable() ) { //it's there and readonly emit error( KIO::ERR_CANNOT_OPEN_FOR_WRITING, m_file.fileName() ); return 0; } } else if ( ! QFileInfo( QFileInfo( m_file ).toLocalFile() ).isWritable() ) { //not allowed to create it emit error( KIO::ERR_CANNOT_OPEN_FOR_WRITING, m_file.fileName() ); return 0; } } return true; } */ void OftMetaTransfer::socketError( QAbstractSocket::SocketError e ) { QString desc = m_socket->errorString(); kWarning(OSCAR_RAW_DEBUG) << "socket error: " << e << " : " << desc; emit transferError( e, desc ); } void OftMetaTransfer::socketRead() { if ( m_state == Receiving ) //raw file data saveData(); else //oft packet readOft(); } void OftMetaTransfer::readOft() { kDebug(OSCAR_RAW_DEBUG) ; QByteArray raw = m_socket->readAll(); //is this safe? OftProtocol p; uint b=0; //remember we're responsible for freeing this! OftTransfer *t = static_cast( p.parse( raw, b ) ); OFT data = t->data(); kDebug(OSCAR_RAW_DEBUG) << "checksum: " << data.checksum; kDebug(OSCAR_RAW_DEBUG) << "sentChecksum: " << data.sentChecksum; switch( data.type ) { case 0x101: handleReceiveSetup( data ); break; case 0x202: handleSendSetup( data ); break; case 0x204: handleSendDone( data ); break; case 0x205: handleSendResumeRequest( data ); break; case 0x106: handleReceiveResumeSetup( data ); break; case 0x207: handleSendResumeSetup( data ); break; default: kWarning(OSCAR_RAW_DEBUG) << "unknown type " << data.type; } delete t; } void OftMetaTransfer::initOft() { //set up the default values for the oft m_oft.type = 0; //invalid m_oft.cookie = 0; m_oft.fileSize = 0; m_oft.modTime = 0; m_oft.checksum = 0xFFFF0000; //file checksum m_oft.bytesSent = 0; m_oft.sentChecksum = 0xFFFF0000; //checksum of transmitted bytes m_oft.flags = 0x20; //flags; 0x20=not done, 1=done m_oft.fileName.clear(); m_oft.fileCount = 1; m_oft.filesLeft = 1; m_oft.partCount = 1; m_oft.partsLeft = 1; m_oft.totalSize = 0; } void OftMetaTransfer::handleReceiveSetup( const OFT &oft ) { if ( m_state != SetupReceive ) return; kDebug(OSCAR_RAW_DEBUG) << "prompt" << endl << "\tmysize " << m_file.size() << endl << "\tsendersize " << oft.fileSize << endl; //do we care about anything *in* the prompt? //just the checksum. m_oft.checksum = oft.checksum; m_oft.modTime = oft.modTime; m_oft.fileCount = oft.fileCount; m_oft.filesLeft = oft.filesLeft; m_oft.partCount = oft.partCount; m_oft.partsLeft = oft.partsLeft; m_oft.totalSize = oft.totalSize; m_oft.fileName = oft.fileName; m_oft.bytesSent = oft.bytesSent; m_oft.fileSize = oft.fileSize; int currentFileIndex = oft.fileCount - oft.filesLeft; if ( currentFileIndex < m_files.count() ) m_file.setFileName( m_files.at( currentFileIndex ) ); else m_file.setFileName( m_dir + oft.fileName ); emit fileStarted( m_oft.fileName, m_file.fileName() ); emit fileStarted( m_file.fileName(), m_oft.fileSize ); if ( m_file.size() > 0 && m_file.size() <= oft.fileSize ) { m_oft.sentChecksum = fileChecksum( m_file ); if ( m_file.size() < oft.fileSize ) { //could be a partial file resume(); return; } else if ( m_oft.checksum == m_oft.sentChecksum ) { //apparently we've already got it //TODO: set bytesSent? done(); //don't redo checksum return; } //if we didn't break then we need the whole file m_oft.sentChecksum = 0xffff0000; } m_file.open( QIODevice::WriteOnly ); //TODO what if open failed? ack(); } void OftMetaTransfer::handleReceiveResumeSetup( const OFT &oft ) { if ( m_state != SetupReceive ) return; kDebug(OSCAR_RAW_DEBUG) << "sender resume" << endl << "\tfilesize\t" << oft.fileSize << endl << "\tmodTime\t" << oft.modTime << endl << "\tbytesSent\t" << oft.bytesSent << endl << "\tflags\t" << oft.flags << endl; QIODevice::OpenMode flags; if ( oft.bytesSent ) //yay, we can resume { flags = QIODevice::WriteOnly | QIODevice::Append; } else { //they insist on sending the whole file :( flags = QIODevice::WriteOnly; m_oft.sentChecksum = 0xffff0000; m_oft.bytesSent = 0; } m_file.open( flags ); //TODO what if open failed? rAck(); } void OftMetaTransfer::handleSendSetup( const OFT &oft ) { if ( m_state != SetupSend ) return; kDebug(OSCAR_RAW_DEBUG) << "ack"; emit fileStarted( m_file.fileName(), oft.fileName ); emit fileStarted( m_file.fileName(), oft.fileSize ); //time to send real data //TODO: validate file again, just to be sure m_file.open( QIODevice::ReadOnly ); m_state = Sending; //use bytesWritten to trigger writes connect( m_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(write()) ); write(); } void OftMetaTransfer::handleSendResumeSetup( const OFT &oft ) { Q_UNUSED(oft); if ( m_state != SetupSend ) return; kDebug(OSCAR_RAW_DEBUG) << "resume ack"; //TODO: validate file again, just to be sure m_file.open( QIODevice::ReadOnly ); m_file.seek( m_oft.bytesSent ); m_state = Sending; //use bytesWritten to trigger writes connect( m_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(write()) ); write(); } void OftMetaTransfer::handleSendResumeRequest( const OFT &oft ) { if ( m_state != SetupSend ) return; kDebug(OSCAR_RAW_DEBUG) << "receiver resume" << endl << "\tfilesize\t" << oft.fileSize << endl << "\tmodTime\t" << oft.modTime << endl << "\tbytesSent\t" << oft.bytesSent << endl << "\tflags\t" << oft.flags << endl; if ( fileChecksum( m_file, oft.bytesSent ) == oft.sentChecksum ) { m_oft.sentChecksum = oft.sentChecksum; m_oft.bytesSent = oft.bytesSent; //ok, we can resume this } rAgree(); } void OftMetaTransfer::handleSendDone( const OFT &oft ) { kDebug(OSCAR_RAW_DEBUG) << "done"; emit fileFinished( m_file.fileName(), oft.bytesSent ); disconnect( m_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(write()) ); if ( oft.sentChecksum != m_oft.checksum ) kDebug(OSCAR_RAW_DEBUG) << "checksums do not match!"; if ( m_oft.filesLeft > 1 ) { // Ready for next file m_state = SetupSend; prompt(); } else { // Last file, ending connection connect( m_socket, SIGNAL(disconnected()), this, SLOT(emitTransferCompleted()) ); m_socket->disconnectFromHost(); } } void OftMetaTransfer::write() { if ( m_socket->bytesToWrite() ) return; //give hte socket time to catch up //an arbitrary amount to send each time. char data[BUFFER_SIZE]; m_file.seek( m_oft.bytesSent ); int read = m_file.read( data, BUFFER_SIZE ); if( read == -1 ) { //FIXME: handle this properly kWarning(OSCAR_RAW_DEBUG) << "failed to read :("; return; } int written = m_socket->write( data, read ); if( written == -1 ) { //FIXME: handle this properly kWarning(OSCAR_RAW_DEBUG) << "failed to write :("; return; } m_oft.sentChecksum = chunkChecksum( data, written, m_oft.sentChecksum, m_oft.bytesSent & 1); m_oft.bytesSent += written; //tell the ui emit fileProcessed( m_oft.bytesSent, m_oft.fileSize ); if ( m_oft.bytesSent >= m_oft.fileSize ) { m_file.close(); disconnect( m_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(write()) ); //now we sit and do nothing until either an OFT Done //arrives or the user cancels. //we *should* always get the OFT done right away. } } void OftMetaTransfer::saveData() { QByteArray raw = m_socket->readAll(); //is this safe? int written = m_file.write( raw ); if( written == -1 ) { //FIXME: handle this properly kWarning(OSCAR_RAW_DEBUG) << "failed to write :("; return; } m_oft.sentChecksum = chunkChecksum( raw.constData(), raw.size(), m_oft.sentChecksum, m_oft.bytesSent & 1); m_oft.bytesSent += written; if ( written != raw.size() ) { //FIXME: handle this properly kWarning(OSCAR_RAW_DEBUG) << "didn't write everything we read"; doCancel(); } //tell the ui emit fileProcessed( m_oft.bytesSent, m_oft.fileSize ); if ( m_oft.bytesSent >= m_oft.fileSize ) { m_file.close(); done(); } } void OftMetaTransfer::sendOft() { //now make a transfer out of it OftTransfer t( m_oft ); int written = m_socket->write( t.toWire() ); if( written == -1 ) //FIXME: handle this properly kDebug(OSCAR_RAW_DEBUG) << "failed to write :("; } void OftMetaTransfer::prompt() { kDebug(OSCAR_RAW_DEBUG) ; m_oft.type = 0x0101; //type = prompt m_oft.filesLeft--; const int index = m_oft.fileCount - m_oft.filesLeft; m_file.setFileName( m_files.at( index ) ); QFileInfo fileInfo( m_file ); m_oft.modTime = fileInfo.lastModified().toTime_t(); m_oft.fileSize = fileInfo.size(); m_oft.fileName = fileInfo.fileName(); m_oft.checksum = fileChecksum( m_file ); m_oft.sentChecksum = 0xFFFF0000; m_oft.bytesSent = 0; sendOft(); //now we wait for the other side to ack } void OftMetaTransfer::ack() { kDebug(OSCAR_RAW_DEBUG) ; m_oft.type = 0x0202; //type = ack sendOft(); m_state = Receiving; } void OftMetaTransfer::rAck() { kDebug(OSCAR_RAW_DEBUG) ; m_oft.type = 0x0207; //type = resume ack sendOft(); m_state = Receiving; } void OftMetaTransfer::done() { kDebug(OSCAR_RAW_DEBUG) ; m_oft.type = 0x0204; //type = done if ( m_oft.sentChecksum != m_oft.checksum ) kDebug(OSCAR_RAW_DEBUG) << "checksums do not match!"; emit fileFinished( m_file.fileName(), m_oft.bytesSent ); if ( m_oft.filesLeft == 1 ) m_oft.flags = 1; sendOft(); if ( m_oft.filesLeft > 1 ) { //Ready for next file m_state = SetupReceive; } else { //Last file, ending connection m_state = Done; connect( m_socket, SIGNAL(disconnected()), this, SLOT(emitTransferCompleted()) ); m_socket->disconnectFromHost(); } } void OftMetaTransfer::resume() { kDebug(OSCAR_RAW_DEBUG) ; m_oft.type = 0x0205; //type = resume m_oft.bytesSent = m_file.size(); sendOft(); } void OftMetaTransfer::rAgree() { kDebug(OSCAR_RAW_DEBUG) ; m_oft.type = 0x0106; //type = sender resume sendOft(); } void OftMetaTransfer::doCancel() { kDebug(OSCAR_RAW_DEBUG) ; //stop our timer in case we were sending stuff disconnect( m_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(write()) ); m_socket->close(); deleteLater(); } void OftMetaTransfer::emitTransferCompleted() { kDebug(OSCAR_RAW_DEBUG) ; emit transferCompleted(); deleteLater(); //yay, it's ok to kill everything now } Oscar::DWORD OftMetaTransfer::fileChecksum( QFile& file, int bytes ) const { Oscar::DWORD checksum = 0xFFFF0000; char data[BUFFER_SIZE]; int read; int totalRead = 0; file.open( QIODevice::ReadOnly ); while ( (read = file.read( data, BUFFER_SIZE )) > 0 ) { if ( bytes != -1 && (totalRead + read) >= bytes ) { read = bytes - totalRead; checksum = chunkChecksum( data, read, checksum, totalRead & 1); break; } else { checksum = chunkChecksum( data, read, checksum, totalRead & 1); } totalRead += read; } file.close(); if ( read == -1 ) return 0xFFFF0000; return checksum; } Oscar::DWORD OftMetaTransfer::chunkChecksum( const char *buffer, int bufferSize, Oscar::DWORD checksum, bool shiftIndex ) const { //code adapted from Miranda's oft_calc_checksum const int evenIndex = (shiftIndex) ? 1 : 0; checksum = (checksum >> 16) & 0xffff; for ( int i = 0; i < bufferSize; i++ ) { quint16 val = (uchar)buffer[i]; if ( (i & 1) == evenIndex ) val = val << 8; if (checksum < val) checksum -= val + 1; else // simulate carry checksum -= val; } checksum = ((checksum & 0x0000ffff) + (checksum >> 16)); checksum = ((checksum & 0x0000ffff) + (checksum >> 16)); return checksum << 16; } diff --git a/protocols/oscar/liboscar/oftmetatransfer.h b/protocols/oscar/liboscar/oftmetatransfer.h index e29d98192..d8c6bff69 100644 --- a/protocols/oscar/liboscar/oftmetatransfer.h +++ b/protocols/oscar/liboscar/oftmetatransfer.h @@ -1,103 +1,103 @@ // oftmetatransfer.h // Copyright (C) 2006 // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without fdeven the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA // 02110-1301 USA #ifndef OFTMETATRANSFER_H #define OFTMETATRANSFER_H -#include -#include +#include +#include #include "oscartypes.h" class QTcpSocket; class OftMetaTransfer : public QObject { Q_OBJECT public: /** Receive constructor * @param files list of file names with path. * @param dir default directory if @p files list isn't big enough. */ OftMetaTransfer( const QByteArray& cookie, const QStringList &files, const QString& dir, QTcpSocket *socket ); /** Send constructor */ OftMetaTransfer( const QByteArray& cookie, const QStringList& files, QTcpSocket *socket ); ~OftMetaTransfer(); void start(); //start sending file public Q_SLOTS: void doCancel(); //one of the users is cancelling us Q_SIGNALS: void fileStarted( const QString& sourceFile, const QString& destinationFile ); void fileStarted( const QString& fileName, unsigned int fileSize ); void fileProcessed( unsigned int bytesSent, unsigned int fileSize ); void fileFinished( const QString& fileName, unsigned int fileSize ); void transferCompleted(); void transferError( int errorCode, const QString &error ); private Q_SLOTS: //bool validFile(); void socketError( QAbstractSocket::SocketError ); void socketRead(); void write(); void emitTransferCompleted(); private: void initOft(); void handleReceiveSetup( const Oscar::OFT &oft ); void handleReceiveResumeSetup( const Oscar::OFT &oft ); void handleSendSetup( const Oscar::OFT &oft ); void handleSendResumeSetup( const Oscar::OFT &oft ); void handleSendResumeRequest( const Oscar::OFT &oft ); void handleSendDone( const Oscar::OFT &oft ); void sendOft(); void prompt(); void ack(); void done(); void resume(); //receiver wants to resume partial file void rAgree(); //sender agrees to resume void rAck(); //resume ack void saveData(); //save incoming data to disk void readOft(); //handle incoming oft packet /** return checksum of our file, up to bytes */ Oscar::DWORD fileChecksum( QFile& file, int bytes = -1 ) const; Oscar::DWORD chunkChecksum( const char *buffer, int bufferSize, Oscar::DWORD checksum, bool shiftIndex ) const; Oscar::OFT m_oft; QFile m_file; QString m_dir; //directory where we save files QStringList m_files; //list of files that we want to send QTcpSocket *m_socket; //where we actually send file data enum State { SetupReceive, SetupSend, Receiving, Sending, Done }; State m_state; }; #endif diff --git a/protocols/oscar/liboscar/oscarclientstream.cpp b/protocols/oscar/liboscar/oscarclientstream.cpp index 87d578ca9..46d530091 100644 --- a/protocols/oscar/liboscar/oscarclientstream.cpp +++ b/protocols/oscar/liboscar/oscarclientstream.cpp @@ -1,366 +1,366 @@ /* oscarclientstream.cpp - Kopete Oscar Protocol Copyright (c) 2004 Matt Rogers Copyright (c) 2007 Roman Jarosz Based on code Copyright (c) 2004 SuSE Linux AG Based on Iris, Copyright (C) 2003 Justin Karneges Kopete (c) 2002-2007 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "oscarclientstream.h" -#include -#include -#include +#include +#include +#include #include #include "connection.h" #include "coreprotocol.h" #include "transfer.h" #define LIBOSCAR_DEBUG 0 void cs_dump( const QByteArray &bytes ); class ClientStream::Private { public: Private() { socket = 0; connection = 0; newTransfers = false; } QString host; quint16 port; QString name; QSslSocket *socket; CoreProtocol client; Connection* connection; bool newTransfers; QQueue in; QTimer noopTimer; // used to send icq keepalive int noop_time; }; ClientStream::ClientStream( QSslSocket *socket, QObject *parent ) : Stream( parent ), d(new Private()) { d->socket = socket; connect( d->socket, SIGNAL(connected()), SLOT(socketConnected()) ); connect( d->socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError)) ); connect(d->socket, SIGNAL(disconnected()), SLOT(socketDisconnected())); connect(d->socket, SIGNAL(readyRead()), SLOT(socketReadyRead())); connect(d->socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64))); connect( &d->client, SIGNAL(outgoingData(QByteArray)), SLOT (cp_outgoingData(QByteArray)) ); connect( &d->client, SIGNAL(incomingData()), SLOT (cp_incomingData()) ); d->noop_time = 0; connect(&d->noopTimer, SIGNAL(timeout()), SLOT(doNoop())); } ClientStream::~ClientStream() { d->noopTimer.stop(); if ( d->socket->isOpen() ) { kDebug(OSCAR_RAW_DEBUG) << "Socket open, disconnecting..."; d->socket->disconnectFromHost(); if ( !d->socket->waitForDisconnected( 10000 ) ) { kDebug(OSCAR_RAW_DEBUG) << "Disconnection error!"; d->socket->close(); } } delete d->socket; delete d; } void ClientStream::connectToServer( const QString& host, quint16 port, bool encrypted, const QString& name ) { d->noopTimer.stop(); if ( d->socket->isOpen() ) { kDebug(OSCAR_RAW_DEBUG) << "Socket open, disconnecting..."; d->socket->disconnectFromHost(); if ( !d->socket->waitForDisconnected( 10000 ) ) { kDebug(OSCAR_RAW_DEBUG) << "Disconnection error!"; d->socket->close(); } } d->client.reset(); d->in.clear(); d->newTransfers = false; d->host = host; d->port = port; d->name = name; kDebug(OSCAR_RAW_DEBUG) << "Connect to: host" << host << "port" << port << "encrypted" << encrypted << "name" << name; if ( encrypted ) { d->socket->ignoreSslErrors(); d->socket->setPeerVerifyMode(QSslSocket::VerifyNone); if ( name.isEmpty() ) d->socket->connectToHostEncrypted( d->host, d->port ); else d->socket->connectToHostEncrypted( d->host, d->port, d->name ); } else { d->socket->connectToHost( d->host, d->port ); } } bool ClientStream::isOpen() const { return d->socket->isOpen(); } void ClientStream::setNoopTime( int mills ) { d->noop_time = mills; if( d->noop_time == 0 ) { d->noopTimer.stop(); return; } if( !d->socket->isOpen() ) return; d->noopTimer.start( d->noop_time ); } QHostAddress ClientStream::localAddress() const { return d->socket->localAddress(); } int ClientStream::error() const { return d->socket->error(); } QString ClientStream::errorString() const { return d->socket->errorString(); } void ClientStream::close() { if( d->socket->isOpen() ) { processNext(); d->socket->disconnectFromHost(); } } void ClientStream::setConnection( Connection *c ) { d->connection = c; } Connection* ClientStream::connection() const { return d->connection; } bool ClientStream::transfersAvailable() const { return ( !d->in.isEmpty() ); } Transfer* ClientStream::read() { if( d->in.isEmpty() ) return 0; //first from queue... else return d->in.dequeue(); } void ClientStream::write( Transfer *request ) { d->client.outgoingTransfer( request ); } void cs_dump( const QByteArray &bytes ) { #if 0 qDebug( "contains: %i bytes ", bytes.count() ); uint count = 0; while ( count < bytes.count() ) { int dword = 0; for ( int i = 0; i < 8; ++i ) { if ( count + i < bytes.count() ) printf( "%02x ", bytes[ count + i ] ); else printf( " " ); if ( i == 3 ) printf( " " ); } printf(" | "); dword = 0; for ( int i = 0; i < 8; ++i ) { if ( count + i < bytes.count() ) { int j = bytes [ count + i ]; if ( j >= 0x20 && j <= 0x7e ) printf( "%2c ", j ); else printf( "%2c ", '.' ); } else printf( " " ); if ( i == 3 ) printf( " " ); } printf( "\n" ); count += 8; } printf( "\n" ); #endif Q_UNUSED( bytes ); } void ClientStream::cp_outgoingData( const QByteArray& outgoingBytes ) { // take formatted bytes from CoreProtocol and put them on the wire d->socket->write( outgoingBytes ); } void ClientStream::cp_incomingData() { Transfer * incoming = d->client.incomingTransfer(); if ( incoming ) { d->in.enqueue( incoming ); d->newTransfers = true; doReadyRead(); } else kDebug(OSCAR_RAW_DEBUG) << "client signalled incomingData but none was available, state is: " << d->client.state() << endl; } void ClientStream::socketConnected() { kDebug(OSCAR_RAW_DEBUG) ; if ( d->noop_time ) d->noopTimer.start( d->noop_time ); emit connected(); } void ClientStream::socketDisconnected() { kDebug(OSCAR_RAW_DEBUG) ; d->noopTimer.stop(); d->client.reset(); emit disconnected(); } void ClientStream::socketError( QAbstractSocket::SocketError socketError ) { kDebug(OSCAR_RAW_DEBUG) << " error: " << int(socketError); d->noopTimer.stop(); if ( socketError == QAbstractSocket::RemoteHostClosedError ) d->socket->abort(); else if ( socketError == QAbstractSocket::SslHandshakeFailedError ) { // nop } else d->socket->close(); kDebug(OSCAR_RAW_DEBUG) << " after error: " << int(socketError); d->client.reset(); emit Stream::error( socketError ); } void ClientStream::socketReadyRead() { QByteArray buffer = d->socket->readAll(); #if LIBOSCAR_DEBUG QByteArray cs(buffer.data(), buffer.size()+1); kDebug(OSCAR_RAW_DEBUG) << "recv: " << buffer.size() << "bytes"; cs_dump( buffer ); #endif d->client.addIncomingData( buffer ); } void ClientStream::socketBytesWritten( qint64 bytes ) { #if LIBOSCAR_DEBUG kDebug(OSCAR_RAW_DEBUG) << bytes << " bytes written"; Q_UNUSED( bytes ); #else Q_UNUSED( bytes ); #endif } void ClientStream::doReadyRead() { emit readyRead(); } void ClientStream::processNext() { if( !d->in.isEmpty() ) { QTimer::singleShot(0, this, SLOT(doReadyRead())); } } void ClientStream::doNoop() { if ( !d->socket->isOpen() ) return; FLAP f = { 0x05, d->connection->flapSequence(), 0 }; Buffer* b = new Buffer(); //deleted in Transfer destructor Transfer* t = new FlapTransfer( f, b ); //deleted after being sent write( t ); } diff --git a/protocols/oscar/liboscar/oscarclientstream.h b/protocols/oscar/liboscar/oscarclientstream.h index b92e2af17..c50c16b74 100644 --- a/protocols/oscar/liboscar/oscarclientstream.h +++ b/protocols/oscar/liboscar/oscarclientstream.h @@ -1,103 +1,103 @@ /* oscarclientstream.h - Kopete Oscar Protocol Copyright (c) 2004 Matt Rogers Copyright (c) 2007 Roman Jarosz Based on code Copyright (c) 2004 SuSE Linux AG Based on Iris, Copyright (C) 2003 Justin Karneges Kopete (c) 2002-2007 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef OSCARCLIENTSTREAM_H #define OSCARCLIENTSTREAM_H #include "stream.h" #include "liboscar_export.h" -#include +#include class Connection; class QHostAddress; class LIBOSCAR_EXPORT ClientStream : public Stream { Q_OBJECT public: explicit ClientStream( QSslSocket *socket, QObject *parent = nullptr ); ~ClientStream(); void connectToServer( const QString& host, quint16 port, bool encrypted, const QString &name ); bool isOpen() const; void close() Q_DECL_OVERRIDE; /** Connection related stuff */ void setConnection( Connection* c ); Connection* connection() const; /** * Are there any messages waiting to be read */ bool transfersAvailable() const Q_DECL_OVERRIDE; /** * Read a message received from the server */ Transfer * read() Q_DECL_OVERRIDE; /** * Send a message to the server */ void write( Transfer* request ) Q_DECL_OVERRIDE; int error() const Q_DECL_OVERRIDE; QString errorString() const Q_DECL_OVERRIDE; void setNoopTime( int mills ); QHostAddress localAddress() const; Q_SIGNALS: void connected(); public Q_SLOTS: void socketError( QAbstractSocket::SocketError ); private Q_SLOTS: /** * collects wire ready outgoing data from the core protocol and sends */ void cp_outgoingData( const QByteArray& ); /** * collects parsed incoming data as a transfer from the core protocol and queues */ void cp_incomingData(); void socketConnected(); void socketDisconnected(); void socketReadyRead(); void socketBytesWritten( qint64 ); void doNoop(); void doReadyRead(); private: class Private; Private * const d; void processNext(); }; #endif diff --git a/protocols/oscar/liboscar/tasks/chatroomtask.cpp b/protocols/oscar/liboscar/tasks/chatroomtask.cpp index 8e8b44947..bc90175bf 100644 --- a/protocols/oscar/liboscar/tasks/chatroomtask.cpp +++ b/protocols/oscar/liboscar/tasks/chatroomtask.cpp @@ -1,193 +1,193 @@ /* Kopete Oscar Protocol Chat Room Task Copyright 2009 Benson Tsai Kopete ( c ) 2002-2009 by the Kopete developers based on filetransfertask.h and filetransfertask.cpp ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or ( at your option ) any later version. * * * ************************************************************************* */ #include "chatroomtask.h" #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include #include "buffer.h" #include "oscarutils.h" #include "oscarmessage.h" #include "connection.h" #include "oscarsettings.h" #include "oftmetatransfer.h" //receive ChatRoomTask::ChatRoomTask(Task* parent, const QString& contact, const QString& self, QByteArray cookie, const QString& msg, const Oscar::WORD exchange, const QString& room) : Task(parent), m_contactName(contact), m_selfName(self), m_cookie(cookie), m_msg(msg), m_exchange(exchange), m_room(room) { } //send ChatRoomTask::ChatRoomTask(Task* parent, const QString& contact, const QString& self, const QString& msg, const Oscar::WORD exchange, const QString& room) : Task(parent), m_contactName(contact), m_selfName(self), m_msg(msg), m_exchange(exchange), m_room(room) { Buffer b; Oscar::DWORD cookie = KRandom::random(); b.addDWord( cookie ); cookie = KRandom::random(); b.addDWord( cookie ); m_cookie = b.buffer(); } ChatRoomTask::~ChatRoomTask() { kDebug(OSCAR_RAW_DEBUG) << "done"; } QString ChatRoomTask::internalId() const { return QString( m_cookie.toHex() ); } QString ChatRoomTask::contactName() const { return m_contactName; } QString ChatRoomTask::inviteMessage() const { return m_msg; } Oscar::WORD ChatRoomTask::exchange() const { return m_exchange; } QString ChatRoomTask::room() const { return m_room; } void ChatRoomTask::onGo() { return; } bool ChatRoomTask::take( Transfer* transfer ) { Q_UNUSED(transfer); return false; } void ChatRoomTask::doInvite() { Buffer* b = new Buffer(); b->addString( m_cookie, 8 ); b->addWord( 0x0002 ); // nick name b->addByte( m_contactName.toUtf8().length() ); b->addString( m_contactName.toUtf8() ); // start creating rendezvous tlv data Buffer b2; // Message type Request b2.addWord( 0x0000 ); // Repeat cookie b2.addString( m_cookie, 8 ); // Add chatroom GUID b2.addString( oscar_caps[CAP_CHAT] ); // unknown b2.addTLV( 0x000a, QByteArray( "\x00\x01", 2 ) ); // unknown b2.addTLV( 0x000f, QByteArray() ); // char set b2.addTLV( 0x000e, QByteArray( "\x30", 1 ) ); // language b2.addTLV( 0x000d, QByteArray( "us-ascii" ) ); // Add invite message b2.addTLV( 0x000c, m_msg.toUtf8() ); // start creating extended tlv data Buffer b3; // unknown 4 bytes b3.addWord( 0x0004 ); b3.addWord( 0x2321 ); QString joinStr = QStringLiteral("aol://2719:10-"); joinStr.append( QString::number( m_exchange ) ); joinStr.append( "-" ); joinStr.append( m_room ); b3.addString( joinStr.toUtf8() ); b3.addWord( 0x0000 ); // add extended data b2.addTLV( 0x2711, b3 ); // add rendezvous data b->addTLV( 0x0005, b2 ); // request ack b->addTLV( 0x0003, QByteArray() ); FLAP f = { 0x02, 0, 0 }; SNAC s = { 0x0004, 0x0006, 0x0000, client()->snacSequence() }; Transfer* t = createTransfer( f, s, b ); send( t ); setSuccess( true ); } void ChatRoomTask::doReject() { qDebug() << "invitation to join chat " << m_room << " rejected!"; Buffer* b = new Buffer(); b->addString( m_cookie, 8 ); b->addWord( 0x0002 ); // nick name b->addByte( m_contactName.toUtf8().length() ); b->addString( m_contactName.toUtf8() ); // rejection! b->addWord( 0x0003 ); b->addWord( 0x0002 ); b->addWord( 0x0001 ); FLAP f = { 0x02, 0, 0 }; SNAC s = { 0x0004, 0x000B, 0x0000, client()->snacSequence() }; Transfer* t = createTransfer( f, s, b ); send( t ); setSuccess( true ); } void ChatRoomTask::doAccept() { qDebug() << "invitation to join chat " << m_room << " accepted!"; emit joinChatRoom( m_room, m_exchange ); setSuccess( true ); } diff --git a/protocols/oscar/liboscar/tasks/chatroomtask.h b/protocols/oscar/liboscar/tasks/chatroomtask.h index 497e81666..b648af519 100644 --- a/protocols/oscar/liboscar/tasks/chatroomtask.h +++ b/protocols/oscar/liboscar/tasks/chatroomtask.h @@ -1,76 +1,76 @@ /* Kopete Oscar Protocol Chat Room Task Copyright 2009 Benson Tsai Kopete ( c ) 2002-2009 by the Kopete developers based on filetransfertask.h and filetransfertask.cpp ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or ( at your option ) any later version. * * * ************************************************************************* */ #ifndef CHATROOMTASK_H #define CHATROOMTASK_H #include "task.h" -#include -#include -#include +#include +#include +#include class Transfer; namespace Oscar { class Message; } class ChatRoomTask : public Task { Q_OBJECT public: /** create an incoming chatroom request */ ChatRoomTask( Task* parent, const QString& contact, const QString& self, QByteArray cookie, const QString& msg, const Oscar::WORD exchange, const QString& room ); /** create an outgoing chatroom request */ ChatRoomTask( Task* parent, const QString& contact, const QString& self, const QString& msg, const Oscar::WORD exchange, const QString& room ); ~ChatRoomTask(); QString internalId() const; QString contactName() const; QString inviteMessage() const; Oscar::WORD exchange() const; QString room() const; //! Task implementation bool take( Transfer* transfer ) Q_DECL_OVERRIDE; protected: void onGo() Q_DECL_OVERRIDE; public Q_SLOTS: void doInvite(); void doReject(); void doAccept(); Q_SIGNALS: void joinChatRoom( const QString& roomName, int exchange ); private: QString m_contactName; //other person's username QString m_selfName; //my username QByteArray m_cookie; QString m_msg; Oscar::WORD m_exchange; QString m_room; }; #endif diff --git a/protocols/oscar/liboscar/tasks/filetransfertask.cpp b/protocols/oscar/liboscar/tasks/filetransfertask.cpp index bea6f56f0..eb834bd67 100644 --- a/protocols/oscar/liboscar/tasks/filetransfertask.cpp +++ b/protocols/oscar/liboscar/tasks/filetransfertask.cpp @@ -1,899 +1,899 @@ /* Kopete Oscar Protocol File Transfer Task Copyright 2006 Chani Armitage Copyright 2007 Matt Rogers Copyright 2008 Roman Jarosz Kopete ( c ) 2002-2008 by the Kopete developers based on ssidata.h and ssidata.cpp ( c ) 2002 Tom Linsky ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or ( at your option ) any later version. * * * ************************************************************************* */ #include "filetransfertask.h" -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include #include "buffer.h" #include "oscarutils.h" #include "oscarmessage.h" #include "connection.h" #include "oscarsettings.h" #include "oftmetatransfer.h" //receive FileTransferTask::FileTransferTask( Task* parent, const QString& contact, const QString& self, QByteArray cookie, Buffer b ) : Task( parent ), m_contactName( contact ), m_selfName( self ), m_timer( this ) { init( Receive ); initOft(); m_oftRendezvous.cookie = cookie; parseReq( b ); } //send FileTransferTask::FileTransferTask( Task* parent, const QString& contact, const QString& self, const QStringList& files ) :Task( parent ), m_contactName( contact ), m_selfName( self ), m_timer( this ) { init( Send ); initOft(); m_oftRendezvous.files = files; m_oftRendezvous.fileCount = files.size(); for ( int i = 0; i < m_oftRendezvous.fileCount; ++i ) { QFileInfo fileInfo( m_oftRendezvous.files.at(i) ); m_oftRendezvous.totalSize += fileInfo.size(); } if ( m_oftRendezvous.fileCount == 1 ) { //get filename without path m_oftRendezvous.fileName = QFileInfo( files.at(0) ).fileName(); } //we get to make up an icbm cookie! Buffer b; Oscar::DWORD cookie = KRandom::random(); b.addDWord( cookie ); cookie = KRandom::random(); b.addDWord( cookie ); m_oftRendezvous.cookie = b.buffer(); } void FileTransferTask::init( Action act ) { m_action = act; m_tcpServer = 0; m_connection = 0; m_port = 0; m_proxy = false; m_proxyRequester = false; m_state = Default; m_fileFinishedBytes = 0; } FileTransferTask::~FileTransferTask() { if( m_tcpServer ) { delete m_tcpServer; m_tcpServer = 0; } if( m_connection ) { m_connection->close(); delete m_connection; m_connection = 0; } kDebug(OSCAR_RAW_DEBUG) << "done"; } QString FileTransferTask::internalId() const { return QString( m_oftRendezvous.cookie.toHex() ); } QString FileTransferTask::contactName() const { return m_contactName; } QString FileTransferTask::fileName() const { return m_oftRendezvous.fileName; } Oscar::WORD FileTransferTask::fileCount() const { return m_oftRendezvous.fileCount; } Oscar::DWORD FileTransferTask::totalSize() const { return m_oftRendezvous.totalSize; } QString FileTransferTask::description() const { return m_desc; } void FileTransferTask::onGo() { if ( m_action == Receive ) return; //else, send if ( m_contactName.isEmpty() ) { setSuccess( 0 ); return; } for ( int i = 0; i < m_oftRendezvous.fileCount; ++i ) { if ( !validFile( m_oftRendezvous.files.at(i) ) ) { setSuccess( 0 ); return; } } if ( client()->settings()->fileProxy() ) { //proxy stage 1 m_proxy = true; m_proxyRequester = true; doConnect(); } else sendReq(); } void FileTransferTask::parseReq( Buffer b ) { QByteArray proxy_ip; QByteArray client_ip; QByteArray verified_ip; QByteArray fileName; QTextCodec *c=0; m_altIp.clear(); //just to be sure while( b.bytesAvailable() ) { TLV tlv = b.getTLV(); Buffer b2( tlv.data ); switch( tlv.type ) { case 0x2711: //file-specific stuff { if ( m_action == Send ) //then we don't care break; bool multipleFiles = (b2.getWord() == 0x02); kDebug(OSCAR_RAW_DEBUG) << "multiple file flag: " << multipleFiles; m_oftRendezvous.fileCount = b2.getWord(); m_oftRendezvous.totalSize = b2.getDWord(); fileName = b2.getBlock( b2.bytesAvailable() - 1 ); //null terminated kDebug(OSCAR_RAW_DEBUG) << "file: " << fileName; kDebug(OSCAR_RAW_DEBUG) << "total size: " << m_oftRendezvous.totalSize << " files: " << m_oftRendezvous.fileCount; break; } case 0x2712: c = Oscar::codecForName( tlv.data ); kDebug(OSCAR_RAW_DEBUG) << "filename encoding " << tlv.data; break; case 2: proxy_ip = tlv.data; kDebug(OSCAR_RAW_DEBUG) << "proxy ip " << QHostAddress( b2.getDWord() ).toString(); break; case 3: client_ip = tlv.data; kDebug(OSCAR_RAW_DEBUG) << "client ip " << QHostAddress( b2.getDWord() ).toString(); break; case 4: verified_ip = tlv.data; kDebug(OSCAR_RAW_DEBUG) << "verified ip " << QHostAddress( b2.getDWord() ).toString(); break; case 5: m_port = b2.getWord(); kDebug(OSCAR_RAW_DEBUG) << "port " << m_port; break; case 0x0c: m_desc = parseDescription( tlv.data ); //FIXME: what codec? kDebug(OSCAR_RAW_DEBUG) << "user message: " << tlv.data; break; case 0x0d: kDebug(OSCAR_RAW_DEBUG) << "default encoding " << tlv.data; break; case 0x0e: kDebug(OSCAR_RAW_DEBUG) << "language " << tlv.data; break; case 0x10: m_proxy = true; break; default: kDebug(OSCAR_RAW_DEBUG) << "ignoring tlv type " << tlv.type; } } if ( !c ) { c = QTextCodec::codecForName( "UTF-8" ); kDebug(OSCAR_RAW_DEBUG) << "no codec, assuming utf8"; } if ( c ) m_oftRendezvous.fileName = c->toUnicode( fileName ); else { kWarning(OSCAR_RAW_DEBUG) << "couldn't get any codec! "; m_oftRendezvous.fileName = fileName; } if( m_proxy ) { kDebug(OSCAR_RAW_DEBUG) << "proxy requested"; m_ip = proxy_ip; } else if ( client_ip.isEmpty() ) m_ip = verified_ip; else if ( client_ip == "\0\0\0\0" ) { //ip is all 0's kDebug(OSCAR_RAW_DEBUG) << "proxy??"; //wtf... I guess it wants *me* to request a proxy? m_proxy = true; m_proxyRequester = true; } else { m_ip = client_ip; if ( verified_ip != client_ip ) m_altIp = verified_ip; } } bool FileTransferTask::validFile( const QString& file ) { QFileInfo fileInfo( file ); if ( m_action == Send ) { if ( ! fileInfo.exists() ) { emit transferError( KIO::ERR_DOES_NOT_EXIST, fileInfo.fileName() ); return 0; } if ( fileInfo.size() == 0 ) { emit transferError( KIO::ERR_COULD_NOT_READ, i18n("file is empty: ") + fileInfo.fileName() ); return 0; } if ( ! fileInfo.isReadable() ) { emit transferError( KIO::ERR_CANNOT_OPEN_FOR_READING, fileInfo.fileName() ); return 0; } } else //receive { //note: opening for writing clobbers the file if ( fileInfo.exists() ) { if ( ! fileInfo.isWritable() ) { //it's there and readonly emit transferError( KIO::ERR_CANNOT_OPEN_FOR_WRITING, fileInfo.fileName() ); return 0; } } else if ( ! QFileInfo( fileInfo.path() ).isWritable() ) { //not allowed to create it emit transferError( KIO::ERR_CANNOT_OPEN_FOR_WRITING, fileInfo.fileName() ); return 0; } } return true; } bool FileTransferTask::validDir( const QString& dir ) { QFileInfo fileInfo( dir ); if ( m_action == Receive ) { if ( fileInfo.exists() && fileInfo.isDir() ) { if ( !fileInfo.isWritable() ) { //it's there and readonly emit transferError( KIO::ERR_CANNOT_OPEN_FOR_WRITING, dir ); return false; } } else { //not allowed o create it emit transferError( KIO::ERR_CANNOT_OPEN_FOR_WRITING, dir ); return false; } } return true; } bool FileTransferTask::take( Transfer* transfer ) { Q_UNUSED(transfer); return false; } bool FileTransferTask::take( int type, QByteArray cookie, Buffer b ) { kDebug(14151) << "comparing to " << m_oftRendezvous.cookie.toHex(); if ( cookie != m_oftRendezvous.cookie ) return false; //ooh, ooh, something happened! switch( type ) { case 0: //direct transfer ain't good enough kDebug(OSCAR_RAW_DEBUG) << "redirect or proxy request"; if ( m_state != Listening ) { kDebug(OSCAR_RAW_DEBUG) << "other client is insane."; break; } m_tcpServer->close(); delete m_tcpServer; m_tcpServer = 0; parseReq( b ); doConnect(); break; case 1: kDebug(OSCAR_RAW_DEBUG) << "other user cancelled filetransfer :("; emit transferCancelled(); //FIXME: what if it's not hooked up? emit cancelOft(); m_timer.stop(); setSuccess( true ); break; case 2: kDebug(OSCAR_RAW_DEBUG) << "other user acceptetd filetransfer :)"; break; default: kWarning(OSCAR_RAW_DEBUG) << "bad request type: " << type; } return true; } bool FileTransferTask::takeAutoResponse( int type, QByteArray cookie, Buffer* b ) { if ( cookie != m_oftRendezvous.cookie ) return false; switch( type ) { case 3: //channel specific data if ( b->getWord() == 0x0002 ) { Oscar::WORD data = b->getWord(); if ( data == 0x0001 ) kDebug(OSCAR_RAW_DEBUG) << "other user cancelled filetransfer :("; else if ( data == 0x0006 ) kDebug(OSCAR_RAW_DEBUG) << "other client terminated filetransfer :("; if ( data == 0x0001 || data == 0x0006 ) { emit transferCancelled(); emit cancelOft(); m_timer.stop(); setSuccess( true ); break; } } case 1: //channel not supported case 2: //busted payload default: kWarning(OSCAR_RAW_DEBUG) << "unknown response for type: " << type; } return true; } void FileTransferTask::readyAccept() { kDebug(OSCAR_RAW_DEBUG) << "******************"; m_connection = m_tcpServer->nextPendingConnection(); // Reparent because we want to delete TcpServer; if ( m_connection ) m_connection->setParent( 0 ); m_tcpServer->close(); //free up the port so others can listen delete m_tcpServer; m_tcpServer = 0; if ( !m_connection ) { //either it wasn't buffered, or it did something weird kDebug(OSCAR_RAW_DEBUG) << "connection failed somehow."; emit transferError( KIO::ERR_COULD_NOT_ACCEPT, QString() ); doCancel(); return; } //ok, so we have a direct connection. for filetransfers. cool. //now we go on to the OFT phase. doOft(); } void FileTransferTask::doOft() { kDebug(OSCAR_RAW_DEBUG) << "******************"; QObject::disconnect( m_connection, 0, 0, 0 ); //disconnect signals m_state = OFT; OftMetaTransfer *oft; if ( m_action == Receive ) oft = new OftMetaTransfer( m_oftRendezvous.cookie, m_oftRendezvous.files, m_oftRendezvous.dir, m_connection ); else oft = new OftMetaTransfer( m_oftRendezvous.cookie, m_oftRendezvous.files, m_connection ); m_connection = 0; //it's not ours any more //might be a good idea to hook up some signals&slots. connect( oft, SIGNAL(fileStarted(QString,uint)), this, SIGNAL(nextFile(QString,uint)) ); connect( oft, SIGNAL(fileStarted(QString,QString)), this, SIGNAL(nextFile(QString,QString)) ); connect( oft, SIGNAL(fileProcessed(uint,uint)), this, SLOT(fileProcessedOft(uint,uint)) ); connect( oft, SIGNAL(fileFinished(QString,uint)), this, SLOT(fileFinishedOft(QString,uint)) ); connect( oft, SIGNAL(transferError(int,QString)), this, SLOT(errorOft(int,QString)) ); connect( oft, SIGNAL(transferCompleted()), this, SLOT(doneOft()) ); connect( this, SIGNAL(cancelOft()), oft, SLOT(doCancel()) ); //now we can finally send the first OFT packet. if ( m_action == Send ) oft->start(); } void FileTransferTask::fileProcessedOft( unsigned int bytesSent, unsigned int fileSize ) { unsigned int bytesSentTotal = m_fileFinishedBytes + bytesSent; emit fileProcessed( bytesSent, fileSize ); emit transferProcessed( bytesSentTotal ); } void FileTransferTask::fileFinishedOft( const QString& /*fileName*/, unsigned int fileSize ) { m_fileFinishedBytes += fileSize; } void FileTransferTask::errorOft( int /*errorCode*/, const QString &error ) { emit transferError( KIO::ERR_CONNECTION_BROKEN, error ); doCancel(); } void FileTransferTask::doneOft() { emit transferFinished(); setSuccess( true ); } void FileTransferTask::socketError( QAbstractSocket::SocketError e ) { //FIXME: handle this properly for all cases QString desc; desc = m_connection->errorString(); kWarning(OSCAR_RAW_DEBUG) << "socket error: " << e << " : " << desc; if ( m_state == Connecting ) { //connection failed, try another way if ( m_proxy ) { //fuck, we failed at a proxy! just give up emit transferError( KIO::ERR_COULD_NOT_CONNECT, desc ); doCancel(); } else { m_timer.stop(); connectFailed(); } } } void FileTransferTask::proxyRead() { if ( m_state != ProxySetup ) { kWarning(OSCAR_RAW_DEBUG) << "reading non-proxy data!"; } kDebug(OSCAR_RAW_DEBUG) ; QByteArray raw = m_connection->readAll(); //is this safe? kDebug(OSCAR_RAW_DEBUG) ; Buffer b( raw ); Oscar::WORD length = b.getWord(); if ( b.bytesAvailable() != length ) kWarning(OSCAR_RAW_DEBUG) << "length is " << length << " but we have " << b.bytesAvailable() << "bytes!"; b.skipBytes( 2 ); //protocol version Oscar::WORD command = b.getWord(); b.skipBytes( 6 ); //4 unknown, 2 flags switch( command ) { case 1: //error { Oscar::WORD err = b.getWord(); QString errMsg; switch( err ) { case 0x0d: //we did something wrong (eg. wrong username) case 0x0e: //we did something wronger (eg. no cookie) errMsg = i18n("Bad Request"); break; case 0x10: //we did something else wrong errMsg = i18n("Request Timed Out"); break; case 0x1a: //other side was too slow errMsg = i18n("Acceptance Period Timed Out"); break; default: errMsg = i18n("Unknown Error: ") + QString::number( err ); } emit transferError( KIO::ERR_COULD_NOT_LOGIN, errMsg ); doCancel(); break; } case 3: //ack m_port = b.getWord(); m_ip = b.getBlock( 4 ); kDebug(OSCAR_RAW_DEBUG) << "got port " << m_port << " ip " << QHostAddress( Buffer( m_ip ).getDWord() ).toString();; //now we send a proxy request to the other side sendReq(); break; case 5: //ready doneConnect(); } } void FileTransferTask::initOft() { //set up the default values for the oft m_oftRendezvous.cookie = 0; m_oftRendezvous.fileCount = 0; m_oftRendezvous.totalSize = 0; } void FileTransferTask::doCancel() { kDebug(OSCAR_RAW_DEBUG) ; //tell the other side if ( m_state != OFT ) { Oscar::Message msg = makeFTMsg(); msg.setRequestType( 1 ); emit sendMessage( msg ); } //stop our timer in case we were doing stuff m_timer.stop(); emit cancelOft(); setSuccess( true ); } void FileTransferTask::doAccept( const QString &localDirecotry ) { kDebug(OSCAR_RAW_DEBUG) << "directory: " << localDirecotry; m_oftRendezvous.files.clear(); m_oftRendezvous.dir = localDirecotry + '/'; if ( validDir( m_oftRendezvous.dir ) ) doConnect(); else doCancel(); } void FileTransferTask::doAccept( const QStringList &localFileNames ) { kDebug(OSCAR_RAW_DEBUG) << "file names: " << localFileNames; if ( localFileNames.isEmpty() ) { doCancel(); return; } m_oftRendezvous.files = localFileNames; // Set default path from first file name in case we get more // files then we have in localFileNames. QFileInfo fileInfo( m_oftRendezvous.files.first() ); m_oftRendezvous.dir = fileInfo.absolutePath() + '/'; for ( int i = 0; i < m_oftRendezvous.files.count(); ++i ) { if ( !validFile( m_oftRendezvous.files.at(i) ) ) { doCancel(); return; } } if ( m_oftRendezvous.files.count() < m_oftRendezvous.fileCount && !validDir( m_oftRendezvous.dir ) ) { doCancel(); return; } doConnect(); } void FileTransferTask::doConnect() { kDebug(OSCAR_RAW_DEBUG) ; QString host; if ( m_proxyRequester ) host = QStringLiteral("ars.oscar.aol.com"); else { if ( m_ip.length() != 4 || ! m_port ) { emit transferError( KIO::ERR_COULD_NOT_CONNECT, i18n("missing IP or port") ); doCancel(); return; } //ksockets demand a qstring Buffer ipBuffer( m_ip ); host = QHostAddress( ipBuffer.getDWord() ).toString(); kDebug(OSCAR_RAW_DEBUG) << "ip: " << host; } //proxies *always* use port 5190; the "port" value is some retarded check m_connection = new QTcpSocket(); connect( m_connection, SIGNAL(readyRead()), this, SLOT(proxyRead()) ); connect( m_connection, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)) ); connect( m_connection, SIGNAL(connected()), this, SLOT(socketConnected())); m_state = Connecting; //socket doesn't seem to have its own timeout, so here's mine m_timer.disconnect(); connect( &m_timer, SIGNAL(timeout()), this, SLOT(timeout()) ); m_timer.start( client()->settings()->timeout() * 1000 ); //try it KSocketFactory::connectToHost( m_connection, QString(), host, m_proxy ? 5190 : m_port ); } void FileTransferTask::socketConnected() { kDebug(OSCAR_RAW_DEBUG) ; m_timer.stop(); if( m_proxy ) //we need to send an init recv first proxyInit(); else doneConnect(); } void FileTransferTask::doneConnect() { m_state = Default; if ( ! m_proxyRequester ) { //yay! send an accept message Oscar::Message msg = makeFTMsg(); msg.setRequestType( 2 ); emit sendMessage( msg ); } //next the receiver should get a prompt from the sender. doOft(); } void FileTransferTask::proxyInit() { m_state = ProxySetup; //init "send" is sent by whoever requested the proxy. //init "recv" is sent by the other side //because the second person has to include the port check Buffer data; data.addBUIN( m_selfName.toLatin1() ); if ( !m_proxyRequester ) //if 'recv' data.addWord( m_port ); data.addString( m_oftRendezvous.cookie ); data.addTLV( 0x0001, oscar_caps[CAP_SENDFILE] ); //cap tlv Buffer header; header.addWord( 10 + data.length() ); //length header.addWord( 0x044a ); //packet version header.addWord( m_proxyRequester ? 2 : 4 ); //command: 2='send' 4='recv' header.addDWord( 0 ); //unknown header.addWord( 0 ); //flags header.addString( data ); //send it to the proxy server int written = m_connection->write( header.buffer() ); if( written == -1 ) //FIXME: handle this properly kDebug(OSCAR_RAW_DEBUG) << "failed to write :("; } void FileTransferTask::timeout() { kDebug(OSCAR_RAW_DEBUG); m_timer.stop(); if ( m_state == Connecting ) { //kbufferedsocket took too damn long if ( m_proxy ) { //fuck, we failed at a proxy! just give up emit transferError( KIO::ERR_COULD_NOT_CONNECT, i18n("Timeout") ); doCancel(); } else connectFailed(); return; } //nothing's happened for ages - assume we're dead. //so tell the user, send off a cancel, and die emit transferError( KIO::ERR_ABORTED, i18n("Timeout") ); doCancel(); } void FileTransferTask::connectFailed() { m_connection->close(); delete m_connection; m_connection = 0; bool proxy = client()->settings()->fileProxy(); if (! proxy ) { if ( ! m_altIp.isEmpty() ) { //there's another ip to try m_ip = m_altIp; m_altIp.clear(); doConnect(); return; } if ( m_action == Receive ) { //try redirect sendReq(); return; } } //proxy stage 2 or 3 m_proxy = true; m_proxyRequester = true; doConnect(); } bool FileTransferTask::listen() { kDebug(OSCAR_RAW_DEBUG) ; m_state = Default; //listen for connections m_tcpServer = new QTcpServer( this ); m_tcpServer->setProxy( KSocketFactory::proxyForListening( QString() ) ); connect( m_tcpServer, SIGNAL(newConnection()), this, SLOT(readyAccept()) ); bool success = false; int first = client()->settings()->firstPort(); int last = client()->settings()->lastPort(); //I don't trust the settings to be sane if ( last < first ) last = first; for ( int i = first; i <= last; i++ ) { //try ports in the range (default 5190-5199) if( ( success = ( m_tcpServer->listen( QHostAddress::Any, i ) ) ) ) { m_port = i; break; } } if ( !success ) { //uhoh... what do we do? FIXME: maybe tell the user too many filetransfers kDebug(OSCAR_RAW_DEBUG) << "listening failed. abandoning"; emit transferError( KIO::ERR_COULD_NOT_LISTEN, QString::number( last ) ); setSuccess(false); return false; } kDebug(OSCAR_RAW_DEBUG) << "listening for connections on port " << m_port; m_state = Listening; return true; } void FileTransferTask::sendReq() { //if we're not using a proxy we need a working serversocket if (!( m_proxy || listen() )) return; Buffer b; b.addString( m_oftRendezvous.cookie ); //set up a message for sendmessagetask Oscar::Message msg = makeFTMsg(); //now set the rendezvous info msg.setRequestType( 0 ); msg.setPort( m_port ); msg.setFileName( m_oftRendezvous.fileName ); msg.setFileCount( m_oftRendezvous.fileCount ); msg.setFilesSize( m_oftRendezvous.totalSize ); if ( m_proxy ) msg.setProxy( m_ip ); if ( m_action == Receive ) msg.setRequestNumber( 2 ); else if ( m_proxy && (! client()->settings()->fileProxy() ) ) msg.setRequestNumber( 3 ); //we're done, send it off! emit sendMessage( msg ); } Oscar::Message FileTransferTask::makeFTMsg() { Oscar::Message msg; msg.setMessageType( Oscar::MessageType::File ); msg.setChannel( 2 ); //rendezvous msg.setIcbmCookie( m_oftRendezvous.cookie ); msg.setReceiver( m_contactName ); return msg; } QString FileTransferTask::parseDescription( const QByteArray &description ) const { QString xmlDesc = QString::fromUtf8( description ); xmlDesc.replace( QLatin1String( ">" ), QLatin1String( ">" ) ); xmlDesc.replace( QLatin1String( "<" ), QLatin1String( "<" ) ); xmlDesc.replace( QLatin1String( """ ), QLatin1String( "\"" ) ); xmlDesc.replace( QLatin1String( " " ), QLatin1String( " " ) ); xmlDesc.replace( QLatin1String( "&" ), QLatin1String( "&" ) ); QDomDocument xmlDocument; if ( !xmlDocument.setContent( xmlDesc ) ) { kDebug(OSCAR_RAW_DEBUG) << "Cannot parse description!"; return QString::fromUtf8( description ); } QDomNodeList descList = xmlDocument.elementsByTagName( QStringLiteral("DESC") ); if ( descList.count() == 1 ) return descList.at( 0 ).toElement().text(); else return QString::fromUtf8( description ); } diff --git a/protocols/oscar/liboscar/tasks/filetransfertask.h b/protocols/oscar/liboscar/tasks/filetransfertask.h index 7a22d8dd5..c9153a848 100644 --- a/protocols/oscar/liboscar/tasks/filetransfertask.h +++ b/protocols/oscar/liboscar/tasks/filetransfertask.h @@ -1,130 +1,130 @@ /* Kopete Oscar Protocol File Transfer Task Copyright 2006 Chani Armitage Copyright 2007 Matt Rogers Kopete ( c ) 2002-2008 by the Kopete developers based on ssidata.h and ssidata.cpp ( c ) 2002 Tom Linsky ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or ( at your option ) any later version. * * * ************************************************************************* */ #ifndef FILETRANSFERTASK_H #define FILETRANSFERTASK_H #include "task.h" -#include -#include -#include +#include +#include +#include class QTcpServer; class QTcpSocket; class Transfer; namespace Oscar { class Message; } class FileTransferTask : public Task { Q_OBJECT public: /** create an incoming filetransfer */ FileTransferTask( Task* parent, const QString& contact, const QString& self, QByteArray cookie, Buffer b ); /** create an outgoing filetransfer */ FileTransferTask( Task* parent, const QString& contact, const QString& self, const QStringList& files ); ~FileTransferTask(); QString internalId() const; QString contactName() const; QString fileName() const; Oscar::WORD fileCount() const; Oscar::DWORD totalSize() const; QString description() const; //! Task implementation void onGo() Q_DECL_OVERRIDE; bool take( Transfer* transfer ) Q_DECL_OVERRIDE; bool take( int type, QByteArray cookie, Buffer b ); bool takeAutoResponse( int type, QByteArray cookie, Buffer* b ); public Q_SLOTS: void doCancel(); void doAccept( const QString &localDirecotry ); void doAccept( const QStringList &localFileNames ); void timeout(); Q_SIGNALS: void transferCancelled(); void transferError( int errorCode, const QString &error ); void transferProcessed( unsigned int totalSent ); void transferFinished(); void nextFile( const QString& sourceFile, const QString& destinationFile ); void nextFile( const QString& fileName, unsigned int fileSize ); void fileProcessed( unsigned int bytesSent, unsigned int fileSize ); void sendMessage( const Oscar::Message &msg ); void cancelOft(); private Q_SLOTS: void readyAccept(); //serversocket got connection void socketError( QAbstractSocket::SocketError ); void proxyRead(); void socketConnected(); void fileProcessedOft( unsigned int bytesSent, unsigned int fileSize ); void fileFinishedOft( const QString& fileName, unsigned int fileSize ); void errorOft( int errorCode, const QString &error ); void doneOft(); //oft told us it's done private: enum Action { Send, Receive }; void init( Action act ); void sendReq(); bool listen(); bool validFile( const QString& file ); bool validDir( const QString& dir ); Oscar::Message makeFTMsg(); void initOft(); void parseReq( Buffer b ); void doConnect(); //attempt connection to other user (direct or redirect) void proxyInit(); //send init command to proxy server void doneConnect(); void connectFailed(); //tries another method of connecting void doOft(); QString parseDescription( const QByteArray &description ) const; Oscar::OFTRendezvous m_oftRendezvous; Action m_action; QString m_contactName; //other person's username QString m_selfName; //my username QString m_desc; //file description QTcpServer *m_tcpServer; //listens for direct connections QTcpSocket *m_connection; //where we actually send file data QTimer m_timer; //if we're idle too long, then give up Oscar::WORD m_port; //to connect to QByteArray m_ip; //to connect to QByteArray m_altIp; //to connect to if m_ip fails bool m_proxy; //are we using a proxy? bool m_proxyRequester; //did we choose to request the proxy? enum State { Default, Listening, Connecting, ProxySetup, OFT, Done }; State m_state; unsigned int m_fileFinishedBytes; }; #endif diff --git a/protocols/oscar/liboscar/tasks/icqtlvinforequesttask.h b/protocols/oscar/liboscar/tasks/icqtlvinforequesttask.h index 09101d34f..0c1bc5d18 100644 --- a/protocols/oscar/liboscar/tasks/icqtlvinforequesttask.h +++ b/protocols/oscar/liboscar/tasks/icqtlvinforequesttask.h @@ -1,71 +1,71 @@ /* Kopete Oscar Protocol icqtlvinforequesttask.h - SNAC 0x15 parsing for full user info (TLV based) Copyright (c) 2007 Roman Jarosz Kopete (c) 2007 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef ICQTLVINFOREQUESTTASK_H #define ICQTLVINFOREQUESTTASK_H #include "icqtask.h" #include "icquserinfo.h" -#include +#include class Transfer; /** * @author Roman Jarosz */ class ICQTlvInfoRequestTask : public ICQTask { Q_OBJECT public: // Short TLVs: 60,85,150,160,170,180,190,200,250,260,280,390,400,410,420,430,440,450,460,470,480,490,500,505,510,520,530,540,550,560 // Medium TLVs: Short + 50,70,85,100,110,120,130,140,300,310,320,330,340,350,360,370,380 // Long TLVs: Medium + 270,290,291,292 enum InfoType { Short = 0x0001, Medium = 0x0002, Long = 0x0003 }; ICQTlvInfoRequestTask( Task* parent ); ~ICQTlvInfoRequestTask(); void setUser( const QString& contactId ) { m_userToRequestFor = contactId; } void setMetaInfoId( const QByteArray& id ) { m_metaInfoId = id; } void setType( InfoType type ) { m_type = type; } ICQFullInfo fullInfoFor( const QString& contact ); bool forMe( const Transfer* transfer ) const Q_DECL_OVERRIDE; bool take( Transfer* transfer ) Q_DECL_OVERRIDE; void onGo() Q_DECL_OVERRIDE; Q_SIGNALS: void receivedInfoFor( const QString& contact ); private: void parse( Oscar::DWORD seq, const QByteArray &data ); QMap m_fullInfoMap; QMap m_contactSequenceMap; QString m_userToRequestFor; InfoType m_type; QByteArray m_metaInfoId; }; #endif diff --git a/protocols/oscar/liboscar/tasks/icquserinfoupdatetask.h b/protocols/oscar/liboscar/tasks/icquserinfoupdatetask.h index 22bbee30e..db6c3ce6f 100644 --- a/protocols/oscar/liboscar/tasks/icquserinfoupdatetask.h +++ b/protocols/oscar/liboscar/tasks/icquserinfoupdatetask.h @@ -1,50 +1,50 @@ /* Kopete Oscar Protocol icquserinfoupdatetask.h - SNAC 0x15 update user info Copyright (c) 2006 Roman Jarosz Kopete (c) 2006 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef ICQUSERINFOUPDATETASK_H #define ICQUSERINFOUPDATETASK_H -#include +#include #include "icqtask.h" #include "icquserinfo.h" class Transfer; /** @author Kopete Developers */ class ICQUserInfoUpdateTask : public ICQTask { public: ICQUserInfoUpdateTask( Task* parent ); ~ICQUserInfoUpdateTask(); void setInfo( const QList& infoList ); bool forMe( const Transfer* transfer ) const Q_DECL_OVERRIDE; bool take( Transfer* transfer ) Q_DECL_OVERRIDE; void onGo() Q_DECL_OVERRIDE; private: QList m_infoList; Oscar::DWORD m_goSequence; }; #endif diff --git a/protocols/oscar/liboscar/tasks/oscarlogintask.cpp b/protocols/oscar/liboscar/tasks/oscarlogintask.cpp index 76048367d..964baa15a 100644 --- a/protocols/oscar/liboscar/tasks/oscarlogintask.cpp +++ b/protocols/oscar/liboscar/tasks/oscarlogintask.cpp @@ -1,281 +1,281 @@ /* Kopete Oscar Protocol oscarlogintask.h - Handles logging into to the OSCAR service Copyright (c) 2004 Matt Rogers Copyright (c) 2007 Roman Jarosz Kopete (c) 2002-2007 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "oscarlogintask.h" -#include +#include #include #include #include #include "connection.h" #include "oscartypes.h" #include "oscarutils.h" #include "transfer.h" using namespace Oscar; OscarLoginTask::OscarLoginTask( Task* parent ) : Task ( parent ) { } OscarLoginTask::~OscarLoginTask() { } void OscarLoginTask::onGo() { //send Snac 17,06 sendAuthStringRequest(); //when we have the authKey, login connect( this, SIGNAL(haveAuthKey()), this, SLOT(sendLoginRequest()) ); } bool OscarLoginTask::forMe( const Transfer* transfer ) const { const SnacTransfer* st = dynamic_cast( transfer ); if (!st) return false; if ( st && st->snacService() == 0x17 ) { Oscar::WORD subtype = st->snacSubtype(); switch ( subtype ) { case 0x0002: case 0x0003: case 0x0006: case 0x0007: return true; break; default: return false; break; } } return false; } const QByteArray& OscarLoginTask::cookie() const { return m_cookie; } const QString& OscarLoginTask::bosHost() const { return m_bosHost; } const QString& OscarLoginTask::bosPort() const { return m_bosPort; } bool OscarLoginTask::bosEncrypted() const { return m_bosEncrypted; } const QString& OscarLoginTask::bosSSLName() const { return m_bosSSLName; } bool OscarLoginTask::take( Transfer* transfer ) { if ( forMe( transfer ) ) { SnacTransfer* st = dynamic_cast( transfer ); if (!st) return false; Oscar::WORD subtype = st->snacSubtype(); switch ( subtype ) { case 0x0003: setTransfer( transfer ); handleLoginResponse(); setTransfer( 0 ); return true; break; case 0x0007: setTransfer( transfer ); processAuthStringReply(); setTransfer( 0 ); return true; break; default: return false; break; } return false; } return false; } void OscarLoginTask::sendAuthStringRequest() { kDebug(OSCAR_RAW_DEBUG) << "SEND CLI_AUTH_REQUEST, sending login request" << endl; FLAP f = { 0x02, 0, 0 }; SNAC s = { 0x0017, 0x0006, 0x0000, client()->snacSequence() }; Buffer* outbuf = new Buffer; outbuf->addTLV(0x0001, client()->userId().toLatin1() ); Transfer* st = createTransfer( f, s, outbuf ); send( st ); } void OscarLoginTask::processAuthStringReply() { kDebug(OSCAR_RAW_DEBUG) << "Got the authorization key"; Buffer* b = transfer()->buffer(); m_authKey = b->getBSTR(); emit haveAuthKey(); } void OscarLoginTask::sendLoginRequest() { kDebug(OSCAR_RAW_DEBUG) << "SEND (CLI_MD5_LOGIN) sending AIM login"; FLAP f = { 0x02, 0, 0 }; SNAC s = { 0x0017, 0x0002, 0x0000, client()->snacSequence() }; Buffer *outbuf = new Buffer; outbuf->addTLV(0x0001, client()->userId().toLatin1()); QByteArray digest = encodePassword(); const Oscar::ClientVersion* version = client()->version(); outbuf->addTLV(0x0025, digest ); outbuf->addTLV(0x0003, version->clientString.toLatin1() ); outbuf->addTLV16(0x0016, version->clientId ); outbuf->addTLV16(0x0017, version->major ); outbuf->addTLV16(0x0018, version->minor ); outbuf->addTLV16(0x0019, version->point ); outbuf->addTLV16(0x001a, version->build ); outbuf->addTLV32(0x0014, version->other ); outbuf->addTLV(0x000f, version->lang.toLatin1() ); outbuf->addTLV(0x000e, version->country.toLatin1() ); if ( !client()->isIcq() ) { //if set, old-style buddy lists will not work... you will need to use SSI outbuf->addTLV8(0x004a,0x01); } Transfer *st = createTransfer( f, s, outbuf ); send( st ); } void OscarLoginTask::handleLoginResponse() { kDebug(OSCAR_RAW_DEBUG) << "RECV SNAC 0x17, 0x07 - AIM Login Response"; SnacTransfer* st = dynamic_cast ( transfer() ); if ( !st ) { setError( -1 , QString() ); return; } QList tlvList = st->buffer()->getTLVList(); TLV uin = findTLV( tlvList, 0x0001 ); if ( uin ) { kDebug(OSCAR_RAW_DEBUG) << "found TLV(1) [SN], SN=" << QString( uin.data ); } TLV err = findTLV( tlvList, 0x0008 ); if ( err ) { Oscar::WORD errorNum = ( ( err.data[0] << 8 ) | err.data[1] ); kDebug(OSCAR_RAW_DEBUG) << "found TLV(8) [ERROR] error= " << errorNum; Oscar::SNAC s = { 0, 0, 0, 0 }; client()->fatalTaskError( s, errorNum ); setError( errorNum, QString() ); return; //if there's an error, we'll need to disconnect anyways } TLV server = findTLV( tlvList, 0x0005 ); if ( server ) { kDebug(OSCAR_RAW_DEBUG) << "found TLV(5) [SERVER] " << QString( server.data ); QString ip = QString( server.data ); int index = ip.indexOf( ':' ); m_bosHost = ip.left( index ); ip.remove( 0 , index+1 ); //get rid of the colon and everything before it m_bosPort = ip; } TLV cookie = findTLV( tlvList, 0x0006 ); if ( cookie ) { kDebug(OSCAR_RAW_DEBUG) << "found TLV(6) [COOKIE]"; m_cookie = cookie.data; } TLV sslcert = findTLV( tlvList, 141 ); if ( sslcert ) { kDebug(OSCAR_RAW_DEBUG) << "found TLV(141) [SSLCERT]"; m_bosSSLName = sslcert.data; } TLV ssl = findTLV( tlvList, 142 ); { kDebug(OSCAR_RAW_DEBUG) << "found TLV(142) [SSL] " << (int)ssl.data[0]; m_bosEncrypted = ssl.data[0]; } tlvList.clear(); if ( m_bosHost.isEmpty() ) { kWarning(OSCAR_RAW_DEBUG) << "Empty host address!"; Oscar::SNAC s = { 0, 0, 0, 0 }; client()->fatalTaskError( s, 0 ); setError( 0, QString() ); return; } kDebug( OSCAR_RAW_DEBUG ) << "We should reconnect to server '" << m_bosHost << "' on port " << m_bosPort << ( m_bosEncrypted ? " with " : " without " ) << "SSL" << endl; setSuccess( 0, QString() ); } QByteArray OscarLoginTask::encodePassword() const { kDebug(OSCAR_RAW_DEBUG) ; QCryptographicHash h(QCryptographicHash::Md5); h.addData( m_authKey ); h.addData( client()->password().toLatin1() ); h.addData( AIM_MD5_STRING, strlen( AIM_MD5_STRING ) ); return h.result(); } diff --git a/protocols/oscar/liboscar/userdetails.cpp b/protocols/oscar/liboscar/userdetails.cpp index c043ec979..60c3fd404 100644 --- a/protocols/oscar/liboscar/userdetails.cpp +++ b/protocols/oscar/liboscar/userdetails.cpp @@ -1,885 +1,885 @@ /* Kopete Oscar Protocol userdetails.cpp - user details from the extended status packet Copyright (c) 2004 by Matt Rogers Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "userdetails.h" #include #include #include #include #include #include "buffer.h" #include "oscarutils.h" #include "oscardebug.h" -#include +#include #define OSCAR_USERINFO_DEBUG using namespace Oscar; UserDetails::UserDetails() { m_capabilities.resize(CAP_LAST); clear(); } UserDetails::~UserDetails() { } void UserDetails::clear() { m_capabilities.fill( false ); m_warningLevel = 0; m_userClass = 0; m_idleTime = 0; m_extendedStatus = 0; m_xtrazStatus = -1; m_statusMood = -1; m_dcPort = 0; m_dcType = 0; m_dcProtoVersion = 0; m_dcAuthCookie = 0; m_dcWebFrontPort = 0; m_dcClientFeatures = 0; m_dcLastInfoUpdateTime = 0; m_dcLastExtInfoUpdateTime = 0; m_dcLastExtStatusUpdateTime = 0; m_onlineStatusMsgSupport = false; m_userClassSpecified = false; m_memberSinceSpecified = false; m_onlineSinceSpecified = false; m_awaySinceSpecified = false; m_numSecondsOnlineSpecified = false; m_idleTimeSpecified = false; m_extendedStatusSpecified = false; m_xtrazStatusSpecified = false; m_statusMoodSpecified = false; m_capabilitiesSpecified = false; m_dcOutsideSpecified = false; m_dcInsideSpecified = false; m_iconSpecified = false; } int UserDetails::warningLevel() const { return m_warningLevel; } QString UserDetails::userId() const { return m_userId; } Oscar::WORD UserDetails::idleTime() const { return m_idleTime; } QHostAddress UserDetails::dcInternalIp() const { return m_dcInsideIp; } QHostAddress UserDetails::dcExternalIp() const { return m_dcOutsideIp; } Oscar::DWORD UserDetails::dcPort() const { return m_dcPort; } Oscar::WORD UserDetails::dcProtoVersion() const { return m_dcProtoVersion; } QDateTime UserDetails::onlineSinceTime() const { return m_onlineSince; } QDateTime UserDetails::awaySinceTime() const { return m_awaySince; } QDateTime UserDetails::memberSinceTime() const { return m_memberSince; } int UserDetails::userClass() const { return m_userClass; } Oscar::DWORD UserDetails::extendedStatus() const { return m_extendedStatus; } int UserDetails::xtrazStatus() const { return m_xtrazStatus; } int UserDetails::statusMood() const { return m_statusMood; } Oscar::WORD UserDetails::iconType() const { return m_iconType; } QString UserDetails::personalMessage() const { return m_personalMessage; } Oscar::BYTE UserDetails::iconCheckSumType() const { return m_iconChecksumType; } QByteArray UserDetails::buddyIconHash() const { return m_md5IconHash; } QString UserDetails::clientName() const { return m_clientName; } void UserDetails::parseCapabilities( Buffer &inbuf, int &xStatus ) { xStatus = -1; QString dbgCaps = QStringLiteral("CAPS: "); while ( inbuf.bytesAvailable() >= 16 ) { bool found = false; Guid cap( inbuf.getGuid() ); int i; for ( i=0; i < CAP_LAST; ++i ) { if ( (i == CAP_KOPETE && cap.isEqual ( oscar_caps[i], 12 ) ) || (i == CAP_MIRANDA && cap.isEqual ( oscar_caps[i], 8 ) ) || (i == CAP_QIP && cap.isEqual ( oscar_caps[i], 16 ) ) || (i == CAP_QIPINFIUM && cap.isEqual ( oscar_caps[i], 16 ) ) || (i == CAP_QIPPDA && cap.isEqual ( oscar_caps[i], 16 ) ) || (i == CAP_QIPSYMBIAN && cap.isEqual ( oscar_caps[i], 16 ) )|| (i == CAP_QIPMOBILE && cap.isEqual ( oscar_caps[i], 16 ) ) || (i == CAP_JIMM && cap.isEqual ( oscar_caps[i], 5 ) ) || (i == CAP_MICQ && cap.isEqual ( oscar_caps[i], 12 ) ) || (i == CAP_SIMNEW && cap.isEqual ( oscar_caps[i], 12 ) ) || (i == CAP_SIMOLD && cap.isEqual ( oscar_caps[i], 15 ) ) || (i == CAP_VMICQ && cap.isEqual ( oscar_caps[i], 6 ) ) || (i == CAP_LICQ && cap.isEqual ( oscar_caps[i], 12 ) ) || (i == CAP_ANDRQ && cap.isEqual ( oscar_caps[i], 9 ) ) || (i == CAP_RANDQ && cap.isEqual ( oscar_caps[i], 9 ) ) || (i == CAP_MCHAT && cap.isEqual ( oscar_caps[i], 10 ) ) ) { m_capabilities[i] = true; dbgCaps += capName(i); m_identCap = cap; found = true; break; } else if(oscar_caps[i] == cap) { m_capabilities[i] = true; dbgCaps += capName(i); found = true; break; } } if(!found && xStatus == -1) { for(i = 0; i < XSTAT_LAST; ++i) { if(oscar_xStatus[i] == cap) { xStatus = i; found = true; break; } } } } kDebug(OSCAR_RAW_DEBUG) << dbgCaps; } void UserDetails::parseNewCapabilities( Buffer &inbuf ) { QString dbgCaps = QStringLiteral("NEW CAPS: "); QByteArray cap = Guid( QStringLiteral("094600004c7f11d18222444553540000")); while ( inbuf.bytesAvailable() >= 2 ) { cap[2] = inbuf.getByte(); cap[3] = inbuf.getByte(); for ( int i = 0; i < CAP_LAST; i++ ) { if ( oscar_caps[i].data() == cap ) { m_capabilities[i] = true; dbgCaps += capName( i ); break; } } } kDebug(OSCAR_RAW_DEBUG) << dbgCaps; } void UserDetails::fill( Buffer * buffer ) { QString user = QString( buffer->getBUIN() ); if ( !user.isEmpty() ) m_userId = user; m_warningLevel = buffer->getWord(); Oscar::WORD numTLVs = buffer->getWord(); kDebug( OSCAR_RAW_DEBUG ) << "Got user info for " << user; #ifdef OSCAR_USERINFO_DEBUG kDebug( OSCAR_RAW_DEBUG ) << "Warning level is " << m_warningLevel; #endif //start parsing TLVs for( int i = 0; i < numTLVs; ++i ) { TLV t = buffer->getTLV(); if ( t ) { Buffer b( t.data, t.length ); switch( t.type ) { case 0x0001: //user class m_userClass = b.getWord(); m_userClassSpecified = true; #ifdef OSCAR_USERINFO_DEBUG kDebug(OSCAR_RAW_DEBUG) << "User class is " << m_userClass; #endif break; case 0x0002: //member since case 0x0005: //member since m_memberSince.setTime_t( b.getDWord() ); m_memberSinceSpecified = true; #ifdef OSCAR_USERINFO_DEBUG kDebug(OSCAR_RAW_DEBUG) << "Member since " << m_memberSince; #endif break; case 0x0003: //sigon time m_onlineSince.setTime_t( b.getDWord() ); m_onlineSinceSpecified = true; #ifdef OSCAR_USERINFO_DEBUG kDebug(OSCAR_RAW_DEBUG) << "Signed on at " << m_onlineSince; #endif break; case 0x0004: //idle time m_idleTime = b.getWord() * 60; m_idleTimeSpecified = true; #ifdef OSCAR_USERINFO_DEBUG kDebug(OSCAR_RAW_DEBUG) << "Idle time is " << m_idleTime; #endif break; case 0x0006: //extended user status m_extendedStatus = b.getDWord(); m_extendedStatusSpecified = true; #ifdef OSCAR_USERINFO_DEBUG kDebug(OSCAR_RAW_DEBUG) << "Extended status is " << QString::number( m_extendedStatus, 16 ); #endif break; case 0x0008: m_onlineStatusMsgSupport = (b.getWord() == 0x0A06); #ifdef OSCAR_USERINFO_DEBUG kDebug(OSCAR_RAW_DEBUG) << "Online status messages support"; #endif break; case 0x000A: //external IP address m_dcOutsideIp.setAddress( b.getDWord() ); m_dcOutsideSpecified = true; #ifdef OSCAR_USERINFO_DEBUG kDebug(OSCAR_RAW_DEBUG) << "External IP address is " << m_dcOutsideIp.toString(); #endif break; case 0x000C: //DC info m_dcInsideIp.setAddress( b.getDWord() ); m_dcPort = b.getDWord(); #ifdef OSCAR_USERINFO_DEBUG kDebug(OSCAR_RAW_DEBUG) << "Internal IP address is " << m_dcInsideIp.toString(); kDebug(OSCAR_RAW_DEBUG) << "Port number is " << m_dcPort; #endif m_dcType = b.getByte(); m_dcProtoVersion = b.getWord(); m_dcAuthCookie = b.getDWord(); m_dcWebFrontPort = b.getDWord(); m_dcClientFeatures = b.getDWord(); m_dcLastInfoUpdateTime = b.getDWord(); m_dcLastExtInfoUpdateTime = b.getDWord(); m_dcLastExtStatusUpdateTime = b.getDWord(); b.getWord(); //unknown. m_dcInsideSpecified = true; #ifdef OSCAR_USERINFO_DEBUG kDebug(OSCAR_RAW_DEBUG) << "Got DC info"; #endif break; case 0x000D: //capability info parseCapabilities(b, m_xtrazStatus); m_capabilitiesSpecified = true; m_xtrazStatusSpecified = true; break; case 0x0010: case 0x000F: //online time m_numSecondsOnline = b.getDWord(); m_numSecondsOnlineSpecified = true; #ifdef OSCAR_USERINFO_DEBUG kDebug(OSCAR_RAW_DEBUG) << "Online for " << m_numSecondsOnline; #endif break; case 0x0019: //new capability info parseNewCapabilities( b ); m_capabilitiesSpecified = true; break; case 0x001D: { if ( t.length == 0 ) break; while ( b.bytesAvailable() > 0 ) { #ifdef OSCAR_USERINFO_DEBUG kDebug(OSCAR_RAW_DEBUG) << "Icon and status message info"; #endif Oscar::WORD type2 = b.getWord(); Oscar::BYTE number = b.getByte(); Oscar::BYTE length = b.getByte(); switch( type2 ) { case 0x0000: b.skipBytes(length); break; case 0x0001: // AIM/ICQ avatar hash case 0x000C: // ICQ contact photo //case 0x0008: // ICQ Flash avatar hash if ( length > 0 && ( number == 0x01 || number == 0x00 ) && ( m_iconSpecified == false || m_iconType < type2 ) ) // Check priority { m_iconType = type2; m_iconChecksumType = number; m_md5IconHash = b.getBlock( length ); m_iconSpecified = true; #ifdef OSCAR_USERINFO_DEBUG kDebug(OSCAR_RAW_DEBUG) << "checksum:" << m_md5IconHash.toHex(); #endif } else { kWarning(OSCAR_RAW_DEBUG) << "icon checksum indicated" << " but unable to parse checksum" << endl; b.skipBytes( length ); } break; case 0x0002: if ( length > 0 ) { Buffer pmBuffer( b.getBBlock( length ) ); QByteArray personalMessageData = pmBuffer.getBSTR(); QTextCodec *codec = 0; if ( pmBuffer.bytesAvailable() >= 4 && pmBuffer.getWord() == 0x0001 ) { pmBuffer.skipBytes( 2 ); QByteArray encoding = pmBuffer.getBSTR(); codec = QTextCodec::codecForName( encoding ); kDebug(OSCAR_RAW_DEBUG) << "Encoding:" << encoding; } if (codec) m_personalMessage = codec->toUnicode( personalMessageData ); else m_personalMessage = QString::fromUtf8( personalMessageData ); #ifdef OSCAR_USERINFO_DEBUG kDebug(OSCAR_RAW_DEBUG) << "personal message:" << m_personalMessage; #endif } else kDebug(OSCAR_RAW_DEBUG) << "not enough bytes for status message"; break; case 0x000E: if ( length > 0 ) { QString mood( b.getBlock( length ) ); m_statusMood = mood.midRef( 7 ).toInt(); } m_statusMoodSpecified = true; #ifdef OSCAR_USERINFO_DEBUG kDebug(OSCAR_RAW_DEBUG) << "status mood:" << m_statusMood; #endif break; default: b.skipBytes( length ); break; } } break; } case 0x0029: m_awaySince.setTime_t( b.getDWord() ); m_awaySinceSpecified = true; #ifdef OSCAR_USERINFO_DEBUG kDebug(OSCAR_RAW_DEBUG) << "Away since " << m_awaySince; #endif break; default: kDebug(OSCAR_RAW_DEBUG) << "Unknown TLV, type=" << t.type << ", length=" << t.length << " in userinfo" << endl; break; }; //detach buffer and free TLV data b.clear(); } } //do client detection on fill if ( m_capabilitiesSpecified ) { detectClient(); } } static QString mirandaVersionToString( Oscar::DWORD v ) { QString ver; ver.sprintf( "%d.%d.%d.%d", (v >> 0x18) & 0x7F, (v >> 0x10) & 0xFF, (v >> 0x08) & 0xFF, v & 0xFF ); if ( v & 0x80000000 ) ver += QLatin1String(" alpha"); return ver; } static QString getMirandaVersion( Oscar::DWORD iver, Oscar::DWORD mver, bool isUnicode ) { if ( !iver ) return QString(); QString ver; if ( !mver && iver == 1 ) { ver = mirandaVersionToString( 0x80010200 ); } else if ( !mver && ( iver & 0x7FFFFFFF ) <= 0x030301 ) { ver = mirandaVersionToString( iver ); } else { if ( mver ) ver = mirandaVersionToString( mver ); if ( isUnicode ) ver += QLatin1String(" Unicode"); ver += " (ICQ v" + mirandaVersionToString( iver ) + ')'; } return ver; } static QString getVersionFromCap( Guid &cap, int s, int f = 16 ) { const char *c = cap.data().data(); int len = 0; for ( int i = s; i < f; i++, len++ ) { if ( c[i] == '\0' ) break; } return QString::fromLatin1(c + s, len); } void UserDetails::detectClient() { // 1 m_dcLastInfoUpdateTime // 2 m_dcLastExtInfoUpdateTime // 3 m_dcLastExtStatusUpdateTime /* Most of this code is based on Miranda ICQ plugin code */ m_clientName = QStringLiteral(""); if ( m_dcLastInfoUpdateTime == 0xFFFFFFFF ) { if ( m_dcLastExtInfoUpdateTime == 0xffffffff ) { m_clientName = QStringLiteral( "Gaim" ); } else if ( !m_dcLastExtInfoUpdateTime && m_dcProtoVersion == 7 ) { m_clientName = QStringLiteral( "WebICQ" ); } else if ( !m_dcLastExtInfoUpdateTime && m_dcLastExtStatusUpdateTime == 0x3B7248ED ) { m_clientName = QStringLiteral( "Spam Bot" ); } else { m_clientName = QStringLiteral( "Miranda IM" ); m_clientName += ' ' + getMirandaVersion( m_dcLastExtInfoUpdateTime, 0, false ); } } else if ( m_dcLastInfoUpdateTime == 0x7FFFFFFF ) { // Miranda with unicode core m_clientName = QStringLiteral( "Miranda IM" ); m_clientName += ' ' + getMirandaVersion( m_dcLastExtInfoUpdateTime, 0, true ); } else if ( ( m_dcLastInfoUpdateTime & 0xFF7F0000 ) == 0x7D000000 ) { //licq } else if ( m_dcLastInfoUpdateTime == 0xFFFFFF8F ) { m_clientName = QStringLiteral( "StrICQ" ); } else if ( m_dcLastInfoUpdateTime == 0xFFFFFF42 ) { m_clientName = QStringLiteral( "mICQ" ); } else if ( m_dcLastInfoUpdateTime == 0xFFFFFFBE ) { m_clientName = QStringLiteral("Alicq %1.%2.%3").arg((m_dcLastExtInfoUpdateTime >> 0x18) & 0xFF).arg((m_dcLastExtInfoUpdateTime >> 0x10) & 0xFF).arg((m_dcLastExtInfoUpdateTime >> 0x08) & 0xFF); } else if ( m_dcLastInfoUpdateTime == 0xFFFFFF7F ) { m_clientName = QStringLiteral( "&RQ" ); } else if ( m_dcLastInfoUpdateTime == 0xFFFFFFAB ) { m_clientName = QStringLiteral( "YSM" ); } else if ( m_dcLastInfoUpdateTime == 0x04031980 ) { m_clientName = QStringLiteral( "vICQ" ); } else if ( m_dcLastInfoUpdateTime == 0x3AA773EE && m_dcLastExtInfoUpdateTime == 0x3AA66380 ) { m_clientName = QStringLiteral( "libicq2000" ); } else if ( m_dcLastInfoUpdateTime == 0x3B75AC09 ) { m_clientName = QStringLiteral( "Trillian" ); } else if ( m_dcLastInfoUpdateTime == 0xFFFFFFFE && m_dcLastExtStatusUpdateTime == 0xFFFFFFFE ) { m_clientName = QStringLiteral( "Jimm" ); } else if ( m_dcLastInfoUpdateTime == 0xFFFFF666 && !m_dcLastExtStatusUpdateTime ) { // this is R&Q (Rapid Edition) m_clientName = QStringLiteral( "R&Q" ); m_clientVersion.sprintf( "%u", m_dcLastExtInfoUpdateTime ); m_clientName += ' ' + m_clientVersion; } // parse capabilities if ( hasCap( CAP_KOPETE ) ) { m_clientName = i18n( "Kopete" ); m_clientVersion.sprintf( "%d.%d.%d", m_identCap.data().at(12), m_identCap.data().at(13), m_identCap.data().at(14) * 100 + m_identCap.data().at(15) ); m_clientName += ' ' + m_clientVersion; return; } if ( hasCap ( CAP_MIRANDA ) ) { m_clientName = QStringLiteral( "Miranda IM" ); Oscar::DWORD iver = m_identCap.data().at(12) << 0x18 | m_identCap.data().at(13) << 0x10 | m_identCap.data().at(14) << 0x08 | m_identCap.data().at(15); Oscar::DWORD mver = m_identCap.data().at(8) << 0x18 | m_identCap.data().at(9) << 0x10 | m_identCap.data().at(10) << 0x08 | m_identCap.data().at(11); m_clientName += ' ' + getMirandaVersion( iver, mver, m_dcLastInfoUpdateTime == 0x7FFFFFFF ); return; } if ( hasCap( CAP_QIP ) ) { m_clientName = QStringLiteral( "QIP" ); if ( m_dcLastExtStatusUpdateTime == 0x0F ) m_clientVersion = QStringLiteral( "2005" ); else m_clientVersion = getVersionFromCap( m_identCap, 11 ); QString build; if ( m_dcLastInfoUpdateTime && m_dcLastExtInfoUpdateTime == 0x0E ) { build.sprintf( "(%d%d%d%d)", m_dcLastInfoUpdateTime >> 0x18, (m_dcLastInfoUpdateTime >> 0x10) & 0xFF, (m_dcLastInfoUpdateTime >> 0x08) & 0xFF, m_dcLastInfoUpdateTime & 0xFF ); } m_clientName += ' ' + m_clientVersion + ' ' + build; return; } if ( hasCap( CAP_QIPINFIUM ) ) { m_clientName = QStringLiteral( "QIP Infium" ); if ( m_dcLastInfoUpdateTime ) { QString build; build.sprintf(" (%d)", m_dcLastInfoUpdateTime ); m_clientName += build; } if ( m_dcLastExtInfoUpdateTime == 0x0B ) m_clientName += QLatin1String(" Beta"); return; } if ( hasCap( CAP_QIPPDA ) ) { m_clientName = QStringLiteral( "QIP PDA (Windows)" ); return; } if ( hasCap( CAP_QIPSYMBIAN ) ) { m_clientName = QStringLiteral( "QIP PDA (Symbian)" ); return; } if ( hasCap( CAP_QIPMOBILE ) ) { m_clientName = QStringLiteral( "QIP Mobile (Java)" ); return; } if ( hasCap( CAP_JIMM ) ) { m_clientName = QStringLiteral( "Jimm" ); m_clientName += ' ' + getVersionFromCap( m_identCap, 5 ); return; } if ( hasCap( CAP_SIMNEW ) ) { m_clientName = QStringLiteral( "SIM" ); m_clientVersion.sprintf( "%d.%d.%d.%d", m_identCap.data().at(12), m_identCap.data().at(13), m_identCap.data().at(14), m_identCap.data().at(15) & 0x0F ); if ( m_identCap.data().at(15) & 0x80 ) m_clientVersion += QLatin1String( " (Win32)" ); else if ( m_identCap.data().at(15) & 0x40 ) m_clientVersion += QLatin1String( " (MacOS X)" ); // Linux version? Fix last number m_clientName += ' ' + m_clientVersion; return; } if ( hasCap( CAP_SIMOLD ) ) { m_clientName = QStringLiteral( "SIM" ); /*int hiVersion = (cap.data()[15] >> 6) - 1; unsigned loVersion = cap.data()[15] & 0x1F; kDebug(14150) << "OLD SIM version : <" << hiVersion << ":" << loVersion << endl; m_capabilities[i] = true; versionString.sprintf("%d.%d", (unsigned int)hiVersion, loVersion); versionString.insert( 0, "SIM " );*/ return; } if ( hasCap( CAP_VMICQ ) ) { m_clientName = QStringLiteral( "VmICQ" ); return; } if ( hasCap( CAP_LICQ ) ) { m_clientName = QStringLiteral( "Licq" ); m_clientVersion.sprintf( "%d.%d.%d", m_identCap.data().at(12), m_identCap.data().at(13) % 100, m_identCap.data().at(14) ); if ( m_identCap.data().at(15) ) m_clientVersion += QLatin1String(" SSL"); m_clientName += ' ' + m_clientVersion; return; } if ( hasCap( CAP_ANDRQ ) ) { m_clientName = QStringLiteral( "&RQ" ); m_clientVersion.sprintf( "%d.%d.%d.%d", m_identCap.data().at(12), m_identCap.data().at(11), m_identCap.data().at(10), m_identCap.data().at(9) ); m_clientName += ' ' + m_clientVersion; return; } if ( hasCap( CAP_RANDQ ) ) { m_clientName = QStringLiteral("R&Q"); m_clientVersion.sprintf("%d.%d.%d.%d", m_identCap.data().at(12), m_identCap.data().at(11), m_identCap.data().at(10), m_identCap.data().at(9)); m_clientName += ' ' + m_clientVersion; return; } if ( hasCap( CAP_MCHAT ) ) { m_clientName = QStringLiteral( "mChat" ); m_clientVersion = getVersionFromCap( m_identCap, 10 ); m_clientName += ' ' + m_clientVersion; return; } if ( m_dcProtoVersion == 9 ) { if ( hasCap( CAP_XTRAZ ) ) { if ( hasCap( CAP_SENDFILE ) ) { if ( hasCap( CAP_TZERS ) ) { if ( hasCap( CAP_HTMLMSGS ) ) m_clientName = QStringLiteral( "ICQ 6" ); else m_clientName = QStringLiteral( "ICQ 5.1" ); } else { m_clientName = QStringLiteral( "ICQ 5" ); } if ( hasCap( CAP_ICQ_RAMBLER ) ) { m_clientName += QLatin1String( " (Rambler)" ); } if ( hasCap( CAP_ICQ_ABV ) ) { m_clientName += QLatin1String( " (Abv)" ); } if ( hasCap( CAP_ICQ_NETVIGATOR ) ) { m_clientName += QLatin1String( " (Netvigator)" ); } return; } } else if ( !hasCap( CAP_DIRECT_ICQ_COMMUNICATION ) ) { if ( hasCap( CAP_UTF8 ) && !hasCap( CAP_RTFMSGS ) ) { m_clientName = QStringLiteral( "pyICQ" ); } } } else if ( m_dcProtoVersion == 0 ) { } if ( !m_clientName.isEmpty() ) return; if ( m_dcProtoVersion == 6 ) { m_clientName = QStringLiteral( "ICQ 99" ); } else if ( m_dcProtoVersion == 7 ) { m_clientName = QStringLiteral( "ICQ 2000/Icq2Go" ); } else if ( m_dcProtoVersion == 8 ) { m_clientName = QStringLiteral( "ICQ 2001-2003a" ); } else if ( m_dcProtoVersion == 9 ) { m_clientName = QStringLiteral( "ICQ Lite" ); } else if ( m_dcProtoVersion == 10 ) { m_clientName = QStringLiteral( "ICQ 2003b" ); } } bool UserDetails::hasCap( int capNumber ) const { return m_capabilities[capNumber]; } bool UserDetails::onlineStatusMsgSupport() const { return m_onlineStatusMsgSupport; } void UserDetails::merge( const UserDetails& ud ) { m_userId = ud.m_userId; m_warningLevel = ud.m_warningLevel; if ( ud.m_userClassSpecified ) { m_userClass = ud.m_userClass; m_userClassSpecified = true; } if ( ud.m_memberSinceSpecified ) { m_memberSince = ud.m_memberSince; m_memberSinceSpecified = true; } if ( ud.m_onlineSinceSpecified ) { m_onlineSince = ud.m_onlineSince; m_onlineSinceSpecified = true; } if ( ud.m_awaySinceSpecified ) { m_awaySince = ud.m_awaySince; m_awaySinceSpecified = true; } if ( ud.m_numSecondsOnlineSpecified ) { m_numSecondsOnline = ud.m_numSecondsOnline; m_numSecondsOnlineSpecified = true; } if ( ud.m_idleTimeSpecified ) { m_idleTime = ud.m_idleTime; m_idleTimeSpecified = true; } if ( ud.m_extendedStatusSpecified ) { m_extendedStatus = ud.m_extendedStatus; m_extendedStatusSpecified = true; } if ( ud.m_xtrazStatusSpecified ) { m_xtrazStatus = ud.m_xtrazStatus; m_xtrazStatusSpecified = true; } if ( ud.m_statusMoodSpecified ) { m_statusMood = ud.m_statusMood; m_statusMoodSpecified = true; } if ( ud.m_capabilitiesSpecified ) { m_capabilities = ud.m_capabilities; m_clientVersion = ud.m_clientVersion; m_clientName = ud.m_clientName; m_capabilitiesSpecified = true; } if ( ud.m_dcOutsideSpecified ) { m_dcOutsideIp = ud.m_dcOutsideIp; m_dcOutsideSpecified = true; } if ( ud.m_dcInsideSpecified ) { m_dcInsideIp = ud.m_dcInsideIp; m_dcPort = ud.m_dcPort; m_dcType = ud.m_dcType; m_dcProtoVersion = ud.m_dcProtoVersion; m_dcAuthCookie = ud.m_dcAuthCookie; m_dcWebFrontPort = ud.m_dcWebFrontPort; m_dcClientFeatures = ud.m_dcClientFeatures; m_dcLastInfoUpdateTime = ud.m_dcLastInfoUpdateTime; m_dcLastExtInfoUpdateTime = ud.m_dcLastExtInfoUpdateTime; m_dcLastExtStatusUpdateTime = ud.m_dcLastExtStatusUpdateTime; m_dcInsideSpecified = true; } if ( ud.m_iconSpecified ) { m_iconType = ud.m_iconType; m_iconChecksumType = ud.m_iconChecksumType; m_md5IconHash = ud.m_md5IconHash; m_iconSpecified = true; } m_personalMessage = ud.m_personalMessage; m_onlineStatusMsgSupport = ud.m_onlineStatusMsgSupport; } diff --git a/protocols/oscar/liboscar/userdetails.h b/protocols/oscar/liboscar/userdetails.h index 3fe9fb4d3..3cc59f69f 100644 --- a/protocols/oscar/liboscar/userdetails.h +++ b/protocols/oscar/liboscar/userdetails.h @@ -1,157 +1,157 @@ /* Kopete Oscar Protocol userdetails.h - user details from the extended status packet Copyright (c) 2004 by Matt Rogers Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef USERDETAILS_H #define USERDETAILS_H -#include -#include +#include +#include #include "oscartypes.h" #include "oscar_export.h" class Buffer; using namespace Oscar; /** * Holds information from the extended user info packet * @author Matt Rogers */ class LIBOSCAR_EXPORT UserDetails { public: UserDetails(); ~UserDetails(); void clear(); QString userId() const; //! User ID accessor int warningLevel() const; //! Warning level accessor Oscar::WORD idleTime() const; //! Idle time accessor QHostAddress dcInternalIp() const; //! DC local IP accessor QHostAddress dcExternalIp() const; //! DC outside IP accessor Oscar::DWORD dcPort() const; //! DC port number Oscar::WORD dcProtoVersion() const; QDateTime onlineSinceTime() const; //! Online since accessor QDateTime awaySinceTime() const; //! Away since accessor QDateTime memberSinceTime() const; //! Member since accessor int userClass() const; //! User class accessor Oscar::DWORD extendedStatus() const; //!User status accessor int xtrazStatus() const; int statusMood() const; Oscar::WORD iconType() const; //!Buddy icon type Oscar::BYTE iconCheckSumType() const; //!Buddy icon hash type QByteArray buddyIconHash() const; //! Buddy icon md5 hash accessor QString clientName() const; //! Client name and version bool hasCap( int capNumber ) const; //! Tell if we have this capability bool onlineStatusMsgSupport() const; //! Client supports online status messages QString personalMessage() const; //! User's status (away or available) message /** * Fill the class with data from a buffer * It only updates what's available. */ void fill( Buffer* buffer ); /** * Merge only those data from another UserDetails * which are marked as specified. */ void merge( const UserDetails& ud ); bool userClassSpecified() const { return m_userClassSpecified; } bool memberSinceSpecified() const { return m_memberSinceSpecified; } bool onlineSinceSpecified() const { return m_onlineSinceSpecified; } bool awaySinceSpecified() const { return m_awaySinceSpecified; } bool numSecondsOnlineSpecified() const { return m_numSecondsOnlineSpecified; } bool idleTimeSpecified() const { return m_idleTimeSpecified; } bool extendedStatusSpecified() const { return m_extendedStatusSpecified; } bool xtrazStatusSpecified() const { return m_xtrazStatusSpecified; } bool statusMoodSpecified() const { return m_statusMoodSpecified; } bool capabilitiesSpecified() const { return m_capabilitiesSpecified; } bool dcOutsideSpecified() const { return m_dcOutsideSpecified; } bool dcInsideSpecified() const { return m_dcInsideSpecified; } bool iconSpecified() const { return m_iconSpecified; } private: /** * Parse the character array for validness and a version string * \param buffer the buffer we'll be parsing for capabilities * \param versionString a QString reference that will contain the * version string of the detected client. Will be QString() if * no client is found */ void parseCapabilities(Buffer &inbuf, int &xStatus); /** * Parse the character array for capabilities (TLV 0x19) * \param inbuf the buffer we'll be parsing for capabilities */ void parseNewCapabilities(Buffer &inbuf); //! Do client detection void detectClient(); private: QString m_userId; /// the screename/uin of the contact int m_warningLevel; /// the warning level of the contact int m_userClass; /// the class of the user - TLV 0x01 QDateTime m_memberSince; /// how long the user's been a member - TLV 0x05 QDateTime m_onlineSince; /// how long the contact's been online - TLV 0x03 QDateTime m_awaySince; /// how long the contact's been away - TLV 0x29 Oscar::DWORD m_numSecondsOnline; /// how long the contact's been online in seconds Oscar::WORD m_idleTime; /// the idle time of the contact - TLV 0x0F Oscar::DWORD m_extendedStatus; /// the extended status of the contact - TLV 0x06 int m_xtrazStatus; int m_statusMood; QBitArray m_capabilities; //TLV 0x05 QString m_clientVersion; /// the version of client they're using QString m_clientName; /// the name of the client they're using QHostAddress m_dcOutsideIp; /// DC Real IP Address - TLV 0x0A QHostAddress m_dcInsideIp; /// DC Internal IP Address - TLV 0x0C Oscar::DWORD m_dcPort; /// DC Port - TLV 0x0C Oscar::BYTE m_dcType; /// DC Type - TLV 0x0C Oscar::WORD m_dcProtoVersion; /// DC Protocol Version - TLV 0x0C Oscar::DWORD m_dcAuthCookie; /// DC Authorization Cookie - TLV 0x0C Oscar::DWORD m_dcWebFrontPort; /// DC Web Front Port - TLV 0x0C Oscar::DWORD m_dcClientFeatures; /// DC client features( whatever they are ) - TLV 0x0C Oscar::DWORD m_dcLastInfoUpdateTime; /// DC last info update time - TLV 0x0C Oscar::DWORD m_dcLastExtInfoUpdateTime; /// DC last exteneded info update time - TLV 0x0C Oscar::DWORD m_dcLastExtStatusUpdateTime; /// DC last extended status update time - TLV 0x0C Oscar::WORD m_iconType; /// The OSCAR icon type for the buddy icon TLV 0x1D Oscar::BYTE m_iconChecksumType; /// The OSCAR checksum type for the buddy icon TLV 0x1D QByteArray m_md5IconHash; /// Buddy Icon MD5 Hash - TLV 0x1D QString m_personalMessage; /// User's away (or available) status message - TLV 0x0D bool m_onlineStatusMsgSupport; /// User's client supports online status messages - TLV 0x08 Guid m_identCap; /// Save guid for client identification bool m_userClassSpecified; bool m_memberSinceSpecified; bool m_onlineSinceSpecified; bool m_awaySinceSpecified; bool m_numSecondsOnlineSpecified; bool m_idleTimeSpecified; bool m_extendedStatusSpecified; bool m_xtrazStatusSpecified; bool m_statusMoodSpecified; bool m_capabilitiesSpecified; bool m_dcOutsideSpecified; bool m_dcInsideSpecified; bool m_iconSpecified; }; #endif diff --git a/protocols/oscar/oscarcontact.cpp b/protocols/oscar/oscarcontact.cpp index 6094fdc89..1502b0a38 100644 --- a/protocols/oscar/oscarcontact.cpp +++ b/protocols/oscar/oscarcontact.cpp @@ -1,663 +1,663 @@ /* oscarcontact.cpp - Oscar Protocol Plugin Copyright (c) 2002 by Tom Linsky Kopete (c) 2002-2008 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #include "oscarcontact.h" #include #include #include #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include #include #include #include #include #include #include "kopeteaccount.h" #include "kopetechatsessionmanager.h" #include "kopetemetacontact.h" #include "kopetecontactlist.h" #include "kopetegroup.h" #include "kopeteuiglobal.h" #include #include "kopetetransfermanager.h" #include "kopeteavatarmanager.h" #include "oscaraccount.h" #include "client.h" #include "contactmanager.h" #include "oscarutils.h" #include "oscarprotocol.h" #include "oscarencodingselectiondialog.h" #include "oscarstatusmanager.h" #include "filetransferhandler.h" #include OscarContact::OscarContact( Kopete::Account* account, const QString& name, Kopete::MetaContact* parent, const QString& icon ) : Kopete::Contact( account, name, parent, icon ) { mAccount = static_cast(account); mName = name; mMsgManager = nullptr; m_buddyIconDirty = false; m_oesd = 0; setFileCapable( true ); QObject::connect( mAccount->engine(), SIGNAL(haveIconForContact(QString,QByteArray)), this, SLOT(haveIcon(QString,QByteArray)) ); QObject::connect( mAccount->engine(), SIGNAL(iconServerConnected()), this, SLOT(requestBuddyIcon()) ); QObject::connect( mAccount->engine(), SIGNAL(receivedAwayMessage(QString,QString)), this, SLOT(receivedStatusMessage(QString,QString)) ); QObject::connect( mAccount->engine(), SIGNAL(messageAck(QString,uint)), this, SLOT(messageAck(QString,uint)) ); QObject::connect( mAccount->engine(), SIGNAL(messageError(QString,uint)), this, SLOT(messageError(QString,uint)) ); } OscarContact::~OscarContact() { } void OscarContact::serialize(QMap &serializedData, QMap &/*addressBookData*/) { serializedData["ssi_name"] = m_ssiItem.name(); serializedData["ssi_type"] = QString::number( m_ssiItem.type() ); serializedData["ssi_gid"] = QString::number( m_ssiItem.gid() ); serializedData["ssi_bid"] = QString::number( m_ssiItem.bid() ); serializedData["ssi_alias"] = m_ssiItem.alias(); serializedData["ssi_waitingAuth"] = m_ssiItem.waitingAuth() ? QString::fromLatin1( "true" ) : QString::fromLatin1( "false" ); serializedData["ssi_metaInfoId"] = m_ssiItem.metaInfoId().toHex(); } bool OscarContact::isOnServer() const { ContactManager* serverList = mAccount->engine()->ssiManager(); OContact ssi = serverList->findContact( Oscar::normalize( contactId() ) ); return ( ssi && ssi.type() != 0xFFFF ); } void OscarContact::setSSIItem( const OContact& ssiItem ) { setCustomName( ssiItem.alias() ); m_ssiItem = ssiItem; } OContact OscarContact::ssiItem() const { return m_ssiItem; } Kopete::ChatSession* OscarContact::manager( CanCreateFlags canCreate ) { if ( !mMsgManager && canCreate ) { /*kDebug(14190) << "Creating new ChatSession for contact '" << displayName() << "'" << endl;*/ QList theContact; theContact.append(this); mMsgManager = Kopete::ChatSessionManager::self()->create(account()->myself(), theContact, protocol()); // This is for when the user types a message and presses send connect(mMsgManager, SIGNAL(messageSent(Kopete::Message&,Kopete::ChatSession*)), this, SLOT(slotSendMsg(Kopete::Message&,Kopete::ChatSession*)) ); // For when the message manager is destroyed connect(mMsgManager, SIGNAL(destroyed()), this, SLOT(chatSessionDestroyed()) ); connect(mMsgManager, SIGNAL(myselfTyping(bool)), this, SLOT(slotTyping(bool)) ); } return mMsgManager; } void OscarContact::deleteContact() { mAccount->engine()->removeContact( contactId() ); deleteLater(); } void OscarContact::chatSessionDestroyed() { mMsgManager = nullptr; } // Called when the metacontact owning this contact has changed groups void OscarContact::sync(unsigned int flags) { /* * If the contact has changed groups, then we update the server * adding the group if it doesn't exist, changing the ssi item * contained in the client and updating the contact's ssi item * Otherwise, we don't do much */ if( !metaContact() || metaContact()->isTemporary() ) return; if ( (flags & Kopete::Contact::MovedBetweenGroup) == Kopete::Contact::MovedBetweenGroup ) { kDebug(OSCAR_GEN_DEBUG) << "Moving a contact between groups"; ContactManager* ssiManager = mAccount->engine()->ssiManager(); OContact oldGroup = ssiManager->findGroup( m_ssiItem.gid() ); Kopete::Group* newGroup = metaContact()->groups().first(); QString newGroupName = newGroup->displayName(); if ( newGroup->type() == Kopete::Group::TopLevel ) newGroupName = "Buddies"; if ( newGroupName == oldGroup.name() ) return; //we didn't really move if ( m_ssiItem.isValid() ) mAccount->changeContactGroupInSSI( contactId(), newGroupName, true ); else mAccount->addContactToSSI( contactId(), newGroupName, true ); } if ( flags & Kopete::Contact::DisplayNameChanged && mAccount->engine() ) { kDebug(OSCAR_GEN_DEBUG) << "Changing contact alias"; mAccount->engine()->changeContactAlias( contactId(), metaContact()->displayName() ); } } void OscarContact::userInfoUpdated( const QString& contact, const UserDetails& details ) { Q_UNUSED( contact ); if ( details.buddyIconHash().size() > 0 && details.buddyIconHash() != m_details.buddyIconHash() ) { OscarProtocol *p = static_cast(protocol()); QString photoPath = property( Kopete::Global::Properties::self()->photo() ).value().toString(); if ( property( p->buddyIconHash ).value().toByteArray() != details.buddyIconHash() || QFileInfo(photoPath).size() == 0 ) { m_buddyIconDirty = true; if ( !mAccount->engine()->hasIconConnection() ) { mAccount->engine()->connectToIconServer(); } else { int time = ( KRandom::random() % 10 ) * 1000; kDebug(OSCAR_GEN_DEBUG) << "updating buddy icon in " << time/1000 << " seconds" << endl; QTimer::singleShot( time, this, SLOT(requestBuddyIcon()) ); } } } setProperty( Kopete::Global::Properties::self()->onlineSince(), details.onlineSinceTime() ); setIdleTime( details.idleTime() ); m_warningLevel = details.warningLevel(); m_details.merge( details ); setFileCapable( m_details.hasCap( CAP_SENDFILE ) ); QStringList capList; // Append client name and version in case we found one //if ( m_details.userClass() & 0x0080 /* WIRELESS */ ) // capList << i18n( "Mobile AIM Client" ); //else //{ // if ( !m_details.clientName().isEmpty() ) // { // capList << i18nc( "Translators: client name and version", // "%1", m_details.clientName() ); // } //} // and now for some general informative capabilities if ( m_details.hasCap( CAP_BUDDYICON ) ) capList << i18n( "Buddy icons" ); if ( m_details.hasCap( CAP_UTF8 ) ) capList << i18n( "UTF-8" ); if ( m_details.hasCap( CAP_RTFMSGS ) ) capList << i18n( "Rich text messages" ); if ( m_details.hasCap( CAP_CHAT ) ) capList << i18n( "Group chat" ); if ( m_details.hasCap( CAP_VOICE ) ) capList << i18n( "Voice chat" ); if ( m_details.hasCap( CAP_IMIMAGE ) ) capList << i18n( "DirectIM/IMImage" ); if ( m_details.hasCap( CAP_SENDBUDDYLIST ) ) capList << i18n( "Send buddy list" ); if ( m_details.hasCap( CAP_SENDFILE ) ) capList << i18n( "File transfers" ); if ( m_details.hasCap( CAP_GAMES ) || m_details.hasCap( CAP_GAMES2 ) ) capList << i18n( "Games" ); m_clientFeatures = capList.join( ", " ); setProperty( static_cast(protocol())->clientFeatures, m_clientFeatures ); setProperty( static_cast(protocol())->memberSince, details.memberSinceTime() ); setProperty( static_cast(protocol())->client, details.clientName() ); setProperty( static_cast(protocol())->protocolVersion, QString::number(details.dcProtoVersion()) ); } void OscarContact::startedTyping() { Kopete::ChatSession* cs = manager(); // We want the user to know if someone is typing a message // but there is no chat session for this contact cs->receivedTypingMsg( this, true ); } void OscarContact::stoppedTyping() { if ( mMsgManager ) mMsgManager->receivedTypingMsg( this, false ); } void OscarContact::slotTyping( bool typing ) { if ( this != account()->myself() ) account()->engine()->sendTyping( contactId(), typing ); } void OscarContact::messageAck( const QString& contact, uint messageId ) { if ( Oscar::normalize( contact ) != Oscar::normalize( contactId() ) ) return; Kopete::ChatSession* chatSession = manager(); if ( chatSession ) chatSession->receivedMessageState( messageId, Kopete::Message::StateSent ); } void OscarContact::messageError( const QString& contact, uint messageId ) { if ( Oscar::normalize( contact ) != Oscar::normalize( contactId() ) ) return; Kopete::ChatSession* chatSession = manager(); if ( chatSession ) chatSession->receivedMessageState( messageId, Kopete::Message::StateError ); } QTextCodec* OscarContact::contactCodec() const { if ( hasProperty( "contactEncoding" ) ) { QTextCodec* codec = QTextCodec::codecForMib( property( "contactEncoding" ).value().toInt() ); if ( codec ) return codec; else return QTextCodec::codecForMib( 4 ); } else return mAccount->defaultCodec(); } bool OscarContact::hasCap( int capNumber ) const { return m_details.hasCap( capNumber ); } void OscarContact::setPresenceTarget( const Oscar::Presence &presence ) { OscarProtocol* p = static_cast(protocol()); setOnlineStatus( p->statusManager()->onlineStatusOf( presence ) ); } void OscarContact::setEncoding( int mib ) { OscarProtocol* p = static_cast( protocol() ); if ( mib != 0 ) { kDebug(OSCAR_GEN_DEBUG) << "setting encoding mib to " << mib << endl; setProperty( p->contactEncoding, m_oesd->selectedEncoding() ); } else { kDebug(OSCAR_GEN_DEBUG) << "setting encoding to default" << endl; removeProperty( p->contactEncoding ); } } //here's where a filetransfer usually begins //could be called by a QAction or our dcop code or something void OscarContact::sendFile( const QUrl &sourceURL, const QString &altFileName, uint fileSize ) { kDebug(OSCAR_GEN_DEBUG) << "file: '" << sourceURL << "' '" << altFileName << "' size " << fileSize << endl; QStringList files; //If the file location is null, then get it from a file open dialog if( !sourceURL.isValid() ) { files = QFileDialog::getOpenFileNames( nullptr, i18n( "Kopete File Transfer" ), QString() , "*"); } else { //FIXME KF5 files << sourceURL.path(KUrl::RemoveTrailingSlash); } if( files.isEmpty() ) { kDebug(OSCAR_GEN_DEBUG) << "files empty, assuming cancel"; return; } kDebug(OSCAR_GEN_DEBUG) << "files: '" << files << "' "; FileTransferHandler *ftHandler = mAccount->engine()->createFileTransfer( mName, files ); Kopete::TransferManager *transferManager = Kopete::TransferManager::transferManager(); Kopete::Transfer *transfer = transferManager->addTransfer( this, files, ftHandler->totalSize(), mName, Kopete::FileTransferInfo::Outgoing); connect( transfer, SIGNAL(transferCanceled()), ftHandler, SLOT(cancel()) ); connect( ftHandler, SIGNAL(transferCancelled()), transfer, SLOT(slotCancelled()) ); connect( ftHandler, SIGNAL(transferError(int,QString)), transfer, SLOT(slotError(int,QString)) ); connect( ftHandler, SIGNAL(transferProcessed(uint)), transfer, SLOT(slotProcessed(uint)) ); connect( ftHandler, SIGNAL(transferFinished()), transfer, SLOT(slotComplete()) ); connect( ftHandler, SIGNAL(transferNextFile(QString,QString)), transfer, SLOT(slotNextFile(QString,QString)) ); ftHandler->send(); } void OscarContact::setAwayMessage( const QString &message ) { kDebug(OSCAR_AIM_DEBUG) << "Called for '" << contactId() << "', away msg='" << message << "'" << endl; if ( !message.isEmpty() ) setProperty( static_cast( protocol() )->statusMessage, filterAwayMessage( message ) ); else removeProperty( static_cast( protocol() )->statusMessage ); emit statusMessageChanged( this ); } void OscarContact::changeContactEncoding() { if ( m_oesd ) return; OscarProtocol* p = static_cast( protocol() ); m_oesd = new OscarEncodingSelectionDialog( Kopete::UI::Global::mainWidget(), property(p->contactEncoding).value().toInt() ); connect( m_oesd, SIGNAL(closing(int)), this, SLOT(changeEncodingDialogClosed(int)) ); m_oesd->show(); } void OscarContact::requestAuthorization() { QString info = i18n("The user %1 requires authorization before being added to a contact list. " "Do you want to send an authorization request?\n\nReason for requesting authorization:", displayName() ); QString reason = QInputDialog::getText( nullptr, i18n("Request Authorization"), info, QLineEdit::Normal, i18n("Please authorize me so I can add you to my contact list") ); if ( !reason.isNull() ) mAccount->engine()->requestAuth( contactId(), reason ); } void OscarContact::slotSendMsg(Kopete::Message& message, Kopete::ChatSession *) { if (message.plainBody().isEmpty()) // no text, do nothing return; //okay, now we need to change the message.escapedBody from real HTML to aimhtml. //looking right now for docs on that "format". //looks like everything except for alignment codes comes in the format of spans //font-style:italic -> //font-weight:600 -> (anything > 400 should be , 400 is not bold) //text-decoration:underline -> //font-family: -> //font-size:xxpt -> QTextDocument doc; doc.setHtml( message.escapedBody() ); QString rtfText = QString( "" ).arg( message.isRightToLeft() ? "rtl" : "ltr" ); bool hasFontTag = false; QTextCharFormat defaultCharFormat; for ( QTextBlock it = doc.begin(); it != doc.end(); it = it.next() ) { QTextBlockFormat blockFormat = it.blockFormat(); // Plain text message has p tags without margin attributes and Qt's topMargin() // returns default margins so we will end up with line break before text. if ( message.format() != Qt::PlainText || it.blockNumber() != 0 ) rtfText += brMargin( blockFormat.topMargin(), defaultCharFormat.fontPointSize() ); bool lastFragmentHasLineSeparator = false; for ( QTextBlock::iterator it2 = it.begin(); !(it2.atEnd()); ++it2 ) { QTextFragment currentFragment = it2.fragment(); if ( currentFragment.isValid() ) { QTextCharFormat format = currentFragment.charFormat(); if ( format.fontFamily() != defaultCharFormat.fontFamily() || format.foreground() != defaultCharFormat.foreground() || oscarFontSize(format.fontPointSize()) != oscarFontSize(defaultCharFormat.fontPointSize()) ) { if ( hasFontTag ) { rtfText += ""; hasFontTag = false; } QString fontTag; if ( !format.fontFamily().isEmpty() ) fontTag += QString( " FACE=\"%1\"" ).arg( format.fontFamily() ); if ( format.fontPointSize() > 0 ) fontTag += QString( " SIZE=%1" ).arg( oscarFontSize( format.fontPointSize() ) ); if ( format.foreground().style() != Qt::NoBrush ) fontTag += QString( " COLOR=%1" ).arg( format.foreground().color().name() ); if ( format.background().style() != Qt::NoBrush ) fontTag += QString( " BACK=%1" ).arg( format.background().color().name() ); if ( !fontTag.isEmpty() ) { rtfText += QString("").arg( fontTag ); hasFontTag = true; } } if ( format.font().bold() != defaultCharFormat.font().bold() ) rtfText += ( format.font().bold() ) ? "" : ""; if ( format.fontItalic() != defaultCharFormat.fontItalic() ) rtfText += ( format.hasProperty(QTextFormat::FontItalic) ) ? "" : ""; if ( format.fontUnderline() != defaultCharFormat.fontUnderline() ) rtfText += ( format.hasProperty(QTextFormat::FontUnderline) ) ? "" : ""; QString text = currentFragment.text(); lastFragmentHasLineSeparator = text.endsWith( QChar::LineSeparator ); rtfText += text.toHtmlEscaped(); defaultCharFormat = format; } } rtfText += brMargin( blockFormat.bottomMargin(), defaultCharFormat.fontPointSize(), !lastFragmentHasLineSeparator ); } rtfText.replace( QChar::LineSeparator, "
" ); if ( rtfText.endsWith( "
" ) ) rtfText.chop(4); if ( hasFontTag ) rtfText += "
"; if ( defaultCharFormat.font().bold() ) rtfText += "
"; if ( defaultCharFormat.hasProperty( QTextFormat::FontItalic ) ) rtfText += "
"; if ( defaultCharFormat.hasProperty( QTextFormat::FontUnderline ) ) rtfText += ""; rtfText += ""; kDebug(OSCAR_GEN_DEBUG) << "sending: " << rtfText; // TODO: Need to check for message size? Oscar::Message msg; // Allow UCS2 because official AIM client doesn't sets the CAP_UTF8 anymore! bool allowUCS2 = !isOnline() || !(m_details.userClass() & Oscar::CLASS_ICQ) || m_details.hasCap( CAP_UTF8 ); msg.setText( Oscar::Message::encodingForText( rtfText, allowUCS2 ), rtfText, contactCodec() ); msg.setId( message.id() ); msg.setReceiver(mName); msg.setSender( mAccount->accountId() ); msg.setTimestamp(message.timestamp()); msg.setChannel(0x01); mAccount->engine()->sendMessage(msg); message.setState( Kopete::Message::StateSending ); // Show the message we just sent in the chat window manager(Kopete::Contact::CanCreate)->appendMessage(message); manager(Kopete::Contact::CanCreate)->messageSucceeded(); } void OscarContact::changeEncodingDialogClosed( int result ) { if ( result == QDialog::Accepted ) setEncoding( m_oesd->selectedEncoding() ); if ( m_oesd ) { m_oesd->deleteLater(); m_oesd = nullptr; } } void OscarContact::requestBuddyIcon() { if ( m_buddyIconDirty && m_details.buddyIconHash().size() > 0 ) { account()->engine()->requestBuddyIcon( contactId(), m_details.buddyIconHash(), m_details.iconType(), m_details.iconCheckSumType() ); } } void OscarContact::haveIcon( const QString& user, QByteArray icon ) { if ( Oscar::normalize( user ) != Oscar::normalize( contactId() ) ) return; kDebug(OSCAR_GEN_DEBUG) << "Updating icon for " << contactId(); QByteArray buddyIconHash = QCryptographicHash::hash( icon, QCryptographicHash::Md5 ); if ( memcmp( buddyIconHash, m_details.buddyIconHash().data(), 16 ) == 0 ) { QImage img; img.loadFromData(icon); Kopete::AvatarManager::AvatarEntry entry; entry.name = contactId(); entry.category = Kopete::AvatarManager::Contact; entry.contact = this; entry.image = img; entry = Kopete::AvatarManager::self()->add(entry); if (!entry.dataPath.isNull()) { removeProperty( Kopete::Global::Properties::self()->photo() ); setProperty( Kopete::Global::Properties::self()->photo(), entry.dataPath ); setProperty( static_cast(protocol())->buddyIconHash, m_details.buddyIconHash() ); } m_buddyIconDirty = false; } else { kDebug(14153) << "Buddy icon hash does not match!"; removeProperty( static_cast(protocol())->buddyIconHash ); removeProperty( Kopete::Global::Properties::self()->photo() ); } } void OscarContact::receivedStatusMessage( const QString& contact, const QString& message ) { if ( Oscar::normalize( contact ) != Oscar::normalize( contactId() ) ) return; setAwayMessage( message ); } QString OscarContact::filterAwayMessage( const QString &message ) const { QString filteredMessage = message; filteredMessage.replace( QRegExp(QString::fromLatin1("<[hH][tT][mM][lL].*>(.*)")), QString::fromLatin1("\\1")); filteredMessage.replace( QRegExp(QString::fromLatin1("<[bB][oO][dD][yY].*>(.*)")), QString::fromLatin1("\\1") ); QRegExp fontRemover( QString::fromLatin1("<[fF][oO][nN][tT].*>(.*)") ); fontRemover.setMinimal(true); while ( filteredMessage.indexOf( fontRemover ) != -1 ) filteredMessage.replace( fontRemover, QString::fromLatin1("\\1") ); return filteredMessage; } int OscarContact::oscarFontSize( int size ) const { if ( size <= 0 ) return 0; else if ( 1 <= size && size <= 9 ) return 1; else if ( 10 <= size && size <= 11 ) return 2; else if ( 12 <= size && size <= 13 ) return 3; else if ( 14 <= size && size <= 16 ) return 4; else if ( 17 <= size && size <= 22 ) return 5; else if ( 23 <= size && size <= 29 ) return 6; else return 7; } QString OscarContact::brMargin( int margin, int fontPointSize, bool forceBr ) const { int brHeight = ( fontPointSize == 0 ) ? 12 : fontPointSize; int brCount = margin / brHeight; if ( brCount <= 0 ) return ( forceBr ) ? "
" : ""; QString s; while ( brCount-- > 0 ) s += "
"; return s; } diff --git a/protocols/oscar/oscarprivacyengine.h b/protocols/oscar/oscarprivacyengine.h index 2dc71e8d6..2ec2299cf 100644 --- a/protocols/oscar/oscarprivacyengine.h +++ b/protocols/oscar/oscarprivacyengine.h @@ -1,80 +1,80 @@ /* oscarprivacyengine.h - Oscar Privacy Engine Copyright (c) 2005-2006 by Roman Jarosz Kopete (c) 2005-2006 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef OSCARPRIVACYENGINE_H #define OSCARPRIVACYENGINE_H -#include +#include -#include -#include -#include +#include +#include +#include #include "oscar_export.h" /** @author Roman Jarosz */ class QComboBox; class QAbstractItemView; class OscarAccount; namespace Oscar { class Client; } class OSCAR_EXPORT OscarPrivacyEngine : public QObject { Q_OBJECT public: enum Type { Visible, Invisible, Ignore }; OscarPrivacyEngine( OscarAccount* account, Type type ); ~OscarPrivacyEngine(); void setContactsView( QAbstractItemView* view ); void setAllContactsView( QComboBox* combo ); public Q_SLOTS: void slotAdd(); void slotRemove(); void storeChanges(); private: typedef QMap ContactMap; void addContacts( const ContactMap& contacts, const QSet& idSet ); void addAllContacts( const ContactMap& contacts ); enum Action{ Remove = 0, Add }; typedef QMap ChangeMap; //map with changes that should be send to server ChangeMap m_changesMap; QSet m_idSet; QStandardItemModel m_contactsModel; QStandardItemModel m_allContactsModel; Oscar::Client* m_client; Type m_type; QComboBox* m_comboBox; QAbstractItemView* m_listView; }; #endif diff --git a/protocols/oscar/oscarversionupdater.cpp b/protocols/oscar/oscarversionupdater.cpp index a32bd1d38..799577997 100644 --- a/protocols/oscar/oscarversionupdater.cpp +++ b/protocols/oscar/oscarversionupdater.cpp @@ -1,295 +1,295 @@ /* oscarversionupdater.cpp - Version Updater Copyright (c) 2006 by Roman Jarosz Kopete (c) 2006 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #include "oscarversionupdater.h" -#include -#include +#include +#include #include #include #include #include QMutex updateMutex; OscarVersionUpdater *OscarVersionUpdater::versionUpdaterStatic = nullptr; OscarVersionUpdater::OscarVersionUpdater() : mStamp( 1 ), mUpdating( false ) { initICQVersionInfo(); initAIMVersionInfo(); } OscarVersionUpdater::~OscarVersionUpdater() { } OscarVersionUpdater *OscarVersionUpdater::self() { if ( !versionUpdaterStatic ) versionUpdaterStatic = new OscarVersionUpdater(); return versionUpdaterStatic; } bool OscarVersionUpdater::update( unsigned int stamp ) { kDebug(OSCAR_GEN_DEBUG) ; bool doUpdate = false; bool isUpdating = false; updateMutex.lock(); if ( !mUpdating && stamp == mStamp ) { doUpdate = true; mUpdating = true; } isUpdating = mUpdating; updateMutex.unlock(); if ( doUpdate ) { mVersionData.resize( 0 ); KConfigGroup config( KSharedConfig::openConfig(), "Oscar" ); QString url = config.readEntry( "NewVersionURL", "http://kopete.kde.org/oscarversions.xml" ); mTransferJob = KIO::get ( url ); kDebug(OSCAR_GEN_DEBUG) << "Download version info from server."; connect ( mTransferJob, SIGNAL (result(KJob*)), this, SLOT (slotTransferResult(KJob*)) ); connect ( mTransferJob, SIGNAL (data(KIO::Job*,QByteArray)), this, SLOT (slotTransferData(KIO::Job*,QByteArray)) ); } return isUpdating; } unsigned int OscarVersionUpdater::stamp() const { return mStamp; } void OscarVersionUpdater::initICQVersionInfo() { kDebug(OSCAR_RAW_DEBUG) ; KConfigGroup config( KSharedConfig::openConfig(), "ICQVersion" ); mICQVersion.clientString = config.readEntry( "ClientString", "ICQ Client" ); mICQVersion.clientId = config.readEntry( "ClientId", "0x010A" ).toUShort( 0, 0 ); mICQVersion.major = config.readEntry( "Major", "0x0006" ).toUShort( 0, 0 ); mICQVersion.minor = config.readEntry( "Minor", "0x0005" ).toUShort( 0, 0 ); mICQVersion.point = config.readEntry( "Point", "0x0000" ).toUShort( 0, 0 ); mICQVersion.build = config.readEntry( "Build", "0x0412" ).toUShort( 0, 0 ); mICQVersion.other = config.readEntry( "Other", "0x00000000" ).toUInt( 0, 0 ); mICQVersion.country = config.readEntry( "Country", "us" ); mICQVersion.lang = config.readEntry( "Lang", "en" ); } void OscarVersionUpdater::initAIMVersionInfo() { kDebug(OSCAR_RAW_DEBUG) ; KConfigGroup config( KSharedConfig::openConfig(), "AIMVersion" ); mAIMVersion.clientString = config.readEntry( "ClientString", "AOL Instant Messenger (SM), version 5.1.3036/WIN32" ); mAIMVersion.clientId = config.readEntry( "ClientId", "0x0109" ).toUShort( 0, 0 ); mAIMVersion.major = config.readEntry( "Major", "0x0005" ).toUShort( 0, 0 ); mAIMVersion.minor = config.readEntry( "Minor", "0x0001" ).toUShort( 0, 0 ); mAIMVersion.point = config.readEntry( "Point", "0x0000" ).toUShort( 0, 0 ); mAIMVersion.build = config.readEntry( "Build", "0x0bdc" ).toUShort( 0, 0 ); mAIMVersion.other = config.readEntry( "Other", "0x000000d2" ).toUInt( 0, 0 ); mAIMVersion.country = config.readEntry( "Country", "us" ); mAIMVersion.lang = config.readEntry( "Lang", "en" ); } void OscarVersionUpdater::printDebug() { kDebug(OSCAR_RAW_DEBUG) << "*************** AIM VERSION INFO ***************"; kDebug(OSCAR_RAW_DEBUG) << "client string: " << mAIMVersion.clientString; kDebug(OSCAR_RAW_DEBUG) << "client id: " << QString::number( mAIMVersion.clientId, 16 ); kDebug(OSCAR_RAW_DEBUG) << "major: " << QString::number( mAIMVersion.major, 16 ); kDebug(OSCAR_RAW_DEBUG) << "minor: " << QString::number( mAIMVersion.minor, 16 ); kDebug(OSCAR_RAW_DEBUG) << "point: " << QString::number( mAIMVersion.point, 16 ); kDebug(OSCAR_RAW_DEBUG) << "build: " << QString::number( mAIMVersion.build, 16 ); kDebug(OSCAR_RAW_DEBUG) << "other: " << QString::number( mAIMVersion.other, 16 ); kDebug(OSCAR_RAW_DEBUG) << "country: " << mAIMVersion.country; kDebug(OSCAR_RAW_DEBUG) << "lang: " << mAIMVersion.lang; kDebug(OSCAR_RAW_DEBUG) << "************************************************"; kDebug(OSCAR_RAW_DEBUG) << "*************** ICQ VERSION INFO ***************"; kDebug(OSCAR_RAW_DEBUG) << "client string: " << mICQVersion.clientString; kDebug(OSCAR_RAW_DEBUG) << "client id: " << QString::number( mICQVersion.clientId, 16 ); kDebug(OSCAR_RAW_DEBUG) << "major: " << QString::number( mICQVersion.major, 16 ); kDebug(OSCAR_RAW_DEBUG) << "minor: " << QString::number( mICQVersion.minor, 16 ); kDebug(OSCAR_RAW_DEBUG) << "point: " << QString::number( mICQVersion.point, 16 ); kDebug(OSCAR_RAW_DEBUG) << "build: " << QString::number( mICQVersion.build, 16 ); kDebug(OSCAR_RAW_DEBUG) << "other: " << QString::number( mICQVersion.other, 16 ); kDebug(OSCAR_RAW_DEBUG) << "country: " << mICQVersion.country; kDebug(OSCAR_RAW_DEBUG) << "lang: " << mICQVersion.lang; kDebug(OSCAR_RAW_DEBUG) << "************************************************"; } void OscarVersionUpdater::slotTransferData ( KIO::Job *job, const QByteArray &data ) { Q_UNUSED( job ) unsigned oldSize = mVersionData.size(); mVersionData.resize ( oldSize + data.size() ); memcpy ( &mVersionData.data()[oldSize], data.data(), data.size() ); kDebug(OSCAR_RAW_DEBUG) << "Data size " << mVersionData.size(); } void OscarVersionUpdater::slotTransferResult ( KJob *job ) { bool bUpdate = false; if ( job->error() || mTransferJob->isErrorPage() ) { //TODO show error kDebug(OSCAR_GEN_DEBUG) << "Download of version info has faild!"; } else { kDebug(OSCAR_GEN_DEBUG) << "Updating version info"; QDomDocument doc; if ( doc.setContent ( mVersionData ) ) { Oscar::ClientVersion tmpICQ = mICQVersion; Oscar::ClientVersion tmpAIM = mAIMVersion; parseDocument( doc ); if ( !equal( tmpICQ, mICQVersion ) ) { storeVersionInfo( QStringLiteral("ICQVersion"), mICQVersion ); bUpdate = true; } if ( !equal( tmpAIM, mAIMVersion ) ) { storeVersionInfo( QStringLiteral("AIMVersion"), mAIMVersion ); bUpdate = true; } } } // clear mVersionData.resize( 0 ); mTransferJob = 0; updateMutex.lock(); if ( bUpdate ) mStamp++; mUpdating = false; updateMutex.unlock(); } void OscarVersionUpdater::parseDocument( QDomDocument& doc ) { kDebug(OSCAR_RAW_DEBUG) ; QDomElement root = doc.documentElement(); if ( root.tagName() != QLatin1String("oscar") ) return; QDomElement versionElement = root.firstChild().toElement(); while( !versionElement.isNull() ) { if ( versionElement.tagName() == QLatin1String("icq") ) parseVersion( mICQVersion, versionElement ); else if ( versionElement.tagName() == QLatin1String("aim") ) parseVersion( mAIMVersion, versionElement ); versionElement = versionElement.nextSibling().toElement(); } } bool OscarVersionUpdater::parseVersion( Oscar::ClientVersion& version, QDomElement& element ) { kDebug(OSCAR_RAW_DEBUG) ; // clear structure version.clientString.clear(); version.clientId = 0x0000; version.major = 0x0000; version.minor = 0x0000; version.point = 0x0000; version.build = 0x0000; version.other = 0x00000000; version.country.clear(); version.lang.clear(); QDomElement versionChild = element.firstChild().toElement(); while ( !versionChild.isNull() ) { if ( versionChild.tagName() == QLatin1String("client") ) version.clientString = versionChild.text(); else if ( versionChild.tagName() == QLatin1String("clientId") ) version.clientId = versionChild.text().toUShort( 0, 0); else if ( versionChild.tagName() == QLatin1String("major") ) version.major = versionChild.text().toUShort( 0, 0 ); else if ( versionChild.tagName() == QLatin1String("minor") ) version.minor = versionChild.text().toUShort( 0, 0 ); else if ( versionChild.tagName() == QLatin1String("point") ) version.point = versionChild.text().toUShort( 0, 0 ); else if ( versionChild.tagName() == QLatin1String("build") ) version.build = versionChild.text().toUShort( 0, 0 ); else if ( versionChild.tagName() == QLatin1String("other") ) version.other = versionChild.text().toUInt( 0, 0 ); else if ( versionChild.tagName() == QLatin1String("country") ) version.country = versionChild.text(); else if ( versionChild.tagName() == QLatin1String("lang") ) version.lang = versionChild.text(); versionChild = versionChild.nextSibling().toElement(); } return true; } void OscarVersionUpdater::storeVersionInfo( const QString& group, const Oscar::ClientVersion& version ) const { kDebug(OSCAR_GEN_DEBUG) << "Storing version info to group: " << group; KConfigGroup config( KSharedConfig::openConfig(), group ); config.writeEntry( "ClientString", version.clientString ); config.writeEntry( "ClientId", uint(version.clientId) ); config.writeEntry( "Major", uint(version.major) ); config.writeEntry( "Minor", uint(version.minor) ); config.writeEntry( "Point", uint(version.point) ); config.writeEntry( "Build", uint(version.build) ); config.writeEntry( "Other", uint(version.other) ); config.writeEntry( "Country", version.country ); config.writeEntry( "Lang", version.lang ); config.sync(); } bool OscarVersionUpdater::equal( const Oscar::ClientVersion& a, const Oscar::ClientVersion& b ) const { if ( a.clientString != b.clientString || a.clientId != b.clientId || a.major != b.major|| a.minor != b.minor || a.point != b.point || a.build != b.build || a.other != b.other || a.country != b.country || a.lang != b.lang ) { return false; } return true; } diff --git a/protocols/oscar/oscarversionupdater.h b/protocols/oscar/oscarversionupdater.h index 10e98fb44..14c2ce0a8 100644 --- a/protocols/oscar/oscarversionupdater.h +++ b/protocols/oscar/oscarversionupdater.h @@ -1,123 +1,123 @@ /* oscarversionupdater.h - Version Updater Copyright (c) 2006 by Roman Jarosz Kopete (c) 2006 by the Kopete developers ************************************************************************* * * * This program 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. * * * ************************************************************************* */ #ifndef OSCARVERSIONUPDATER_H #define OSCARVERSIONUPDATER_H -#include +#include #include #include class KJob; namespace KIO { class Job; class TransferJob; } class QDomElement; class QDomDocument; /** @author Roman Jarosz */ class OscarVersionUpdater : public QObject { Q_OBJECT public: OscarVersionUpdater(); ~OscarVersionUpdater(); static OscarVersionUpdater* self(); /** * Update version info from server. * @param stamp is update number. */ bool update( unsigned int stamp ); /** * Update version info from server. * @return true if update is in progress or starts. */ unsigned int stamp() const; /** * Return structure with version info for ICQ. * @return Oscar::ClientVersion. */ const Oscar::ClientVersion* getICQVersion() const { return &mICQVersion; } /** * Return structure with version info for AIM. * @return Oscar::ClientVersion. */ const Oscar::ClientVersion* getAIMVersion() const { return &mAIMVersion; } /** * Set structure with ICQ version info to default. */ void initICQVersionInfo(); /** * Set structure with AIM version info to default. */ void initAIMVersionInfo(); /** * Print debug info. */ void printDebug(); private Q_SLOTS: void slotTransferData( KIO::Job *job, const QByteArray &data ); void slotTransferResult( KJob *job ); private: void parseDocument( QDomDocument& doc ); bool parseVersion( Oscar::ClientVersion& version, QDomElement& element ); /** * Store version info structure to KConfigGroup * @param group is the group name. * @param version is version info structure. */ void storeVersionInfo( const QString& group, const Oscar::ClientVersion& version ) const; /** * Compare two versions. * @return true if a and b is equal. */ bool equal( const Oscar::ClientVersion& a, const Oscar::ClientVersion& b ) const; private: static OscarVersionUpdater *versionUpdaterStatic; Oscar::ClientVersion mICQVersion; Oscar::ClientVersion mAIMVersion; KIO::TransferJob *mTransferJob; QByteArray mVersionData; unsigned int mStamp; bool mUpdating; }; #endif diff --git a/protocols/skype/skypebuttons/qtbrowserplugin/qtbrowserplugin.h b/protocols/skype/skypebuttons/qtbrowserplugin/qtbrowserplugin.h index ea4415b62..0e6d58802 100644 --- a/protocols/skype/skypebuttons/qtbrowserplugin/qtbrowserplugin.h +++ b/protocols/skype/skypebuttons/qtbrowserplugin/qtbrowserplugin.h @@ -1,160 +1,160 @@ /**************************************************************************** ** ** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved. ** ** This file is part of a Qt Solutions component. ** ** This file may be used under the terms of the GNU General Public ** License version 2.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of ** this file. Please review the following information to ensure GNU ** General Public Licensing requirements will be met: ** http://www.trolltech.com/products/qt/opensource.html ** ** If you are unsure which license is appropriate for your use, please ** review the following information: ** http://www.trolltech.com/products/qt/licensing.html or contact the ** Trolltech sales department at sales@trolltech.com. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ****************************************************************************/ #ifndef QTBROWSERPLUGIN_H #define QTBROWSERPLUGIN_H -#include -#include -#include -#include +#include +#include +#include +#include #include struct QtNPInstance; class QtNPBindable; class QtNPStreamPrivate; struct NPP_t; typedef NPP_t* NPP; class QtNPBindable { friend class QtNPStream; public: enum Reason { ReasonDone = 0, ReasonBreak = 1, ReasonError = 2, ReasonUnknown = -1 }; enum DisplayMode { Embedded = 1, Fullpage = 2 }; QMap parameters() const; DisplayMode displayMode() const; QString mimeType() const; QString userAgent() const; void getNppVersion(int *major, int *minor) const; void getBrowserVersion(int *major, int *minor) const; // incoming streams (SRC=... tag) virtual bool readData(QIODevice *source, const QString &format); // URL stuff int openUrl(const QString &url, const QString &window = QString()); int uploadData(const QString &url, const QString &window, const QByteArray &data); int uploadFile(const QString &url, const QString &window, const QString &filename); virtual void transferComplete(const QString &url, int id, Reason r); NPP instance() const; protected: QtNPBindable(); virtual ~QtNPBindable(); private: QtNPInstance* pi; }; class QtNPFactory { public: QtNPFactory(); virtual ~QtNPFactory(); virtual QStringList mimeTypes() const = 0; virtual QObject* createObject(const QString &type) = 0; virtual QString pluginName() const = 0; virtual QString pluginDescription() const = 0; }; extern QtNPFactory *qtNPFactory(); template class QtNPClass : public QtNPFactory { public: QtNPClass() {} QObject *createObject(const QString &key) { foreach (QString mime, mimeTypes()) { if (mime.left(mime.indexOf(':')) == key) return new T; } return 0; } QStringList mimeTypes() const { const QMetaObject &mo = T::staticMetaObject; return QString::fromLatin1(mo.classInfo(mo.indexOfClassInfo("MIME")).value()).split(';'); } QString pluginName() const { return QString(); } QString pluginDescription() const { return QString(); } }; #define QTNPFACTORY_BEGIN(Name, Description) \ class QtNPClassList : public QtNPFactory \ { \ QHash factories; \ QStringList mimeStrings; \ QString m_name, m_description; \ public: \ QtNPClassList() \ : m_name(Name), m_description(Description) \ { \ QtNPFactory *factory = 0; \ QStringList keys; \ #define QTNPCLASS(Class) \ { \ factory = new QtNPClass; \ keys = factory->mimeTypes(); \ foreach (QString key, keys) { \ mimeStrings.append(key); \ factories.insert(key.left(key.indexOf(':')), factory); \ } \ } \ #define QTNPFACTORY_END() \ } \ ~QtNPClassList() { /*crashes? qDeleteAll(factories);*/ } \ QObject *createObject(const QString &mime) { \ QtNPFactory *factory = factories.value(mime); \ return factory ? factory->createObject(mime) : 0; \ } \ QStringList mimeTypes() const { return mimeStrings; } \ QString pluginName() const { return m_name; } \ QString pluginDescription() const { return m_description; } \ }; \ QtNPFactory *qtns_instantiate() { return new QtNPClassList; } \ #define QTNPFACTORY_EXPORT(Class) \ QtNPFactory *qtns_instantiate() { return new Class; } #endif // QTBROWSERPLUGIN_H diff --git a/protocols/skype/skypebuttons/qtbrowserplugin/qtbrowserplugin_p.h b/protocols/skype/skypebuttons/qtbrowserplugin/qtbrowserplugin_p.h index 4ac0c0d94..71703c093 100644 --- a/protocols/skype/skypebuttons/qtbrowserplugin/qtbrowserplugin_p.h +++ b/protocols/skype/skypebuttons/qtbrowserplugin/qtbrowserplugin_p.h @@ -1,83 +1,83 @@ /**************************************************************************** ** ** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved. ** ** This file is part of a Qt Solutions component. ** ** This file may be used under the terms of the GNU General Public ** License version 2.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of ** this file. Please review the following information to ensure GNU ** General Public Licensing requirements will be met: ** http://www.trolltech.com/products/qt/opensource.html ** ** If you are unsure which license is appropriate for your use, please ** review the following information: ** http://www.trolltech.com/products/qt/licensing.html or contact the ** Trolltech sales department at sales@trolltech.com. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ****************************************************************************/ #ifndef QTBROWSERPLUGIN_P_H #define QTBROWSERPLUGIN_P_H -#include -#include -#include +#include +#include +#include #ifdef Q_WS_X11 # include class QtNPStream; class QtNPBindable; #endif struct QtNPInstance { NPP npp; short fMode; #ifdef Q_OS_WIN typedef HWND Widget; #endif #ifdef Q_WS_X11 typedef Window Widget; Display *display; #endif #ifdef Q_OS_MAC typedef NPPort* Widget; QWidget *rootWidget; #endif Widget window; QRect geometry; QString mimetype; QByteArray htmlID; union { QObject* object; QWidget* widget; } qt; QtNPStream *pendingStream; QtNPBindable* bindable; QObject *filter; QMap parameters; qint32 notificationSeqNum; QMutex seqNumMutex; qint32 getNotificationSeqNum() { QMutexLocker locker(&seqNumMutex); if (++notificationSeqNum < 0) notificationSeqNum = 1; return notificationSeqNum; } }; #endif // QTBROWSERPLUGIN_P_H diff --git a/protocols/yahoo/libkyahoo/listtask.cpp b/protocols/yahoo/libkyahoo/listtask.cpp index 7c1e63c46..8bb695292 100644 --- a/protocols/yahoo/libkyahoo/listtask.cpp +++ b/protocols/yahoo/libkyahoo/listtask.cpp @@ -1,108 +1,108 @@ /* Kopete Yahoo Protocol Handles several lists such as buddylist, ignorelist and so on Copyright (c) 2005 André Duffeck ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "listtask.h" -#include -#include +#include +#include #include "transfer.h" #include "ymsgtransfer.h" #include "client.h" #include "yahoo_protocol_debug.h" ListTask::ListTask(Task *parent) : Task(parent) { qCDebug(YAHOO_PROTOCOL_LOG); } ListTask::~ListTask() { } bool ListTask::take(Transfer *transfer) { if (!forMe(transfer)) { return false; } YMSGTransfer *t = static_cast(transfer); parseBuddyList(t); return true; } bool ListTask::forMe(const Transfer *transfer) const { const YMSGTransfer *t = nullptr; t = dynamic_cast(transfer); if (!t) { return false; } if (t->service() == Yahoo::ServiceBuddyList) { return true; } else { return false; } } void ListTask::parseBuddyList(YMSGTransfer *t) { qCDebug(YAHOO_PROTOCOL_LOG); QString group; QString buddy; // We need some low-level parsing here foreach (const Param &p, t->paramList()) { qCDebug(YAHOO_PROTOCOL_LOG) << "1:" << p.first; qCDebug(YAHOO_PROTOCOL_LOG) << "2:" << p.second; switch (p.first) { case 65: group = p.second; break; case 7: buddy = p.second; break; case 301: if (p.second == "319") { emit gotBuddy(buddy, QString(), group); } break; case 317: if (p.second == "2") { qCDebug(YAHOO_PROTOCOL_LOG) << "Stealthed setting on" << buddy; emit stealthStatusChanged(buddy, Yahoo::StealthActive); } break; /** * Note: michaelacole * Other buddy codes are here for add to list and blacklist * I will need to capute more codes for addition here. * Blacklist is done on the server at Yahoo whereas * Kopete has its own plugin for blacklisting. */ } } /** * Note: michaelacole * Since you can log in from other places and remove or add Perm Offline status * We have to reset both conditions at login * Yahoo sends this data at this time, * so better to compile list of both now then notify kopete client. */ } diff --git a/tests/protocols/oscar/buffertest.cpp b/tests/protocols/oscar/buffertest.cpp index 9a58b3da5..1f2e436ce 100755 --- a/tests/protocols/oscar/buffertest.cpp +++ b/tests/protocols/oscar/buffertest.cpp @@ -1,113 +1,113 @@ /* Buffer Test Kopete (c) 2002-2006 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ -#include +#include #include "buffer.h" class BufferTest : public QObject { Q_OBJECT private slots: void testAddByte(); void testAddWord(); void testAddDWord(); void testGetTLV(); void testBytesAvailable(); void testLength(); void testGuid(); }; void BufferTest::testAddByte() { Buffer b; b.addByte(0x00); QVERIFY(b.length() == 1); QVERIFY(b.getByte() == 0x00); } void BufferTest::testAddWord() { Buffer b; b.addWord(0x0101); QVERIFY(b.length() == 2); QVERIFY(b.getWord() == 0x0101); } void BufferTest::testAddDWord() { Buffer b; b.addDWord(0x01010101); QVERIFY(b.length() == 4); QVERIFY(b.getDWord() == 0x01010101); } void BufferTest::testGetTLV() { char raw[] = { 0x00, 0x00, 0x00, 0x01 }; Buffer b; b.addDWord(0x00030004); b.addDWord(0x00000001); TLV t = b.getTLV(); QVERIFY( t.type == 0x0003 ); QVERIFY( t.length == 0x0004 ); QVERIFY( t.data == QByteArray::fromRawData( raw, 4 ) ); } void BufferTest::testBytesAvailable() { Buffer b; QVERIFY(b.length() == 0); QVERIFY(b.bytesAvailable() == 0); b.addByte(0x01); b.addWord(0x0203); b.addDWord(0x04050607); QVERIFY(b.bytesAvailable() == 7); b.skipBytes(7); QVERIFY(b.bytesAvailable() == 0); } void BufferTest::testLength() { Buffer b; QVERIFY(b.length() == 0); b.addByte(0x01); b.addWord(0x0203); b.addDWord(0x04050607); b.addWord(0x0809); QVERIFY(b.length() == 9); b.getWord(); QVERIFY(b.length() == 9); } void BufferTest::testGuid() { Buffer b; Guid g( QByteArray( "asdfghjkqwertyui" ) ); b.addGuid( g ); QVERIFY( b.bytesAvailable() == 16 ); Guid h = b.getGuid(); QVERIFY( b.bytesAvailable() == 0 ); QCOMPARE( g, h ); } QTEST_MAIN(BufferTest) #include "buffertest.moc" diff --git a/tests/protocols/oscar/guidtest.cpp b/tests/protocols/oscar/guidtest.cpp index 01e5402af..3537e829e 100755 --- a/tests/protocols/oscar/guidtest.cpp +++ b/tests/protocols/oscar/guidtest.cpp @@ -1,62 +1,62 @@ #include "guidtest.h" -#include +#include #include "oscarguid.h" QTEST_MAIN( GuidTest ) void GuidTest::testConstructors() { QByteArray id = "0123456789abcdef"; Oscar::Guid g(id); QVERIFY( g.isValid() ); QCOMPARE( g.data(), id ); Oscar::Guid h( QLatin1String( "0a-1b-2c" ) ); QVERIFY( ! h.isValid() ); Oscar::Guid i( QLatin1String( "30313233--3435-3637-3839-616263646566" ) ); QVERIFY( i.isValid() ); QCOMPARE( i.data(), id ); Oscar::Guid j( QByteArray::fromRawData( "Kopete ICQ \0\xc\0\0", 16 ) ); QVERIFY( j.isValid() ); } void GuidTest::testSetData() { QByteArray id = "0123456789abcdef"; QVERIFY( id.length() == 16 ); Oscar::Guid g; QVERIFY( ! g.isValid() ); g.setData(id); QVERIFY( g.isValid() ); QCOMPARE( g.data(), id ); } void GuidTest::testIsVaild() { Oscar::Guid g; QVERIFY( ! g.isValid() ); g.setData( QByteArray( "" ) ); QVERIFY( ! g.isValid() ); g.setData( QByteArray( "asdfghjkqwertyu" ) ); QVERIFY( ! g.isValid() ); g.setData( QByteArray( "asdfghjkqwertyui" ) ); QVERIFY( g.isValid() ); g.setData( QByteArray( "asdfghjkqwertyuio" ) ); QVERIFY( ! g.isValid() ); } void GuidTest::testCompare() { Oscar::Guid g( QByteArray( "asdfghjkqwertyui" ) ); Oscar::Guid h( g ); Oscar::Guid i( QByteArray( "asdfghjkqwertyui" ) ); Oscar::Guid j( QByteArray( "qwertyuiasdfghjk" ) ); QCOMPARE( g, h ); QCOMPARE( g, i ); QCOMPARE( h, i ); QVERIFY( !( j == g ) ); //there is no != } diff --git a/tests/protocols/oscar/oscartestbase.h b/tests/protocols/oscar/oscartestbase.h index bbc574a06..058993bb1 100755 --- a/tests/protocols/oscar/oscartestbase.h +++ b/tests/protocols/oscar/oscartestbase.h @@ -1,65 +1,65 @@ /* oscartestbase.h - OSCAR Testlib base Copyright (c) 2006 by Brian Smith Kopete (c) 2002-2006 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #ifndef OSCARTESTBASE_H #define OSCARTESTBASE_H -#include +#include #include class Buffer; /** * @brief Base testcase class */ class OscarTestBase : public QObject { Q_OBJECT public: OscarTestBase(); /** Default destructor */ ~OscarTestBase(); /** * Set the directory to use to load test files */ void setPath( const QString& path ); /** * Takes a file @p file and attempts to load the file, prepending * the path specified in the constructor as test data. * @returns true on success. */ bool loadFile(const QString& file); protected: Buffer* m_data; QString m_dataDir; }; #define OSCAR_TEST_MAIN(TestObject) \ int main(int argc, char **argv) \ { \ QCoreApplication app(argc, argv); \ TestObject tc; \ if(argv[1]) \ tc.setPath( argv[1] ); \ else \ tc.setPath( KDESRCDIR ); \ return QTest::qExec( &tc, 0, 0 ); \ } #endif