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 buf
+= _("Server-based contact");
1143 buf
+= _("Awaiting authorization");
1147 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+15, conf
.getcolor(cp_main_highlight
), buf
);
1150 void icqface::infohome(dialogbox
&db
, icqcontact
*c
) {
1153 icqcontact::basicinfo bi
= c
->getbasicinfo();
1154 icqcontact::moreinfo mi
= c
->getmoreinfo();
1156 workarealine(sizeWArea
.y1
+10);
1159 mainw
.write(x
, sizeWArea
.y1
+2, conf
.getcolor(cp_main_highlight
), _("Address"));
1160 mainw
.write(x
, sizeWArea
.y1
+3, conf
.getcolor(cp_main_highlight
), _("Location"));
1161 mainw
.write(x
, sizeWArea
.y1
+4, conf
.getcolor(cp_main_highlight
), _("Zip code"));
1162 mainw
.write(x
, sizeWArea
.y1
+5, conf
.getcolor(cp_main_highlight
), _("Phone"));
1163 mainw
.write(x
, sizeWArea
.y1
+6, conf
.getcolor(cp_main_highlight
), _("Fax"));
1164 mainw
.write(x
, sizeWArea
.y1
+7, conf
.getcolor(cp_main_highlight
), _("Cellular"));
1165 mainw
.write(x
, sizeWArea
.y1
+8, conf
.getcolor(cp_main_highlight
), _("Timezone"));
1167 mainw
.write(x
, sizeWArea
.y1
+10, conf
.getcolor(cp_main_highlight
), _("Homepage"));
1169 if(!bi
.state
.empty()) {
1170 if(bi
.city
.size()) bi
.city
+= ", ";
1171 bi
.city
+= bi
.state
;
1175 if(bi
.city
.size()) bi
.city
+= ", ";
1176 bi
.city
+= abstracthook::getCountryIDtoString(bi
.country
);
1180 mainw
.write(x
, sizeWArea
.y1
+2, conf
.getcolor(cp_main_text
), bi
.street
);
1181 mainw
.write(x
, sizeWArea
.y1
+3, conf
.getcolor(cp_main_text
), bi
.city
);
1182 mainw
.write(x
, sizeWArea
.y1
+4, conf
.getcolor(cp_main_text
), bi
.zip
);
1183 mainw
.write(x
, sizeWArea
.y1
+5, conf
.getcolor(cp_main_text
), bi
.phone
);
1184 mainw
.write(x
, sizeWArea
.y1
+6, conf
.getcolor(cp_main_text
), bi
.fax
);
1185 mainw
.write(x
, sizeWArea
.y1
+7, conf
.getcolor(cp_main_text
), bi
.cellular
);
1186 mainw
.write(x
, sizeWArea
.y1
+8, conf
.getcolor(cp_main_text
), mi
.strtimezone());
1188 for(i
= 0; !mi
.homepage
.empty(); i
++) {
1189 mainw
.write(x
, sizeWArea
.y1
+10+i
, conf
.getcolor(cp_main_text
),
1190 mi
.homepage
.substr(0, sizeWArea
.x2
-sizeWArea
.x1
-12));
1191 mi
.homepage
.erase(0, sizeWArea
.x2
-sizeWArea
.x1
-12);
1195 void icqface::infowork(dialogbox
&db
, icqcontact
*c
) {
1197 icqcontact::workinfo wi
= c
->getworkinfo();
1199 workarealine(sizeWArea
.y1
+6);
1200 workarealine(sizeWArea
.y1
+11);
1202 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+2, conf
.getcolor(cp_main_highlight
), _("Address"));
1203 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+3, conf
.getcolor(cp_main_highlight
), _("Location"));
1204 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+4, conf
.getcolor(cp_main_highlight
), _("Zip code"));
1206 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+6, conf
.getcolor(cp_main_highlight
), _("Company"));
1207 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+7, conf
.getcolor(cp_main_highlight
), _("Department"));
1208 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+8, conf
.getcolor(cp_main_highlight
), _("Title"));
1210 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+11, conf
.getcolor(cp_main_highlight
), _("Phone"));
1211 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+12, conf
.getcolor(cp_main_highlight
), _("Fax"));
1212 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+13, conf
.getcolor(cp_main_highlight
), _("Homepage"));
1214 if(!wi
.state
.empty()) {
1215 if(wi
.city
.size()) wi
.city
+= ", ";
1216 wi
.city
+= wi
.state
;
1220 if(wi
.city
.size()) wi
.city
+= ", ";
1221 wi
.city
+= abstracthook::getCountryIDtoString(wi
.country
);
1224 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+2, conf
.getcolor(cp_main_text
), wi
.street
);
1225 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+3, conf
.getcolor(cp_main_text
), wi
.city
);
1226 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+4, conf
.getcolor(cp_main_text
), wi
.zip
);
1227 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+6, conf
.getcolor(cp_main_text
), wi
.company
);
1228 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+7, conf
.getcolor(cp_main_text
), wi
.dept
);
1229 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+8, conf
.getcolor(cp_main_text
), wi
.position
);
1230 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+11, conf
.getcolor(cp_main_text
), wi
.phone
);
1231 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+12, conf
.getcolor(cp_main_text
), wi
.fax
);
1233 for(i
= 0; !wi
.homepage
.empty(); i
++) {
1234 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+13+i
, conf
.getcolor(cp_main_text
),
1235 wi
.homepage
.substr(0, sizeWArea
.x2
-sizeWArea
.x1
-14));
1236 wi
.homepage
.erase(0, sizeWArea
.x2
-sizeWArea
.x1
-14);
1240 void icqface::infoabout(dialogbox
&db
, icqcontact
*c
) {
1241 db
.getbrowser()->setbuf(c
->getabout());
1244 void icqface::infointerests(dialogbox
&db
, icqcontact
*c
) {
1246 vector
<string
> data
;
1247 vector
<string
>::iterator i
;
1249 data
= c
->getinterests();
1252 text
+= (string
) "* " + _("Interests") + "\n";
1254 for(i
= data
.begin(); i
!= data
.end(); ++i
) {
1255 text
+= " + " + *i
+ "\n";
1261 data
= c
->getbackground();
1264 text
+= (string
) "* " + _("Background") + "\n";
1266 for(i
= data
.begin(); i
!= data
.end(); ++i
)
1267 text
+= " + " + *i
+ "\n";
1271 db
.getbrowser()->setbuf(text
);
1274 void icqface::inforss(dialogbox
&db
, icqcontact
*c
) {
1275 icqcontact::basicinfo bi
= c
->getbasicinfo();
1276 icqcontact::moreinfo mi
= c
->getmoreinfo();
1277 icqcontact::workinfo wi
= c
->getworkinfo();
1279 workarealine(sizeWArea
.y1
+7);
1280 workarealine(sizeWArea
.y1
+10);
1282 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+2, conf
.getcolor(cp_main_highlight
), _("Handle"));
1283 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+3, conf
.getcolor(cp_main_highlight
), _("RSS doc"));
1284 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+4, conf
.getcolor(cp_main_highlight
), _("Version"));
1285 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+5, conf
.getcolor(cp_main_highlight
), _("Encoding"));
1287 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+7, conf
.getcolor(cp_main_highlight
), _("Title"));
1288 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+8, conf
.getcolor(cp_main_highlight
), _("Link"));
1290 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+10, conf
.getcolor(cp_main_highlight
), _("Frequency"));
1291 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+11, conf
.getcolor(cp_main_highlight
), _("Last check"));
1292 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+12, conf
.getcolor(cp_main_highlight
), _("Next check"));
1293 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+13, conf
.getcolor(cp_main_highlight
), _("Last result"));
1295 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+2, conf
.getcolor(cp_main_text
), c
->getnick());
1296 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+3, conf
.getcolor(cp_main_text
), wi
.homepage
);
1297 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+4, conf
.getcolor(cp_main_text
), bi
.city
);
1298 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+5, conf
.getcolor(cp_main_text
), bi
.state
);
1300 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+7, conf
.getcolor(cp_main_text
), bi
.fname
);
1301 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+8, conf
.getcolor(cp_main_text
), mi
.homepage
);
1303 string freq
, last
, next
;
1307 snprintf(buf
, sizeof(buf
), _("%lu minutes"), mi
.checkfreq
);
1309 if(mi
.checklast
) next
= strdateandtime(mi
.checklast
+mi
.checkfreq
*60);
1310 else next
= _("Now");
1312 freq
= next
= _("Never");
1315 if(mi
.checklast
) last
= strdateandtime(mi
.checklast
);
1316 else last
= _("Never");
1318 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+10, conf
.getcolor(cp_main_text
), freq
);
1319 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+11, conf
.getcolor(cp_main_text
), last
);
1320 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+12, conf
.getcolor(cp_main_text
), next
);
1321 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+13, conf
.getcolor(cp_main_text
), bi
.lname
);
1324 void icqface::infoljrss(dialogbox
&db
, icqcontact
*c
) {
1325 icqcontact::basicinfo bi
= c
->getbasicinfo();
1326 icqcontact::moreinfo mi
= c
->getmoreinfo();
1328 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+2, conf
.getcolor(cp_main_highlight
), _("Birthdate"));
1329 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
+3, conf
.getcolor(cp_main_highlight
), _("Full name"));
1331 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+2, conf
.getcolor(cp_main_text
), mi
.strbirthdate());
1332 mainw
.write(sizeWArea
.x1
+14, sizeWArea
.y1
+3, conf
.getcolor(cp_main_text
), bi
.email
);
1335 void icqface::userinfo(const imcontact
&cinfo
, const imcontact
&realinfo
) {
1336 bool finished
= false, showinfo
;
1337 textbrowser
tb(conf
.getcolor(cp_main_text
));
1341 imcontact savepassinfo
= passinfo
;
1342 icqcontact
*c
= clist
.get(passinfo
= realinfo
);
1348 status(_("%s to URLs, %s external actions, %s close"),
1349 getstatkey(key_show_urls
, section_info
).c_str(),
1350 getstatkey(key_user_external_action
, section_info
).c_str(),
1351 getstatkey(key_quit
, section_editor
).c_str());
1353 xtermtitle(_("user info for %s"), realinfo
.totext().c_str());
1355 db
.setwindow(new textwindow(sizeWArea
.x1
+1, sizeWArea
.y1
+2, sizeWArea
.x2
,
1356 sizeWArea
.y2
, conf
.getcolor(cp_main_text
), TW_NOBORDER
));
1358 if(cinfo
.pname
== rss
) {
1359 if(c
->inlist() && realinfo
!= contactroot
) {
1360 db
.setbar(new horizontalbar(sizeWArea
.x1
+2, sizeWArea
.y2
-1,
1361 conf
.getcolor(cp_main_highlight
), conf
.getcolor(cp_main_selected
),
1362 _("Info"), _("About"), _("Check"), _("Edit"), islivejournal(c
) ? _("LJ") : 0, (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"), _("About"), _("Retreive"), (char*)0));
1369 } else if(cinfo
.pname
== livejournal
) {
1370 db
.setbar(new horizontalbar(sizeWArea
.x1
+2, sizeWArea
.y2
-1,
1371 conf
.getcolor(cp_main_highlight
), conf
.getcolor(cp_main_selected
),
1372 _("Info"), _("Friend of"), (char*)0));
1376 db
.setbar(new horizontalbar(sizeWArea
.x1
+2, sizeWArea
.y2
-1,
1377 conf
.getcolor(cp_main_highlight
), conf
.getcolor(cp_main_selected
),
1378 _("Info"), _("Home"), _("Work"), _("More"), _("About"),
1379 cinfo
.pname
!= infocard
? _("Retrieve") : _("Edit"), (char*)0));
1385 db
.idle
= &dialogidle
;
1386 db
.otherkeys
= &userinfokeys
;
1390 if(cicq
.idle(HIDL_SOCKEXIT
)) {
1391 finished
= !db
.open(k
, b
);
1392 showinfo
= !finished
;
1403 infoclear(db
, c
, cinfo
);
1405 if(cinfo
.pname
== rss
) switch(b
) {
1406 case 0: inforss(db
, c
); break;
1408 db
.setbrowser(&tb
, false);
1410 infoclear(db
, c
, cinfo
);
1413 gethook(cinfo
.pname
).ping(c
);
1417 updatedetails(c
, c
->getdesc().pname
);
1421 case 4: infoljrss(db
, c
); break;
1423 } else if(cinfo
.pname
== livejournal
) switch(b
) {
1424 case 0: infolivejournal(db
, c
); break;
1426 db
.setbrowser(&tb
, false);
1428 infoclear(db
, c
, cinfo
);
1432 case 0: infogeneral(db
, c
); break;
1433 case 1: infohome(db
, c
); break;
1434 case 2: infowork(db
, c
); break;
1436 db
.setbrowser(&tb
, false);
1437 infointerests(db
, c
);
1438 infoclear(db
, c
, cinfo
);
1441 db
.setbrowser(&tb
, false);
1443 infoclear(db
, c
, cinfo
);
1446 switch(cinfo
.pname
) {
1453 gethook(cinfo
.pname
).requestinfo(cinfo
);
1471 passinfo
= savepassinfo
;
1474 void icqface::makeprotocolmenu(verticalmenu
&m
) {
1475 icqconf::imaccount ia
;
1476 protocolname ipname
;
1478 static const string pitems
[protocolname_size
] = {
1479 _(" [icq] ICQ network"),
1481 _(" [msn] M$ Messenger"),
1482 _(" [aim] AOL TOC"),
1486 _(" [lj] LiveJournal"),
1487 _(" [gg] Gadu-Gadu"),
1491 for(ipname
= icq
; ipname
!= protocolname_size
; ipname
++) {
1492 ia
= conf
.getourid(ipname
);
1495 m
.additem(0, ipname
, pitems
[ipname
]);
1500 bool icqface::changestatus(vector
<protocolname
> &pnames
, imstatus
&st
) {
1501 int i
, choice
, protcount
;
1502 bool r
, alrlogged
= false;
1503 verticalmenu
m(conf
.getcolor(cp_main_text
), conf
.getcolor(cp_main_selected
));
1505 vector
<imstatus
> mst
;
1506 vector
<imstatus
>::iterator im
;
1507 protocolname pname
, onechoice
;
1509 m
.setwindow(textwindow(sizeWArea
.x1
, sizeWArea
.y1
, sizeWArea
.x1
+27,
1510 sizeWArea
.y1
+9, conf
.getcolor(cp_main_text
)));
1514 for(protcount
= 0, pname
= icq
; pname
!= protocolname_size
; pname
++) {
1515 if(!conf
.getourid(pname
).empty()) {
1520 alrlogged
= alrlogged
|| gethook(pname
).getstatus() != offline
;
1528 m
.additem(0, -1, _(" All protocols"));
1529 if(alrlogged
) m
.additem(0, -2, _(" Already logged in only"));
1531 makeprotocolmenu(m
);
1535 choice
= (intptr_t) m
.getref(i
-1);
1543 for(pname
= icq
; pname
!= protocolname_size
; pname
++)
1544 if(!conf
.getourid(pname
).empty())
1545 pnames
.push_back(pname
);
1548 for(pname
= icq
; pname
!= protocolname_size
; pname
++)
1549 if(!conf
.getourid(pname
).empty())
1550 if(gethook(pname
).getstatus() != offline
)
1551 pnames
.push_back(pname
);
1554 pnames
.push_back((protocolname
) choice
);
1560 mst
.push_back(available
);
1561 mst
.push_back(offline
);
1562 mst
.push_back(away
);
1563 mst
.push_back(dontdisturb
);
1564 mst
.push_back(notavail
);
1565 mst
.push_back(outforlunch
);
1566 mst
.push_back(occupied
);
1567 mst
.push_back(freeforchat
);
1568 mst
.push_back(invisible
);
1570 for(im
= mst
.begin(); im
!= mst
.end(); ++im
) {
1571 string sst
= (string
) " [" + imstatus2char
[*im
] + "] " + imstatus2str(*im
);
1572 m
.additem(0, *im
, sst
);
1574 if(pnames
.size() == 1)
1575 if(gethook(pnames
.front()).getstatus() == *im
)
1576 m
.setpos(m
.getcount()-1);
1579 if(pnames
.size() > 1) {
1583 m
.otherkeys
= &statuskeys
;
1591 st
= (imstatus
) ((intptr_t) m
.getref(i
-1));
1598 #define INPUT_POS LINES-2
1600 string
icqface::inputstr(const string
&q
, const string
&defl
, char passwdchar
) {
1601 screenarea
sa(0, INPUT_POS
, COLS
, INPUT_POS
);
1603 attrset(conf
.getcolor(cp_status
));
1604 mvhline(INPUT_POS
, 0, ' ', COLS
);
1605 kwriteatf(0, INPUT_POS
, conf
.getcolor(cp_status
), "%s", q
.c_str());
1607 input
.setpasswordchar(passwdchar
);
1608 input
.removeselector();
1609 input
.setvalue(defl
);
1610 input
.setcoords(q
.size(), INPUT_POS
, COLS
-q
.size());
1614 return input
.getvalue();
1617 string
icqface::inputfile(const string
&q
, const string
&defl
) {
1618 screenarea
sa(0, INPUT_POS
, COLS
, INPUT_POS
);
1621 mvhline(INPUT_POS
, 0, ' ', COLS
);
1622 kwriteatf(0, INPUT_POS
, conf
.getcolor(cp_status
), "%s", q
.c_str());
1623 kwriteatf(COLS
-8, INPUT_POS
, conf
.getcolor(cp_status
), "[Ctrl-T]");
1625 selector
.setoptions(0);
1626 selector
.setwindow(textwindow(0, 0, sizeDlg
.width
, sizeDlg
.height
,
1627 conf
.getcolor(cp_dialog_frame
), TW_CENTERED
,
1628 conf
.getcolor(cp_dialog_highlight
),
1629 _(" <Space> or <Enter> confirm, <Esc> cancel ")));
1631 input
.connectselector(selector
);
1633 input
.setcoords(q
.size(), INPUT_POS
, COLS
-q
.size()-8);
1634 input
.setvalue(defl
);
1636 r
= input
.getvalue();
1638 if(r
.rfind("/") != -1) {
1639 selector
.setstartpoint(r
.substr(0, r
.find("/")));
1646 string
icqface::inputdir(const string
&q
, const string
&defl
) {
1647 screenarea
sa(0, INPUT_POS
, COLS
, INPUT_POS
);
1650 mvhline(INPUT_POS
, 0, ' ', COLS
);
1651 kwriteatf(0, INPUT_POS
, conf
.getcolor(cp_status
), "%s", q
.c_str());
1652 kwriteatf(COLS
-8, INPUT_POS
, conf
.getcolor(cp_status
), "[Ctrl-T]");
1654 selector
.setoptions(FSEL_DIRSELECT
);
1655 selector
.setwindow(textwindow(0, 0, sizeDlg
.width
, sizeDlg
.height
,
1656 conf
.getcolor(cp_dialog_frame
), TW_CENTERED
,
1657 conf
.getcolor(cp_dialog_highlight
),
1658 _(" <Space> confirm, <Esc> cancel ")));
1660 input
.connectselector(selector
);
1662 input
.setcoords(q
.size(), INPUT_POS
, COLS
-q
.size()-8);
1663 input
.setvalue(defl
);
1665 r
= input
.getvalue();
1667 if(r
.rfind("/") != -1) {
1668 selector
.setstartpoint(r
.substr(0, r
.find("/")));
1675 int icqface::getlastinputkey() const {
1676 return input
.getlastkey();
1679 void catqstr(string
&q
, int option
, int defl
) {
1680 char c
= q
[q
.size()-1];
1681 if(!strchr("(/", c
)) q
+= '/';
1684 case ASK_YES
: q
+= 'y'; break;
1685 case ASK_NO
: q
+= 'n'; break;
1686 case ASK_CANCEL
: q
+= 'c'; break;
1689 if(defl
== option
) q
[q
.size()-1] = toupper(q
[q
.size()-1]);
1692 int icqface::ask(string q
, int options
, int deflt
) {
1694 screenarea
sa(0, INPUT_POS
, COLS
, INPUT_POS
);
1697 if(options
& ASK_YES
) catqstr(q
, ASK_YES
, deflt
);
1698 if(options
& ASK_NO
) catqstr(q
, ASK_NO
, deflt
);
1699 if(options
& ASK_CANCEL
) catqstr(q
, ASK_CANCEL
, deflt
);
1702 attrset(conf
.getcolor(cp_status
));
1703 mvhline(INPUT_POS
, 0, ' ', COLS
);
1704 kwriteatf(0, INPUT_POS
, conf
.getcolor(cp_status
), "%s", q
.c_str());
1706 for(ret
= -1; ret
== -1; ) {
1710 if(options
& ASK_YES
) ret
= ASK_YES
;
1714 if(options
& ASK_NO
) ret
= ASK_NO
;
1718 if(options
& ASK_CANCEL
) ret
= ASK_CANCEL
;
1721 if(deflt
!= -1) ret
= deflt
;
1730 void icqface::saveworkarea() {
1732 chtype
**workareabuf
= (chtype
**) malloc(sizeof(chtype
*) * (sizeWArea
.y2
-sizeWArea
.y1
+1));
1734 for(i
= 0; i
<= sizeWArea
.y2
-sizeWArea
.y1
; i
++) {
1735 workareabuf
[i
] = (chtype
*) malloc(sizeof(chtype
) * (sizeWArea
.x2
-sizeWArea
.x1
+2));
1736 mvinchnstr(sizeWArea
.y1
+i
, sizeWArea
.x1
, workareabuf
[i
], sizeWArea
.x2
-sizeWArea
.x1
+1);
1739 workareas
.add(workareabuf
);
1742 void icqface::restoreworkarea() {
1744 chtype
**workareabuf
= (chtype
**) workareas
.at(workareas
.count
-1);
1746 if(workareabuf
&& !dotermresize
) {
1747 for(i
= 0; i
<= sizeWArea
.y2
-sizeWArea
.y1
; i
++) {
1748 mvaddchnstr(sizeWArea
.y1
+i
, sizeWArea
.x1
,
1749 workareabuf
[i
], sizeWArea
.x2
-sizeWArea
.x1
+1);
1755 workareas
.remove(workareas
.count
-1);
1758 void icqface::clearworkarea() {
1761 attrset(conf
.getcolor(cp_main_text
));
1762 for(i
= sizeWArea
.y1
+1; i
< sizeWArea
.y2
; i
++) {
1763 mvhline(i
, sizeWArea
.x1
+1, ' ', sizeWArea
.x2
-sizeWArea
.x1
-1);
1768 void icqface::freeworkareabuf(void *p
) {
1769 chtype
**workareabuf
= (chtype
**) p
;
1771 for(int i
= 0; i
<= face
.sizeWArea
.y2
-face
.sizeWArea
.y1
; i
++) {
1772 free((chtype
*) workareabuf
[i
]);
1779 void icqface::workarealine(int l
, chtype c
) {
1780 attrset(conf
.getcolor(cp_main_frame
));
1781 mvhline(l
, sizeWArea
.x1
+1, c
, sizeWArea
.x2
-sizeWArea
.x1
-1);
1784 void icqface::modelist(contactstatus cs
) {
1789 vector
<imcontact
>::iterator ic
;
1794 db
.setwindow(new textwindow(sizeWArea
.x1
+1, sizeWArea
.y1
+2, sizeWArea
.x2
,
1795 sizeWArea
.y2
, conf
.getcolor(cp_main_text
), TW_NOBORDER
));
1797 db
.setmenu(new verticalmenu(conf
.getcolor(cp_main_text
),
1798 conf
.getcolor(cp_main_selected
)));
1800 db
.setbar(new horizontalbar(conf
.getcolor(cp_main_highlight
),
1801 conf
.getcolor(cp_main_selected
),
1802 _("Details"), _("Add"), _("Remove"), _("Move to contacts"), (char*)0));
1805 db
.idle
= &dialogidle
;
1806 db
.addkey(KEY_IC
, 1);
1807 db
.addkey(KEY_DC
, 2);
1810 workarealine(sizeWArea
.y1
+2);
1811 workarealine(sizeWArea
.y2
-2);
1813 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
, conf
.getcolor(cp_main_highlight
),
1814 cs
== csignore
? _("Ignore list") :
1815 cs
== csvisible
? _("Visible list") :
1816 cs
== csinvisible
? _("Invisible list") : "");
1818 set
<protocolname
> ps
;
1819 if(cs
== csvisible
|| cs
== csinvisible
) {
1820 for(protocolname pname
= icq
; pname
!= protocolname_size
; pname
++)
1821 if(gethook(pname
).getCapabs().count(hookcapab::visibility
))
1825 lst
.fillmenu(db
.getmenu(), cs
);
1827 while(db
.open(i
, b
)) {
1828 if(!db
.getmenu()->getcount() && b
!= 1) continue;
1829 if(b
!= 1) it
= lst
.menuat(i
-1);
1833 cicq
.userinfo(it
.getdesc());
1838 if(multicontacts(_("Select contacts to add to the list"), ps
, cs
)) {
1841 if(cs
== csignore
) {
1843 snprintf(buf
, sizeof(buf
), _("Remove the %d contacts from the contact list as well?"), muins
.size());
1844 removecl
= face
.ask(buf
, ASK_YES
| ASK_NO
, ASK_NO
) == ASK_YES
;
1847 for(ic
= muins
.begin(); ic
!= muins
.end(); ++ic
) {
1848 lst
.push_back(modelistitem(clist
.get(*ic
)->getdispnick(), *ic
, cs
));
1850 if(removecl
&& cs
== csignore
)
1854 lst
.fillmenu(db
.getmenu(), cs
);
1855 db
.getmenu()->redraw();
1859 lst
.del(it
.getdesc(), cs
);
1860 lst
.fillmenu(db
.getmenu(), cs
);
1861 db
.getmenu()->redraw();
1864 if(c
= cicq
.addcontact(it
.getdesc())) {
1865 c
->setdispnick(it
.getnick());
1866 lst
.del(it
.getdesc(), cs
);
1867 lst
.fillmenu(db
.getmenu(), cs
);
1868 db
.getmenu()->redraw();
1873 face
.relaxedupdate();
1880 bool icqface::multicontacts(const string
&ahead
,
1881 const set
<protocolname
> &protos
, contactstatus cs
) {
1883 int i
, savefirst
, saveelem
, prevgid
;
1884 bool ret
= true, finished
= false;
1885 string head
= ahead
;
1888 vector
<imcontact
>::iterator c
, cc
;
1889 vector
<imcontact
> mlst
;
1891 map
<int, bool> groupcheck
;
1894 verticalmenu
m(sizeWArea
.x1
+1, sizeWArea
.y1
+3, sizeWArea
.x2
, sizeWArea
.y2
,
1895 conf
.getcolor(cp_main_text
), conf
.getcolor(cp_main_selected
));
1900 workarealine(sizeWArea
.y1
+2);
1902 if(!head
.size()) head
= _("Event recipients");
1903 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
, conf
.getcolor(cp_main_highlight
), head
);
1905 vector
<icqgroup
>::iterator ig
= groups
.begin();
1907 while(ig
!= groups
.end()) {
1908 for(i
= 0; i
< clist
.count
; i
++) {
1909 icqcontact
*c
= (icqcontact
*) clist
.at(i
);
1910 imcontact desc
= c
->getdesc();
1913 if(c
->getgroupid() == ig
->getid() || conf
.getgroupmode() == icqconf::nogroups
)
1914 if(protos
.empty() || protos
.count(desc
.pname
))
1915 if(!lst
.inlist(desc
, cs
))
1916 mlst
.push_back(desc
);
1923 m
.otherkeys
= &multiplekeys
;
1926 m
.getpos(saveelem
, savefirst
);
1931 for(c
= mlst
.begin(); c
!= mlst
.end(); ++c
) {
1932 cont
= (icqcontact
*) clist
.get(*c
);
1934 if(conf
.getgroupmode() != icqconf::nogroups
)
1935 if(cont
->getgroupid() != prevgid
) {
1936 prevgid
= cont
->getgroupid();
1938 if(groupcheck
.find(prevgid
) == groupcheck
.end())
1939 groupcheck
[prevgid
] = false;
1941 m
.additemf(conf
.getcolor(cp_main_highlight
), 0, "\002[%c]\002\002 %s",
1942 groupcheck
[prevgid
] ? 'x' : ' ',
1943 groups
.getname(prevgid
).c_str());
1946 m
.additemf(conf
.getprotcolor(c
->pname
), cont
, " [%c] %s",
1947 find(muins
.begin(), muins
.end(), *c
) != muins
.end() ? 'x' : ' ',
1948 cont
->getdispnick().c_str());
1951 m
.setpos(saveelem
, savefirst
);
1955 if(m
.getref(m
.getpos())) {
1956 ic
= ((icqcontact
*) m
.getref(m
.getpos()))->getdesc();
1957 c
= find(muins
.begin(), muins
.end(), ic
);
1959 if(c
!= muins
.end()) muins
.erase(c
);
1960 else muins
.push_back(ic
);
1962 cont
= clist
.get(ic
);
1963 groupcheck
[cont
->getgroupid()] = false;
1967 int gid
= ((icqcontact
*) m
.getref(m
.getpos()+1))->getgroupid();
1968 groupcheck
[gid
] = !groupcheck
[gid
];
1970 for(c
= mlst
.begin(); c
!= mlst
.end(); ++c
) {
1971 cont
= (icqcontact
*) clist
.get(*c
);
1973 if(cont
->getgroupid() == gid
) {
1975 cc
= find(muins
.begin(), muins
.end(), *c
);
1977 if(groupcheck
[gid
] && cc
== muins
.end()) {
1978 muins
.push_back(*c
);
1979 } else if(!groupcheck
[gid
] && cc
!= muins
.end()) {
1982 } else if(been
) break;
2004 void icqface::log(const char *fmt
, ...) {
2009 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
2014 void icqface::log(const string
&atext
) {
2016 string text
= atext
;
2020 flog
<< text
<< endl
;
2022 /*! Add a timestamp if needed
2026 conf
.getlogoptions(lts
, lo
);
2030 if(ispunct(text
[0]) && isspace(text
[1]) && !isspace(text
[2])) {
2034 strftime(stime
, 64, conf
.getlogtimestampformat(), localtime(&t
));
2035 text
.insert(2, stime
);
2038 while((i
= text
.find("\n")) != -1) text
[i
] = ' ';
2039 while((i
= text
.find("\r")) != -1) text
[i
] = ' ';
2041 while((lastlog
.size() > LINES
-sizeWArea
.y2
-2) && !lastlog
.empty())
2042 lastlog
.erase(lastlog
.begin());
2044 lastlog
.push_back(text
);
2046 if(!mainscreenblock
&& (sizeWArea
.x2
-sizeWArea
.x1
> 0)) {
2047 chtype
*logline
= new chtype
[sizeWArea
.x2
-sizeWArea
.x1
+2];
2048 attrset(conf
.getcolor(cp_main_text
));
2050 for(i
= sizeWArea
.y2
+2; i
< LINES
-2; i
++) {
2051 mvinchnstr(i
, sizeWArea
.x1
+1, logline
, sizeWArea
.x2
-sizeWArea
.x1
);
2052 mvaddchnstr(i
-1, sizeWArea
.x1
+1, logline
, sizeWArea
.x2
-sizeWArea
.x1
);
2057 if(text
.size() > sizeWArea
.x2
-sizeWArea
.x1
-2) text
.resize(sizeWArea
.x2
-sizeWArea
.x1
-2);
2058 mvhline(LINES
-3, sizeWArea
.x1
+2, ' ', sizeWArea
.x2
-sizeWArea
.x1
-2);
2059 kwriteatf(sizeWArea
.x1
+2, LINES
-3, conf
.getcolor(cp_main_text
), "%s", text
.c_str());
2063 void icqface::status(const string
&text
) {
2067 if(!fstatus
.empty()) fstatus
.pop_back();
2068 if(!fstatus
.empty()) t
= fstatus
.back();
2070 } else if(t
== "#") {
2071 if(!fstatus
.empty()) t
= fstatus
.back();
2074 fstatus
.push_back(t
);
2075 while(fstatus
.size() > 5)
2076 fstatus
.erase(fstatus
.begin());
2080 attrset(conf
.getcolor(cp_status
));
2081 mvhline(LINES
-1, 0, ' ', COLS
);
2082 kwriteatf(0, LINES
-1, conf
.getcolor(cp_status
), "%s", t
.c_str());
2085 void icqface::status(const char *fmt
, ...) {
2090 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
2091 status((string
) buf
);
2095 void icqface::blockmainscreen() {
2096 mainscreenblock
= true;
2099 void icqface::unblockmainscreen() {
2100 mainscreenblock
= false;
2104 void icqface::quickfind(verticalmenu
*multi
) {
2106 string nick
, disp
, upnick
, upcurrent
;
2107 string::iterator is
;
2108 int k
, i
, len
, lx
, ly
;
2111 verticalmenu
*cm
= (multi
? multi
: &mcontacts
->menu
);
2113 status(_("QuickSearch: type to find, %s find again, Enter finish"),
2114 getstatkey(key_quickfind
, section_contact
).c_str());
2116 xtermtitle(_("contact list quick search"));
2119 lx
= sizeWArea
.x1
+2;
2126 for(fin
= false; !fin
; ) {
2127 attrset(conf
.getcolor(cp_main_frame
));
2128 mvhline(ly
, lx
, HLINE
, 23);
2130 if(disp
.size() > 18) disp
.replace(0, disp
.size()-18, "");
2131 kwriteatf(lx
, ly
, conf
.getcolor(cp_main_highlight
), "[ %s ]", disp
.c_str());
2132 kgotoxy(lx
+2+disp
.size(), ly
);
2136 switch(k
= getkey()) {
2144 if(!nick
.empty()) nick
.resize(nick
.size()-1);
2149 if(isprint(k
) || (key2action(k
, section_contact
) == key_quickfind
)) {
2150 i
= cm
->getpos() + (multi
? 1 : 2);
2157 for(is
= nick
.begin(), upnick
= ""; is
!= nick
.end(); ++is
)
2158 upnick
+= toupper(*is
);
2166 if(i
> cm
->getcount()) {
2176 if(!multi
&& mcontacts
->isnode(i
)) {
2179 c
= (icqcontact
*) mcontacts
->getref(i
);
2181 c
= (icqcontact
*) cm
->getref(i
);
2184 if((intptr_t) c
> 100) {
2185 string current
= c
->getdispnick();
2186 len
= current
.size();
2187 if(len
> nick
.size()) len
= nick
.size();
2190 for(is
= current
.begin(), upcurrent
= "";
2191 is
!= current
.end(); ++is
)
2192 upcurrent
+= toupper(*is
);
2194 if(upnick
== upcurrent
) {
2195 cm
->setpos(i
- (multi
? 0 : 1));
2201 if(!multi
) mcontacts
->redraw();
2208 attrset(conf
.getcolor(cp_main_frame
));
2209 mvhline(ly
, lx
, HLINE
, 23);
2212 void icqface::extracturls(const string
&buf
) {
2216 const char *pp
= buf
.c_str();
2218 extractedurls
.clear();
2219 if(!regcomp(&r
, "(http://[^ \t\n]+|https://[^ \t\n]+|ftp://[^ \t\n]+|www\\.[^ \t\n]+)", REG_EXTENDED
)) {
2220 while(!regexec(&r
, buf
.substr(pos
).c_str(), 1, rm
, 0)) {
2221 extractedurls
.push_back(buf
.substr(pos
+rm
[0].rm_so
, rm
[0].rm_eo
-rm
[0].rm_so
));
2228 void icqface::showextractedurls() {
2229 if(extractedurls
.empty()) {
2230 log(_("+ no URLs within the current context"));
2233 vector
<string
>::iterator i
;
2234 verticalmenu
m(sizeWArea
.x1
+1, sizeWArea
.y1
+3, sizeWArea
.x2
, sizeWArea
.y2
,
2235 conf
.getcolor(cp_main_text
), conf
.getcolor(cp_main_selected
));
2239 workarealine(sizeWArea
.y1
+2);
2241 mainw
.writef(sizeWArea
.x1
+2, sizeWArea
.y1
,
2242 conf
.getcolor(cp_main_highlight
),
2243 _("URLs within the current context"));
2245 for(i
= extractedurls
.begin(); i
!= extractedurls
.end(); ++i
)
2246 m
.additem(" " + *i
);
2249 conf
.execaction("openurl", extractedurls
[n
-1]);
2255 void icqface::userinfoexternal(const imcontact
&ic
) {
2256 vector
<pair
<int, string
> > r
= external
.getlist(imexternal::aomanual
, ic
.pname
);
2259 log(_("+ no external actions defined for %s"), conf
.getprotocolname(ic
.pname
).c_str());
2262 verticalmenu
m(conf
.getcolor(cp_main_text
), conf
.getcolor(cp_main_selected
));
2264 m
.setwindow(textwindow(sizeWArea
.x1
, sizeWArea
.y1
, sizeWArea
.x1
+27, sizeWArea
.y1
+9, conf
.getcolor(cp_main_text
)));
2267 vector
<pair
<int, string
> >::const_iterator ir
= r
.begin();
2268 while(ir
!= r
.end()) {
2269 m
.additem((string(" ") + ir
->second
).c_str());
2279 snprintf(cbuf
, sizeof(cbuf
), _("Result of the external action %s:"),
2280 (r
.begin()+i
-1)->second
.c_str());
2283 external
.execmanual(ic
, i
-1, buf
);
2286 imnotification
ev(ic
, (string
) cbuf
+ "\n\n" + buf
);
2288 eventview(&ev
, vector
<eventviewresult
>(), true);
2295 void icqface::showeventbottom(const imcontact
&ic
) {
2296 const char *text
= ischannel(ic
) ?
2297 _("%s send, %s multi, %s/%s pr/nxt chat, %s hist, %s URLs, %s expand, %s memb") :
2298 _("%s send, %s multi, %s/%s pr/nxt chat, %s hist, %s URLs, %s expand, %s info");
2301 getstatkey(key_send_message
, section_editor
).c_str(),
2302 getstatkey(key_multiple_recipients
, section_editor
).c_str(),
2303 getstatkey(key_prev_chat
, section_editor
).c_str(),
2304 getstatkey(key_next_chat
, section_editor
).c_str(),
2305 getstatkey(key_history
, section_editor
).c_str(),
2306 getstatkey(key_show_urls
, section_editor
).c_str(),
2307 getstatkey(key_fullscreen
, section_editor
).c_str(),
2308 getstatkey(key_info
, section_editor
).c_str());
2311 bool icqface::eventedit(imevent
&ev
) {
2317 editdone
= r
= false;
2318 passinfo
= ev
.getcontact();
2320 editor
.addscheme(cp_main_text
, cp_main_text
, 0, 0);
2321 editor
.otherkeys
= &editmsgkeys
;
2322 editor
.idle
= &editidle
;
2324 editor
.smarttab
= false;
2325 editor
.emacs
= conf
.getemacs();
2330 peerinfo(2, ev
.getcontact());
2332 mainw
.writef(sizeWArea
.x1
+2, sizeWArea
.y1
, conf
.getcolor(cp_main_highlight
),
2333 _("Outgoing %s"), streventname(ev
.gettype()));
2335 showeventbottom(ev
.getcontact());
2337 if(ev
.gettype() == imevent::message
) {
2338 editor
.setcoords(sizeWArea
.x1
+2, sizeWArea
.y1
+3, sizeWArea
.x2
, sizeWArea
.y2
);
2340 immessage
*m
= static_cast<immessage
*>(&ev
);
2341 editor
.load(msg
= m
->gettext(), "");
2347 /* TODO, should we relly use a pointer here ? */
2348 char *p
= editor
.save("\r\n");
2349 *m
= immessage(ev
.getcontact(), imevent::outgoing
, p
);
2351 if(c
= clist
.get(ev
.getcontact()))
2352 c
->setpostponed(r
? "" : p
);
2355 } else if(ev
.gettype() == imevent::xml
) {
2356 editor
.setcoords(sizeWArea
.x1
+2, sizeWArea
.y1
+3, sizeWArea
.x2
, sizeWArea
.y2
);
2359 imxmlevent
*m
= static_cast<imxmlevent
*>(&ev
);
2360 editor
.load(msg
= m
->gettext(), "");
2366 char *p
= editor
.save("\r\n");
2367 m
->setfield("text", p
);
2370 if(ev
.getcontact().pname
== livejournal
)
2371 if(!setljparams(m
)){
2376 if(c
= clist
.get(ev
.getcontact()))
2377 c
->setpostponed(r
? "" : p
);
2383 } else if(ev
.gettype() == imevent::url
) {
2384 static textinputline urlinp
;
2385 imurl
*m
= static_cast<imurl
*>(&ev
);
2387 urlinp
.setvalue(m
->geturl());
2388 urlinp
.setcoords(sizeWArea
.x1
+2, sizeWArea
.y1
+3, sizeWArea
.x2
-sizeWArea
.x1
-2);
2389 urlinp
.setcolor(conf
.getcolor(cp_main_highlight
));
2390 urlinp
.idle
= &textinputidle
;
2392 workarealine(sizeWArea
.y1
+4);
2396 string url
= urlinp
.getlastkey() != KEY_ESC
? urlinp
.getvalue() : "";
2399 editor
.setcoords(sizeWArea
.x1
+2, sizeWArea
.y1
+5, sizeWArea
.x2
, sizeWArea
.y2
);
2400 editor
.load(m
->getdescription(), "");
2405 char *p
= editor
.save("\r\n");
2406 *m
= imurl(ev
.getcontact(), imevent::outgoing
, url
, p
);
2410 } else if(ev
.gettype() == imevent::sms
) {
2411 imsms
*m
= static_cast<imsms
*>(&ev
);
2413 editor
.setcoords(sizeWArea
.x1
+2, sizeWArea
.y1
+3, sizeWArea
.x2
, sizeWArea
.y2
);
2414 editor
.load(msg
= m
->getmessage(), "");
2419 auto_ptr
<char> p(editor
.save("\r\n"));
2420 *m
= imsms(ev
.getcontact(), imevent::outgoing
, p
.get(), m
->getphone());
2422 if(c
= clist
.get(ev
.getcontact()))
2423 c
->setpostponed(r
? "" : p
.get());
2425 } else if(ev
.gettype() == imevent::authorization
) {
2426 imauthorization
*m
= static_cast<imauthorization
*>(&ev
);
2428 if (gethook(ev
.getcontact().pname
).getCapabs().count(hookcapab::authreqwithmessages
)) {
2429 editor
.setcoords(sizeWArea
.x1
+2, sizeWArea
.y1
+3, sizeWArea
.x2
, sizeWArea
.y2
);
2430 editor
.load(msg
= m
->getmessage(), "");
2432 char *p
= editor
.save("\r\n");
2433 *m
= imauthorization(ev
.getcontact(), imevent::outgoing
, imauthorization::Request
, p
);
2437 *m
= imauthorization(ev
.getcontact(), imevent::outgoing
, imauthorization::Request
, "");
2442 } else if(ev
.gettype() == imevent::contacts
) {
2443 imcontacts
*m
= static_cast<imcontacts
*>(&ev
);
2446 vector
<imcontact
> smuins
= muins
;
2447 vector
<imcontact
>::iterator imc
;
2449 vector
< pair
<unsigned int, string
> > clst
;
2450 vector
< pair
<unsigned int, string
> >::const_iterator icc
;
2454 for(icc
= m
->getcontacts().begin(); icc
!= m
->getcontacts().end(); ++icc
) {
2456 cont
.pname
= ev
.getcontact().pname
;
2458 if(icc
->first
) cont
.uin
= icc
->first
; else
2459 cont
.nickname
= icc
->second
;
2461 muins
.push_back(cont
);
2464 set
<protocolname
> ps
;
2465 ps
.insert(ev
.getcontact().pname
);
2466 r
= multicontacts(_("Send contacts.."), ps
);
2468 for(imc
= muins
.begin(); imc
!= muins
.end(); ++imc
) {
2470 icqcontact
*cc
= clist
.get(*imc
);
2471 if(cc
) imc
->nickname
= cc
->getnick();
2474 clst
.push_back(make_pair(imc
->uin
, imc
->nickname
));
2479 *m
= imcontacts(ev
.getcontact(), imevent::outgoing
, clst
);
2481 } else if(ev
.gettype() == imevent::file
) {
2484 bool finished
= false, floop
= true;
2485 vector
<imfile::record
>::const_iterator ir
;
2487 imfile
*m
= static_cast<imfile
*>(&ev
);
2489 db
.setwindow(new textwindow(sizeWArea
.x1
+1, sizeWArea
.y1
+2, sizeWArea
.x2
,
2490 sizeWArea
.y2
, conf
.getcolor(cp_main_text
), TW_NOBORDER
));
2491 db
.setmenu(new verticalmenu(conf
.getcolor(cp_main_menu
),
2492 conf
.getcolor(cp_main_selected
)));
2493 db
.setbar(new horizontalbar(conf
.getcolor(cp_main_highlight
),
2494 conf
.getcolor(cp_main_selected
),
2495 _("Add"), _("Remove"), _("Send"), (char*)0));
2497 db
.addkey(KEY_IC
, 0);
2498 db
.addkey(KEY_DC
, 1);
2501 db
.idle
= &dialogidle
;
2505 workarealine(sizeWArea
.y1
+2);
2506 workarealine(sizeWArea
.y2
-2);
2508 while(!finished
&& !r
) {
2509 db
.getmenu()->clear();
2511 for(ir
= m
->getfiles().begin(); ir
!= m
->getfiles().end(); ++ir
)
2512 db
.getmenu()->additemf(" %s", ir
->fname
.c_str());
2518 finished
= !db
.open(mitem
, baritem
);
2522 vector
<imfile::record
> files
= m
->getfiles();
2526 if((msg
= inputfile(_("file name: "))).size()) {
2529 if(!stat(msg
.c_str(), &st
)) {
2532 fr
.size
= st
.st_size
;
2533 files
.push_back(fr
);
2538 if(mitem
> 0 && mitem
<= m
->getfiles().size())
2539 files
.erase(files
.begin()+mitem
-1);
2557 string
icqface::extracttime(const imevent
&ev
) {
2563 ds1
= time2str(&(t
= ev
.gettimestamp()), conf
.gettimestampformat(), buf
);
2564 ds2
= time2str(&(ts
= ev
.getsenttimestamp()), conf
.gettimestampformat(), buf
);
2568 if(tdiff
< 0) tdiff
*= -1;
2571 if(ds1
!= ds2
) r
+= (string
) "[" + ds2
+ "] ";
2576 void icqface::renderchathistory() {
2577 int count
, chatmargin
;
2582 vector
<imevent
*> events
;
2583 typedef pair
<imevent::imdirection
, vector
<string
> > histentry
;
2584 vector
<histentry
> toshow
;
2585 vector
<histentry
>::iterator ir
;
2586 vector
<string
>::reverse_iterator il
;
2588 static imevent
*lastev
= 0;
2591 passevent
= lastev
= 0;
2595 icqcontact
*c
= clist
.get(passinfo
);
2600 if(!stat((c
->getdirname() + "history").c_str(), &st
)) {
2601 count
= st
.st_size
-chatlines
*(sizeWArea
.x2
-sizeWArea
.x1
)*2;
2602 if(count
< 0) count
= 0;
2605 // Skip history items that won't be displayed
2606 c
->sethistoffset(count
);
2607 if (chatlastread
== 0) chatlastread
= 1;
2610 events
= em
.getevents(passinfo
, chatlastread
);
2612 lastread
= c
->getlastread();
2615 c
->setlastread(events
.back()->gettimestamp());
2618 while(events
.size() > chatlines
) {
2619 delete events
.front();
2620 events
.erase(events
.begin());
2623 while(events
.size()) {
2624 if(events
.back()->getdirection() == imevent::incoming
) {
2625 if(events
.back()->gettimestamp() > lastread
) {
2626 if(events
.back()->gettype() == imevent::authorization
2627 || events
.back()->gettype() == imevent::contacts
2628 || events
.back()->gettype() == imevent::file
) {
2630 fin
= enough
= false;
2633 while(!fin
&& !enough
)
2634 cicq
.readevent(*events
.back(), enough
, fin
);
2641 if(count
< chatlines
) {
2642 text
= extracttime(*events
.back());
2643 text
+= events
.back()->gettext();
2644 chatlastread
= events
.back()->gettimestamp()-1;
2647 h
.first
= events
.back()->getdirection();
2648 breakintolines(text
, h
.second
, sizeWArea
.x2
-sizeWArea
.x1
-2);
2649 toshow
.push_back(h
);
2652 if(h
.first
== imevent::incoming
) {
2653 passevent
= lastev
= events
.back()->getevent();
2657 count
+= h
.second
.size();
2660 delete events
.back();
2664 chatmargin
= sizeWArea
.y1
+chatlines
;
2665 text
= string(sizeWArea
.x2
-sizeWArea
.x1
-2, ' ');
2667 attrset(conf
.getcolor(cp_main_text
));
2668 for(count
= 0; count
< chatlines
; count
++)
2669 mvprintw(chatmargin
-count
, sizeWArea
.x1
+2, "%s", text
.c_str());
2671 for(count
= 0, ir
= toshow
.begin(); ir
!= toshow
.end() && count
< chatlines
; ++ir
) {
2673 case imevent::incoming
:
2674 attrset(conf
.getcolor(cp_main_history_incoming
));
2676 case imevent::outgoing
:
2677 attrset(conf
.getcolor(cp_main_history_outgoing
));
2681 for(il
= ir
->second
.rbegin(); il
!= ir
->second
.rend() && count
< chatlines
; ++il
) {
2682 kgotoxy(sizeWArea
.x1
+2, chatmargin
-count
);
2688 peerinfo(chatlines
+1, passinfo
);
2691 void icqface::peerinfo(int line
, const imcontact
&ic
) {
2692 workarealine(sizeWArea
.y1
+line
);
2694 icqcontact
*c
= clist
.get(ic
);
2697 string text
= conf
.getprotocolname(passinfo
.pname
) + " " + c
->getdispnick();
2698 int maxsize
= sizeWArea
.x2
-sizeWArea
.x1
-10;
2701 if(text
.size() > maxsize
) {
2702 text
.erase(maxsize
);
2707 if(pgpon
= pgp
.enabled(passinfo
))
2708 text
+= string(4, ' ');
2712 text
+= " OTR: " + otr
.is_verified(ic
.pname
, c
->getnick()) + " " + otr
.get_msg_state(ic
.pname
, c
->getnick());
2715 text
= (string
) "[ " + text
+ " ]";
2717 kwriteatf(sizeWArea
.x2
-text
.size()-1, sizeWArea
.y1
+line
,
2718 conf
.getcolor(cp_main_text
), "%s", text
.c_str());
2721 kwriteatf(sizeWArea
.x2
-6, sizeWArea
.y1
+line
,
2722 conf
.getcolor(cp_main_highlight
), "PGP");
2726 bool icqface::chat(const imcontact
&ic
) {
2729 vector
<imcontact
>::iterator i
;
2731 int chatlines_diff
= 0; // could get rid of?
2732 bool return_status
= false ;
2733 face
.stay_in_chat
= false ;
2735 icqcontact
*c
= clist
.get(ic
);
2736 if(!c
) return false;
2744 c
->setopenedforchat(true);
2747 muins
.push_back(passinfo
);
2749 // resizing doesn't change the effect, so we work from the bottom, not the top
2750 chatlines_diff
= sizeWArea
.y2
- sizeWArea
.y1
;
2751 chatlines
= conf
.getchatpanelheight();
2752 if( chatlines
== 0 ) { // allow disabling reszing by setting it to zero
2753 chatlines
= (int) (chatlines_diff
*0.75);
2755 chatlines
= chatlines_diff
- chatlines
; // changes where the guide line is
2757 if( chatlines
< MinPanelHeight
) // bottom
2758 chatlines
= (int) (MinPanelHeight
);
2760 if( chatlines
> (chatlines_diff
- MinPanelHeight
)) // top
2761 chatlines
= (int) (chatlines_diff
- MinPanelHeight
) ;
2764 conf
.setchatpanelheight(chatlines_diff
- chatlines
);
2766 // workarealine(sizeWArea.y1+chatlines+1);
2768 editor
.addscheme(cp_main_text
, cp_main_text
, 0, 0);
2769 editor
.otherkeys
= &editmsgkeys
;
2770 editor
.idle
= &editchatidle
;
2772 editor
.smarttab
= false;
2773 editor
.emacs
= conf
.getemacs();
2774 editor
.setcoords(sizeWArea
.x1
+2, sizeWArea
.y1
+chatlines
+2, sizeWArea
.x2
, sizeWArea
.y2
);
2775 editor
.load(c
->getpostponed(), "");
2777 showeventbottom(ic
);
2779 for(bool finished
= false; !finished
&& clist
.get(ic
); ) {
2780 renderchathistory();
2784 auto_ptr
<char> p(editor
.save("\r\n"));
2787 editor
.load("", "");
2790 auto_ptr
<imevent
> ev(new immessage(ic
, imevent::outgoing
, p
.get()));
2792 for(i
= muins
.begin(); i
!= muins
.end(); ++i
) {
2793 ev
.get()->setcontact(*i
);
2794 em
.store(*ev
.get());
2798 muins
.push_back(passinfo
);
2804 c
->setpostponed(editdone
? "" : p
.get());
2807 c
->toggleopenedforchat();
2814 if ( face
.stay_in_chat
== true ) {
2815 return_status
= true;
2816 face
.stay_in_chat
= false;
2819 return return_status
;
2822 icqface::eventviewresult
icqface::eventview(const imevent
*ev
,
2823 vector
<eventviewresult
> abuttons
, bool nobuttons
) {
2825 string title_event
, title_timestamp
, text
;
2826 horizontalbar
*bar
= 0;
2830 static int elem
= 0;
2832 vector
<eventviewresult
> actions
;
2833 vector
<eventviewresult
>::iterator ia
;
2836 if(ev
->gettype() == imevent::message
2837 || ev
->gettype() == imevent::notification
2838 || ev
->gettype() == imevent::xml
) {
2839 actions
.push_back(forward
);
2841 if(ev
->getdirection() == imevent::incoming
)
2842 if(ev
->getcontact().pname
!= rss
/*|| islivejournal(ev->getcontact())*/)
2843 actions
.push_back(reply
);
2845 } else if(ev
->gettype() == imevent::url
) {
2846 actions
.push_back(forward
);
2847 actions
.push_back(open
);
2849 if(ev
->getdirection() == imevent::incoming
) {
2850 actions
.push_back(reply
);
2853 } else if(ev
->gettype() == imevent::sms
) {
2854 if(ev
->getdirection() == imevent::incoming
) {
2855 actions
.push_back(reply
);
2858 } else if(ev
->gettype() == imevent::authorization
) {
2859 if(ev
->getdirection() == imevent::incoming
) {
2860 actions
.push_back(info
);
2861 actions
.push_back(accept
);
2862 actions
.push_back(reject
);
2865 } else if(ev
->gettype() == imevent::contacts
) {
2866 actions
.push_back(info
);
2867 actions
.push_back(add
);
2869 } else if(ev
->gettype() == imevent::email
) {
2870 actions
.push_back(forward
);
2872 } else if(ev
->gettype() == imevent::file
) {
2873 actions
.push_back(info
);
2875 if(gethook(ev
->getcontact().pname
).knowntransfer(*static_cast<const imfile
*>(ev
))) {
2876 actions
.push_back(accept
);
2877 actions
.push_back(reject
);
2883 actions
.push_back(ok
);
2884 copy(abuttons
.begin(), abuttons
.end(), back_inserter(actions
));
2886 switch(ev
->getdirection()) {
2887 case imevent::outgoing
:
2888 title_event
= _("Outgoing %s to %s");
2889 title_timestamp
= _("Sent on %s");
2891 case imevent::incoming
:
2892 title_event
= _("Incoming %s from %s");
2893 title_timestamp
= _("Received on %s");
2899 db
.setwindow(new textwindow(sizeWArea
.x1
+1, sizeWArea
.y1
+3, sizeWArea
.x2
,
2900 sizeWArea
.y2
, conf
.getcolor(cp_main_text
), TW_NOBORDER
));
2902 db
.setbar(bar
= new horizontalbar(conf
.getcolor(cp_main_highlight
),
2903 conf
.getcolor(cp_main_selected
), 0));
2905 bar
->item
= actions
.size()-1;
2907 for(ia
= actions
.begin(); ia
!= actions
.end(); ++ia
)
2908 bar
->items
.push_back(geteventviewresult(*ia
));
2910 mainw
.writef(sizeWArea
.x1
+2, sizeWArea
.y1
, conf
.getcolor(cp_main_highlight
),
2911 title_event
.c_str(), streventname(ev
->gettype()), ev
->getcontact().totext().c_str());
2913 mainw
.writef(sizeWArea
.x1
+2, sizeWArea
.y1
+1, conf
.getcolor(cp_main_highlight
),
2914 title_timestamp
.c_str(), extracttime(*ev
).c_str());
2918 if(ev
->gettype() == imevent::contacts
) {
2919 const imcontacts
*m
= static_cast<const imcontacts
*>(ev
);
2921 db
.setmenu(new verticalmenu(conf
.getcolor(cp_main_menu
),
2922 conf
.getcolor(cp_main_selected
)));
2924 vector
< pair
<unsigned int, string
> > lst
= m
->getcontacts();
2925 vector
< pair
<unsigned int, string
> >::const_iterator il
;
2927 for(il
= lst
.begin(); il
!= lst
.end(); ++il
) {
2928 db
.getmenu()->additemf(" %s", il
->second
.c_str());
2931 db
.getmenu()->setpos(elem
-1);
2934 text
= ev
->gettext();
2935 db
.setbrowser(new textbrowser(conf
.getcolor(cp_main_text
)));
2936 db
.getbrowser()->setbuf(text
);
2939 status(_("%s to URLs, %s to full-screenize, %s close"),
2940 getstatkey(key_show_urls
, section_history
).c_str(),
2941 getstatkey(key_fullscreen
, section_history
).c_str(),
2942 getstatkey(key_quit
, section_editor
).c_str());
2948 workarealine(sizeWArea
.y1
+3);
2949 workarealine(sizeWArea
.y2
-2);
2951 db
.otherkeys
= &eventviewkeys
;
2952 db
.idle
= &dialogidle
;
2956 if(db
.open(mitem
, baritem
)) {
2957 r
= actions
[baritem
];
2975 void icqface::fullscreenize(const imevent
*ev
) {
2976 textwindow
w(0, 1, COLS
, LINES
-1, conf
.getcolor(cp_main_text
), TW_NOBORDER
);
2977 textbrowser
tb(0, 4, COLS
, LINES
-1, conf
.getcolor(cp_main_text
));
2980 char buf
[512], *fmt
= 0;
2981 vector
<string
> lines
;
2982 vector
<string
>::const_iterator il
;
2986 switch(ev
->getdirection()) {
2987 case imevent::incoming
: fmt
= _("%s from %s, received on %s"); break;
2988 case imevent::outgoing
: fmt
= _("%s to %s, sent on %s"); break;
2991 snprintf(buf
, sizeof(buf
), fmt
, streventname(ev
->gettype()),
2992 ev
->getcontact().totext().c_str(),
2993 strdateandtime(ev
->gettimestamp()).c_str());
2995 w
.write(0, 1, conf
.getcolor(cp_main_highlight
), buf
);
2997 xtermtitle((string
) _("full-screen view") + " " + buf
);
2999 tb
.setbuf(ev
->gettext());
3003 status(_("%s or %s to close, Up/Down and PgUp/PgDn to scroll"),
3004 getstatkey(key_quit
, section_editor
).c_str(),
3005 getstatkey(key_fullscreen
, section_editor
).c_str());
3007 tb
.idle
= &textbrowseridle
;
3008 tb
.otherkeys
= &fullscreenkeys
;
3011 unblockmainscreen();
3017 void icqface::histmake(const vector
<imevent
*> &hist
) {
3018 vector
<imevent
*>::const_reverse_iterator i
;
3027 for(i
= hist
.rbegin(); i
!= hist
.rend(); ++i
) {
3032 t
= ev
.gettimestamp();
3033 ts
= ev
.getsenttimestamp();
3034 text
= (string
) + " " + time2str(&t
, conf
.gettimestampformat(), buf
) + " ";
3036 text
+= (string
) + "[" + time2str(&ts
, conf
.gettimestampformat(), buf
) + "] ";
3037 text
+= ev
.gettext();
3039 if(ev
.getdirection() == imevent::incoming
) {
3040 color
= conf
.getcolor(cp_main_history_incoming
);
3041 } else if(ev
.getdirection() == imevent::outgoing
) {
3042 color
= conf
.getcolor(cp_main_history_outgoing
);
3045 mhist
.additem(color
, (void *) *i
, text
);
3049 bool icqface::histexec(imevent
*&im
) {
3058 if(!mhist
.empty()) {
3059 db
.setwindow(new textwindow(sizeWArea
.x1
+1, sizeWArea
.y1
+2, sizeWArea
.x2
,
3060 sizeWArea
.y2
, conf
.getcolor(cp_main_text
), TW_NOBORDER
));
3062 db
.setmenu(&mhist
, false);
3064 im
= static_cast<imevent
*> (mhist
.getref(0));
3068 * Now set the menu position
3072 for(k
= 0; k
< mhist
.getcount(); k
++) {
3073 imevent
*rim
= static_cast<imevent
*> (mhist
.getref(k
));
3080 db
.idle
= &dialogidle
;
3081 db
.otherkeys
= &historykeys
;
3087 workarealine(sizeWArea
.y1
+2);
3090 snprintf(buf
, sizeof(buf
), _("History for %s, %d events total"),
3091 im
->getcontact().totext().c_str(),
3094 mainw
.write(sizeWArea
.x1
+2, sizeWArea
.y1
, conf
.getcolor(cp_main_highlight
), buf
);
3096 status(_("%s search, %s again, %s cancel"),
3097 getstatkey(key_search
, section_history
).c_str(),
3098 getstatkey(key_search_again
, section_history
).c_str(),
3099 getstatkey(key_quit
, section_editor
).c_str());
3105 sub
= face
.inputstr(_("search for: "), sub
);
3106 if(input
.getlastkey() == KEY_ESC
) break;
3109 for(k
= mhist
.getpos()+1; k
< mhist
.getcount(); k
++) {
3110 im
= static_cast<imevent
*> (mhist
.getref(k
));
3112 if(im
->contains(sub
)) {
3124 if(mhist
.getref(k
-1)) {
3125 im
= static_cast<imevent
*> (mhist
.getref(k
-1));
3143 // ----------------------------------------------------------------------------
3145 void icqface::menuidle(verticalmenu
&m
) {
3148 if(face
.dotermresize
) {
3149 if(&m
== &face
.mcontacts
->menu
) {
3151 face
.dotermresize
= false;
3157 void icqface::dialogidle(dialogbox
&caller
) {
3161 void icqface::textbrowseridle(textbrowser
&b
) {
3165 void icqface::transferidle(dialogbox
&b
) {
3166 time_t tstart
= time(0);
3168 while(!cicq
.idle(HIDL_SOCKEXIT
)) {
3169 if(time(0)-tstart
> 3) {
3170 b
.gettree()->menu
.abort();
3176 string
icqface::getstatkey(int key
, int section
) const {
3179 string keys
= action2key(key
, section
);
3181 while((key2
= action2key(key
, section
, i
)) != "") {
3189 string
icqface::getmenuitem(string mtext
, int width
, int key
, int section
) {
3191 string text
= " " + mtext
+ " ";
3192 string keyname
= action2key(key
, section
);
3194 int s
= keyname
.size()+text
.size();
3199 while ((key2
= action2key(key
, section
, i
)) != "" && (s
+= key2
.size()+1) < width
) {
3200 keyname
+= "/" + key2
;
3204 for (s
= keyname
.size()+text
.size(); s
< width
; s
++)
3212 int icqface::key2action(int k
, int s
) {
3213 for(vector
<icqconf::keybinding
>::size_type i
= 0; i
< icqconf::keys
.size(); i
++)
3214 if(k
== icqconf::keys
[i
].key
&& s
== icqconf::keys
[i
].section
)
3215 return icqconf::keys
[i
].action
;
3220 string
icqface::action2key(int a
, int s
, int n
) const {
3223 std::ostringstream o
;
3227 vector
<icqconf::keybinding
>::size_type i
= 0;
3229 for( ; i
< icqconf::keys
.size(); i
++)
3230 if(a
== icqconf::keys
[i
].action
&& s
== icqconf::keys
[i
].section
) {
3236 if (i
== icqconf::keys
.size())
3238 else if(icqconf::keys
[i
].key
== '\r')
3240 else if(icqconf::keys
[i
].key
== ' ')
3242 else if(icqconf::keys
[i
].key
== '/')
3244 else if(icqconf::keys
[i
].key
== ALT('\r'))
3246 else if(icqconf::keys
[i
].key
== CTRL(' '))
3248 else if(icqconf::keys
[i
].key
== ALT(' '))
3250 else if(icqconf::keys
[i
].key
== 339)
3252 else if(icqconf::keys
[i
].key
== 338)
3254 else if(icqconf::keys
[i
].key
== 9)
3256 else if(icqconf::keys
[i
].key
== 27)
3258 else if(icqconf::keys
[i
].key
== 331)
3260 else if(icqconf::keys
[i
].key
== KEY_DC
)
3262 else if(icqconf::keys
[i
].alt
&& icqconf::keys
[i
].ctrl
)
3263 o
<< "F" << (icqconf::keys
[i
].key
-KEY_F0
);
3264 else if(icqconf::keys
[i
].alt
)
3265 o
<< "alt-" << (char)icqconf::keys
[i
].key
;
3266 else if(icqconf::keys
[i
].ctrl
)
3267 o
<< "^" << (char)(icqconf::keys
[i
].key
+64);
3269 o
<< (char)icqconf::keys
[i
].key
;
3275 ret
= string(o
.str(), o
.pcount());
3282 int icqface::contactskeys(verticalmenu
&m
, int k
) {
3283 icqcontact
*c
= NULL
;
3285 int id
= face
.mcontacts
->getid(face
.mcontacts
->menu
.getpos());
3286 if(id
!= -1 && ! face
.mcontacts
->isnode(id
))
3287 c
= (icqcontact
*) face
.mcontacts
->getref(m
.getpos()+1);
3289 set
<hookcapab::enumeration
> capab
;
3294 if(c
->getdesc() != contactroot
) {
3295 capab
= gethook(c
->getdesc().pname
).getCapabs();
3298 switch(face
.key2action(k
, section_contact
)) {
3300 face
.extk
= ACT_INFO
;
3304 face
.extk
= ACT_REMOVE
;
3308 if (conf
.getaskquit())
3309 if(face
.ask("Really Quit?", ASK_YES
| ASK_NO
, ASK_NO
) == ASK_NO
)
3311 face
.extk
= ACT_QUIT
;
3315 if(capab
.count(hookcapab::urls
))
3316 face
.extk
= ACT_URL
;
3319 case key_change_status
:
3320 face
.extk
= ACT_STATUS
;
3324 face
.extk
= ACT_HISTORY
;
3328 face
.extk
= ACT_DUMMY
;
3329 face
.next_chat(true);
3333 face
.extk
= ACT_DUMMY
;
3334 face
.next_chat(false);
3337 case key_add
: face
.extk
= ACT_ADD
; break;
3339 case key_send_contact
:
3340 if(capab
.count(hookcapab::contacts
))
3341 face
.extk
= ACT_CONTACT
;
3344 if(c
&& c
->getdesc().pname
== rss
)
3345 face
.extk
= ACT_PING
;
3348 case key_fetch_away_message
:
3349 if(capab
.count(hookcapab::fetchaway
))
3350 face
.extk
= ACT_FETCHAWAY
;
3354 face
.extk
= ACT_MENU
;
3357 case key_general_menu
:
3358 face
.extk
= ACT_GMENU
;
3361 case key_hide_offline
:
3362 face
.extk
= ACT_HIDEOFFLINE
;
3365 case key_contact_external_action
:
3366 if(!ischannel(c
) && c
)
3367 face
.extk
= ACT_EXTERN
;
3371 if(!ischannel(c
) && c
)
3372 face
.extk
= ACT_RENAME
;
3376 if(capab
.count(hookcapab::version
))
3377 face
.extk
= ACT_VERSION
;
3381 if(!ischannel(c
) && c
)
3382 face
.extk
= ACT_EDITUSER
;
3386 if(c
) face
.extk
= ACT_IGNORE
;
3389 case key_left_panel_move_right
:
3390 face
.leftpanelwidth_inc(1);
3394 case key_left_panel_move_left
:
3395 face
.leftpanelwidth_inc(-1);
3399 case key_log_panel_move_up
:
3400 face
.logpanelheight_inc(1);
3404 case key_log_panel_move_down
:
3405 face
.logpanelheight_inc(-1);
3409 case key_quickfind
: face
.extk
= ACT_QUICKFIND
; break;
3412 if(face
.extk
&& face
.key2action(k
, section_contact
) != -1) {
3413 return m
.getpos()+1;
3419 int icqface::multiplekeys(verticalmenu
&m
, int k
) {
3429 if(face
.key2action(k
, section_contact
) == key_quickfind
)
3435 int icqface::findpgpkeys(dialogbox
&db
, int k
) {
3438 r
= face
.key2action(k
, section_contact
);
3447 string
icqface::getprotocolchar(protocolname pname
) const {
3448 static const string pprefixes
[protocolname_size
] = {
3449 "i", "y", "m", "a", "#", "j", "r", "l", "g", "n"
3452 if(pname
> protocolname_size
)
3455 return pprefixes
[pname
];
3458 int icqface::historykeys(dialogbox
&db
, int k
) {
3461 switch(face
.key2action(k
, section_history
)) {
3464 case key_search_again
:
3473 int icqface::editmsgkeys(texteditor
&e
, int k
) {
3476 if(k
== '\r' && conf
.getentersends(face
.passinfo
.pname
)) {
3478 face
.editdone
= strlen(p
);
3480 if(face
.editdone
) return -1; else return 0;
3483 switch(face
.key2action(k
, section_editor
)) {
3484 case key_send_message
:
3486 face
.editdone
= strlen(p
);
3488 if(face
.editdone
) return -1; else break;
3489 case key_multiple_recipients
:
3490 face
.multicontacts("");
3493 cicq
.history(face
.passinfo
);
3496 face
.editdone
= false;
3497 face
.next_chat(false);
3500 face
.editdone
= false;
3501 face
.next_chat(true);
3504 face
.editdone
= false;
3505 face
.next_chat(false);
3506 face
.last_selected
= (icqcontact
* ) clist
.at(0);
3509 cicq
.userinfo(face
.passinfo
);
3512 face
.showextractedurls(); break;
3513 case key_fullscreen
:
3515 face
.fullscreenize(face
.passevent
);
3517 case key_chat_panel_move_up
:
3518 face
.chatpanelheight_inc(1);
3519 face
.stay_in_chat
= true;
3522 case key_chat_panel_move_down
:
3523 face
.chatpanelheight_inc(-1);
3524 face
.stay_in_chat
= true;
3529 case key_otr_start_session
:
3530 otr
.start_session(face
.last_selected
);
3531 face
.stay_in_chat
= true;
3534 case key_otr_end_session
:
3535 otr
.end_session(face
.last_selected
);
3536 face
.stay_in_chat
= true;
3548 int icqface::userinfokeys(dialogbox
&db
, int k
) {
3549 switch(face
.key2action(k
, section_info
)) {
3550 case key_show_urls
: face
.showextractedurls(); break;
3551 case key_user_external_action
: face
.userinfoexternal(face
.passinfo
); break;
3557 int icqface::eventviewkeys(dialogbox
&db
, int k
) {
3558 switch(face
.key2action(k
, section_history
)) {
3560 face
.showextractedurls();
3562 case key_fullscreen
:
3563 face
.fullscreenize(face
.passevent
);
3572 int icqface::findreskeys(dialogbox
&db
, int k
) {
3573 if(face
.key2action(k
, section_contact
) == key_quickfind
)
3579 int icqface::statuskeys(verticalmenu
&m
, int k
) {
3580 char *status_order
= "o_adnlcfi"; // Shortcuts for status
3581 char *p
= strchr(status_order
, k
);
3583 return (1 + p
- status_order
);
3587 int icqface::fullscreenkeys(textbrowser
&m
, int k
) {
3588 switch(face
.key2action(k
, section_editor
)) {
3589 case key_fullscreen
:
3596 void icqface::editidle(texteditor
&e
) {
3600 void icqface::editchatidle(texteditor
&e
) {
3603 cicq
.idle(HIDL_SOCKEXIT
);
3605 if(c
= clist
.get(face
.passinfo
))
3606 if(c
->hasevents()) {
3607 face
.renderchathistory();
3611 void icqface::textinputidle(textinputline
&il
) {
3615 void icqface::termresize(void) {
3616 face
.dotermresize
= true;
3619 void icqface::relaxedupdate() {
3623 bool icqface::updaterequested() {
3627 void icqface::redraw() {
3628 if(!mainscreenblock
) {
3634 * Terminal resize specific
3637 vector
<string
> flog
;
3638 vector
<string
>::iterator il
;
3642 flog
= face
.lastlog
;
3643 face
.lastlog
.clear();
3646 conf
.getlogoptions(lts
, lo
);
3647 conf
.setlogoptions(false, lo
);
3649 for(il
= flog
.begin() ; il
!= flog
.end(); ++il
)
3652 conf
.setlogoptions(lts
, lo
);
3654 doredraw
= fneedupdate
= false;
3656 doredraw
= fneedupdate
= true;
3660 void icqface::xtermtitle(const string
&text
) {
3661 if(conf
.getxtitles()) {
3662 string term
= getenv("TERM") ? getenv("TERM") : "";
3664 if(term
== "xterm" || term
== "Eterm" || term
== "aterm"
3665 || term
== "rxvt" || term
.substr(0, 6) == "screen")
3666 cout
<< "\x1b]1;\x07\x1b]0;" << "centerim" << (text
.empty() ? "" : (string
) ": " + text
) << "\x07" << flush
;
3670 void icqface::xtermtitle(const char *fmt
, ...) {
3671 if(conf
.getxtitles()) {
3676 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
3677 xtermtitle((string
) buf
);
3682 void icqface::xtermtitlereset() {
3683 if(conf
.getxtitles()) {
3684 const char *p
= getenv("TERM");
3685 if(p
) xtermtitle((string
) p
);
3689 // ----------------------------------------------------------------------------
3691 icqface::icqprogress::icqprogress() {
3695 icqface::icqprogress::~icqprogress() {
3699 void icqface::icqprogress::log(const char *fmt
, ...) {
3704 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
3707 if(curline
>= face
.sizeDlg
.height
-1) {
3712 w
->write(2, 1+curline
++, buf
);
3715 void icqface::icqprogress::show(const string
&title
) {
3717 w
= new textwindow(0, 0, face
.sizeDlg
.width
, face
.sizeDlg
.height
,
3718 conf
.getcolor(cp_dialog_frame
), TW_CENTERED
);
3721 w
->set_title(conf
.getcolor(cp_dialog_highlight
), title
);
3727 void icqface::icqprogress::hide() {
3731 void icqface::leftpanelwidth_inc(const int inc
) {
3732 int i
= conf
.getleftpanelwidth();
3733 if ( ((i
+inc
) >= MinPanelWidth
) && ((i
+inc
) <= (COLS
- MinPanelWidth
))) {
3734 conf
.setleftpanelwidth(i
+inc
);
3735 dotermresize
= true ;
3739 void icqface::logpanelheight_inc(const int inc
) {
3740 int i
= conf
.getlogpanelheight();
3741 if (((i
+inc
) >= MinPanelHeight
) && ((i
+inc
) <= (LINES
- MinPanelHeight
))) {
3742 conf
.setlogpanelheight(i
+inc
);
3743 dotermresize
= true ;
3747 void icqface::chatpanelheight_inc(const int inc
) {
3748 chatlines
= conf
.getchatpanelheight()+inc
;
3749 conf
.setchatpanelheight(chatlines
);