3 * centerim user interface class
4 * $Id: icqface.cc,v 1.249 2005/08/28 01:33:21 konst Exp $
6 * Copyright (C) 2001-2004 by Konstantin Klyagin <k@thekonst.net>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25 #include <stdint.h> /* for intptr_t */
30 #include "icqcontact.h"
31 #include "icqcontacts.h"
33 #include "icqgroups.h"
34 #include "abstracthook.h"
37 #include "imexternal.h"
43 const char *stryesno(bool b
) {
44 return b
? _("yes") : _("no");
47 const char *strgender(imgender g
) {
49 case genderMale
: return _("Male");
50 case genderFemale
: return _("Female");
53 return _("Not specified");
56 const char *geteventviewresult(icqface::eventviewresult r
) {
58 case icqface::ok
: return _("Ok");
59 case icqface::next
: return _("Next");
60 case icqface::forward
: return _("Fwd");
61 case icqface::reply
: return _("Reply");
62 case icqface::open
: return _("Open");
63 case icqface::accept
: return _("Accept");
64 case icqface::reject
: return _("Reject");
65 case icqface::info
: return _("User info");
66 case icqface::add
: return _("Add");
67 case icqface::prev
: return _("Prev");
73 const char *strregsound(icqconf::regsound s
) {
75 case icqconf::rscard
: return _("sound card");
76 case icqconf::rsspeaker
: return _("speaker");
77 case icqconf::rsdisable
: return _("disable");
80 return _("don't change");
83 const char *strregcolor(icqconf::regcolor c
) {
85 case icqconf::rcdark
: return _("dark");
86 case icqconf::rcblue
: return _("blue");
89 return _("don't change");
92 const char *strcolormode(icqconf::colormode cm
) {
94 case icqconf::cmproto
: return _("protocol");
95 case icqconf::cmstatus
: return _("status");
98 return _("don't change");
101 const char *strint(unsigned int i
) {
105 snprintf(buf
, sizeof(buf
), "%lu", i
);
113 const char *strgroupmode(icqconf::groupmode gmode
) {
115 case icqconf::group1
: return _("mode 1");
116 case icqconf::group2
: return _("mode 2");
123 workareas
.freeitem
= &freeworkareabuf
;
125 mainscreenblock
= inited
= onlinefolder
= dotermresize
=
126 inchat
= doredraw
= false;
131 icqface::~icqface() {
135 for(int i
= 0; i
< LINES
; i
++) printf("\n");
143 void icqface::init() {
145 if(!flog
.is_open()) {
146 time_t logtime
= time(0);
148 flog
.open((conf
.getdirname() + "debug").c_str(), ios::app
);
150 flog
<< endl
<< "-- centerim debug log started on " << ctime(&logtime
);
153 /* Calculate various sizes and coordinates */
155 sizeDlg
.width
= COLS
-20;
156 sizeDlg
.height
= LINES
-10;
158 sizeBigDlg
.width
= COLS
-10;
159 sizeBigDlg
.height
= LINES
-7;
161 sizeWArea
.x1
= conf
.getleftpanelwidth();
162 if(sizeWArea
.x1
< MinPanelWidth
|| sizeWArea
.x1
> (COLS
- MinPanelWidth
)) {
163 sizeWArea
.x1
= (int) (COLS
*0.32);
164 conf
.setleftpanelwidth(sizeWArea
.x1
);
167 sizeWArea
.x2
= COLS
-1;
170 sizeWArea
.y2
= conf
.getlogpanelheight();
171 if(sizeWArea
.y2
< MinPanelHeight
|| sizeWArea
.y2
> (LINES
- MinPanelHeight
)) {
172 sizeWArea
.y2
= (int) LINES
/ 4;
173 conf
.setlogpanelheight(sizeWArea
.y2
);
175 sizeWArea
.y2
= LINES
- sizeWArea
.y2
;
178 mcontacts
= new treeview(conf
.getcolor(cp_main_menu
),
179 conf
.getcolor(cp_main_selected
),
180 conf
.getcolor(cp_main_menu
),
181 conf
.getcolor(cp_main_menu
));
184 mcontacts
->setcoords(1, 2, sizeWArea
.x1
, LINES
-2);
185 mcontacts
->menu
.idle
= &menuidle
;
186 mcontacts
->menu
.otherkeys
= &contactskeys
;
188 input
.setcolor(conf
.getcolor(cp_status
));
189 input
.idle
= &textinputidle
;
191 mainw
= textwindow(0, 1, COLS
-1, LINES
-2, conf
.getcolor(cp_main_frame
));
193 selector
.setcolor(conf
.getcolor(cp_dialog_menu
),
194 conf
.getcolor(cp_dialog_highlight
),
195 conf
.getcolor(cp_dialog_selected
),
196 conf
.getcolor(cp_dialog_frame
));
198 mhist
= verticalmenu(conf
.getcolor(cp_main_text
),
199 conf
.getcolor(cp_main_selected
));
201 attrset(conf
.getcolor(cp_status
));
202 mvhline(0, 0, ' ', COLS
);
203 mvhline(LINES
, 0, ' ', COLS
);
206 kt_resize_event
= &termresize
;
209 void icqface::done() {
215 void icqface::draw() {
217 mainw
.separatex(sizeWArea
.x1
);
218 workarealine(sizeWArea
.y2
);
219 mvhline(sizeWArea
.y2
, sizeWArea
.x1
, LTEE
, 1);
220 mvhline(sizeWArea
.y2
, sizeWArea
.x2
, RTEE
, 1);
225 void icqface::showtopbar() {
228 icqconf::imaccount ia
;
230 for(pname
= icq
; pname
!= protocolname_size
; pname
++) {
231 ia
= conf
.getourid(pname
);
235 buf
+= conf
.getprotocolname(pname
) + ":";
236 buf
+= imstatus2char
[gethook(pname
).getstatus()];
241 attrset(conf
.getcolor(cp_status
));
242 mvhline(0, 0, ' ', COLS
);
243 mvprintw(0, 0, _(" CENTERIM %s UNSENT: %lu"), centerim::version
, em
.getunsentcount());
244 mvprintw(0, COLS
-buf
.size()-1, "%s", buf
.c_str());
247 void icqface::update() {
251 if(doredraw
) redraw();
254 int icqface::contextmenu(icqcontact
*c
) {
256 static int lastr
= 0;
262 verticalmenu
m(conf
.getcolor(cp_main_text
),
263 conf
.getcolor(cp_main_selected
));
265 static map
<int, string
> actnames
;
267 if(actnames
.empty()) {
268 actnames
[ACT_URL
] = getmenuitem(_("Send an URL"), 25, key_send_url
, section_contact
);
269 actnames
[ACT_SMS
] = _(" Send an SMS");
270 actnames
[ACT_CONTACT
] = getmenuitem(_("Send contacts"), 25, key_send_contact
, section_contact
);
271 actnames
[ACT_AUTH
] = _(" Request authorization");
272 actnames
[ACT_EDITUSER
] = getmenuitem(_("Edit details"), 25, key_edit
, section_contact
);
273 actnames
[ACT_FETCHAWAY
] = getmenuitem(_("Fetch away message"), 25, key_fetch_away_message
, section_contact
);
274 actnames
[ACT_ADD
] = getmenuitem(_("Add to list"), 25, key_add
, section_contact
);
275 actnames
[ACT_RENAME
] = getmenuitem(_("Rename contact"), 25, key_rename
, section_contact
);
276 actnames
[ACT_GROUPMOVE
] = _(" Move to group..");
277 actnames
[ACT_PING
] = _(" Ping");
278 actnames
[ACT_VERSION
] = getmenuitem(_("Fetch version info"), 25, key_rename
, section_contact
);
279 actnames
[ACT_FILE
] = _(" Send file(s)");
280 actnames
[ACT_CONFER
] = _(" Invite to conference..");
284 m
.setwindow(textwindow(sizeWArea
.x1
, sizeWArea
.y1
, sizeWArea
.x1
+33,
285 sizeWArea
.y1
+6, conf
.getcolor(cp_main_text
)));
287 actnames
[ACT_MSG
] = _(" Send a channel message enter");
288 actnames
[ACT_HISTORY
] = getmenuitem(_("Channel chat history"), 25, key_history
, section_contact
);
289 actnames
[ACT_REMOVE
] = _(" Remove channel del");
290 actnames
[ACT_JOIN
] = _(" Join channel");
291 actnames
[ACT_LEAVE
] = _(" Leave channel");
292 actnames
[ACT_INFO
] = getmenuitem(_("List nicknames"), 25, key_info
, section_contact
);
294 if(lst
.inlist(c
, csignore
))
295 actnames
[ACT_IGNORE
] = getmenuitem(_("UnBlock channel messages"), 25, key_ignore
, section_contact
);
297 actnames
[ACT_IGNORE
] = getmenuitem(_("Block channel messages"), 25, key_ignore
, section_contact
);
300 m
.setwindow(textwindow(sizeWArea
.x1
, sizeWArea
.y1
, sizeWArea
.x1
+27,
301 sizeWArea
.y1
+6, conf
.getcolor(cp_main_text
)));
303 if(c
->getdesc().pname
!= rss
)
304 actnames
[ACT_MSG
] = getmenuitem(_("Send a message"), 25, key_compose
, section_contact
);
306 actnames
[ACT_HISTORY
] = getmenuitem(_("Event history"), 25, key_history
, section_contact
);
307 actnames
[ACT_REMOVE
] = getmenuitem(_("Remove user"), 25, key_remove
, section_contact
);
308 actnames
[ACT_INFO
] = getmenuitem(_("User's details"), 25, key_info
, section_contact
);
309 actnames
[ACT_EXTERN
] = getmenuitem(_("External actions.."), 25, key_contact_external_action
, section_contact
);
311 actnames
[ACT_IGNORE
] = getmenuitem(lst
.inlist(c
, csignore
) ?
312 _("Unset ignore user") : _("Ignore user"), 25, key_ignore
,
315 actnames
[ACT_PGPKEY
] = c
->getpgpkey().empty() ?
316 _(" Assign PGP key..") : _(" Unassign PGP key");
318 snprintf(buf
, sizeof(buf
), _(" Turn PGP encryption %s"), c
->getusepgpkey() ? "OFF" : "ON");
319 actnames
[ACT_PGPSWITCH
] = buf
;
321 if(c
->getdesc().pname
== rss
)
322 actnames
[ACT_PING
] = getmenuitem(_("Force check"), 25,
323 key_rss_check
, section_contact
);
329 set
<hookcapab::enumeration
> capab
= gethook(cont
.pname
).getCapabs();
332 vector
<int>::const_iterator ia
;
334 if(ischannel(cont
)) {
335 actions
.push_back(ACT_MSG
);
336 actions
.push_back(ACT_HISTORY
);
337 actions
.push_back(ACT_REMOVE
);
338 actions
.push_back(ACT_IGNORE
);
340 if(gethook(cont
.pname
).logged()) {
341 actions
.push_back(ACT_INFO
);
342 actions
.push_back((c
->getstatus() != offline
) ? ACT_LEAVE
: ACT_JOIN
);
345 if(conf
.getgroupmode() != icqconf::nogroups
)
346 actions
.push_back(ACT_GROUPMOVE
);
348 } else if(c
->getdesc().pname
!= rss
) {
349 if(cont
.pname
!= infocard
) actions
.push_back(ACT_MSG
);
350 if(capab
.count(hookcapab::urls
)) actions
.push_back(ACT_URL
);
351 if(!conf
.getourid(icq
).empty()) actions
.push_back(ACT_SMS
);
352 if(capab
.count(hookcapab::contacts
)) actions
.push_back(ACT_CONTACT
);
353 if(capab
.count(hookcapab::authrequests
)) actions
.push_back(ACT_AUTH
);
354 if(capab
.count(hookcapab::files
)) actions
.push_back(ACT_FILE
);
357 if(capab
.count(hookcapab::pgp
)) {
358 actions
.push_back(ACT_PGPKEY
);
359 if(pgp
.havekey(c
->getpgpkey()))
360 actions
.push_back(ACT_PGPSWITCH
);
365 actions
.push_back(0);
367 actions
.push_back(ACT_INFO
);
368 actions
.push_back(ACT_EDITUSER
);
370 if(c
->getstatus() != offline
) {
371 if(capab
.count(hookcapab::fetchaway
)) actions
.push_back(ACT_FETCHAWAY
);
372 if(capab
.count(hookcapab::version
)) actions
.push_back(ACT_VERSION
);
373 if(capab
.count(hookcapab::ping
)) actions
.push_back(ACT_PING
);
374 if(capab
.count(hookcapab::conferencesaretemporary
)) actions
.push_back(ACT_CONFER
);
377 actions
.push_back(ACT_HISTORY
);
378 actions
.push_back(ACT_EXTERN
);
380 actions
.push_back(0);
381 actions
.push_back(ACT_IGNORE
);
382 if(!c
->inlist()) actions
.push_back(ACT_ADD
);
384 actions
.push_back(ACT_REMOVE
);
385 actions
.push_back(ACT_RENAME
);
387 if(conf
.getgroupmode() != icqconf::nogroups
&& c
->inlist())
388 actions
.push_back(ACT_GROUPMOVE
);
391 actions
.push_back(ACT_HISTORY
);
392 actions
.push_back(ACT_REMOVE
);
393 actions
.push_back(ACT_IGNORE
);
394 actions
.push_back(ACT_INFO
);
395 actions
.push_back(ACT_EDITUSER
);
396 actions
.push_back(ACT_PING
);
398 if(conf
.getgroupmode() != icqconf::nogroups
)
399 actions
.push_back(ACT_GROUPMOVE
);
403 for(ia
= actions
.begin(); ia
!= actions
.end(); ++ia
) {
405 m
.additem(0, *ia
, actnames
[*ia
].c_str());
406 if(*ia
== lastr
) m
.setpos(m
.getcount()-1);
414 i
= (intptr_t) m
.getref(m
.open()-1);
421 int icqface::generalmenu() {
423 static int lastitem
= 0;
425 verticalmenu
m(conf
.getcolor(cp_main_text
), conf
.getcolor(cp_main_selected
));
426 m
.setwindow(textwindow(sizeWArea
.x1
, sizeWArea
.y1
, sizeWArea
.x1
+40, sizeWArea
.y1
+11, conf
.getcolor(cp_main_text
)));
429 m
.additem(0, ACT_STATUS
, getmenuitem(_("Change status"), 38, key_change_status
, section_contact
));
430 m
.additem(0, ACT_QUICKFIND
, getmenuitem(_("Go to contact.."), 38, key_quickfind
, section_contact
));
431 m
.additem(0, ACT_DETAILS
, _(" Accounts.."));
432 m
.additem(0, ACT_CONF
, _(" CenterIM config options"));
434 m
.additem(0, ACT_OTR
, _(" OTR options and fingerprints"));
436 m
.additem(0, ACT_TRANSFERS
, _(" File transfers monitor"));
438 m
.additem(0, ACT_FIND
, _(" Find/add users"));
439 m
.additem(0, ACT_JOINDIALOG
, _(" Join channel/conference"));
441 m
.additem(0, ACT_RSS
, _(" Link an RSS feed"));
444 m
.additem(0, ACT_IGNORELIST
, _(" View/edit ignore list"));
445 m
.additem(0, ACT_INVISLIST
, _(" View/edit invisible list"));
446 m
.additem(0, ACT_VISIBLELIST
, _(" View/edit visible list"));
448 if(conf
.gethideoffline())
449 m
.additem(0, ACT_HIDEOFFLINE
, getmenuitem(_("Show offline users"), 38, key_hide_offline
, section_contact
));
451 m
.additem(0, ACT_HIDEOFFLINE
, getmenuitem(_("Hide offline users"), 38, key_hide_offline
, section_contact
));
453 if(conf
.getgroupmode() != icqconf::nogroups
) {
454 m
.additem(0, ACT_ORG_GROUPS
, _(" Organize contact groups"));
455 m
.additem(0, ACT_MASS_MOVE
, _(" Mass group move.."));
466 r
= (intptr_t) m
.getref(lastitem
);
472 /* called to prepare the next chat contact, returns true if it found one, false otherwise
473 parameter is true if its next chat contact or false if is the previous
475 bool icqface::next_chat(bool next
) {
476 find_next_action
= (next
? 1:-1);
477 if (last_selected
) last_selected
->setopenedforchat(false);
481 icqcontact
*icqface::find_next_chat() {
482 if (find_next_action
== 0) return 0;
485 for(i
= 0; i
< clist
.count
&& clist
.at(i
) != last_selected
; i
++)
487 i
+= find_next_action
;
489 else i
= find_next_action
== 1 ? 0 : clist
.count
-1;
492 for (; i
< clist
.count
&& i
>= 0; i
+= find_next_action
){
493 c
= (icqcontact
*) clist
.at(i
);
494 if (c
->isopenedforchat() || c
->hasevents()) {
495 find_next_action
= 0;
501 find_next_action
= 0;
505 icqcontact
*icqface::mainloop(int &action
) {
507 icqcontact
*c
= 0, *c1
= 0; icqgroup
*g
;
510 for(fin
= false; !fin
; ) {
513 /* Obtain the (icqcontact *) from the treeview. If a node is
514 selected, throw out the contact and obtain the correct (icqgroup *). */
516 if (!(c
= c1
= find_next_chat())){ //check if next_chat was called from inside a chat window
517 last_selected
= 0; // next_chat (if called) was called from contacts menu so there was no last selected contact
518 c
= (icqcontact
*) mcontacts
->open(&i
);
519 if ((c1
= find_next_chat())) c
= c1
; //check if next_chat was called from contacts menu
522 if(!c1
&& c
&& mcontacts
->isnode(i
)) {
524 g
= (icqgroup
*) mcontacts
->getref(mcontacts
->getid(mcontacts
->menu
.getpos()));
529 if((intptr_t) c
< 100) c
= 0;
532 switch(action
= extk
) {
534 if(!(action
= generalmenu())) {
543 if(action
== ACT_MSG
&& !c
->hasevents()) {
544 switch(c
->getdesc().pname
) {
545 case infocard
: action
= ACT_SMS
; break;
546 case livejournal
: action
= ACT_LJ
; break;
550 if(action
== ACT_MENU
)
551 if(!(action
= contextmenu(c
))) continue;
555 curid
= mcontacts
->getid(mcontacts
->menu
.getpos());
557 /* kkconsui::treeview has collapsing built in, but when doing it
558 this way contacts with pending messages get moved to the top
559 even if their group is colapsed. */
561 if(mcontacts
->isnodeopen(curid
)) {
562 mcontacts
->closenode(curid
);
564 mcontacts
->opennode(curid
);
567 /* Handling of collapse events should happen in centerim::
568 mainloop, but as it stands this method doesn't handle
569 icqgroups, only icqcontacts, so we'll deal with collapsing
573 g
->changecollapsed();
581 case ACT_HIDEOFFLINE
:
591 if (c
) last_selected
= c
;
596 #define ADDGROUP(nn) { \
597 if(groupchange && !strchr("!", sc)) \
598 ngroup = mcontacts->addnode(nn, conf.getcolor(cp_main_highlight), \
599 g, " " + g->getname() + " " \
600 + (g->iscollapsed() ? "(" + string(i2str(g->getcount(c->getstatus() != offline, !conf.gethideoffline() && !(c->getstatus() != offline && conf.getgroupmode() == icqconf::group2)))) + ") " : "")); \
603 void icqface::fillcontactlist() {
604 int i
, id
, nnode
, ngroup
, prevgid
, n
, nonline
;
608 char prevsc
= 'x', sc
;
610 vector
<icqgroup
>::iterator ig
;
612 bool online_added
, prevoffline
, grouponline
, groupchange
,
613 ontop
, iscurrentnode
, birthday
;
615 time_t timer
= time(0);
618 online_added
= prevoffline
= false;
619 nnode
= ngroup
= prevgid
= 0;
621 iscurrentnode
= mcontacts
->isnode(mcontacts
->getid(mcontacts
->menu
.getpos()));
622 ontop
= !mcontacts
->menu
.getpos() && iscurrentnode
;
624 savec
= mcontacts
->getref(mcontacts
->getid(mcontacts
->menu
.getpos()));
626 int ccolor
= conf
.getcolor(cp_main_text
);
628 if(!iscurrentnode
&& savec
) {
629 ig
= find(groups
.begin(), groups
.end(), ((icqcontact
*) savec
)->getgroupid());
631 if(ig
!= groups
.end()) {
633 if(g
->iscollapsed() && !((icqcontact
*) savec
)->hasevents())
638 /* if savec is a group, we need to figure out of it's the top or bottom
639 one when we're in groupmode mode 2. */
641 if(savec
&& iscurrentnode
&& conf
.getgroupmode() == icqconf::group2
) {
642 for(i
= 0; i
< mcontacts
->getcount(); i
++) {
643 if(mcontacts
->getref(mcontacts
->getid(i
)) == savec
) {
644 if(mcontacts
->getid(i
) != mcontacts
->getid(mcontacts
->menu
.getpos()))
654 for(i
= 0; i
< clist
.count
; i
++) {
655 c
= (icqcontact
*) clist
.at(i
);
657 ig
= find(groups
.begin(), groups
.end(), c
->getgroupid());
658 if(ig
!= groups
.end()) {
662 if(c
->getdesc() == contactroot
)
665 c
->remindbirthday(birthday
= c
->isbirthday());
667 abstracthook
&h
= gethook(c
->getdesc().pname
);
669 if(c
->getstatus() == offline
)
670 if(conf
.gethideoffline())
672 if(c
->inlist() || !h
.logged() || h
.getCapabs().count(hookcapab::cltemporary
)) {
676 sc
= icqcontacts::sort_order
->sortstatus(*c
);
679 (conf
.getgroupmode() != icqconf::nogroups
) &&
680 ((c
->getgroupid() != prevgid
) ||
681 ((conf
.getgroupmode() == icqconf::group2
) &&
682 (prevoffline
== false) && (c
->getstatus() == offline
))) &&
685 if(conf
.getgroupmode() == icqconf::group1
)
688 if(groupchange
|| (sc
!= '#')) {
689 if(strchr("candilfo", sc
)) sc
= 'O';
691 if((sc
!= prevsc
) || groupchange
) {
692 switch(conf
.getgroupmode()) {
693 case icqconf::group1
:
696 case icqconf::group2
:
708 /* Hide 'offline' and 'online' items when in group mode 1 and the current
709 group is collapsed */
714 nnode
= (conf
.getgroupmode() == icqconf::group1
&& g
->iscollapsed()) ||
715 (conf
.gethideoffline() && (conf
.getgroupmode() != icqconf::nogroups
)) ?
716 n
: mcontacts
->addnode(n
,
717 conf
.getcolor(cp_main_highlight
), 0, " Online ");
722 nnode
= (conf
.getgroupmode() == icqconf::group1
&& g
->iscollapsed()) ?
723 n
: mcontacts
->addnode(n
, conf
.getcolor(cp_main_highlight
), 0, " Offline ");
727 nnode
= mcontacts
->addnode(ngroup
,
728 conf
.getcolor(cp_main_highlight
), 0, " Not in list ");
735 if(conf
.getgroupmode() == icqconf::group2
)
736 if(groupchange
&& (sc
!= '!')) {
742 if(groupchange
) prevgid
= c
->getgroupid();
743 prevoffline
= (c
->getstatus() == offline
) ? true : false;
747 dnick
= c
->getdispnick();
749 if(birthday
) dnick
+= " :)";
751 if(conf
.getgroupmode() != icqconf::nogroups
&& g
->iscollapsed() &&
752 !c
->hasevents() && sc
!= '!')
755 if(conf
.getcolormode() == icqconf::cmstatus
) {
756 ccolor
= conf
.getstatuscolor(c
->getstatus());
758 ccolor
= conf
.getprotcolor(c
->getdesc().pname
);
761 if(c
->getstatus() == offline
) {
762 mcontacts
->addleaff(nnode
,
763 c
->hasevents() ? conf
.getcolor(cp_main_highlight
) : ccolor
,
764 c
, "%s%s ", c
->hasevents() ? "#" : c
->getpostponed().empty() ? (c
->isopenedforchat() ? "*" : " ") : ">", dnick
.c_str());
768 if(conf
.getcolormode() == icqconf::cmstatus
) {
769 // When: 'Color contacts according to: status' is selected; protocol is not visible. Ordered by status
770 char *fmt
= "%s[%c]%s%s ";
772 if(lst
.inlist(c
->getdesc(), csvisible
)) fmt
= "%s<%c>%s%s "; else
773 if(lst
.inlist(c
->getdesc(), csinvisible
)) fmt
= "%s{%c}%s%s ";
775 char shortstatus
= c
->getshortstatus();
777 if(c
->getlasttyping()) {
778 if(timer
-c
->getlasttyping() > PERIOD_TYPING
) c
->setlasttyping(0);
779 else shortstatus
= 'T';
782 mcontacts
->addleaff(nnode
,
783 c
->hasevents() ? conf
.getcolor(cp_main_highlight
) : ccolor
,
784 c
, fmt
, c
->hasevents() ? "#" : (c
->isopenedforchat() ? "*" : " "), shortstatus
,
785 c
->getpostponed().empty() ? " " : ">", dnick
.c_str());
788 // Color contact by protocol. Ordered by status
789 char *fmt
= "%s[%c]%s%s ";
791 if(lst
.inlist(c
->getdesc(), csvisible
)) fmt
= "%s<%c>%s%s "; else
792 if(lst
.inlist(c
->getdesc(), csinvisible
)) fmt
= "%s{%c}%s%s ";
794 char shortstatus
= c
->getshortstatus();
796 if(c
->getlasttyping()) {
797 if(timer
-c
->getlasttyping() > PERIOD_TYPING
) c
->setlasttyping(0);
798 else shortstatus
= 'T';
801 mcontacts
->addleaff(nnode
,
802 c
->hasevents() ? conf
.getcolor(cp_main_highlight
) : ccolor
,
803 c
, fmt
, c
->hasevents() ? "#" : (c
->isopenedforchat() ? "*" : " "), shortstatus
,
804 c
->getpostponed().empty() ? " " : ">", dnick
.c_str());
810 if(!mainscreenblock
) mcontacts
->redraw();
812 if(!savec
|| ontop
|| (!onlinefolder
&& online_added
&& conf
.gethideoffline())) {
813 mcontacts
->menu
.setpos(0);
816 for(i
= 0; i
< mcontacts
->menu
.getcount(); i
++)
817 if(mcontacts
->getref(mcontacts
->getid(i
)) == savec
) {
818 if(!grouponline
) grouponline
= true; else {
819 mcontacts
->menu
.setpos(i
);
826 onlinefolder
= online_added
;
828 if(!mainscreenblock
) {
829 mcontacts
->menu
.redraw();
833 bool icqface::findresults(const imsearchparams
&sp
, bool fauto
) {
834 bool finished
= false, ret
= false;
844 abstracthook
&h
= gethook(sp
.pname
);
846 db
.setwindow(new textwindow(sizeWArea
.x1
+1, sizeWArea
.y1
+2, sizeWArea
.x2
,
847 sizeWArea
.y2
, conf
.getcolor(cp_main_text
), TW_NOBORDER
));
848 db
.setmenu(new verticalmenu(conf
.getcolor(cp_main_menu
),
849 conf
.getcolor(cp_main_selected
)));
851 if(!h
.getCapabs().count(hookcapab::nochat
)) {
852 db
.setbar(new horizontalbar(conf
.getcolor(cp_main_highlight
),
853 conf
.getcolor(cp_main_selected
), _("Details"), _("Message"),
854 _("Add"), fauto
? 0 : _("New search"), (char*)0));
856 db
.setbar(new horizontalbar(conf
.getcolor(cp_main_highlight
),
857 conf
.getcolor(cp_main_selected
), _("Details"), _("Add"),
858 fauto
? 0 : _("New search"), (char*)0));
864 if(!sp
.nick
.empty() && h
.getCapabs().count(hookcapab::directadd
)) {
865 imcontact
ic(sp
.nick
, sp
.pname
);
866 static icqcontact
*singlec
= 0, *c
;
871 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
,
872 conf
.getcolor(cp_main_highlight
), _("Contact to add"));
875 if(!c
) c
= singlec
= new icqcontact(ic
);
877 db
.getmenu()->additem(conf
.getprotcolor(sp
.pname
),
878 c
, (string
) " " + sp
.nick
);
881 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
,
882 conf
.getcolor(cp_main_highlight
), _("Searching contacts.."));
884 h
.lookup(sp
, *db
.getmenu());
888 db
.idle
= &dialogidle
;
889 db
.otherkeys
= &findreskeys
;
891 workarealine(sizeWArea
.y1
+2);
892 workarealine(sizeWArea
.y2
-2);
895 finished
= !db
.open(r
, b
);
898 if(h
.getCapabs().count(hookcapab::nochat
) && b
> 0)
903 quickfind(db
.getmenu());
908 c
= (icqcontact
*) db
.getmenu()->getref(r
-1);
909 if(c
) cicq
.userinfo(c
->getdesc());
916 if(c
= (icqcontact
*) db
.getmenu()->getref(r
-1)) {
917 imcontact cont
= c
->getdesc();
918 existed
= (c
= clist
.get(cont
));
919 if(!existed
) c
= clist
.addnew(cont
);
922 if(!cicq
.sendevent(immessage(cont
, imevent::outgoing
, ""), icqface::ok
))
931 c
= (icqcontact
*) db
.getmenu()->getref(r
-1);
932 if(c
) cicq
.addcontact(c
->getdesc(), c
->getbasicinfo().requiresauth
);
937 ret
= finished
= true;
950 void icqface::findready() {
951 mvhline(sizeWArea
.x1
+2, sizeWArea
.y1
, ' ', sizeWArea
.x2
-sizeWArea
.x1
-2);
952 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
,
953 conf
.getcolor(cp_main_highlight
), _("Search results [done]"));
956 void icqface::infoclear(dialogbox
&db
, icqcontact
*c
, const imcontact realdesc
) {
957 for(int i
= sizeWArea
.y1
+1; i
< sizeWArea
.y2
; i
++) {
958 workarealine(i
, ' ');
963 mainw
.writef(sizeWArea
.x1
+2, sizeWArea
.y1
, conf
.getcolor(cp_main_highlight
),
964 _("Information about %s"), realdesc
.totext().c_str());
966 workarealine(sizeWArea
.y1
+2);
967 workarealine(sizeWArea
.y2
-2);
969 icqcontact::basicinfo bi
= c
->getbasicinfo();
970 icqcontact::moreinfo mi
= c
->getmoreinfo();
971 icqcontact::workinfo wi
= c
->getworkinfo();
973 extracturls(bi
.city
+ " " + bi
.state
+ " " + bi
.street
+ " " +
974 wi
.city
+ " " + wi
.state
+ " " + wi
.street
+ " " +
975 wi
.company
+ " " + wi
.dept
+ " " + wi
.position
+ " " +
978 if(!mi
.homepage
.empty())
979 extractedurls
.push_back(mi
.homepage
);
980 if(!wi
.homepage
.empty())
981 extractedurls
.push_back(wi
.homepage
);
984 void commacat(string
&text
, string sub
, bool nocomma
= false) {
987 if(text
[text
.size()-1] != ',') text
+= ",";
993 void commaform(string
&text
) {
996 while((pos
= text
.find(",", pos
)) != -1) {
997 if(text
.substr(pos
+1, 1) != " ") {
998 text
.insert(pos
+1, " ");
1003 if(text
.substr(ipos
, 1) == " ") {
1004 text
.erase(ipos
--, 1);
1014 void icqface::infolivejournal(dialogbox
&db
, icqcontact
*c
) {
1015 icqcontact::basicinfo bi
= c
->getbasicinfo();
1016 icqcontact::moreinfo mi
= c
->getmoreinfo();
1018 workarealine(sizeWArea
.y1
+5);
1019 workarealine(sizeWArea
.y1
+7);
1021 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+2, conf
.getcolor(cp_main_highlight
), _("Nickname"));
1022 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+3, conf
.getcolor(cp_main_highlight
), _("Name"));
1023 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+5, conf
.getcolor(cp_main_highlight
), _("URL"));
1025 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+2, conf
.getcolor(cp_main_text
), c
->getnick());
1026 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+3, conf
.getcolor(cp_main_text
), bi
.fname
+ " " + bi
.lname
);
1027 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+5, conf
.getcolor(cp_main_text
), mi
.homepage
);
1029 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+7, conf
.getcolor(cp_main_highlight
), _("This is your LiveJournal account. Use it to"));
1030 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+8, conf
.getcolor(cp_main_highlight
), _("post new entries to your journal."));
1033 void icqface::infofriends(dialogbox
&db
, icqcontact
*c
) {
1035 icqcontact::basicinfo bi
= c
->getbasicinfo();
1037 text
+= (string
) "* " + _("The following users have you listed as their friend:") + " ";
1038 while(!(buf
= getword(bi
.zip
)).empty()) {
1040 if(!bi
.zip
.empty()) text
+= ", ";
1043 db
.getbrowser()->setbuf(text
);
1046 void icqface::infogeneral(dialogbox
&db
, icqcontact
*c
) {
1047 string langs
, options
, buf
;
1048 icqcontact::basicinfo bi
= c
->getbasicinfo();
1049 icqcontact::moreinfo mi
= c
->getmoreinfo();
1051 workarealine(sizeWArea
.y1
+8);
1052 workarealine(sizeWArea
.y1
+12);
1055 if(gethook(c
->getdesc().pname
).getCapabs().count(hookcapab::pgp
))
1056 if(!c
->getpgpkey().empty()) {
1057 buf
= (string
) "[" + string(5, ' ') + c
->getpgpkey() + ": ";
1059 if(pgp
.havekey(c
->getpgpkey())) {
1062 buf
+= (pgp
.enabled(c
) ? _("used") : _("not used"));
1064 buf
+= _("not found");
1069 mainw
.write(sizeWArea
.x2
-buf
.size()-1, sizeWArea
.y1
+11,
1070 conf
.getcolor(cp_main_text
), buf
);
1072 mainw
.write(sizeWArea
.x2
-buf
.size()+1, sizeWArea
.y1
+11,
1073 conf
.getcolor(cp_main_highlight
), "PGP");
1077 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+2, conf
.getcolor(cp_main_highlight
), _("Nickname"));
1078 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+3, conf
.getcolor(cp_main_highlight
), _("Name"));
1079 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+4, conf
.getcolor(cp_main_highlight
), _("E-mail"));
1080 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+5, conf
.getcolor(cp_main_highlight
), _("2nd e-mail"));
1081 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+6, conf
.getcolor(cp_main_highlight
), _("Old e-mail"));
1082 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+8, conf
.getcolor(cp_main_highlight
), _("Gender"));
1083 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+9, conf
.getcolor(cp_main_highlight
), _("Birthdate"));
1084 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+10, conf
.getcolor(cp_main_highlight
), _("Age"));
1085 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+12, conf
.getcolor(cp_main_highlight
), _("Languages"));
1086 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+13, conf
.getcolor(cp_main_highlight
), _("Last IP"));
1087 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+2, conf
.getcolor(cp_main_text
), c
->getnick());
1088 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+3, conf
.getcolor(cp_main_text
), bi
.fname
+ " " + bi
.lname
);
1089 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+4, conf
.getcolor(cp_main_text
), bi
.email
);
1091 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+8, conf
.getcolor(cp_main_text
), strgender(mi
.gender
));
1092 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+9, conf
.getcolor(cp_main_text
), mi
.strbirthdate());
1093 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+10, conf
.getcolor(cp_main_text
), mi
.age
? i2str(mi
.age
) : "");
1095 if(mi
.lang1
) commacat(langs
, abstracthook::getLanguageIDtoString(mi
.lang1
), langs
.empty());
1096 if(mi
.lang2
) commacat(langs
, abstracthook::getLanguageIDtoString(mi
.lang2
), langs
.empty());
1097 if(mi
.lang3
) commacat(langs
, abstracthook::getLanguageIDtoString(mi
.lang3
), langs
.empty());
1100 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+12, conf
.getcolor(cp_main_text
), langs
);
1101 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+13, conf
.getcolor(cp_main_text
), c
->getlastip());
1103 time_t ls
= c
->getlastseen();
1106 if(c
->getstatus() == offline
) {
1107 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+14, conf
.getcolor(cp_main_highlight
), _("Last seen"));
1108 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+14, conf
.getcolor(cp_main_text
),
1109 ls
? strdateandtime(ls
) : _("Never"));
1111 } else if(c
->getdesc() != contactroot
) {
1112 int days
, hours
, minutes
, tdiff
= timer_current
-ls
;
1114 days
= (int) (tdiff
/86400);
1115 hours
= (int) ((tdiff
-days
*86400)/3600);
1116 minutes
= (int) ((tdiff
-days
*8600-hours
*3600)/60);
1118 if(days
) buf
= i2str(days
) + " " + _("days");
1121 if(!buf
.empty()) buf
+= ", ";
1122 buf
+= i2str(hours
) + " " + _("hours");
1126 if(!buf
.empty()) buf
+= ", ";
1127 buf
+= i2str(minutes
) + " " + _("min");
1131 buf
= i2str(tdiff
) + " " + _("seconds");
1133 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+14, conf
.getcolor(cp_main_highlight
), _("Online"));
1134 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+14, conf
.getcolor(cp_main_text
), buf
);
1138 void icqface::infohome(dialogbox
&db
, icqcontact
*c
) {
1141 icqcontact::basicinfo bi
= c
->getbasicinfo();
1142 icqcontact::moreinfo mi
= c
->getmoreinfo();
1144 workarealine(sizeWArea
.y1
+10);
1147 mainw
.write(x
, sizeWArea
.y1
+2, conf
.getcolor(cp_main_highlight
), _("Address"));
1148 mainw
.write(x
, sizeWArea
.y1
+3, conf
.getcolor(cp_main_highlight
), _("Location"));
1149 mainw
.write(x
, sizeWArea
.y1
+4, conf
.getcolor(cp_main_highlight
), _("Zip code"));
1150 mainw
.write(x
, sizeWArea
.y1
+5, conf
.getcolor(cp_main_highlight
), _("Phone"));
1151 mainw
.write(x
, sizeWArea
.y1
+6, conf
.getcolor(cp_main_highlight
), _("Fax"));
1152 mainw
.write(x
, sizeWArea
.y1
+7, conf
.getcolor(cp_main_highlight
), _("Cellular"));
1153 mainw
.write(x
, sizeWArea
.y1
+8, conf
.getcolor(cp_main_highlight
), _("Timezone"));
1155 mainw
.write(x
, sizeWArea
.y1
+10, conf
.getcolor(cp_main_highlight
), _("Homepage"));
1157 if(!bi
.state
.empty()) {
1158 if(bi
.city
.size()) bi
.city
+= ", ";
1159 bi
.city
+= bi
.state
;
1163 if(bi
.city
.size()) bi
.city
+= ", ";
1164 bi
.city
+= abstracthook::getCountryIDtoString(bi
.country
);
1168 mainw
.write(x
, sizeWArea
.y1
+2, conf
.getcolor(cp_main_text
), bi
.street
);
1169 mainw
.write(x
, sizeWArea
.y1
+3, conf
.getcolor(cp_main_text
), bi
.city
);
1170 mainw
.write(x
, sizeWArea
.y1
+4, conf
.getcolor(cp_main_text
), bi
.zip
);
1171 mainw
.write(x
, sizeWArea
.y1
+5, conf
.getcolor(cp_main_text
), bi
.phone
);
1172 mainw
.write(x
, sizeWArea
.y1
+6, conf
.getcolor(cp_main_text
), bi
.fax
);
1173 mainw
.write(x
, sizeWArea
.y1
+7, conf
.getcolor(cp_main_text
), bi
.cellular
);
1174 mainw
.write(x
, sizeWArea
.y1
+8, conf
.getcolor(cp_main_text
), mi
.strtimezone());
1176 for(i
= 0; !mi
.homepage
.empty(); i
++) {
1177 mainw
.write(x
, sizeWArea
.y1
+10+i
, conf
.getcolor(cp_main_text
),
1178 mi
.homepage
.substr(0, sizeWArea
.x2
-sizeWArea
.x1
-12));
1179 mi
.homepage
.erase(0, sizeWArea
.x2
-sizeWArea
.x1
-12);
1183 void icqface::infowork(dialogbox
&db
, icqcontact
*c
) {
1185 icqcontact::workinfo wi
= c
->getworkinfo();
1187 workarealine(sizeWArea
.y1
+6);
1188 workarealine(sizeWArea
.y1
+11);
1190 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+2, conf
.getcolor(cp_main_highlight
), _("Address"));
1191 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+3, conf
.getcolor(cp_main_highlight
), _("Location"));
1192 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+4, conf
.getcolor(cp_main_highlight
), _("Zip code"));
1194 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+6, conf
.getcolor(cp_main_highlight
), _("Company"));
1195 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+7, conf
.getcolor(cp_main_highlight
), _("Department"));
1196 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+8, conf
.getcolor(cp_main_highlight
), _("Title"));
1198 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+11, conf
.getcolor(cp_main_highlight
), _("Phone"));
1199 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+12, conf
.getcolor(cp_main_highlight
), _("Fax"));
1200 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+13, conf
.getcolor(cp_main_highlight
), _("Homepage"));
1202 if(!wi
.state
.empty()) {
1203 if(wi
.city
.size()) wi
.city
+= ", ";
1204 wi
.city
+= wi
.state
;
1208 if(wi
.city
.size()) wi
.city
+= ", ";
1209 wi
.city
+= abstracthook::getCountryIDtoString(wi
.country
);
1212 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+2, conf
.getcolor(cp_main_text
), wi
.street
);
1213 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+3, conf
.getcolor(cp_main_text
), wi
.city
);
1214 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+4, conf
.getcolor(cp_main_text
), wi
.zip
);
1215 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+6, conf
.getcolor(cp_main_text
), wi
.company
);
1216 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+7, conf
.getcolor(cp_main_text
), wi
.dept
);
1217 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+8, conf
.getcolor(cp_main_text
), wi
.position
);
1218 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+11, conf
.getcolor(cp_main_text
), wi
.phone
);
1219 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+12, conf
.getcolor(cp_main_text
), wi
.fax
);
1221 for(i
= 0; !wi
.homepage
.empty(); i
++) {
1222 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+13+i
, conf
.getcolor(cp_main_text
),
1223 wi
.homepage
.substr(0, sizeWArea
.x2
-sizeWArea
.x1
-14));
1224 wi
.homepage
.erase(0, sizeWArea
.x2
-sizeWArea
.x1
-14);
1228 void icqface::infoabout(dialogbox
&db
, icqcontact
*c
) {
1229 db
.getbrowser()->setbuf(c
->getabout());
1232 void icqface::infointerests(dialogbox
&db
, icqcontact
*c
) {
1234 vector
<string
> data
;
1235 vector
<string
>::iterator i
;
1237 data
= c
->getinterests();
1240 text
+= (string
) "* " + _("Interests") + "\n";
1242 for(i
= data
.begin(); i
!= data
.end(); ++i
) {
1243 text
+= " + " + *i
+ "\n";
1249 data
= c
->getbackground();
1252 text
+= (string
) "* " + _("Background") + "\n";
1254 for(i
= data
.begin(); i
!= data
.end(); ++i
)
1255 text
+= " + " + *i
+ "\n";
1259 db
.getbrowser()->setbuf(text
);
1262 void icqface::inforss(dialogbox
&db
, icqcontact
*c
) {
1263 icqcontact::basicinfo bi
= c
->getbasicinfo();
1264 icqcontact::moreinfo mi
= c
->getmoreinfo();
1265 icqcontact::workinfo wi
= c
->getworkinfo();
1267 workarealine(sizeWArea
.y1
+7);
1268 workarealine(sizeWArea
.y1
+10);
1270 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+2, conf
.getcolor(cp_main_highlight
), _("Handle"));
1271 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+3, conf
.getcolor(cp_main_highlight
), _("RSS doc"));
1272 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+4, conf
.getcolor(cp_main_highlight
), _("Version"));
1273 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+5, conf
.getcolor(cp_main_highlight
), _("Encoding"));
1275 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+7, conf
.getcolor(cp_main_highlight
), _("Title"));
1276 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+8, conf
.getcolor(cp_main_highlight
), _("Link"));
1278 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+10, conf
.getcolor(cp_main_highlight
), _("Frequency"));
1279 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+11, conf
.getcolor(cp_main_highlight
), _("Last check"));
1280 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+12, conf
.getcolor(cp_main_highlight
), _("Next check"));
1281 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+13, conf
.getcolor(cp_main_highlight
), _("Last result"));
1283 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+2, conf
.getcolor(cp_main_text
), c
->getnick());
1284 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+3, conf
.getcolor(cp_main_text
), wi
.homepage
);
1285 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+4, conf
.getcolor(cp_main_text
), bi
.city
);
1286 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+5, conf
.getcolor(cp_main_text
), bi
.state
);
1288 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+7, conf
.getcolor(cp_main_text
), bi
.fname
);
1289 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+8, conf
.getcolor(cp_main_text
), mi
.homepage
);
1291 string freq
, last
, next
;
1295 snprintf(buf
, sizeof(buf
), _("%lu minutes"), mi
.checkfreq
);
1297 if(mi
.checklast
) next
= strdateandtime(mi
.checklast
+mi
.checkfreq
*60);
1298 else next
= _("Now");
1300 freq
= next
= _("Never");
1303 if(mi
.checklast
) last
= strdateandtime(mi
.checklast
);
1304 else last
= _("Never");
1306 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+10, conf
.getcolor(cp_main_text
), freq
);
1307 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+11, conf
.getcolor(cp_main_text
), last
);
1308 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+12, conf
.getcolor(cp_main_text
), next
);
1309 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+13, conf
.getcolor(cp_main_text
), bi
.lname
);
1312 void icqface::infoljrss(dialogbox
&db
, icqcontact
*c
) {
1313 icqcontact::basicinfo bi
= c
->getbasicinfo();
1314 icqcontact::moreinfo mi
= c
->getmoreinfo();
1316 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+2, conf
.getcolor(cp_main_highlight
), _("Birthdate"));
1317 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+3, conf
.getcolor(cp_main_highlight
), _("Full name"));
1319 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+2, conf
.getcolor(cp_main_text
), mi
.strbirthdate());
1320 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+3, conf
.getcolor(cp_main_text
), bi
.email
);
1323 void icqface::userinfo(const imcontact
&cinfo
, const imcontact
&realinfo
) {
1324 bool finished
= false, showinfo
;
1325 textbrowser
tb(conf
.getcolor(cp_main_text
));
1329 imcontact savepassinfo
= passinfo
;
1330 icqcontact
*c
= clist
.get(passinfo
= realinfo
);
1336 status(_("%s to URLs, %s external actions, %s close"),
1337 getstatkey(key_show_urls
, section_info
).c_str(),
1338 getstatkey(key_user_external_action
, section_info
).c_str(),
1339 getstatkey(key_quit
, section_editor
).c_str());
1341 xtermtitle(_("user info for %s"), realinfo
.totext().c_str());
1343 db
.setwindow(new textwindow(sizeWArea
.x1
+1, sizeWArea
.y1
+2, sizeWArea
.x2
,
1344 sizeWArea
.y2
, conf
.getcolor(cp_main_text
), TW_NOBORDER
));
1346 if(cinfo
.pname
== rss
) {
1347 if(c
->inlist() && realinfo
!= contactroot
) {
1348 db
.setbar(new horizontalbar(sizeWArea
.x1
+2, sizeWArea
.y2
-1,
1349 conf
.getcolor(cp_main_highlight
), conf
.getcolor(cp_main_selected
),
1350 _("Info"), _("About"), _("Check"), _("Edit"), islivejournal(c
) ? _("LJ") : 0, (char*)0));
1352 db
.setbar(new horizontalbar(sizeWArea
.x1
+2, sizeWArea
.y2
-1,
1353 conf
.getcolor(cp_main_highlight
), conf
.getcolor(cp_main_selected
),
1354 _("Info"), _("About"), _("Retreive"), (char*)0));
1357 } else if(cinfo
.pname
== livejournal
) {
1358 db
.setbar(new horizontalbar(sizeWArea
.x1
+2, sizeWArea
.y2
-1,
1359 conf
.getcolor(cp_main_highlight
), conf
.getcolor(cp_main_selected
),
1360 _("Info"), _("Friend of"), (char*)0));
1364 db
.setbar(new horizontalbar(sizeWArea
.x1
+2, sizeWArea
.y2
-1,
1365 conf
.getcolor(cp_main_highlight
), conf
.getcolor(cp_main_selected
),
1366 _("Info"), _("Home"), _("Work"), _("More"), _("About"),
1367 cinfo
.pname
!= infocard
? _("Retrieve") : _("Edit"), (char*)0));
1373 db
.idle
= &dialogidle
;
1374 db
.otherkeys
= &userinfokeys
;
1378 if(cicq
.idle(HIDL_SOCKEXIT
)) {
1379 finished
= !db
.open(k
, b
);
1380 showinfo
= !finished
;
1391 infoclear(db
, c
, cinfo
);
1393 if(cinfo
.pname
== rss
) switch(b
) {
1394 case 0: inforss(db
, c
); break;
1396 db
.setbrowser(&tb
, false);
1398 infoclear(db
, c
, cinfo
);
1401 gethook(cinfo
.pname
).ping(c
);
1405 updatedetails(c
, c
->getdesc().pname
);
1409 case 4: infoljrss(db
, c
); break;
1411 } else if(cinfo
.pname
== livejournal
) switch(b
) {
1412 case 0: infolivejournal(db
, c
); break;
1414 db
.setbrowser(&tb
, false);
1416 infoclear(db
, c
, cinfo
);
1420 case 0: infogeneral(db
, c
); break;
1421 case 1: infohome(db
, c
); break;
1422 case 2: infowork(db
, c
); break;
1424 db
.setbrowser(&tb
, false);
1425 infointerests(db
, c
);
1426 infoclear(db
, c
, cinfo
);
1429 db
.setbrowser(&tb
, false);
1431 infoclear(db
, c
, cinfo
);
1434 switch(cinfo
.pname
) {
1441 gethook(cinfo
.pname
).requestinfo(cinfo
);
1459 passinfo
= savepassinfo
;
1462 void icqface::makeprotocolmenu(verticalmenu
&m
) {
1463 icqconf::imaccount ia
;
1464 protocolname ipname
;
1466 static const string pitems
[protocolname_size
] = {
1467 _(" [icq] ICQ network"),
1469 _(" [msn] M$ Messenger"),
1470 _(" [aim] AOL TOC"),
1474 _(" [lj] LiveJournal"),
1475 _(" [gg] Gadu-Gadu"),
1479 for(ipname
= icq
; ipname
!= protocolname_size
; ipname
++) {
1480 ia
= conf
.getourid(ipname
);
1483 m
.additem(0, ipname
, pitems
[ipname
]);
1488 bool icqface::changestatus(vector
<protocolname
> &pnames
, imstatus
&st
) {
1489 int i
, choice
, protcount
;
1490 bool r
, alrlogged
= false;
1491 verticalmenu
m(conf
.getcolor(cp_main_text
), conf
.getcolor(cp_main_selected
));
1493 vector
<imstatus
> mst
;
1494 vector
<imstatus
>::iterator im
;
1495 protocolname pname
, onechoice
;
1497 m
.setwindow(textwindow(sizeWArea
.x1
, sizeWArea
.y1
, sizeWArea
.x1
+27,
1498 sizeWArea
.y1
+9, conf
.getcolor(cp_main_text
)));
1502 for(protcount
= 0, pname
= icq
; pname
!= protocolname_size
; pname
++) {
1503 if(!conf
.getourid(pname
).empty()) {
1508 alrlogged
= alrlogged
|| gethook(pname
).getstatus() != offline
;
1516 m
.additem(0, -1, _(" All protocols"));
1517 if(alrlogged
) m
.additem(0, -2, _(" Already logged in only"));
1519 makeprotocolmenu(m
);
1523 choice
= (intptr_t) m
.getref(i
-1);
1531 for(pname
= icq
; pname
!= protocolname_size
; pname
++)
1532 if(!conf
.getourid(pname
).empty())
1533 pnames
.push_back(pname
);
1536 for(pname
= icq
; pname
!= protocolname_size
; pname
++)
1537 if(!conf
.getourid(pname
).empty())
1538 if(gethook(pname
).getstatus() != offline
)
1539 pnames
.push_back(pname
);
1542 pnames
.push_back((protocolname
) choice
);
1548 mst
.push_back(available
);
1549 mst
.push_back(offline
);
1550 mst
.push_back(away
);
1551 mst
.push_back(dontdisturb
);
1552 mst
.push_back(notavail
);
1553 mst
.push_back(outforlunch
);
1554 mst
.push_back(occupied
);
1555 mst
.push_back(freeforchat
);
1556 mst
.push_back(invisible
);
1558 for(im
= mst
.begin(); im
!= mst
.end(); ++im
) {
1559 string sst
= (string
) " [" + imstatus2char
[*im
] + "] " + imstatus2str(*im
);
1560 m
.additem(0, *im
, sst
);
1562 if(pnames
.size() == 1)
1563 if(gethook(pnames
.front()).getstatus() == *im
)
1564 m
.setpos(m
.getcount()-1);
1567 if(pnames
.size() > 1) {
1571 m
.otherkeys
= &statuskeys
;
1579 st
= (imstatus
) ((intptr_t) m
.getref(i
-1));
1586 #define INPUT_POS LINES-2
1588 string
icqface::inputstr(const string
&q
, const string
&defl
, char passwdchar
) {
1589 screenarea
sa(0, INPUT_POS
, COLS
, INPUT_POS
);
1591 attrset(conf
.getcolor(cp_status
));
1592 mvhline(INPUT_POS
, 0, ' ', COLS
);
1593 kwriteatf(0, INPUT_POS
, conf
.getcolor(cp_status
), "%s", q
.c_str());
1595 input
.setpasswordchar(passwdchar
);
1596 input
.removeselector();
1597 input
.setvalue(defl
);
1598 input
.setcoords(q
.size(), INPUT_POS
, COLS
-q
.size());
1602 return input
.getvalue();
1605 string
icqface::inputfile(const string
&q
, const string
&defl
) {
1606 screenarea
sa(0, INPUT_POS
, COLS
, INPUT_POS
);
1609 mvhline(INPUT_POS
, 0, ' ', COLS
);
1610 kwriteatf(0, INPUT_POS
, conf
.getcolor(cp_status
), "%s", q
.c_str());
1611 kwriteatf(COLS
-8, INPUT_POS
, conf
.getcolor(cp_status
), "[Ctrl-T]");
1613 selector
.setoptions(0);
1614 selector
.setwindow(textwindow(0, 0, sizeDlg
.width
, sizeDlg
.height
,
1615 conf
.getcolor(cp_dialog_frame
), TW_CENTERED
,
1616 conf
.getcolor(cp_dialog_highlight
),
1617 _(" <Space> or <Enter> confirm, <Esc> cancel ")));
1619 input
.connectselector(selector
);
1621 input
.setcoords(q
.size(), INPUT_POS
, COLS
-q
.size()-8);
1622 input
.setvalue(defl
);
1624 r
= input
.getvalue();
1626 if(r
.rfind("/") != -1) {
1627 selector
.setstartpoint(r
.substr(0, r
.find("/")));
1634 string
icqface::inputdir(const string
&q
, const string
&defl
) {
1635 screenarea
sa(0, INPUT_POS
, COLS
, INPUT_POS
);
1638 mvhline(INPUT_POS
, 0, ' ', COLS
);
1639 kwriteatf(0, INPUT_POS
, conf
.getcolor(cp_status
), "%s", q
.c_str());
1640 kwriteatf(COLS
-8, INPUT_POS
, conf
.getcolor(cp_status
), "[Ctrl-T]");
1642 selector
.setoptions(FSEL_DIRSELECT
);
1643 selector
.setwindow(textwindow(0, 0, sizeDlg
.width
, sizeDlg
.height
,
1644 conf
.getcolor(cp_dialog_frame
), TW_CENTERED
,
1645 conf
.getcolor(cp_dialog_highlight
),
1646 _(" <Space> confirm, <Esc> cancel ")));
1648 input
.connectselector(selector
);
1650 input
.setcoords(q
.size(), INPUT_POS
, COLS
-q
.size()-8);
1651 input
.setvalue(defl
);
1653 r
= input
.getvalue();
1655 if(r
.rfind("/") != -1) {
1656 selector
.setstartpoint(r
.substr(0, r
.find("/")));
1663 int icqface::getlastinputkey() const {
1664 return input
.getlastkey();
1667 void catqstr(string
&q
, int option
, int defl
) {
1668 char c
= q
[q
.size()-1];
1669 if(!strchr("(/", c
)) q
+= '/';
1672 case ASK_YES
: q
+= 'y'; break;
1673 case ASK_NO
: q
+= 'n'; break;
1674 case ASK_CANCEL
: q
+= 'c'; break;
1677 if(defl
== option
) q
[q
.size()-1] = toupper(q
[q
.size()-1]);
1680 int icqface::ask(string q
, int options
, int deflt
) {
1682 screenarea
sa(0, INPUT_POS
, COLS
, INPUT_POS
);
1685 if(options
& ASK_YES
) catqstr(q
, ASK_YES
, deflt
);
1686 if(options
& ASK_NO
) catqstr(q
, ASK_NO
, deflt
);
1687 if(options
& ASK_CANCEL
) catqstr(q
, ASK_CANCEL
, deflt
);
1690 attrset(conf
.getcolor(cp_status
));
1691 mvhline(INPUT_POS
, 0, ' ', COLS
);
1692 kwriteatf(0, INPUT_POS
, conf
.getcolor(cp_status
), "%s", q
.c_str());
1694 for(ret
= -1; ret
== -1; ) {
1698 if(options
& ASK_YES
) ret
= ASK_YES
;
1702 if(options
& ASK_NO
) ret
= ASK_NO
;
1706 if(options
& ASK_CANCEL
) ret
= ASK_CANCEL
;
1709 if(deflt
!= -1) ret
= deflt
;
1718 void icqface::saveworkarea() {
1720 chtype
**workareabuf
= (chtype
**) malloc(sizeof(chtype
*) * (sizeWArea
.y2
-sizeWArea
.y1
+1));
1722 for(i
= 0; i
<= sizeWArea
.y2
-sizeWArea
.y1
; i
++) {
1723 workareabuf
[i
] = (chtype
*) malloc(sizeof(chtype
) * (sizeWArea
.x2
-sizeWArea
.x1
+2));
1724 mvinchnstr(sizeWArea
.y1
+i
, sizeWArea
.x1
, workareabuf
[i
], sizeWArea
.x2
-sizeWArea
.x1
+1);
1727 workareas
.add(workareabuf
);
1730 void icqface::restoreworkarea() {
1732 chtype
**workareabuf
= (chtype
**) workareas
.at(workareas
.count
-1);
1734 if(workareabuf
&& !dotermresize
) {
1735 for(i
= 0; i
<= sizeWArea
.y2
-sizeWArea
.y1
; i
++) {
1736 mvaddchnstr(sizeWArea
.y1
+i
, sizeWArea
.x1
,
1737 workareabuf
[i
], sizeWArea
.x2
-sizeWArea
.x1
+1);
1743 workareas
.remove(workareas
.count
-1);
1746 void icqface::clearworkarea() {
1749 attrset(conf
.getcolor(cp_main_text
));
1750 for(i
= sizeWArea
.y1
+1; i
< sizeWArea
.y2
; i
++) {
1751 mvhline(i
, sizeWArea
.x1
+1, ' ', sizeWArea
.x2
-sizeWArea
.x1
-1);
1756 void icqface::freeworkareabuf(void *p
) {
1757 chtype
**workareabuf
= (chtype
**) p
;
1759 for(int i
= 0; i
<= face
.sizeWArea
.y2
-face
.sizeWArea
.y1
; i
++) {
1760 free((chtype
*) workareabuf
[i
]);
1767 void icqface::workarealine(int l
, chtype c
) {
1768 attrset(conf
.getcolor(cp_main_frame
));
1769 mvhline(l
, sizeWArea
.x1
+1, c
, sizeWArea
.x2
-sizeWArea
.x1
-1);
1772 void icqface::modelist(contactstatus cs
) {
1777 vector
<imcontact
>::iterator ic
;
1782 db
.setwindow(new textwindow(sizeWArea
.x1
+1, sizeWArea
.y1
+2, sizeWArea
.x2
,
1783 sizeWArea
.y2
, conf
.getcolor(cp_main_text
), TW_NOBORDER
));
1785 db
.setmenu(new verticalmenu(conf
.getcolor(cp_main_text
),
1786 conf
.getcolor(cp_main_selected
)));
1788 db
.setbar(new horizontalbar(conf
.getcolor(cp_main_highlight
),
1789 conf
.getcolor(cp_main_selected
),
1790 _("Details"), _("Add"), _("Remove"), _("Move to contacts"), (char*)0));
1793 db
.idle
= &dialogidle
;
1794 db
.addkey(KEY_IC
, 1);
1795 db
.addkey(KEY_DC
, 2);
1798 workarealine(sizeWArea
.y1
+2);
1799 workarealine(sizeWArea
.y2
-2);
1801 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
, conf
.getcolor(cp_main_highlight
),
1802 cs
== csignore
? _("Ignore list") :
1803 cs
== csvisible
? _("Visible list") :
1804 cs
== csinvisible
? _("Invisible list") : "");
1806 set
<protocolname
> ps
;
1807 if(cs
== csvisible
|| cs
== csinvisible
) {
1808 for(protocolname pname
= icq
; pname
!= protocolname_size
; pname
++)
1809 if(gethook(pname
).getCapabs().count(hookcapab::visibility
))
1813 lst
.fillmenu(db
.getmenu(), cs
);
1815 while(db
.open(i
, b
)) {
1816 if(!db
.getmenu()->getcount() && b
!= 1) continue;
1817 if(b
!= 1) it
= lst
.menuat(i
-1);
1821 cicq
.userinfo(it
.getdesc());
1826 if(multicontacts(_("Select contacts to add to the list"), ps
, cs
)) {
1829 if(cs
== csignore
) {
1831 snprintf(buf
, sizeof(buf
), _("Remove the %d contacts from the contact list as well?"), muins
.size());
1832 removecl
= face
.ask(buf
, ASK_YES
| ASK_NO
, ASK_NO
) == ASK_YES
;
1835 for(ic
= muins
.begin(); ic
!= muins
.end(); ++ic
) {
1836 lst
.push_back(modelistitem(clist
.get(*ic
)->getdispnick(), *ic
, cs
));
1838 if(removecl
&& cs
== csignore
)
1842 lst
.fillmenu(db
.getmenu(), cs
);
1843 db
.getmenu()->redraw();
1847 lst
.del(it
.getdesc(), cs
);
1848 lst
.fillmenu(db
.getmenu(), cs
);
1849 db
.getmenu()->redraw();
1852 if(c
= cicq
.addcontact(it
.getdesc())) {
1853 c
->setdispnick(it
.getnick());
1854 lst
.del(it
.getdesc(), cs
);
1855 lst
.fillmenu(db
.getmenu(), cs
);
1856 db
.getmenu()->redraw();
1861 face
.relaxedupdate();
1868 bool icqface::multicontacts(const string
&ahead
,
1869 const set
<protocolname
> &protos
, contactstatus cs
) {
1871 int i
, savefirst
, saveelem
, prevgid
;
1872 bool ret
= true, finished
= false;
1873 string head
= ahead
;
1876 vector
<imcontact
>::iterator c
, cc
;
1877 vector
<imcontact
> mlst
;
1879 map
<int, bool> groupcheck
;
1882 verticalmenu
m(sizeWArea
.x1
+1, sizeWArea
.y1
+3, sizeWArea
.x2
, sizeWArea
.y2
,
1883 conf
.getcolor(cp_main_text
), conf
.getcolor(cp_main_selected
));
1888 workarealine(sizeWArea
.y1
+2);
1890 if(!head
.size()) head
= _("Event recipients");
1891 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
, conf
.getcolor(cp_main_highlight
), head
);
1893 vector
<icqgroup
>::iterator ig
= groups
.begin();
1895 while(ig
!= groups
.end()) {
1896 for(i
= 0; i
< clist
.count
; i
++) {
1897 icqcontact
*c
= (icqcontact
*) clist
.at(i
);
1898 imcontact desc
= c
->getdesc();
1901 if(c
->getgroupid() == ig
->getid() || conf
.getgroupmode() == icqconf::nogroups
)
1902 if(protos
.empty() || protos
.count(desc
.pname
))
1903 if(!lst
.inlist(desc
, cs
))
1904 mlst
.push_back(desc
);
1911 m
.otherkeys
= &multiplekeys
;
1914 m
.getpos(saveelem
, savefirst
);
1919 for(c
= mlst
.begin(); c
!= mlst
.end(); ++c
) {
1920 cont
= (icqcontact
*) clist
.get(*c
);
1922 if(conf
.getgroupmode() != icqconf::nogroups
)
1923 if(cont
->getgroupid() != prevgid
) {
1924 prevgid
= cont
->getgroupid();
1926 if(groupcheck
.find(prevgid
) == groupcheck
.end())
1927 groupcheck
[prevgid
] = false;
1929 m
.additemf(conf
.getcolor(cp_main_highlight
), 0, "\002[%c]\002\002 %s",
1930 groupcheck
[prevgid
] ? 'x' : ' ',
1931 groups
.getname(prevgid
).c_str());
1934 m
.additemf(conf
.getprotcolor(c
->pname
), cont
, " [%c] %s",
1935 find(muins
.begin(), muins
.end(), *c
) != muins
.end() ? 'x' : ' ',
1936 cont
->getdispnick().c_str());
1939 m
.setpos(saveelem
, savefirst
);
1943 if(m
.getref(m
.getpos())) {
1944 ic
= ((icqcontact
*) m
.getref(m
.getpos()))->getdesc();
1945 c
= find(muins
.begin(), muins
.end(), ic
);
1947 if(c
!= muins
.end()) muins
.erase(c
);
1948 else muins
.push_back(ic
);
1950 cont
= clist
.get(ic
);
1951 groupcheck
[cont
->getgroupid()] = false;
1955 int gid
= ((icqcontact
*) m
.getref(m
.getpos()+1))->getgroupid();
1956 groupcheck
[gid
] = !groupcheck
[gid
];
1958 for(c
= mlst
.begin(); c
!= mlst
.end(); ++c
) {
1959 cont
= (icqcontact
*) clist
.get(*c
);
1961 if(cont
->getgroupid() == gid
) {
1963 cc
= find(muins
.begin(), muins
.end(), *c
);
1965 if(groupcheck
[gid
] && cc
== muins
.end()) {
1966 muins
.push_back(*c
);
1967 } else if(!groupcheck
[gid
] && cc
!= muins
.end()) {
1970 } else if(been
) break;
1992 void icqface::log(const char *fmt
, ...) {
1997 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
2002 void icqface::log(const string
&atext
) {
2004 string text
= atext
;
2008 flog
<< text
<< endl
;
2010 /*! Add a timestamp if needed
2014 conf
.getlogoptions(lts
, lo
);
2018 if(ispunct(text
[0]) && isspace(text
[1]) && !isspace(text
[2])) {
2022 strftime(stime
, 64, conf
.getlogtimestampformat(), localtime(&t
));
2023 text
.insert(2, stime
);
2026 while((i
= text
.find("\n")) != -1) text
[i
] = ' ';
2027 while((i
= text
.find("\r")) != -1) text
[i
] = ' ';
2029 while((lastlog
.size() > LINES
-sizeWArea
.y2
-2) && !lastlog
.empty())
2030 lastlog
.erase(lastlog
.begin());
2032 lastlog
.push_back(text
);
2034 if(!mainscreenblock
&& (sizeWArea
.x2
-sizeWArea
.x1
> 0)) {
2035 chtype
*logline
= new chtype
[sizeWArea
.x2
-sizeWArea
.x1
+2];
2036 attrset(conf
.getcolor(cp_main_text
));
2038 for(i
= sizeWArea
.y2
+2; i
< LINES
-2; i
++) {
2039 mvinchnstr(i
, sizeWArea
.x1
+1, logline
, sizeWArea
.x2
-sizeWArea
.x1
);
2040 mvaddchnstr(i
-1, sizeWArea
.x1
+1, logline
, sizeWArea
.x2
-sizeWArea
.x1
);
2045 if(text
.size() > sizeWArea
.x2
-sizeWArea
.x1
-2) text
.resize(sizeWArea
.x2
-sizeWArea
.x1
-2);
2046 mvhline(LINES
-3, sizeWArea
.x1
+2, ' ', sizeWArea
.x2
-sizeWArea
.x1
-2);
2047 kwriteatf(sizeWArea
.x1
+2, LINES
-3, conf
.getcolor(cp_main_text
), "%s", text
.c_str());
2051 void icqface::status(const string
&text
) {
2055 if(!fstatus
.empty()) fstatus
.pop_back();
2056 if(!fstatus
.empty()) t
= fstatus
.back();
2058 } else if(t
== "#") {
2059 if(!fstatus
.empty()) t
= fstatus
.back();
2062 fstatus
.push_back(t
);
2063 while(fstatus
.size() > 5)
2064 fstatus
.erase(fstatus
.begin());
2068 attrset(conf
.getcolor(cp_status
));
2069 mvhline(LINES
-1, 0, ' ', COLS
);
2070 kwriteatf(0, LINES
-1, conf
.getcolor(cp_status
), "%s", t
.c_str());
2073 void icqface::status(const char *fmt
, ...) {
2078 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
2079 status((string
) buf
);
2083 void icqface::blockmainscreen() {
2084 mainscreenblock
= true;
2087 void icqface::unblockmainscreen() {
2088 mainscreenblock
= false;
2092 void icqface::quickfind(verticalmenu
*multi
) {
2094 string nick
, disp
, upnick
, upcurrent
;
2095 string::iterator is
;
2096 int k
, i
, len
, lx
, ly
;
2099 verticalmenu
*cm
= (multi
? multi
: &mcontacts
->menu
);
2101 status(_("QuickSearch: type to find, %s find again, Enter finish"),
2102 getstatkey(key_quickfind
, section_contact
).c_str());
2104 xtermtitle(_("contact list quick search"));
2107 lx
= sizeWArea
.x1
+2;
2114 for(fin
= false; !fin
; ) {
2115 attrset(conf
.getcolor(cp_main_frame
));
2116 mvhline(ly
, lx
, HLINE
, 23);
2118 if(disp
.size() > 18) disp
.replace(0, disp
.size()-18, "");
2119 kwriteatf(lx
, ly
, conf
.getcolor(cp_main_highlight
), "[ %s ]", disp
.c_str());
2120 kgotoxy(lx
+2+disp
.size(), ly
);
2124 switch(k
= getkey()) {
2132 if(!nick
.empty()) nick
.resize(nick
.size()-1);
2137 if(isprint(k
) || (key2action(k
, section_contact
) == key_quickfind
)) {
2138 i
= cm
->getpos() + (multi
? 1 : 2);
2145 for(is
= nick
.begin(), upnick
= ""; is
!= nick
.end(); ++is
)
2146 upnick
+= toupper(*is
);
2154 if(i
> cm
->getcount()) {
2164 if(!multi
&& mcontacts
->isnode(i
)) {
2167 c
= (icqcontact
*) mcontacts
->getref(i
);
2169 c
= (icqcontact
*) cm
->getref(i
);
2172 if((intptr_t) c
> 100) {
2173 string current
= c
->getdispnick();
2174 len
= current
.size();
2175 if(len
> nick
.size()) len
= nick
.size();
2178 for(is
= current
.begin(), upcurrent
= "";
2179 is
!= current
.end(); ++is
)
2180 upcurrent
+= toupper(*is
);
2182 if(upnick
== upcurrent
) {
2183 cm
->setpos(i
- (multi
? 0 : 1));
2189 if(!multi
) mcontacts
->redraw();
2196 attrset(conf
.getcolor(cp_main_frame
));
2197 mvhline(ly
, lx
, HLINE
, 23);
2200 void icqface::extracturls(const string
&buf
) {
2204 const char *pp
= buf
.c_str();
2206 extractedurls
.clear();
2207 if(!regcomp(&r
, "(http://[^ \t\n]+|https://[^ \t\n]+|ftp://[^ \t\n]+|www\\.[^ \t\n]+)", REG_EXTENDED
)) {
2208 while(!regexec(&r
, buf
.substr(pos
).c_str(), 1, rm
, 0)) {
2209 extractedurls
.push_back(buf
.substr(pos
+rm
[0].rm_so
, rm
[0].rm_eo
-rm
[0].rm_so
));
2216 void icqface::showextractedurls() {
2217 if(extractedurls
.empty()) {
2218 log(_("+ no URLs within the current context"));
2221 vector
<string
>::iterator i
;
2222 verticalmenu
m(sizeWArea
.x1
+1, sizeWArea
.y1
+3, sizeWArea
.x2
, sizeWArea
.y2
,
2223 conf
.getcolor(cp_main_text
), conf
.getcolor(cp_main_selected
));
2227 workarealine(sizeWArea
.y1
+2);
2229 mainw
.writef(sizeWArea
.x1
+2, sizeWArea
.y1
,
2230 conf
.getcolor(cp_main_highlight
),
2231 _("URLs within the current context"));
2233 for(i
= extractedurls
.begin(); i
!= extractedurls
.end(); ++i
)
2234 m
.additem(" " + *i
);
2237 conf
.execaction("openurl", extractedurls
[n
-1]);
2243 void icqface::userinfoexternal(const imcontact
&ic
) {
2244 vector
<pair
<int, string
> > r
= external
.getlist(imexternal::aomanual
, ic
.pname
);
2247 log(_("+ no external actions defined for %s"), conf
.getprotocolname(ic
.pname
).c_str());
2250 verticalmenu
m(conf
.getcolor(cp_main_text
), conf
.getcolor(cp_main_selected
));
2252 m
.setwindow(textwindow(sizeWArea
.x1
, sizeWArea
.y1
, sizeWArea
.x1
+27, sizeWArea
.y1
+9, conf
.getcolor(cp_main_text
)));
2255 vector
<pair
<int, string
> >::const_iterator ir
= r
.begin();
2256 while(ir
!= r
.end()) {
2257 m
.additem((string(" ") + ir
->second
).c_str());
2267 snprintf(cbuf
, sizeof(cbuf
), _("Result of the external action %s:"),
2268 (r
.begin()+i
-1)->second
.c_str());
2271 external
.execmanual(ic
, i
-1, buf
);
2274 imnotification
ev(ic
, (string
) cbuf
+ "\n\n" + buf
);
2276 eventview(&ev
, vector
<eventviewresult
>(), true);
2283 void icqface::showeventbottom(const imcontact
&ic
) {
2284 const char *text
= ischannel(ic
) ?
2285 _("%s send, %s multi, %s/%s pr/nxt chat, %s hist, %s URLs, %s expand, %s memb") :
2286 _("%s send, %s multi, %s/%s pr/nxt chat, %s hist, %s URLs, %s expand, %s info");
2289 getstatkey(key_send_message
, section_editor
).c_str(),
2290 getstatkey(key_multiple_recipients
, section_editor
).c_str(),
2291 getstatkey(key_prev_chat
, section_editor
).c_str(),
2292 getstatkey(key_next_chat
, section_editor
).c_str(),
2293 getstatkey(key_history
, section_editor
).c_str(),
2294 getstatkey(key_show_urls
, section_editor
).c_str(),
2295 getstatkey(key_fullscreen
, section_editor
).c_str(),
2296 getstatkey(key_info
, section_editor
).c_str());
2299 bool icqface::eventedit(imevent
&ev
) {
2305 editdone
= r
= false;
2306 passinfo
= ev
.getcontact();
2308 editor
.addscheme(cp_main_text
, cp_main_text
, 0, 0);
2309 editor
.otherkeys
= &editmsgkeys
;
2310 editor
.idle
= &editidle
;
2312 editor
.smarttab
= false;
2313 editor
.emacs
= conf
.getemacs();
2318 peerinfo(2, ev
.getcontact());
2320 mainw
.writef(sizeWArea
.x1
+2, sizeWArea
.y1
, conf
.getcolor(cp_main_highlight
),
2321 _("Outgoing %s"), streventname(ev
.gettype()));
2323 showeventbottom(ev
.getcontact());
2325 if(ev
.gettype() == imevent::message
) {
2326 editor
.setcoords(sizeWArea
.x1
+2, sizeWArea
.y1
+3, sizeWArea
.x2
, sizeWArea
.y2
);
2328 immessage
*m
= static_cast<immessage
*>(&ev
);
2329 editor
.load(msg
= m
->gettext(), "");
2335 /* TODO, should we relly use a pointer here ? */
2336 char *p
= editor
.save("\r\n");
2337 *m
= immessage(ev
.getcontact(), imevent::outgoing
, p
);
2339 if(c
= clist
.get(ev
.getcontact()))
2340 c
->setpostponed(r
? "" : p
);
2343 } else if(ev
.gettype() == imevent::xml
) {
2344 editor
.setcoords(sizeWArea
.x1
+2, sizeWArea
.y1
+3, sizeWArea
.x2
, sizeWArea
.y2
);
2347 imxmlevent
*m
= static_cast<imxmlevent
*>(&ev
);
2348 editor
.load(msg
= m
->gettext(), "");
2354 char *p
= editor
.save("\r\n");
2355 m
->setfield("text", p
);
2358 if(ev
.getcontact().pname
== livejournal
)
2359 if(!setljparams(m
)){
2364 if(c
= clist
.get(ev
.getcontact()))
2365 c
->setpostponed(r
? "" : p
);
2371 } else if(ev
.gettype() == imevent::url
) {
2372 static textinputline urlinp
;
2373 imurl
*m
= static_cast<imurl
*>(&ev
);
2375 urlinp
.setvalue(m
->geturl());
2376 urlinp
.setcoords(sizeWArea
.x1
+2, sizeWArea
.y1
+3, sizeWArea
.x2
-sizeWArea
.x1
-2);
2377 urlinp
.setcolor(conf
.getcolor(cp_main_highlight
));
2378 urlinp
.idle
= &textinputidle
;
2380 workarealine(sizeWArea
.y1
+4);
2384 string url
= urlinp
.getlastkey() != KEY_ESC
? urlinp
.getvalue() : "";
2387 editor
.setcoords(sizeWArea
.x1
+2, sizeWArea
.y1
+5, sizeWArea
.x2
, sizeWArea
.y2
);
2388 editor
.load(m
->getdescription(), "");
2393 char *p
= editor
.save("\r\n");
2394 *m
= imurl(ev
.getcontact(), imevent::outgoing
, url
, p
);
2398 } else if(ev
.gettype() == imevent::sms
) {
2399 imsms
*m
= static_cast<imsms
*>(&ev
);
2401 editor
.setcoords(sizeWArea
.x1
+2, sizeWArea
.y1
+3, sizeWArea
.x2
, sizeWArea
.y2
);
2402 editor
.load(msg
= m
->getmessage(), "");
2407 auto_ptr
<char> p(editor
.save("\r\n"));
2408 *m
= imsms(ev
.getcontact(), imevent::outgoing
, p
.get(), m
->getphone());
2410 if(c
= clist
.get(ev
.getcontact()))
2411 c
->setpostponed(r
? "" : p
.get());
2413 } else if(ev
.gettype() == imevent::authorization
) {
2414 imauthorization
*m
= static_cast<imauthorization
*>(&ev
);
2416 if (gethook(ev
.getcontact().pname
).getCapabs().count(hookcapab::authreqwithmessages
)) {
2417 editor
.setcoords(sizeWArea
.x1
+2, sizeWArea
.y1
+3, sizeWArea
.x2
, sizeWArea
.y2
);
2418 editor
.load(msg
= m
->getmessage(), "");
2420 char *p
= editor
.save("\r\n");
2421 *m
= imauthorization(ev
.getcontact(), imevent::outgoing
, imauthorization::Request
, p
);
2425 *m
= imauthorization(ev
.getcontact(), imevent::outgoing
, imauthorization::Request
, "");
2430 } else if(ev
.gettype() == imevent::contacts
) {
2431 imcontacts
*m
= static_cast<imcontacts
*>(&ev
);
2434 vector
<imcontact
> smuins
= muins
;
2435 vector
<imcontact
>::iterator imc
;
2437 vector
< pair
<unsigned int, string
> > clst
;
2438 vector
< pair
<unsigned int, string
> >::const_iterator icc
;
2442 for(icc
= m
->getcontacts().begin(); icc
!= m
->getcontacts().end(); ++icc
) {
2444 cont
.pname
= ev
.getcontact().pname
;
2446 if(icc
->first
) cont
.uin
= icc
->first
; else
2447 cont
.nickname
= icc
->second
;
2449 muins
.push_back(cont
);
2452 set
<protocolname
> ps
;
2453 ps
.insert(ev
.getcontact().pname
);
2454 r
= multicontacts(_("Send contacts.."), ps
);
2456 for(imc
= muins
.begin(); imc
!= muins
.end(); ++imc
) {
2458 icqcontact
*cc
= clist
.get(*imc
);
2459 if(cc
) imc
->nickname
= cc
->getnick();
2462 clst
.push_back(make_pair(imc
->uin
, imc
->nickname
));
2467 *m
= imcontacts(ev
.getcontact(), imevent::outgoing
, clst
);
2469 } else if(ev
.gettype() == imevent::file
) {
2472 bool finished
= false, floop
= true;
2473 vector
<imfile::record
>::const_iterator ir
;
2475 imfile
*m
= static_cast<imfile
*>(&ev
);
2477 db
.setwindow(new textwindow(sizeWArea
.x1
+1, sizeWArea
.y1
+2, sizeWArea
.x2
,
2478 sizeWArea
.y2
, conf
.getcolor(cp_main_text
), TW_NOBORDER
));
2479 db
.setmenu(new verticalmenu(conf
.getcolor(cp_main_menu
),
2480 conf
.getcolor(cp_main_selected
)));
2481 db
.setbar(new horizontalbar(conf
.getcolor(cp_main_highlight
),
2482 conf
.getcolor(cp_main_selected
),
2483 _("Add"), _("Remove"), _("Send"), (char*)0));
2485 db
.addkey(KEY_IC
, 0);
2486 db
.addkey(KEY_DC
, 1);
2489 db
.idle
= &dialogidle
;
2493 workarealine(sizeWArea
.y1
+2);
2494 workarealine(sizeWArea
.y2
-2);
2496 while(!finished
&& !r
) {
2497 db
.getmenu()->clear();
2499 for(ir
= m
->getfiles().begin(); ir
!= m
->getfiles().end(); ++ir
)
2500 db
.getmenu()->additemf(" %s", ir
->fname
.c_str());
2506 finished
= !db
.open(mitem
, baritem
);
2510 vector
<imfile::record
> files
= m
->getfiles();
2514 if((msg
= inputfile(_("file name: "))).size()) {
2517 if(!stat(msg
.c_str(), &st
)) {
2520 fr
.size
= st
.st_size
;
2521 files
.push_back(fr
);
2526 if(mitem
> 0 && mitem
<= m
->getfiles().size())
2527 files
.erase(files
.begin()+mitem
-1);
2545 string
icqface::extracttime(const imevent
&ev
) {
2551 ds1
= time2str(&(t
= ev
.gettimestamp()), conf
.gettimestampformat(), buf
);
2552 ds2
= time2str(&(ts
= ev
.getsenttimestamp()), conf
.gettimestampformat(), buf
);
2556 if(tdiff
< 0) tdiff
*= -1;
2559 if(ds1
!= ds2
) r
+= (string
) "[" + ds2
+ "] ";
2564 void icqface::renderchathistory() {
2565 int count
, chatmargin
;
2570 vector
<imevent
*> events
;
2571 typedef pair
<imevent::imdirection
, vector
<string
> > histentry
;
2572 vector
<histentry
> toshow
;
2573 vector
<histentry
>::iterator ir
;
2574 vector
<string
>::reverse_iterator il
;
2576 static imevent
*lastev
= 0;
2579 passevent
= lastev
= 0;
2583 icqcontact
*c
= clist
.get(passinfo
);
2588 if(!stat((c
->getdirname() + "history").c_str(), &st
)) {
2589 count
= st
.st_size
-chatlines
*(sizeWArea
.x2
-sizeWArea
.x1
)*2;
2590 if(count
< 0) count
= 0;
2593 // Skip history items that won't be displayed
2594 c
->sethistoffset(count
);
2595 if (chatlastread
== 0) chatlastread
= 1;
2598 events
= em
.getevents(passinfo
, chatlastread
);
2600 lastread
= c
->getlastread();
2603 c
->setlastread(events
.back()->gettimestamp());
2606 while(events
.size() > chatlines
) {
2607 delete events
.front();
2608 events
.erase(events
.begin());
2611 while(events
.size()) {
2612 if(events
.back()->getdirection() == imevent::incoming
) {
2613 if(events
.back()->gettimestamp() > lastread
) {
2614 if(events
.back()->gettype() == imevent::authorization
2615 || events
.back()->gettype() == imevent::contacts
2616 || events
.back()->gettype() == imevent::file
) {
2618 fin
= enough
= false;
2621 while(!fin
&& !enough
)
2622 cicq
.readevent(*events
.back(), enough
, fin
);
2629 if(count
< chatlines
) {
2630 text
= extracttime(*events
.back());
2631 text
+= events
.back()->gettext();
2632 chatlastread
= events
.back()->gettimestamp()-1;
2635 h
.first
= events
.back()->getdirection();
2636 breakintolines(text
, h
.second
, sizeWArea
.x2
-sizeWArea
.x1
-2);
2637 toshow
.push_back(h
);
2640 if(h
.first
== imevent::incoming
) {
2641 passevent
= lastev
= events
.back()->getevent();
2645 count
+= h
.second
.size();
2648 delete events
.back();
2652 chatmargin
= sizeWArea
.y1
+chatlines
;
2653 text
= string(sizeWArea
.x2
-sizeWArea
.x1
-2, ' ');
2655 attrset(conf
.getcolor(cp_main_text
));
2656 for(count
= 0; count
< chatlines
; count
++)
2657 mvprintw(chatmargin
-count
, sizeWArea
.x1
+2, "%s", text
.c_str());
2659 for(count
= 0, ir
= toshow
.begin(); ir
!= toshow
.end() && count
< chatlines
; ++ir
) {
2661 case imevent::incoming
:
2662 attrset(conf
.getcolor(cp_main_history_incoming
));
2664 case imevent::outgoing
:
2665 attrset(conf
.getcolor(cp_main_history_outgoing
));
2669 for(il
= ir
->second
.rbegin(); il
!= ir
->second
.rend() && count
< chatlines
; ++il
) {
2670 kgotoxy(sizeWArea
.x1
+2, chatmargin
-count
);
2676 peerinfo(chatlines
+1, passinfo
);
2679 void icqface::peerinfo(int line
, const imcontact
&ic
) {
2680 workarealine(sizeWArea
.y1
+line
);
2682 icqcontact
*c
= clist
.get(ic
);
2685 string text
= conf
.getprotocolname(passinfo
.pname
) + " " + c
->getdispnick();
2686 int maxsize
= sizeWArea
.x2
-sizeWArea
.x1
-10;
2689 if(text
.size() > maxsize
) {
2690 text
.erase(maxsize
);
2695 if(pgpon
= pgp
.enabled(passinfo
))
2696 text
+= string(4, ' ');
2700 text
+= " OTR: " + otr
.is_verified(ic
.pname
, c
->getnick()) + " " + otr
.get_msg_state(ic
.pname
, c
->getnick());
2703 text
= (string
) "[ " + text
+ " ]";
2705 kwriteatf(sizeWArea
.x2
-text
.size()-1, sizeWArea
.y1
+line
,
2706 conf
.getcolor(cp_main_text
), "%s", text
.c_str());
2709 kwriteatf(sizeWArea
.x2
-6, sizeWArea
.y1
+line
,
2710 conf
.getcolor(cp_main_highlight
), "PGP");
2714 bool icqface::chat(const imcontact
&ic
) {
2717 vector
<imcontact
>::iterator i
;
2719 int chatlines_diff
= 0; // could get rid of?
2720 bool return_status
= false ;
2721 face
.stay_in_chat
= false ;
2723 icqcontact
*c
= clist
.get(ic
);
2724 if(!c
) return false;
2732 c
->setopenedforchat(true);
2735 muins
.push_back(passinfo
);
2737 // resizing doesn't change the effect, so we work from the bottom, not the top
2738 chatlines_diff
= sizeWArea
.y2
- sizeWArea
.y1
;
2739 chatlines
= conf
.getchatpanelheight();
2740 if( chatlines
== 0 ) { // allow disabling reszing by setting it to zero
2741 chatlines
= (int) (chatlines_diff
*0.75);
2743 chatlines
= chatlines_diff
- chatlines
; // changes where the guide line is
2745 if( chatlines
< MinPanelHeight
) // bottom
2746 chatlines
= (int) (MinPanelHeight
);
2748 if( chatlines
> (chatlines_diff
- MinPanelHeight
)) // top
2749 chatlines
= (int) (chatlines_diff
- MinPanelHeight
) ;
2752 conf
.setchatpanelheight(chatlines_diff
- chatlines
);
2754 // workarealine(sizeWArea.y1+chatlines+1);
2756 editor
.addscheme(cp_main_text
, cp_main_text
, 0, 0);
2757 editor
.otherkeys
= &editmsgkeys
;
2758 editor
.idle
= &editchatidle
;
2760 editor
.smarttab
= false;
2761 editor
.emacs
= conf
.getemacs();
2762 editor
.setcoords(sizeWArea
.x1
+2, sizeWArea
.y1
+chatlines
+2, sizeWArea
.x2
, sizeWArea
.y2
);
2763 editor
.load(c
->getpostponed(), "");
2765 showeventbottom(ic
);
2767 for(bool finished
= false; !finished
&& clist
.get(ic
); ) {
2768 renderchathistory();
2772 auto_ptr
<char> p(editor
.save("\r\n"));
2775 editor
.load("", "");
2778 auto_ptr
<imevent
> ev(new immessage(ic
, imevent::outgoing
, p
.get()));
2780 for(i
= muins
.begin(); i
!= muins
.end(); ++i
) {
2781 ev
.get()->setcontact(*i
);
2782 em
.store(*ev
.get());
2786 muins
.push_back(passinfo
);
2792 c
->setpostponed(editdone
? "" : p
.get());
2795 c
->toggleopenedforchat();
2802 if ( face
.stay_in_chat
== true ) {
2803 return_status
= true;
2804 face
.stay_in_chat
= false;
2807 return return_status
;
2810 icqface::eventviewresult
icqface::eventview(const imevent
*ev
,
2811 vector
<eventviewresult
> abuttons
, bool nobuttons
) {
2813 string title_event
, title_timestamp
, text
;
2814 horizontalbar
*bar
= 0;
2818 static int elem
= 0;
2820 vector
<eventviewresult
> actions
;
2821 vector
<eventviewresult
>::iterator ia
;
2824 if(ev
->gettype() == imevent::message
2825 || ev
->gettype() == imevent::notification
2826 || ev
->gettype() == imevent::xml
) {
2827 actions
.push_back(forward
);
2829 if(ev
->getdirection() == imevent::incoming
)
2830 if(ev
->getcontact().pname
!= rss
/*|| islivejournal(ev->getcontact())*/)
2831 actions
.push_back(reply
);
2833 } else if(ev
->gettype() == imevent::url
) {
2834 actions
.push_back(forward
);
2835 actions
.push_back(open
);
2837 if(ev
->getdirection() == imevent::incoming
) {
2838 actions
.push_back(reply
);
2841 } else if(ev
->gettype() == imevent::sms
) {
2842 if(ev
->getdirection() == imevent::incoming
) {
2843 actions
.push_back(reply
);
2846 } else if(ev
->gettype() == imevent::authorization
) {
2847 if(ev
->getdirection() == imevent::incoming
) {
2848 actions
.push_back(info
);
2849 actions
.push_back(accept
);
2850 actions
.push_back(reject
);
2853 } else if(ev
->gettype() == imevent::contacts
) {
2854 actions
.push_back(info
);
2855 actions
.push_back(add
);
2857 } else if(ev
->gettype() == imevent::email
) {
2858 actions
.push_back(forward
);
2860 } else if(ev
->gettype() == imevent::file
) {
2861 actions
.push_back(info
);
2863 if(gethook(ev
->getcontact().pname
).knowntransfer(*static_cast<const imfile
*>(ev
))) {
2864 actions
.push_back(accept
);
2865 actions
.push_back(reject
);
2871 actions
.push_back(ok
);
2872 copy(abuttons
.begin(), abuttons
.end(), back_inserter(actions
));
2874 switch(ev
->getdirection()) {
2875 case imevent::outgoing
:
2876 title_event
= _("Outgoing %s to %s");
2877 title_timestamp
= _("Sent on %s");
2879 case imevent::incoming
:
2880 title_event
= _("Incoming %s from %s");
2881 title_timestamp
= _("Received on %s");
2887 db
.setwindow(new textwindow(sizeWArea
.x1
+1, sizeWArea
.y1
+3, sizeWArea
.x2
,
2888 sizeWArea
.y2
, conf
.getcolor(cp_main_text
), TW_NOBORDER
));
2890 db
.setbar(bar
= new horizontalbar(conf
.getcolor(cp_main_highlight
),
2891 conf
.getcolor(cp_main_selected
), 0));
2893 bar
->item
= actions
.size()-1;
2895 for(ia
= actions
.begin(); ia
!= actions
.end(); ++ia
)
2896 bar
->items
.push_back(geteventviewresult(*ia
));
2898 mainw
.writef(sizeWArea
.x1
+2, sizeWArea
.y1
, conf
.getcolor(cp_main_highlight
),
2899 title_event
.c_str(), streventname(ev
->gettype()), ev
->getcontact().totext().c_str());
2901 mainw
.writef(sizeWArea
.x1
+2, sizeWArea
.y1
+1, conf
.getcolor(cp_main_highlight
),
2902 title_timestamp
.c_str(), extracttime(*ev
).c_str());
2906 if(ev
->gettype() == imevent::contacts
) {
2907 const imcontacts
*m
= static_cast<const imcontacts
*>(ev
);
2909 db
.setmenu(new verticalmenu(conf
.getcolor(cp_main_menu
),
2910 conf
.getcolor(cp_main_selected
)));
2912 vector
< pair
<unsigned int, string
> > lst
= m
->getcontacts();
2913 vector
< pair
<unsigned int, string
> >::const_iterator il
;
2915 for(il
= lst
.begin(); il
!= lst
.end(); ++il
) {
2916 db
.getmenu()->additemf(" %s", il
->second
.c_str());
2919 db
.getmenu()->setpos(elem
-1);
2922 text
= ev
->gettext();
2923 db
.setbrowser(new textbrowser(conf
.getcolor(cp_main_text
)));
2924 db
.getbrowser()->setbuf(text
);
2927 status(_("%s to URLs, %s to full-screenize, %s close"),
2928 getstatkey(key_show_urls
, section_history
).c_str(),
2929 getstatkey(key_fullscreen
, section_history
).c_str(),
2930 getstatkey(key_quit
, section_editor
).c_str());
2936 workarealine(sizeWArea
.y1
+3);
2937 workarealine(sizeWArea
.y2
-2);
2939 db
.otherkeys
= &eventviewkeys
;
2940 db
.idle
= &dialogidle
;
2944 if(db
.open(mitem
, baritem
)) {
2945 r
= actions
[baritem
];
2963 void icqface::fullscreenize(const imevent
*ev
) {
2964 textwindow
w(0, 1, COLS
, LINES
-1, conf
.getcolor(cp_main_text
), TW_NOBORDER
);
2965 textbrowser
tb(0, 4, COLS
, LINES
-1, conf
.getcolor(cp_main_text
));
2968 char buf
[512], *fmt
= 0;
2969 vector
<string
> lines
;
2970 vector
<string
>::const_iterator il
;
2974 switch(ev
->getdirection()) {
2975 case imevent::incoming
: fmt
= _("%s from %s, received on %s"); break;
2976 case imevent::outgoing
: fmt
= _("%s to %s, sent on %s"); break;
2979 snprintf(buf
, sizeof(buf
), fmt
, streventname(ev
->gettype()),
2980 ev
->getcontact().totext().c_str(),
2981 strdateandtime(ev
->gettimestamp()).c_str());
2983 w
.write(0, 1, conf
.getcolor(cp_main_highlight
), buf
);
2985 xtermtitle((string
) _("full-screen view") + " " + buf
);
2987 tb
.setbuf(ev
->gettext());
2991 status(_("%s or %s to close, Up/Down and PgUp/PgDn to scroll"),
2992 getstatkey(key_quit
, section_editor
).c_str(),
2993 getstatkey(key_fullscreen
, section_editor
).c_str());
2995 tb
.idle
= &textbrowseridle
;
2996 tb
.otherkeys
= &fullscreenkeys
;
2999 unblockmainscreen();
3005 void icqface::histmake(const vector
<imevent
*> &hist
) {
3006 vector
<imevent
*>::const_reverse_iterator i
;
3015 for(i
= hist
.rbegin(); i
!= hist
.rend(); ++i
) {
3020 t
= ev
.gettimestamp();
3021 ts
= ev
.getsenttimestamp();
3022 text
= (string
) + " " + time2str(&t
, conf
.gettimestampformat(), buf
) + " ";
3024 text
+= (string
) + "[" + time2str(&ts
, conf
.gettimestampformat(), buf
) + "] ";
3025 text
+= ev
.gettext();
3027 if(ev
.getdirection() == imevent::incoming
) {
3028 color
= conf
.getcolor(cp_main_history_incoming
);
3029 } else if(ev
.getdirection() == imevent::outgoing
) {
3030 color
= conf
.getcolor(cp_main_history_outgoing
);
3033 mhist
.additem(color
, (void *) *i
, text
);
3037 bool icqface::histexec(imevent
*&im
) {
3046 if(!mhist
.empty()) {
3047 db
.setwindow(new textwindow(sizeWArea
.x1
+1, sizeWArea
.y1
+2, sizeWArea
.x2
,
3048 sizeWArea
.y2
, conf
.getcolor(cp_main_text
), TW_NOBORDER
));
3050 db
.setmenu(&mhist
, false);
3054 * Now set the menu position
3058 for(k
= 0; k
< mhist
.getcount(); k
++) {
3059 imevent
*rim
= static_cast<imevent
*> (mhist
.getref(k
));
3066 db
.idle
= &dialogidle
;
3067 db
.otherkeys
= &historykeys
;
3073 workarealine(sizeWArea
.y1
+2);
3075 im
= static_cast<imevent
*> (mhist
.getref(0));
3077 snprintf(buf
, sizeof(buf
), _("History for %s, %d events total"),
3078 im
->getcontact().totext().c_str(),
3081 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
, conf
.getcolor(cp_main_highlight
), buf
);
3083 status(_("%s search, %s again, %s cancel"),
3084 getstatkey(key_search
, section_history
).c_str(),
3085 getstatkey(key_search_again
, section_history
).c_str(),
3086 getstatkey(key_quit
, section_editor
).c_str());
3092 sub
= face
.inputstr(_("search for: "), sub
);
3093 if(input
.getlastkey() == KEY_ESC
) break;
3096 for(k
= mhist
.getpos()+1; k
< mhist
.getcount(); k
++) {
3097 im
= static_cast<imevent
*> (mhist
.getref(k
));
3099 if(im
->contains(sub
)) {
3111 if(mhist
.getref(k
-1)) {
3112 im
= static_cast<imevent
*> (mhist
.getref(k
-1));
3130 // ----------------------------------------------------------------------------
3132 void icqface::menuidle(verticalmenu
&m
) {
3135 if(face
.dotermresize
) {
3136 if(&m
== &face
.mcontacts
->menu
) {
3138 face
.dotermresize
= false;
3144 void icqface::dialogidle(dialogbox
&caller
) {
3148 void icqface::textbrowseridle(textbrowser
&b
) {
3152 void icqface::transferidle(dialogbox
&b
) {
3153 time_t tstart
= time(0);
3155 while(!cicq
.idle(HIDL_SOCKEXIT
)) {
3156 if(time(0)-tstart
> 3) {
3157 b
.gettree()->menu
.abort();
3163 string
icqface::getstatkey(int key
, int section
) const {
3166 string keys
= action2key(key
, section
);
3168 while((key2
= action2key(key
, section
, i
)) != "") {
3176 string
icqface::getmenuitem(string mtext
, int width
, int key
, int section
) {
3178 string text
= " " + mtext
+ " ";
3179 string keyname
= action2key(key
, section
);
3181 int s
= keyname
.size()+text
.size();
3186 while ((key2
= action2key(key
, section
, i
)) != "" && (s
+= key2
.size()+1) < width
) {
3187 keyname
+= "/" + key2
;
3191 for (s
= keyname
.size()+text
.size(); s
< width
; s
++)
3199 int icqface::key2action(int k
, int s
) {
3200 for(vector
<icqconf::keybinding
>::size_type i
= 0; i
< icqconf::keys
.size(); i
++)
3201 if(k
== icqconf::keys
[i
].key
&& s
== icqconf::keys
[i
].section
)
3202 return icqconf::keys
[i
].action
;
3207 string
icqface::action2key(int a
, int s
, int n
) const {
3210 std::ostringstream o
;
3214 vector
<icqconf::keybinding
>::size_type i
= 0;
3216 for( ; i
< icqconf::keys
.size(); i
++)
3217 if(a
== icqconf::keys
[i
].action
&& s
== icqconf::keys
[i
].section
) {
3223 if (i
== icqconf::keys
.size())
3225 else if(icqconf::keys
[i
].key
== '\r')
3227 else if(icqconf::keys
[i
].key
== ' ')
3229 else if(icqconf::keys
[i
].key
== '/')
3231 else if(icqconf::keys
[i
].key
== ALT('\r'))
3233 else if(icqconf::keys
[i
].key
== CTRL(' '))
3235 else if(icqconf::keys
[i
].key
== ALT(' '))
3237 else if(icqconf::keys
[i
].key
== 339)
3239 else if(icqconf::keys
[i
].key
== 338)
3241 else if(icqconf::keys
[i
].key
== 9)
3243 else if(icqconf::keys
[i
].key
== 27)
3245 else if(icqconf::keys
[i
].key
== 331)
3247 else if(icqconf::keys
[i
].key
== KEY_DC
)
3249 else if(icqconf::keys
[i
].alt
&& icqconf::keys
[i
].ctrl
)
3250 o
<< "F" << (icqconf::keys
[i
].key
-KEY_F0
);
3251 else if(icqconf::keys
[i
].alt
)
3252 o
<< "alt-" << (char)icqconf::keys
[i
].key
;
3253 else if(icqconf::keys
[i
].ctrl
)
3254 o
<< "^" << (char)(icqconf::keys
[i
].key
+64);
3256 o
<< (char)icqconf::keys
[i
].key
;
3262 ret
= string(o
.str(), o
.pcount());
3269 int icqface::contactskeys(verticalmenu
&m
, int k
) {
3270 icqcontact
*c
= NULL
;
3272 int id
= face
.mcontacts
->getid(face
.mcontacts
->menu
.getpos());
3273 if(id
!= -1 && ! face
.mcontacts
->isnode(id
))
3274 c
= (icqcontact
*) face
.mcontacts
->getref(m
.getpos()+1);
3276 set
<hookcapab::enumeration
> capab
;
3281 if(c
->getdesc() != contactroot
) {
3282 capab
= gethook(c
->getdesc().pname
).getCapabs();
3285 switch(face
.key2action(k
, section_contact
)) {
3287 face
.extk
= ACT_INFO
;
3291 face
.extk
= ACT_REMOVE
;
3295 if (conf
.getaskquit())
3296 if(face
.ask("Really Quit?", ASK_YES
| ASK_NO
, ASK_NO
) == ASK_NO
)
3298 face
.extk
= ACT_QUIT
;
3302 if(capab
.count(hookcapab::urls
))
3303 face
.extk
= ACT_URL
;
3306 case key_change_status
:
3307 face
.extk
= ACT_STATUS
;
3311 face
.extk
= ACT_HISTORY
;
3315 face
.extk
= ACT_DUMMY
;
3316 face
.next_chat(true);
3320 face
.extk
= ACT_DUMMY
;
3321 face
.next_chat(false);
3324 case key_add
: face
.extk
= ACT_ADD
; break;
3326 case key_send_contact
:
3327 if(capab
.count(hookcapab::contacts
))
3328 face
.extk
= ACT_CONTACT
;
3331 if(c
&& c
->getdesc().pname
== rss
)
3332 face
.extk
= ACT_PING
;
3335 case key_fetch_away_message
:
3336 if(capab
.count(hookcapab::fetchaway
))
3337 face
.extk
= ACT_FETCHAWAY
;
3341 face
.extk
= ACT_MENU
;
3344 case key_general_menu
:
3345 face
.extk
= ACT_GMENU
;
3348 case key_hide_offline
:
3349 face
.extk
= ACT_HIDEOFFLINE
;
3352 case key_contact_external_action
:
3353 if(!ischannel(c
) && c
)
3354 face
.extk
= ACT_EXTERN
;
3358 if(!ischannel(c
) && c
)
3359 face
.extk
= ACT_RENAME
;
3363 if(capab
.count(hookcapab::version
))
3364 face
.extk
= ACT_VERSION
;
3368 if(!ischannel(c
) && c
)
3369 face
.extk
= ACT_EDITUSER
;
3373 if(c
) face
.extk
= ACT_IGNORE
;
3376 case key_left_panel_move_right
:
3377 face
.leftpanelwidth_inc(1);
3381 case key_left_panel_move_left
:
3382 face
.leftpanelwidth_inc(-1);
3386 case key_log_panel_move_up
:
3387 face
.logpanelheight_inc(1);
3391 case key_log_panel_move_down
:
3392 face
.logpanelheight_inc(-1);
3396 case key_quickfind
: face
.extk
= ACT_QUICKFIND
; break;
3399 if(face
.extk
&& face
.key2action(k
, section_contact
) != -1) {
3400 return m
.getpos()+1;
3406 int icqface::multiplekeys(verticalmenu
&m
, int k
) {
3416 if(face
.key2action(k
, section_contact
) == key_quickfind
)
3422 int icqface::findpgpkeys(dialogbox
&db
, int k
) {
3425 r
= face
.key2action(k
, section_contact
);
3434 string
icqface::getprotocolchar(protocolname pname
) const {
3435 static const string pprefixes
[protocolname_size
] = {
3436 "i", "y", "m", "a", "#", "j", "r", "l", "g", "n"
3439 if(pname
> protocolname_size
)
3442 return pprefixes
[pname
];
3445 int icqface::historykeys(dialogbox
&db
, int k
) {
3448 switch(face
.key2action(k
, section_history
)) {
3451 case key_search_again
:
3460 int icqface::editmsgkeys(texteditor
&e
, int k
) {
3463 if(k
== '\r' && conf
.getentersends(face
.passinfo
.pname
)) {
3465 face
.editdone
= strlen(p
);
3467 if(face
.editdone
) return -1; else return 0;
3470 switch(face
.key2action(k
, section_editor
)) {
3471 case key_send_message
:
3473 face
.editdone
= strlen(p
);
3475 if(face
.editdone
) return -1; else break;
3476 case key_multiple_recipients
:
3477 face
.multicontacts("");
3480 cicq
.history(face
.passinfo
);
3483 face
.editdone
= false;
3484 face
.next_chat(false);
3487 face
.editdone
= false;
3488 face
.next_chat(true);
3491 face
.editdone
= false;
3492 face
.next_chat(false);
3493 face
.last_selected
= (icqcontact
* ) clist
.at(0);
3496 cicq
.userinfo(face
.passinfo
);
3499 face
.showextractedurls(); break;
3500 case key_fullscreen
:
3502 face
.fullscreenize(face
.passevent
);
3504 case key_chat_panel_move_up
:
3505 face
.chatpanelheight_inc(1);
3506 face
.stay_in_chat
= true;
3509 case key_chat_panel_move_down
:
3510 face
.chatpanelheight_inc(-1);
3511 face
.stay_in_chat
= true;
3516 case key_otr_start_session
:
3517 otr
.start_session(face
.last_selected
);
3518 face
.stay_in_chat
= true;
3521 case key_otr_end_session
:
3522 otr
.end_session(face
.last_selected
);
3523 face
.stay_in_chat
= true;
3535 int icqface::userinfokeys(dialogbox
&db
, int k
) {
3536 switch(face
.key2action(k
, section_info
)) {
3537 case key_show_urls
: face
.showextractedurls(); break;
3538 case key_user_external_action
: face
.userinfoexternal(face
.passinfo
); break;
3544 int icqface::eventviewkeys(dialogbox
&db
, int k
) {
3545 switch(face
.key2action(k
, section_history
)) {
3547 face
.showextractedurls();
3549 case key_fullscreen
:
3550 face
.fullscreenize(face
.passevent
);
3559 int icqface::findreskeys(dialogbox
&db
, int k
) {
3560 if(face
.key2action(k
, section_contact
) == key_quickfind
)
3566 int icqface::statuskeys(verticalmenu
&m
, int k
) {
3567 char *status_order
= "o_adnlcfi"; // Shortcuts for status
3568 char *p
= strchr(status_order
, k
);
3570 return (1 + p
- status_order
);
3574 int icqface::fullscreenkeys(textbrowser
&m
, int k
) {
3575 switch(face
.key2action(k
, section_editor
)) {
3576 case key_fullscreen
:
3583 void icqface::editidle(texteditor
&e
) {
3587 void icqface::editchatidle(texteditor
&e
) {
3590 cicq
.idle(HIDL_SOCKEXIT
);
3592 if(c
= clist
.get(face
.passinfo
))
3593 if(c
->hasevents()) {
3594 face
.renderchathistory();
3598 void icqface::textinputidle(textinputline
&il
) {
3602 void icqface::termresize(void) {
3603 face
.dotermresize
= true;
3606 void icqface::relaxedupdate() {
3610 bool icqface::updaterequested() {
3614 void icqface::redraw() {
3615 if(!mainscreenblock
) {
3621 * Terminal resize specific
3624 vector
<string
> flog
;
3625 vector
<string
>::iterator il
;
3629 flog
= face
.lastlog
;
3630 face
.lastlog
.clear();
3633 conf
.getlogoptions(lts
, lo
);
3634 conf
.setlogoptions(false, lo
);
3636 for(il
= flog
.begin() ; il
!= flog
.end(); ++il
)
3639 conf
.setlogoptions(lts
, lo
);
3641 doredraw
= fneedupdate
= false;
3643 doredraw
= fneedupdate
= true;
3647 void icqface::xtermtitle(const string
&text
) {
3648 if(conf
.getxtitles()) {
3649 string term
= getenv("TERM") ? getenv("TERM") : "";
3651 if(term
== "xterm" || term
== "Eterm" || term
== "aterm"
3652 || term
== "rxvt" || term
.substr(0, 6) == "screen")
3653 cout
<< "\x1b]1;\x07\x1b]0;" << "centerim" << (text
.empty() ? "" : (string
) ": " + text
) << "\x07" << flush
;
3657 void icqface::xtermtitle(const char *fmt
, ...) {
3658 if(conf
.getxtitles()) {
3663 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
3664 xtermtitle((string
) buf
);
3669 void icqface::xtermtitlereset() {
3670 if(conf
.getxtitles()) {
3671 const char *p
= getenv("TERM");
3672 if(p
) xtermtitle((string
) p
);
3676 // ----------------------------------------------------------------------------
3678 icqface::icqprogress::icqprogress() {
3682 icqface::icqprogress::~icqprogress() {
3686 void icqface::icqprogress::log(const char *fmt
, ...) {
3691 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
3694 if(curline
>= face
.sizeDlg
.height
-1) {
3699 w
->write(2, 1+curline
++, buf
);
3702 void icqface::icqprogress::show(const string
&title
) {
3704 w
= new textwindow(0, 0, face
.sizeDlg
.width
, face
.sizeDlg
.height
,
3705 conf
.getcolor(cp_dialog_frame
), TW_CENTERED
);
3708 w
->set_title(conf
.getcolor(cp_dialog_highlight
), title
);
3714 void icqface::icqprogress::hide() {
3718 void icqface::leftpanelwidth_inc(const int inc
) {
3719 int i
= conf
.getleftpanelwidth();
3720 if ( ((i
+inc
) >= MinPanelWidth
) && ((i
+inc
) <= (COLS
- MinPanelWidth
))) {
3721 conf
.setleftpanelwidth(i
+inc
);
3722 dotermresize
= true ;
3726 void icqface::logpanelheight_inc(const int inc
) {
3727 int i
= conf
.getlogpanelheight();
3728 if (((i
+inc
) >= MinPanelHeight
) && ((i
+inc
) <= (LINES
- MinPanelHeight
))) {
3729 conf
.setlogpanelheight(i
+inc
);
3730 dotermresize
= true ;
3734 void icqface::chatpanelheight_inc(const int inc
) {
3735 chatlines
= conf
.getchatpanelheight()+inc
;
3736 conf
.setchatpanelheight(chatlines
);