/* * eventdlg.cpp - dialog for sending / receiving messages and events * Copyright (C) 2001, 2002 Justin Karneges * * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include"eventdlg.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include"psievent.h" #include"psicon.h" #include"psiaccount.h" #include"msgmle.h" #include"common.h" #include"userlist.h" #include"iconwidget.h" #include"fancylabel.h" #include"iconselect.h" #include"iconwidget.h" static QString findJid(const QString &s, int x, int *p1, int *p2) { // scan backward for the beginning of a Jid int n1 = x; if(n1 >= (int)s.length()) n1 = s.length()-1; for(; n1 >= 0; --n1) { if(s.at(n1) == ',') { ++n1; break; } } if(n1 < 0) n1 = 0; // go forward, skipping whitespace for(; n1 < (int)s.length(); ++n1) { if(!s.at(n1).isSpace()) break; } // now find the end of the Jid int n2 = n1; for(; n2 < (int)s.length(); ++n2) { if(s.at(n2) == ',') break; } --n2; // scan backwards from the end, skipping whitespace for(; n2 > n1; --n2) { if(!s.at(n2).isSpace()) break; } ++n2; *p1 = n1; *p2 = n2; return s.mid(n1, n2-n1); } //---------------------------------------------------------------------------- // ELineEdit - a line edit that handles advanced Jid entry //---------------------------------------------------------------------------- // hack hack hack hack struct QLineEditPrivate { // qt 3.3.1 /*QLineEdit *q; QString text; int cursor; int cursorTimer; QPoint tripleClick; int tripleClickTimer; uint frame : 1; uint cursorVisible : 1; uint separator : 1; uint readOnly : 1; uint modified : 1; uint direction : 5; uint dragEnabled : 1; uint alignment : 3; uint echoMode : 2; uint textDirty : 1; uint selDirty : 1; uint validInput : 1; int ascent; int maxLength; int menuId; int hscroll;*/ char pad[sizeof(QLineEdit *) + sizeof(QString) + (sizeof(int)*2) + sizeof(QPoint) + sizeof(int) + 3 + (sizeof(int)*3)]; int hscroll; }; ELineEdit::ELineEdit(EventDlg *parent, const char *name) :QLineEdit(parent, name) { setAcceptDrops(TRUE); } void ELineEdit::dragEnterEvent(QDragEnterEvent *e) { e->accept(QTextDrag::canDecode(e)); } void ELineEdit::dropEvent(QDropEvent *e) { QString str; if(QTextDrag::decode(e, str)) { Jid jid(str); if(!jid.isValid()) setText(str); else { EventDlg *e = (EventDlg *)parent(); QString name = e->jidToString(jid); bool hasComma = false, hasText = false; int len = text().length(); while ( --len >= 0 ) { QChar c = text().at( len ); if ( c == ',' ) { hasComma = true; break; } else if ( !c.isSpace() ) { hasText = true; break; } } if ( hasComma || !hasText ) setText(text() + ' ' + name); else setText(text() + ", " + name); } setCursorPosition(text().length()); repaint(); } } void ELineEdit::keyPressEvent(QKeyEvent *e) { QLineEdit::keyPressEvent(e); if(e->ascii() >= 32 && e->ascii() < 127) tryComplete(); } QPopupMenu *ELineEdit::createPopupMenu() { EventDlg *e = (EventDlg *)parent(); int xoff = mapFromGlobal(QCursor::pos()).x(); int x = characterAt(d->hscroll + xoff, 0); QString str = text(); int p1, p2; QString j = findJid(str, x, &p1, &p2); if(j.isEmpty()) return QLineEdit::createPopupMenu(); UserResourceList list = e->getResources(j); setCursorPosition(p1); setSelection(p1, p2-p1); url = list; url.sort(); int n = 100; QPopupMenu *rm = new QPopupMenu(this); //= new QPopupMenu(pm); connect(rm, SIGNAL(activated(int)), SLOT(resourceMenuActivated(int))); rm->insertItem(tr("Recipient Default"), n++); if(!list.isEmpty()) { rm->insertSeparator(); for(UserResourceList::ConstIterator it = url.begin(); it != url.end(); ++it) { const UserResource &r = *it; QString name; if(r.name().isEmpty()) name = QObject::tr("[blank]"); else name = r.name(); rm->insertItem(is->status(r.status()), name, n++); } } //pm->insertItem("Change Resource", rm, -1, 0); //pm->insertSeparator(1); return rm; } void ELineEdit::resourceMenuActivated(int x) { if(x < 100) return; QString name; if(x == 100) name = ""; else { int n = 101; for(UserResourceList::ConstIterator it = url.begin(); it != url.end(); ++it) { if(n == x) { name = (*it).name(); break; } ++n; } } url.clear(); changeResource(name); } //---------------------------------------------------------------------------- // AttachView //---------------------------------------------------------------------------- class AttachViewItem : public QListViewItem { public: AttachViewItem(const QString &_url, const QString &_desc, AttachView *par) :QListViewItem(par) { type = 0; url = _url; desc = _desc; setPixmap(0, IconsetFactory::icon("psi/www")); setText(0, url + " (" + desc + ')'); setMultiLinesEnabled(true); } AttachViewItem(const QString &_gc, AttachView *par) :QListViewItem(par) { type = 1; gc = _gc; setPixmap(0, IconsetFactory::icon("psi/groupChat")); setText(0, gc); setMultiLinesEnabled(true); } int rtti() const { return 9100; } QString url, desc; QString gc; int type; }; AttachView::AttachView(QWidget *parent, const char *name) :QListView(parent, name) { v_readOnly = false; addColumn(tr("Attachments")); setResizeMode(QListView::AllColumns); connect(this, SIGNAL(contextMenuRequested(QListViewItem *, const QPoint &, int)), SLOT(qlv_context(QListViewItem *, const QPoint &, int))); connect(this, SIGNAL(doubleClicked(QListViewItem *)), SLOT(qlv_doubleClicked(QListViewItem *))); }; AttachView::~AttachView() { } void AttachView::setReadOnly(bool b) { v_readOnly = b; } void AttachView::urlAdd(const QString &url, const QString &desc) { new AttachViewItem(url, desc, this); childCountChanged(); } void AttachView::gcAdd(const QString &gc) { new AttachViewItem(gc, this); childCountChanged(); } void AttachView::qlv_context(QListViewItem *lvi, const QPoint &pos, int) { AttachViewItem *i = (AttachViewItem *)lvi; if(!i) return; QPopupMenu pm(this); if(i->type == 0) { pm.insertItem(tr("Go to &URL..."), 0); pm.insertItem(tr("Copy location"), 1); } else pm.insertItem(tr("Join &Groupchat..."), 0); pm.insertSeparator(); pm.insertItem(tr("Remove"), 2); if(v_readOnly) pm.setItemEnabled(2, false); int n = pm.exec(pos); if(n == -1) return; if(n == 0) { if(i->type == 0) goURL(i->url); else actionGCJoin(i->gc); } else if(n == 1) { QApplication::clipboard()->setText(i->url, QClipboard::Clipboard); if(QApplication::clipboard()->supportsSelection()) QApplication::clipboard()->setText(i->url, QClipboard::Selection); } else if(n == 2) { delete i; childCountChanged(); } } void AttachView::qlv_doubleClicked(QListViewItem *lvi) { AttachViewItem *i = (AttachViewItem *)lvi; if(!i) return; if(i->type == 0) goURL(i->url); else actionGCJoin(i->gc); } void AttachView::goURL(const QString &_url) { if(_url.isEmpty()) return; QString url = _url; if(url.find("://") == -1) url.insert(0, "http://"); openURL(url); } UrlList AttachView::urlList() const { UrlList list; for(AttachViewItem *i = (AttachViewItem *)firstChild(); i; i = (AttachViewItem *)i->nextSibling()) list += Url(i->url, i->desc); return list; } void AttachView::addUrlList(const UrlList &list) { for(QValueList::ConstIterator it = list.begin(); it != list.end(); ++it) { const Url &u = *it; urlAdd(u.url(), u.desc()); } } //---------------------------------------------------------------------------- // AddUrlDlg //---------------------------------------------------------------------------- AddUrlDlg::AddUrlDlg(QWidget *parent, const char *name) :AddUrlUI(parent, name, true) { #ifndef Q_WS_MAC setIcon(IconsetFactory::icon("psi/www")); #endif connect(pb_close, SIGNAL(clicked()), SLOT(reject())); connect(pb_ok, SIGNAL(clicked()), SLOT(accept())); } AddUrlDlg::~AddUrlDlg() { } //---------------------------------------------------------------------------- // EventDlg - a window to read and write events //---------------------------------------------------------------------------- class EventDlg::Private : public QObject { Q_OBJECT public: Private(EventDlg *d) { dlg = d; } EventDlg *dlg; PsiCon *psi; PsiAccount *pa; bool composing; AccountsComboBox *cb_ident; QComboBox *cb_type; QLabel *lb_ident, *lb_time; IconLabel *lb_status; ELineEdit *le_to; QLineEdit *le_from, *le_subj; QLCDNumber *lcd_count; IconToolButton *tb_url, *tb_info, *tb_history, *tb_pgp, *tb_icon; IconLabel *lb_pgp; bool enc; int transid; IconButton *pb_next; IconButton *pb_close, *pb_quote, *pb_deny, *pb_send, *pb_reply, *pb_chat, *pb_auth; ChatView *mle; AttachView *attachView; QTimer *whois; QString lastWhois; Jid jid, realJid; QString thread; QStringList completionList; Icon *anim, *nextAnim; int nextAmount; bool urlOnShow; Message m; QStringList sendLeft; public slots: void addEmoticon(const Icon *icon) { if ( !dlg->isActiveWindow() ) return; QString text; QDict itext = icon->text(); QDictIterator it ( itext ); for ( ; it.current(); ++it) { if ( it.current() && !it.current()->isEmpty() ) { text = *(it.current()) + " "; break; } } if ( !text.isEmpty() ) mle->insert( text ); } void addEmoticon(QString text) { if ( !dlg->isActiveWindow() ) return; mle->insert( text + " " ); } void updateCounter() { lcd_count->display((int)mle->text().length()); } }; EventDlg::EventDlg(const QString &to, PsiCon *psi, PsiAccount *pa) :AdvancedWidget(0, 0, WDestructiveClose | WGroupLeader) { d = new Private(this); d->composing = true; d->psi = psi; d->pa = 0; d->psi->dialogRegister(this); d->anim = 0; d->nextAnim = 0; d->nextAmount = 0; d->urlOnShow = false; setAccount(pa); d->whois = new QTimer; connect(d->whois, SIGNAL(timeout()), SLOT(doWhois())); init(); d->cb_ident->setAccount(pa); d->pb_send->show(); d->le_to->setText(expandAddresses(to, false)); d->le_to->setCursorPosition(0); if(option.grabUrls) { // url in clipboard? QClipboard *cb = QApplication::clipboard(); QCString subtype("plain"); bool oldmode = cb->selectionModeEnabled(); cb->setSelectionMode(false); QString text = cb->text(subtype); if(!text && cb->supportsSelection()) { cb->setSelectionMode(true); text = cb->text(subtype); } if(text) { if(text.left(7) == "http://") { d->attachView->urlAdd(text, ""); cb->setSelectionMode(false); cb->clear(); cb->setSelectionMode(true); cb->clear(); } } cb->setSelectionMode(oldmode); } updateIdentity(pa); X11WM_CLASS("event"); if(d->le_to->text().isEmpty()) d->le_to->setFocus(); else d->mle->setFocus(); if(d->tb_pgp) { UserListItem *u = d->pa->findFirstRelavent(d->jid); if(u && u->isSecure(d->jid.resource())) d->tb_pgp->setOn(true); } } EventDlg::EventDlg(const Jid &j, PsiAccount *pa, bool unique) :AdvancedWidget(0, 0, WDestructiveClose | WGroupLeader) { d = new Private(this); d->composing = false; d->psi = pa->psi(); d->pa = pa; d->jid = j; d->realJid = j; if(unique) d->pa->dialogRegister(this, j); else d->pa->dialogRegister(this); d->anim = 0; d->nextAnim = 0; d->nextAmount = 0; d->urlOnShow = false; init(); d->le_from->setText(expandAddresses(d->jid.full(), false)); d->le_from->setCursorPosition(0); doWhois(); d->pb_next->show(); d->pb_close->setFocus(); X11WM_CLASS("event"); setTime(QDateTime::currentDateTime(), true); } EventDlg::~EventDlg() { if(d->composing) { delete d->whois; d->psi->dialogUnregister(this); } else { d->pa->dialogUnregister(this); } delete d; } void EventDlg::init() { QVBoxLayout *vb1 = new QVBoxLayout(this, 4); QLabel *l; // first row QHBoxLayout *hb1 = new QHBoxLayout(vb1); l = new QLabel(tr("Identity:"), this); hb1->addWidget(l); d->enc = false; d->transid = -1; if(d->composing) { d->cb_ident = d->psi->accountsComboBox(this); connect(d->cb_ident, SIGNAL(activated(PsiAccount *)), SLOT(updateIdentity(PsiAccount *))); hb1->addWidget(d->cb_ident); } else { d->lb_ident = d->pa->accountLabel(this); d->lb_ident->setSizePolicy(QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed )); hb1->addWidget(d->lb_ident); } if(d->composing) { l = new QLabel(tr("Type:"), this); hb1->addWidget(l); d->cb_type = new QComboBox(this); d->cb_type->insertItem(tr("Normal")); d->cb_type->insertItem(tr("Chat")); hb1->addWidget(d->cb_type); } else { l = new QLabel(tr("Time:"), this); hb1->addWidget(l); d->lb_time = new QLabel(this); d->lb_time->setFrameStyle( QFrame::Panel | QFrame::Sunken ); hb1->addWidget(d->lb_time); } // second row QHBoxLayout *hb2 = new QHBoxLayout(vb1); d->lb_status = new IconLabel(this); d->lb_status->setIcon(IconsetFactory::iconPtr("status/noauth")); if(d->composing) { l = new QLabel(tr("To:"), this); hb2->addWidget(l); hb2->addWidget(d->lb_status); d->le_to = new ELineEdit(this); connect(d->le_to, SIGNAL(textChanged(const QString &)), SLOT(to_textChanged(const QString &))); connect(d->le_to, SIGNAL(changeResource(const QString &)), SLOT(to_changeResource(const QString &))); connect(d->le_to, SIGNAL(tryComplete()), SLOT(to_tryComplete())); hb2->addWidget(d->le_to); } else { l = new QLabel(tr("From:"), this); hb2->addWidget(l); hb2->addWidget(d->lb_status); d->le_from = new QLineEdit(this); d->le_from->setReadOnly(true); hb2->addWidget(d->le_from); } // icon select //connect(d->psi->iconSelectPopup(), SIGNAL(iconSelected(const Icon *)), d, SLOT(addEmoticon(const Icon *))); connect(d->psi->iconSelectPopup(), SIGNAL(textSelected(QString)), d, SLOT(addEmoticon(QString))); d->tb_icon = new IconToolButton(this); d->tb_icon->setIcon(IconsetFactory::iconPtr("psi/smile")); d->tb_icon->setPopup(d->psi->iconSelectPopup()); d->tb_icon->setPopupDelay (1); QToolTip::add(d->tb_icon, tr("Select icon")); if ( !d->composing ) d->tb_icon->setEnabled(false); // message length counter d->le_subj = new QLineEdit(this); d->lcd_count = new QLCDNumber(this); QToolTip::add(d->lcd_count, tr("Message length")); d->lcd_count->setFixedWidth(50); if(d->composing) { d->tb_pgp = new IconToolButton(this); d->tb_pgp->setToggleButton(true); QToolTip::add(d->tb_pgp, tr("Toggle encryption")); d->lb_pgp = 0; } else { d->lb_pgp = new IconLabel(this); d->lb_pgp->setIcon(IconsetFactory::iconPtr("psi/cryptoNo")); d->tb_pgp = 0; } d->tb_url = new IconToolButton(this); connect(d->tb_url, SIGNAL(clicked()), SLOT(addUrl())); QToolTip::add(d->tb_url, tr("Add URL")); d->tb_info = new IconToolButton(this); connect(d->tb_info, SIGNAL(clicked()), SLOT(doInfo())); QToolTip::add(d->tb_info, tr("User info")); d->tb_history = new IconToolButton(this); connect(d->tb_history, SIGNAL(clicked()), SLOT(doHistory())); QToolTip::add(d->tb_history, tr("Message history")); QHBoxLayout *hb3 = new QHBoxLayout(vb1); // if(d->composing /* && config->showsubject */) { if(option.showSubjects) { // third row l = new QLabel(tr("Subject:"), this); hb3->addWidget(l); hb3->addWidget(d->le_subj); hb3->addWidget(d->lcd_count); hb3->addWidget(d->tb_icon); hb3->addWidget(d->tb_url); hb3->addWidget(d->tb_info); hb3->addWidget(d->tb_history); if(!d->composing) { d->le_subj->setReadOnly(true); d->tb_url->setEnabled(false); hb3->addWidget(d->lb_pgp); } else hb3->addWidget(d->tb_pgp); } else { d->le_subj->hide(); hb2->addWidget(d->lcd_count); hb2->addWidget(d->tb_icon); hb2->addWidget(d->tb_url); hb2->addWidget(d->tb_info); hb2->addWidget(d->tb_history); if(d->composing) hb2->addWidget(d->tb_pgp); else hb2->addWidget(d->lb_pgp); } // text area d->mle = new ChatView(this); d->mle->setReadOnly(false); d->mle->setUndoRedoEnabled(true); d->mle->setTextFormat(PlainText); d->mle->setMinimumHeight(50); vb1->addWidget(d->mle); connect(d->mle, SIGNAL(textChanged()), d, SLOT(updateCounter())); d->mle->setTextFormat(QTextEdit::PlainText); if(!d->composing) { d->mle->setReadOnly(true); d->mle->setUndoRedoEnabled(false); } // attachment view d->attachView = new AttachView(this); d->attachView->setFixedHeight(80); d->attachView->hide(); connect(d->attachView, SIGNAL(childCountChanged()), SLOT(showHideAttachView())); connect(d->attachView, SIGNAL(actionGCJoin(const QString &)), SLOT(actionGCJoin(const QString &))); vb1->addWidget(d->attachView); if(!d->composing) d->attachView->setReadOnly(true); // bottom row QHBoxLayout *hb4 = new QHBoxLayout(vb1); d->pb_close = new IconButton(this); d->pb_close->setText(tr("&Close")); connect(d->pb_close, SIGNAL(clicked()), SLOT(close())); d->pb_close->setMinimumWidth(80); hb4->addWidget(d->pb_close); hb4->addStretch(1); d->pb_next = new IconButton(this); connect(d->pb_next, SIGNAL(clicked()), SLOT(doReadNext())); d->pb_next->setText(tr("&Next")); d->pb_next->hide(); d->pb_next->setMinimumWidth(96); d->pb_next->setEnabled(false); hb4->addWidget(d->pb_next); d->pb_quote = new IconButton(this); d->pb_quote->setText(tr("&Quote")); connect(d->pb_quote, SIGNAL(clicked()), SLOT(doQuote())); d->pb_quote->hide(); d->pb_quote->setMinimumWidth(96); hb4->addWidget(d->pb_quote); d->pb_deny = new IconButton(this); d->pb_deny->setText(tr("&Deny")); connect(d->pb_deny, SIGNAL(clicked()), SLOT(doDeny())); d->pb_deny->hide(); d->pb_deny->setMinimumWidth(96); hb4->addWidget(d->pb_deny); d->pb_auth = new IconButton(this); d->pb_auth->setText(tr("&Add/Auth")); connect(d->pb_auth, SIGNAL(clicked()), SLOT(doAuth())); d->pb_auth->setIcon(IconsetFactory::iconPtr("psi/addContact")); d->pb_auth->hide(); d->pb_auth->setMinimumWidth(96); hb4->addWidget(d->pb_auth); d->pb_send = new IconButton(this); d->pb_send->setText(tr("&Send")); connect(d->pb_send, SIGNAL(clicked()), SLOT(doSend())); d->pb_send->hide(); d->pb_send->setMinimumWidth(96); hb4->addWidget(d->pb_send); d->pb_chat = new IconButton(this); d->pb_chat->setText(tr("&Chat")); connect(d->pb_chat, SIGNAL(clicked()), SLOT(doChat())); d->pb_chat->hide(); d->pb_chat->setMinimumWidth(96); hb4->addWidget(d->pb_chat); d->pb_reply = new IconButton(this); d->pb_reply->setText(tr("&Reply")); connect(d->pb_reply, SIGNAL(clicked()), SLOT(doReply())); d->pb_reply->hide(); d->pb_reply->setMinimumWidth(96); hb4->addWidget(d->pb_reply); setTabOrder(d->mle, d->pb_send); updatePGP(); connect(d->pa, SIGNAL(pgpKeyChanged()), SLOT(updatePGP())); connect(d->pa, SIGNAL(encryptedMessageSent(int, bool)), SLOT(encryptedMessageSent(int, bool))); resize(option.sizeEventDlg); optionsUpdate(); } void EventDlg::setAccount(PsiAccount *pa) { if(d->pa) disconnect(d->pa, SIGNAL(updatedActivity()), this, SLOT(accountUpdatedActivity())); d->pa = pa; connect(d->pa, SIGNAL(updatedActivity()), this, SLOT(accountUpdatedActivity())); } void EventDlg::updateIdentity(PsiAccount *pa) { if(!pa) { close(); return; } setAccount(pa); buildCompletionList(); doWhois(true); } void EventDlg::accountUpdatedActivity() { // TODO: act on account activity change } QString EventDlg::text() const { return d->mle->text(); } void EventDlg::setText(const QString &s) { d->mle->setText(s); d->mle->moveCursor(QTextEdit::MoveEnd, false); } void EventDlg::setSubject(const QString &s) { d->le_subj->setText(s); } void EventDlg::setThread(const QString &t) { d->thread = t; } void EventDlg::setUrlOnShow() { d->urlOnShow = true; } PsiAccount *EventDlg::psiAccount() { return d->pa; } QStringList EventDlg::stringToList(const QString &s, bool enc) const { QStringList list; int x1, x2; x1 = 0; x2 = 0; while(1) { // scan along for a comma bool found = false; for(int n = x1; n < (int)s.length(); ++n) { if(s.at(n) == ',') { found = true; x2 = n; break; } } if(!found) x2 = s.length(); QString c = s.mid(x1, (x2-x1)); QString j; if(enc) j = findJidInString(c); else j = c; if(j.isEmpty()) j = c; j = j.stripWhiteSpace(); //printf("j=[%s]\n", j.latin1()); if(!j.isEmpty()) list += j; if(!found) break; x1 = x2+1; } return list; } QString EventDlg::findJidInString(const QString &s) const { int a = s.find('<'); if(a != -1) { ++a; int b = s.find('>', a); if(b != -1) return dec822jid(s.mid(a, b-a)); } return ""; } QString EventDlg::expandAddresses(const QString &in, bool enc) const { //printf("in: [%s]\n", in.latin1()); QString str; QStringList list = stringToList(in, enc); bool first = true; for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) { if(!first) str += ", "; first = false; Jid j(*it); QPtrList ul = d->pa->findRelavent(j); if(ul.isEmpty()) { str += j.full(); continue; } UserListItem *u = ul.first(); Jid jid; if(j.resource().isEmpty()) jid = u->jid().full(); else jid = u->jid().userHost() + '/' + j.resource(); QString name; if(!u->name().isEmpty()) name += u->name() + QString(" <%1>").arg(enc822jid(jid.full())); else name = enc822jid(jid.full()); str += name; } //printf("expanding: [%s]\n", str.latin1()); return str; } void EventDlg::to_textChanged(const QString &) { d->whois->start(250); } void EventDlg::to_changeResource(const QString &r) { QString str = d->le_to->text(); int start, len; if(!d->le_to->getSelection(&start, &len)) { //printf("bad selection\n"); return; } //printf("selection: [%d,%d]\n", start, len); int p1, p2; QString s = findJid(str, start, &p1, &p2); QString j = findJidInString(s); if(j.isEmpty()) j = s; Jid jid(j); if(!jid.isValid()) { //printf("invalid jid\n"); return; } //printf("s=[%s], j=[%s], p: [%d,%d]\n", s.latin1(), j.latin1(), p1, p2); QString js = jidToString(jid, r); //printf("js=[%s]\n", js.latin1()); /*str.remove(start, len); str.insert(start, js); d->le_to->deselect(); d->le_to->setCursorPosition(0); d->le_to->setText(str); //d->le_to->setCursorPosition(start + js.length());*/ d->le_to->insert(js); } void EventDlg::to_tryComplete() { if(!option.jidComplete) return; QString str = d->le_to->text(); int x = d->le_to->cursorPosition(); int p1, p2; QString s = findJid(str, x, &p1, &p2); if(s.length() < 1 || x != p2) return; for(QStringList::ConstIterator it = d->completionList.begin(); it != d->completionList.end(); ++it) { QString name = *it; if(s.length() > name.length()) continue; bool ok = true; int n; for(n = 0; n < (int)s.length(); ++n) { if(s.at(n).lower() != name.at(n).lower()) { ok = false; break; } } name = name.mid(n); if(ok) { d->le_to->insert(name); d->le_to->setCursorPosition(x); d->le_to->setSelection(x, name.length()); break; } } } void EventDlg::buildCompletionList() { d->completionList.clear(); d->completionList += d->pa->jid().full(); UserListIt it(*d->pa->userList()); for(UserListItem *u; (u = it.current()); ++it) { QString j = u->jid().full(); if(!u->name().isEmpty()) d->completionList += u->name() + " <"+j+'>'; d->completionList += j; } } QString EventDlg::jidToString(const Jid &jid, const QString &r) const { QString name; QPtrList ul = d->pa->findRelavent(jid); if(!ul.isEmpty()) { UserListItem *u = ul.first(); QString j; if(r.isEmpty()) j = u->jid().full(); else j = u->jid().userHost() + '/' + r; if(!u->name().isEmpty()) name = u->name() + QString(" <%1>").arg(enc822jid(j)); else name = enc822jid(j); } else name = enc822jid(jid.full()); return name; } void EventDlg::doWhois(bool force) { QString str; if(d->composing) { str = d->le_to->text(); if(str == d->lastWhois && !force) return; } else { str = d->le_from->text(); } //printf("whois: [%s]\n", str.latin1()); d->lastWhois = str; QStringList list = stringToList(str); bool found = false; if(list.count() == 1) { Jid j(list[0]); d->jid = j; QPtrList ul = d->pa->findRelavent(j); if(!ul.isEmpty()) { d->tb_info->setEnabled(true); d->tb_history->setEnabled(true); found = true; } updateContact(d->jid); } if(!found) { d->jid = ""; d->lb_status->setIcon(IconsetFactory::iconPtr("status/noauth")); d->tb_info->setEnabled(false); d->tb_history->setEnabled(false); setCaption(tr("Send Message")); QToolTip::remove(d->lb_status); } } UserResourceList EventDlg::getResources(const QString &s) const { UserResourceList list; QString j = findJidInString(s); if(j.isEmpty()) j = s; Jid jid(j); if(!jid.isValid()) return list; QPtrList ul = d->pa->findRelavent(jid); if(!ul.isEmpty()) { UserListItem *u = ul.first(); if(u->isAvailable()) return u->userResourceList(); } return list; } void EventDlg::optionsUpdate() { // update the font QFont f; f.fromString(option.font[fMessage]); d->mle->setFont(f); // update status icon doWhois(true); if ( option.showCounter && d->composing ) d->lcd_count->show(); else d->lcd_count->hide(); if ( option.useEmoticons ) d->tb_icon->show(); else d->tb_icon->hide(); // tool buttons: not required d->tb_url->setIcon(IconsetFactory::iconPtr("psi/www")); d->tb_info->setIcon(IconsetFactory::iconPtr("psi/vCard")); d->tb_history->setIcon(IconsetFactory::iconPtr("psi/history")); if(d->tb_pgp) { QIconSet i; i.setPixmap(IconsetFactory::icon("psi/cryptoNo"), QIconSet::Automatic, QIconSet::Normal, QIconSet::Off); i.setPixmap(IconsetFactory::icon("psi/cryptoYes"), QIconSet::Automatic, QIconSet::Normal, QIconSet::On); d->tb_pgp->setIconSet(i); } if(d->lb_pgp) d->lb_pgp->setIcon(IconsetFactory::iconPtr(d->enc ? "psi/cryptoYes" : "psi/cryptoNo")); // update the readnext icon if(d->nextAmount > 0) d->pb_next->forceSetIcon(d->nextAnim); // update the widget icon #ifndef Q_WS_MAC if(d->composing) { setIcon(IconsetFactory::icon("psi/sendMessage")); } else { if(d->anim) setIcon(d->anim->impix()); } #endif } QSize EventDlg::defaultSize() { return QSize(420, 280); } void EventDlg::showEvent(QShowEvent *e) { QWidget::showEvent(e); if(d->urlOnShow) { d->urlOnShow = false; QTimer::singleShot(1, this, SLOT(addUrl())); } } void EventDlg::resizeEvent(QResizeEvent *e) { if(option.keepSizes) option.sizeEventDlg = e->size(); } void EventDlg::keyPressEvent(QKeyEvent *e) { if(e->key() == Key_Escape) close(); #ifdef Q_WS_MAC else if(e->key() == Key_W && e->state() & ControlButton) close(); #endif else if(d->composing && e->key() == Key_Return && ((e->state() & ControlButton) || (e->state() & AltButton)) ) doSend(); else if(e->key() == Key_H && (e->state() & ControlButton)) doHistory(); else if(e->key() == Key_I && (e->state() & ControlButton)) doInfo(); else e->ignore(); } void EventDlg::closeEvent(QCloseEvent *e) { // really lame way of checking if we are encrypting if(!d->mle->isEnabled()) return; e->accept(); } void EventDlg::doSend() { if(!d->composing) return; if(!d->pb_send->isEnabled()) return; if(!d->pa->checkConnected(this)) return; if(d->mle->text().isEmpty() && d->attachView->childCount() == 0) { QMessageBox::information(this, tr("Warning"), tr("Please type in a message first.")); return; } QStringList list = stringToList(d->le_to->text()); if(list.isEmpty()) { QMessageBox::warning(this, tr("Warning"), tr("No recipients have been specified!")); return; } Message m; if(d->cb_type->currentItem() == 0) m.setType(""); else m.setType("chat"); m.setBody(d->mle->text()); m.setSubject(d->le_subj->text()); m.setUrlList(d->attachView->urlList()); m.setTimeStamp(QDateTime::currentDateTime()); m.setThread(d->thread); if(d->tb_pgp->isOn()) m.setWasEncrypted(true); d->m = m; d->enc = false; if(d->tb_pgp->isOn()) { d->le_to->setEnabled(false); d->mle->setEnabled(false); d->enc = true; d->sendLeft = list; trySendEncryptedNext(); } else { for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) { m.setTo(Jid(*it)); d->pa->dj_sendMessage(m); } doneSend(); } } void EventDlg::doneSend() { close(); } void EventDlg::doReadNext() { aReadNext(d->realJid); } void EventDlg::doChat() { QStringList list = stringToList(d->le_from->text()); if(list.isEmpty()) return; // FIXME: Maybe it's better without bare(), but then PsiAccount::actionChat // doesn't find the UserListItem to chat with :-( Jid jf(list[0]); Jid j(jf.bare()); aChat(j); } void EventDlg::doReply() { QStringList list = stringToList(d->le_from->text()); if(list.isEmpty()) return; Jid j(list[0]); aReply(j, "", d->le_subj->text(), d->thread); } void EventDlg::doQuote() { QStringList list = stringToList(d->le_from->text()); if(list.isEmpty()) return; Jid j(list[0]); QString body; if(d->mle->hasSelectedText()) body = rich2plain(d->mle->selectedText()); else body = rich2plain(d->mle->text()); aReply(j, body, d->le_subj->text(), d->thread); } void EventDlg::doDeny() { if(!d->pa->checkConnected(this)) return; QStringList list = stringToList(d->le_from->text()); if(list.isEmpty()) return; Jid j(list[0]); aDeny(j); close(); } void EventDlg::doAuth() { if(!d->pa->checkConnected(this)) return; QStringList list = stringToList(d->le_from->text()); if(list.isEmpty()) return; Jid j(list[0]); aAuth(j); d->pb_auth->setEnabled(false); closeAfterReply(); } void EventDlg::doHistory() { d->pa->actionHistory(d->jid.withResource("")); } void EventDlg::doInfo() { d->pa->actionInfo(d->jid); } void EventDlg::closeAfterReply() { if(d->nextAmount == 0) close(); } void EventDlg::addUrl() { AddUrlDlg *w = new AddUrlDlg(this); int n = w->exec(); if(n != QDialog::Accepted) { delete w; return; } QString url = w->le_url->text(); QString desc = w->le_desc->text(); delete w; d->attachView->urlAdd(url, desc); } void EventDlg::showHideAttachView() { if(d->attachView->childCount() > 0) { if(d->attachView->isHidden()) d->attachView->show(); } else { if(!d->attachView->isHidden()) d->attachView->hide(); } } void EventDlg::updateContact(const Jid &jid) { if(d->jid.compare(jid, false)) { QString rname = d->jid.resource(); QPtrList ul = d->pa->findRelavent(d->jid); UserListItem *u = 0; int status = -1; if(!ul.isEmpty()) { u = ul.first(); if(rname.isEmpty()) { // use priority if(!u->isAvailable()) status = STATUS_OFFLINE; else status = makeSTATUS((*u->userResourceList().priority()).status()); } else { // use specific UserResourceList::ConstIterator rit = u->userResourceList().find(rname); if(rit != u->userResourceList().end()) status = makeSTATUS((*rit).status()); else status = STATUS_OFFLINE; } } if(status == -1 || !u) d->lb_status->setIcon(IconsetFactory::iconPtr("status/noauth")); else d->lb_status->setIcon(is->statusPtr(jid, status)); if(u) QToolTip::add(d->lb_status, u->makeTip(true, false)); else QToolTip::remove(d->lb_status); if(u) setCaption(jidnick(u->jid().full(), u->name())); } } void EventDlg::setTime(const QDateTime &t, bool late) { QString str; //str.sprintf("%02d/%02d %02d:%02d:%02d", t.date().month(), t.date().day(), t.time().hour(), t.time().minute(), t.time().second()); str = QString("") + t.toString(LocalDate) + ""; if(late) str = QString("") + str + ""; d->lb_time->setText(str); } void EventDlg::updateEvent(PsiEvent *e) { Icon *oldanim = d->anim; d->anim = is->event2icon(e); if(d->anim != oldanim) setIcon(d->anim->impix()); d->le_from->setText(expandAddresses(e->from().full(), false)); d->le_from->setCursorPosition(0); QToolTip::add(d->le_from, e->from().full()); setTime(e->timeStamp(), e->late()); d->enc = false; if(e->type() == PsiEvent::Message) { MessageEvent *me = (MessageEvent *)e; const Message &m = me->message(); d->enc = m.wasEncrypted(); d->pb_auth->hide(); d->pb_deny->hide(); d->pb_chat->show(); d->pb_reply->show(); d->pb_quote->show(); QString txt = plain2rich(m.body()); // show subject line if the incoming message has one if(m.subject() != "" && !option.showSubjects) txt = "

" + tr("Subject:") + " " + m.subject() + "

" + txt; d->mle->moveCursor(QTextEdit::MoveHome, false); d->mle->setTextFormat(RichText); if(option.useEmoticons) txt = emoticonify(txt); d->mle->setText("" + linkify(txt) + ""); d->le_subj->setText(m.subject()); d->le_subj->setCursorPosition(0); d->thread = m.thread(); d->attachView->clear(); d->attachView->addUrlList(m.urlList()); if(!m.invite().isEmpty()) d->attachView->gcAdd(m.invite()); showHideAttachView(); } else if(e->type() == PsiEvent::Auth) { AuthEvent *ae = (AuthEvent *)e; QString type = ae->authType(); d->le_subj->setText(""); if(type == "subscribe") { QString body(tr("[System Message]
This user wants to subscribe to your presence. Click the button labelled \"Add/Auth\" to authorize the subscription. This will also add the person to your contact list if it is not already there.")); d->mle->moveCursor(QTextEdit::MoveHome, false); d->mle->setTextFormat(RichText); d->mle->setText("" + body + ""); d->pb_chat->show(); d->pb_reply->hide(); d->pb_quote->hide(); d->pb_auth->setEnabled(true); d->pb_auth->show(); d->pb_deny->show(); } else if(type == "subscribed") { QString body(tr("[System Message]
You are now authorized.")); d->mle->moveCursor(QTextEdit::MoveHome, false); d->mle->setTextFormat(RichText); d->mle->setText("" + body + ""); d->pb_auth->hide(); d->pb_deny->hide(); d->pb_chat->show(); d->pb_reply->show(); d->pb_quote->show(); } else if(type == "unsubscribed") { QString body(tr("[System Message]
Your authorization has been removed!")); d->mle->moveCursor(QTextEdit::MoveHome, false); d->mle->setTextFormat(RichText); d->mle->setText("" + body + ""); d->pb_auth->hide(); d->pb_deny->hide(); d->pb_chat->show(); d->pb_reply->show(); d->pb_quote->show(); } } if(d->lb_pgp) d->lb_pgp->setIcon( IconsetFactory::iconPtr(d->enc ? "psi/cryptoYes" : "psi/cryptoNo") ); if(!d->le_subj->text().isEmpty()) QToolTip::add(d->le_subj, d->le_subj->text()); else QToolTip::remove(d->le_subj); doWhois(); } void EventDlg::updateReadNext(Icon *nextAnim, int nextAmount) { int oldAmount = d->nextAmount; d->nextAnim = nextAnim; d->nextAmount = nextAmount; if(nextAmount == 0) { d->nextAnim = 0; d->pb_next->forceSetIcon(0); d->pb_next->setEnabled(false); d->pb_next->setText(tr("&Next")); if(d->pb_reply->isEnabled()) d->pb_reply->setFocus(); else if(d->pb_auth->isVisible()) d->pb_auth->setFocus(); } else { d->pb_next->setEnabled(true); QString str(tr("&Next")); str += QString(" - %1").arg(nextAmount); d->pb_next->setText(str); d->pb_next->forceSetIcon(d->nextAnim); if(d->nextAmount > oldAmount) d->pb_next->setFocus(); } } void EventDlg::actionGCJoin(const QString &gc) { Jid j(gc); d->pa->actionJoin(j.withResource("")); } void EventDlg::updatePGP() { if(d->tb_pgp) { if(!d->pa->pgpKey().isEmpty()) { d->tb_pgp->setEnabled(true); } else { d->tb_pgp->setOn(false); d->tb_pgp->setEnabled(false); } } } void EventDlg::trySendEncryptedNext() { if(d->sendLeft.isEmpty()) return; Message m = d->m; m.setTo(Jid(d->sendLeft.first())); d->transid = d->pa->sendMessageEncrypted(m); if(d->transid == -1) { d->le_to->setEnabled(true); d->mle->setEnabled(true); d->mle->setFocus(); return; } } void EventDlg::encryptedMessageSent(int x, bool b) { if(d->transid == -1) return; if(d->transid != x) return; d->transid = -1; if(b) { // remove the item QStringList::Iterator it = d->sendLeft.begin(); Jid j(*it); d->sendLeft.remove(it); //d->pa->toggleSecurity(j, d->enc); if(d->sendLeft.isEmpty()) { d->le_to->setEnabled(true); d->mle->setEnabled(true); doneSend(); } else { trySendEncryptedNext(); return; } } else QMessageBox::information(this, tr("Error"), tr("There was an error trying to send the message encrypted.\nCheck your OpenPGP application/settings.")); d->le_to->setEnabled(true); d->mle->setEnabled(true); d->mle->setFocus(); } #include "eventdlg.moc"