summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS17
-rw-r--r--README43
-rw-r--r--TODO43
-rw-r--r--config64
-rw-r--r--configure.in6
-rw-r--r--docs/manual.txt983
-rw-r--r--docs/signals.txt3
-rw-r--r--docs/special_vars.txt3
-rw-r--r--po/POTFILES.in12
-rw-r--r--src/common-setup.h3
-rw-r--r--src/core/levels.c1
-rw-r--r--src/core/levels.h19
-rw-r--r--src/core/server.c10
-rw-r--r--src/core/settings.c21
-rw-r--r--src/fe-common/core/Makefile.am2
-rw-r--r--src/fe-common/core/autorun.c2
-rw-r--r--src/fe-common/core/command-history.c4
-rw-r--r--src/fe-common/core/fe-common-core.c51
-rw-r--r--src/fe-common/core/fe-core-commands.c77
-rw-r--r--src/fe-common/core/fe-log.c37
-rw-r--r--src/fe-common/core/fe-server.c10
-rw-r--r--src/fe-common/core/fe-settings.c13
-rw-r--r--src/fe-common/core/hilight-text.c2
-rw-r--r--src/fe-common/core/module-formats.c8
-rw-r--r--src/fe-common/core/module-formats.h6
-rw-r--r--src/fe-common/core/printtext.c34
-rw-r--r--src/fe-common/core/printtext.h3
-rw-r--r--src/fe-common/core/window-activity.c (renamed from src/fe-common/core/nick-hilight.c)10
-rw-r--r--src/fe-common/core/windows.c395
-rw-r--r--src/fe-common/core/windows.h5
-rw-r--r--src/fe-common/irc/Makefile.am4
-rw-r--r--src/fe-common/irc/dcc/module-formats.h2
-rw-r--r--src/fe-common/irc/fe-channels.c141
-rw-r--r--src/fe-common/irc/fe-common-irc.c20
-rw-r--r--src/fe-common/irc/fe-events-numeric.c2
-rw-r--r--src/fe-common/irc/fe-events.c51
-rw-r--r--src/fe-common/irc/fe-ignore.c4
-rw-r--r--src/fe-common/irc/fe-irc-commands.c119
-rw-r--r--src/fe-common/irc/fe-irc-server.c215
-rw-r--r--src/fe-common/irc/fe-netsplit.c69
-rw-r--r--src/fe-common/irc/fe-query.c62
-rw-r--r--src/fe-common/irc/irc-window-activity.c (renamed from src/fe-common/irc/irc-nick-hilight.c)6
-rw-r--r--src/fe-common/irc/module-formats.c19
-rw-r--r--src/fe-common/irc/module-formats.h19
-rw-r--r--src/fe-none/.cvsignore1
-rw-r--r--src/fe-text/Makefile.am11
-rw-r--r--src/fe-text/gui-entry.c30
-rw-r--r--src/fe-text/gui-entry.h4
-rw-r--r--src/fe-text/gui-mainwindows.c66
-rw-r--r--src/fe-text/gui-mainwindows.h21
-rw-r--r--src/fe-text/gui-printtext.c12
-rw-r--r--src/fe-text/gui-readline.c516
-rw-r--r--src/fe-text/gui-statusbar-items.h7
-rw-r--r--src/fe-text/gui-statusbar.h21
-rw-r--r--src/fe-text/gui-textwidget.c15
-rw-r--r--src/fe-text/gui-windows.c312
-rw-r--r--src/fe-text/gui-windows.h120
-rw-r--r--src/fe-text/irssi.c149
-rw-r--r--src/fe-text/mainwindows.c606
-rw-r--r--src/fe-text/mainwindows.h29
-rw-r--r--src/fe-text/module-formats.c3
-rw-r--r--src/fe-text/module-formats.h9
-rw-r--r--src/fe-text/screen.c246
-rw-r--r--src/fe-text/statusbar-items.c (renamed from src/fe-text/gui-statusbar-items.c)454
-rw-r--r--src/fe-text/statusbar.c266
-rw-r--r--src/fe-text/statusbar.h45
-rw-r--r--src/irc/core/bans.c17
-rw-r--r--src/irc/core/channel-events.c34
-rw-r--r--src/irc/core/channels-query.c4
-rw-r--r--src/irc/core/channels-setup.c85
-rw-r--r--src/irc/core/channels-setup.h3
-rw-r--r--src/irc/core/channels.c19
-rw-r--r--src/irc/core/channels.h1
-rw-r--r--src/irc/core/ctcp.c2
-rw-r--r--src/irc/core/ignore.c5
-rw-r--r--src/irc/core/irc-commands.c59
-rw-r--r--src/irc/core/irc-log.c4
-rw-r--r--src/irc/core/irc-server.c6
-rw-r--r--src/irc/core/irc-server.h1
-rw-r--r--src/irc/core/irc.c1
-rw-r--r--src/irc/core/ircnet-setup.c1
-rw-r--r--src/irc/core/massjoin.c17
-rw-r--r--src/irc/core/modes.c89
-rw-r--r--src/irc/core/netsplit.c80
-rw-r--r--src/irc/core/netsplit.h12
-rw-r--r--src/irc/core/nicklist.c21
-rw-r--r--src/irc/core/nicklist.h2
-rw-r--r--src/irc/core/server-reconnect.c26
-rw-r--r--src/irc/core/server-setup.c129
-rw-r--r--src/irc/core/server-setup.h9
-rw-r--r--src/irc/dcc/Makefile.am4
-rw-r--r--src/irc/dcc/dcc-chat.c2
-rw-r--r--src/irc/dcc/dcc-chat.h7
-rw-r--r--src/irc/dcc/dcc-files.c2
-rw-r--r--src/irc/dcc/dcc-files.h7
-rw-r--r--src/irc/dcc/dcc.c26
-rw-r--r--src/irc/flood/autoignore.c4
-rw-r--r--src/irc/flood/flood.c122
-rw-r--r--src/irc/notifylist/notify-commands.c2
-rw-r--r--src/irc/notifylist/notify-whois.c2
-rw-r--r--src/perl/irssi-perl.c53
-rw-r--r--src/perl/xs/Irssi-core.xs13
-rw-r--r--src/perl/xs/Irssi-netsplit.xs23
-rw-r--r--src/perl/xs/Irssi-server.xs2
-rw-r--r--src/perl/xs/module.h1
-rw-r--r--src/perl/xs/typemap1
106 files changed, 4864 insertions, 1597 deletions
diff --git a/NEWS b/NEWS
index c8f4a8ba..58bfd9ac 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,11 @@ v0.7.90 2000-04-xx Timo Sirainen <tss@iki.fi>
compatible with EPIC as much as possible (except the scripting,
perl should be enough?)
+ * DOCUMENTATION! See docs/manual.txt
+
+ This NEWS file contains only the biggest new features, you should
+ browse through the documentation to find the rest.
+
* Irssi isn't anymore IRC specific client, you could easily take the
whole IRC part away and use some other chat protocol instead, or
use both at the same time. Currently however, only IRC protocol
@@ -54,6 +59,8 @@ v0.7.90 2000-04-xx Timo Sirainen <tss@iki.fi>
This can be changed from settings `cmd_max_at_once' and
`cmd_queue_speed'. If you want to disable this for some reason, use
/SET cmd_queue_speed 0
+ + Split windows in text version, all the normal ircII /WINDOW
+ commands should work: new, kill, grow, shrink, balance, show, hide
+ /EVAL <commands> - Expand all the special variables from string and
run it. Commands can be split with ; character. See
docs/special_vars.txt for more info.
@@ -62,7 +69,7 @@ v0.7.90 2000-04-xx Timo Sirainen <tss@iki.fi>
$1..$9, now they're in $0..$8 so it messes up existing themes..
+ /SET [key [value]] - no more the '=' character. Boolean values
also need to be changed with ON/OFF/TOGGLE values (not yes/no).
- + /SAVE [<filename>] - saves the settings to disk.
+ + /SAVE [<filename>] - saves the settings to file.
/REHASH [<filename>] - re-read the configuration file on the fly
+ /TOGGLE <key> [ON/OFF] - same as /SET <key> TOGGLE
+ /ALIAS [-]<alias> [<command>], /UNALIAS <alias>
@@ -113,11 +120,11 @@ v0.7.90 2000-04-xx Timo Sirainen <tss@iki.fi>
The best match always wins, so you can have:
/IGNORE * CTCPS
/IGNORE -except *!*@host.org CTCPS
- + /LOG OPEN [-noopen] [-autoopen] [-channels <channels>] [-window]
+ + /LOG OPEN [-noopen] [-autoopen] [-targets <targets>] [-window]
[-rotate hour|day|month] <filename> [<levels>]
-noopen: create the entry to log list, but don't start logging
-autoopen: automatically open this log file at startup
- -channels: log only in specified channels/nicks
+ -targets: log only in specified channels/nicks
-window: Log this window
-rotate: Reopen the log file every hour, day or month. This
makes only sense if you specify date/time formats
@@ -157,6 +164,10 @@ v0.7.90 2000-04-xx Timo Sirainen <tss@iki.fi>
your previous user mode and away message (and rejoin the channels,
which it already did before) after reconnected. If you use /SERVER
to connect to different IRC network, none of this will be done.
+ + /CAT <filename> - prints the file to screen
+ + /SET query_auto_close <secs> - automatically close queries after
+ <secs> seconds. It won't close queries that have unread messages,
+ and it won't close queries in the active window.
v0.7.28 2000-03-11 Timo Sirainen <tss@iki.fi>
diff --git a/README b/README
index 1da069f1..dfadac08 100644
--- a/README
+++ b/README
@@ -13,8 +13,10 @@ also like to see KDE version.
* FEATURES
-See docs/COMMANDS file for list of (almost) all commands irssi knows.
-See docs/PERL for some documentation of Perl scripting.
+docs/manual.txt - new manual
+
+See docs/commands.txt file for list of (almost) all commands irssi knows.
+See docs/perl.txt for some documentation of Perl scripting.
I've been asked quite a lot about why should one use irssi, what does it do
that other IRC clients don't? Well, to tell you the truth, I have no idea :)
@@ -23,7 +25,6 @@ ever used :) Let's see.. It should be easy to use, it has most of the
features IRC client needs and it's pretty stable. Here's a small list of what
it does:
- - Nice configuration :) Especially the color settings.
- You can connect to multiple servers. Irssi is also IRC network aware so
you can specify some settings to work only in specified IRC networks.
- Automatically connect to IRC server(s) at startup, automatically join to
@@ -60,42 +61,6 @@ where your irc server is connected. Now just connect your clients to
the proxy. There's not much features yet, if you want to use multiple
servers you'll need to start multiple irssi-texts now..
- * INSTALLATION
-
-./configure
-make
-make install
-
-Configure can use these parameters (all of these defaults to yes):
-
- --with-servertest Build test irc server which you can use to try crash
- irc clients
- --with-socks Build with socks library
- --with-mysql=dir Build with mysql plugin
- --without-gtk Build without GTK frontend
- --without-textui Build without text frontend
- --without-bot Build without irssibot
- --without-gnome Build without GNOME libraries
- --without-gnome-panel Build without GNOME panel
- --without-imlib Build without Imlib library (you can use only .xpm
- files as backgrounds)
- --enable-memdebug Enable memory debugging, great for finding memory
- leaks
- --enable-gtk-hebrew Enable Hebrew support - see README-HEBREW
- --disable-perl Disable Perl support
-
-There's also some others, you can get a full list with ./configure --help
-
-
- * COMMAND LINE PARAMETERS
-
- --no-applet Don't start gnome panel applet
- --connect -c <server> Connect to server at startup
- --port -p <port> - specify port
- --noconnect -! Don't autoconnect to any servers at startup
- --nick -n Specify what nick to use
- --hostname -h Specify what host name to use
-
* BUGS / SUGGESTIONS
See TODO file if it is already listed in there - if not send me email..
diff --git a/TODO b/TODO
index 5745b584..f3e34d3f 100644
--- a/TODO
+++ b/TODO
@@ -1,7 +1,23 @@
+- /IRCNET ADD/REMOVE
+- mites se awaylogi? se /cattaamaan myös se /away:n jälkeen
+- poista se common-setup.h
+- quitissa se räpeltää ruutua liikaa..
+- perli kaatui välillä ym. kivaa.
+
+[21:48] < santo> [20:51] ¤¤¤ #twiggy,#tanum,#d2mac,#linux.nu,#sweden2k
+Cannot join channel (illegal name)
+.. /mode #a,#b voi sanoa myös jossain serverillä jotain outoa.. irc.carnet.hr
+
+.. logit rehashissa sammuu, /window logit katoaa kokonaan? kai /window logit
+ pelaa oikein jos ikkunan refnum vaihtuu?
+.. joosella oli joku bufferibugi. bufferi pieneksi, pguppia, paljon tekstiä
+lisää, alas, --more-- jää
+.. /sb bugaa! /SB GOTO 23:59 tms. ei pelaa
+
- rikki:
- dcc
- gnome versio..
- - pluginit, perlskriptit
+ - pluginit
- teemat (toimiiko ne edes?)
- teeman vaihto tekstiversiolla, tekstien muuttaminen tekstiversiolla
@@ -12,31 +28,23 @@
- use different themes in different channels/queries?
- logi voisi käyttää omaa teemaa
-- mites se awaylogi?
-- /WALL, ja sen replyt
-- /ON
-- /CAT
-- servereiden ja ircnettien asetusten käpistelyyn jotkut käskyt
-- curses sijainti jotain rikkoo
+- /set hold_mode, ja /CAT toimimaan sen kanssa jotenkin nerokkaasti..
+- curses sijainti jotain rikkoo, ja openbsd:ssä on -lcurses, ei -lncurses
- /msg =dcc_chatti,#kanava .. ei pelaa tollanen. voisi laittaa coreen tuon
ja jotain hookkeja et eri chattiprotoille voisi vaikka mennä se teksti..
ctcp:lle sama?
- who ja listiin ne eri vipuset
+- /ON
- - raiseta ikkuna jossa on tekstiä mut ei over aktiivisen päälle
- line-split.c: varmista että se 64k limitti toimii eikä esim. kaada!
-- vaihda /set nimet järkevimmiksi
- /exec
- autorun.ircnet
- - bottipluginiin tms. .. channel not available tms. rejoini
+ - channel not available rejoini
*** Bugs
- %| doesn't work with irssi text widget
- - when changing server (/server), irssi will automatically join back to the
- channels that were joined in previous server. If IRC network is different
- than in previous server it shouldn't join the channels..
- some problems when using multiple windows with focus being all the time in
one of the windows and it can't be changed to different window?! Probably
has something to do with click to focus.
@@ -48,12 +56,11 @@
*** text UI
- - split windows
- statusbar:
+ - you can't configure it in any way!
- when starting to run out of space some items could be made smaller,
activity for example .. make some generic flag for items to use.
- "you have new mail"
- - active server tag somewhere in window
*** Big things
@@ -90,7 +97,7 @@
*** Needs rethinking ..
- * Notify list, join the two different dialogs
+ * Notify list GUI
- _one_ popup dialog could open which lists all nicks in notifylist, maybe
sorted by arrival time, display the dates, latest joined could be with
different color? etc.
@@ -122,7 +129,6 @@
mouse...
- if some other window has got much text, switching to it first time
takes some time..?
- - exceptions for ignoring
- editor in setup for ~/.irssi/startup
- gui help
- change signal handling in gui-gnome so that the actual drawing and
@@ -132,8 +138,6 @@
who are away and who are not.. optionally it could instead just watch if
someone hasn't written anything to channel in n minutes and mark it "away"
to nicklist.
- - /connect ircnet could connect to ircnet
- - change some GLists to GHashTables, aliases at least
- check new irssi versions with http rather than with irssibot..
- implement requesting files with DCC GET from remote client for dcc file
servers. good for people behind firewalls.
@@ -145,6 +149,5 @@
- dcc send: allow selection of multiple files to send (also for dnd from
gmc!) Allow dropping files to anywhere in irssi.
- /timer, /clones
- - display net splits?
- {}|~ are same as []\^ (not in all irc networks) - does this really affect
irssi at all..?
diff --git a/config b/config
index 98fb3c65..50015df9 100644
--- a/config
+++ b/config
@@ -1,19 +1,19 @@
-setupservers = (
- {server = "irc.funet.fi"; ircnet = IRCNet; port = 6667; autoconnect = No;},
- {server = "irc.efnet.net"; ircnet = EFNet; port = 6667; autoconnect = No;},
- {server = "irc.undernet.net"; ircnet = Undernet; port = 6667; autoconnect = No;},
- {server = "irc.dal.net"; ircnet = DALNet; port = 6667; autoconnect = No;},
- {server = "irc.openprojects.net"; ircnet = OPN; port = 6667; autoconnect = No;},
- {server = "irc.ptlink.net"; ircnet = PTlink; port = 6667; autoconnect = No;}
+servers = (
+ { address = "irc.funet.fi"; ircnet = IRCNet; port = 6667; },
+ { address = "irc.efnet.net"; ircnet = EFNet; port = 6667; },
+ { address = "irc.undernet.net"; ircnet = Undernet; port = 6667; },
+ { address = "irc.dal.net"; ircnet = DALNet; port = 6667; },
+ { address = "irc.openprojects.net"; ircnet = OPN; port = 6667; },
+ { address = "irc.ptlink.net"; ircnet = PTlink; port = 6667; }
);
ircnets = (
- {name = IRCNet; max_kicks = 4; max_modes = 3; max_msgs = 5; max_whois = 4;},
- {name = EFNet; max_kicks = 4; max_modes = 4; max_msgs = 3;},
- {name = Undernet; max_kicks = 4; max_modes = 3; max_msgs = 3;},
- {name = DALNet; max_kicks = 4; max_modes = 6; max_msgs = 3;},
- {name = OPN; max_kicks = 1; max_modes = 6; max_msgs = 100;},
- {name = PTlink; max_kicks = 1; max_modes = 6; max_msgs = 100;}
+ { name = IRCNet; max_kicks = 4; max_modes = 3; max_msgs = 5; max_whois = 4; },
+ { name = EFNet; max_kicks = 4; max_modes = 4; max_msgs = 3; },
+ { name = Undernet; max_kicks = 4; max_modes = 3; max_msgs = 3; },
+ { name = DALNet; max_kicks = 4; max_modes = 6; max_msgs = 3; },
+ { name = OPN; max_kicks = 1; max_modes = 6; max_msgs = 100; },
+ { name = PTlink; max_kicks = 1; max_modes = 6; max_msgs = 100; }
);
channels = (
@@ -28,6 +28,7 @@ channels = (
autojoin = No;
}
);
+
aliases = {
J = "join";
LEAVE = "part";
@@ -62,23 +63,24 @@ aliases = {
WC = "window close";
WN = "window new";
};
+
popups = (
- {label = "<MULTICOMMA>Whois"; command = "/whois %s";},
- {label = "DCC Send File"; command = "/dcc send %s";},
- {label = "Open DCC Chat"; command = "/dcc chat %s";},
- {label = Query; command = "/query %s";},
- {label = "<MENU><OP>"; command = "Op";},
- {label = "<MULTI>Op"; command = "/op %s";},
- {label = "<MULTI>Deop"; command = "/deop %s";},
- {label = "<MULTI>Voice"; command = "/voice %s";},
- {label = "<MULTI>Devoice"; command = "/devoice %s";},
- {label = "<KICK>Kick"; command = "/kick %s %s";},
- {label = "<MULTI>Ban"; command = "/ban %s";},
- {label = "<KICK>Kick+ban"; command = "/kickban %s %s";},
- {label = "<KICK>Knockout"; command = "/knockout %s %s";},
- {label = "</MENU>"; command = "";},
- {label = "<MENU>"; command = "CTCP";},
- {label = Ping; command = "/ping %s";},
- {label = Version; command = "/ver %s";},
- {label = "</MENU>"; command = "";}
+ { label = "<MULTICOMMA>Whois"; command = "/whois %s"; },
+ { label = "DCC Send File"; command = "/dcc send %s"; },
+ { label = "Open DCC Chat"; command = "/dcc chat %s"; },
+ { label = Query; command = "/query %s"; },
+ { label = "<MENU><OP>"; command = "Op"; },
+ { label = "<MULTI>Op"; command = "/op %s"; },
+ { label = "<MULTI>Deop"; command = "/deop %s"; },
+ { label = "<MULTI>Voice"; command = "/voice %s"; },
+ { label = "<MULTI>Devoice"; command = "/devoice %s"; },
+ { label = "<KICK>Kick"; command = "/kick %s %s"; },
+ { label = "<MULTI>Ban"; command = "/ban %s"; },
+ { label = "<KICK>Kick+ban"; command = "/kickban %s %s"; },
+ { label = "<KICK>Knockout"; command = "/knockout %s %s"; },
+ { label = "</MENU>"; command = ""; },
+ { label = "<MENU>"; command = "CTCP"; },
+ { label = Ping; command = "/ping %s"; },
+ { label = Version; command = "/ver %s"; },
+ { label = "</MENU>"; command = ""; }
);
diff --git a/configure.in b/configure.in
index e9873024..5ffee09a 100644
--- a/configure.in
+++ b/configure.in
@@ -487,9 +487,9 @@ if test "x$want_perl" = "xyes"; then
old_dir=`pwd` && cd $srcdir && whole_dir=`pwd` && cd $old_dir
if test "x$old_dir" != "x$whole_dir"; then
- ln -sf $whole_dir/plugins/perl/xs/typemap plugins/perl/xs/typemap
- ln -sf $whole_dir/plugins/perl/xs/Irssi.xs plugins/perl/xs/Irssi.xs
- ln -sf $whole_dir/plugins/perl/xs/Irssi.pm plugins/perl/xs/Irssi.pm
+ ln -sf $whole_dir/src/perl/xs/typemap src/perl/xs/typemap
+ ln -sf $whole_dir/src/perl/xs/Irssi.xs src/perl/xs/Irssi.xs
+ ln -sf $whole_dir/src/perl/xs/Irssi.pm src/perl/xs/Irssi.pm
fi
fi
diff --git a/docs/manual.txt b/docs/manual.txt
new file mode 100644
index 00000000..90cacac4
--- /dev/null
+++ b/docs/manual.txt
@@ -0,0 +1,983 @@
+
+ Irssi 0.8 documentation
+
+ Copyright(c) 2000 Timo Sirainen
+
+
+ Index
+
+ 0. Generic babbling
+ 1. Installation
+ 2. Message levels
+ 3. Flood protection
+ 4. Configuration
+ 5. Servers
+ 6. Channels
+ 7. IRC commands and features
+ 8. Notify list
+ 9. Text highlighting
+ 10. Ignoring
+ 11. Logging
+ 12. Aliases
+ 13. Themes
+ 14. Last log (currently text version only)
+ 15. Nick and word completion
+ 16. Translation tables
+ 17. Windowing system (text version)
+ 18. Keyboard (text version)
+ 19. Perl scripting
+
+
+
+ 0. Generic babbling
+
+ 0.1 History
+
+ Hello. I'm Timo Sirainen aka. cras, and I'm IRC addict. :)
+
+ I'm actually quite new in IRC, I got my first internet connection
+ sometimes around fall 1997 and I started actively IRCing around
+ christmas. I used EPIC and BitchX mostly at the start, but soon
+ found some nice KDE IRC client which name I can't remember anymore.
+ It's author however stopped developing it after I had been using it
+ a few months. And since it had bugs and all, I wanted another nice
+ GUI IRC client. I didn't find any.
+
+ Since I've always been a coder and do-it-yourself guy (my own
+ offline reader and BBS software in the BBS ages), I started my own
+ IRC client at spring 1998. I called it yagIRC standing for "Yet
+ another GTK IRC client". GTK was in around version 1.0 back then,
+ and it had a lot of features/bugs which I found all the time as I
+ tried to do some "different" things than other people. These
+ sometimes prevented me of doing something some feature I wanted.
+
+ So, in summer 1998 I went to army and I passed development of yagIRC
+ to two guys, they did a few new features and released a version or
+ two, but finally (in summer 1999?) they put a message to web page
+ which told that they finally had stopped developing it entirely,
+ also saying that my code was a total mess :) (yes, it was a mess)
+
+ I got out of the army 1.1.1999. I promised to myself that I wouldn't
+ do another IRC client, but after trying to use BitchX a while, I
+ started dreaming about an IRC client which would have an excellent
+ look and feel. After trying various things, I only came up with the
+ GNOME panel applet which people still tell me that it's a great
+ feature. I was more like thinking some pretty little icons in
+ some corner telling me about new messages and other stuff..
+
+ I thought that I would keep Irssi a small project, just doing a few
+ little features that *I* wanted, nothing for others. But after few
+ versions and few interested people, I started coding it more and
+ more generic..
+
+ Finally, after releasing version 0.6.0 (february, 1999) I realized
+ that things were getting into a big mess again. I started a rewrite,
+ I organized the code into irc-base, irc-extra, user interface and
+ GUI directories, created the signalling system for letting them
+ communicate themselves easily and released 0.7.0. This was the base
+ for the rest of the 0.7.x releases, and it did work pretty well.
+ The signalling system was excellent, for example creating text mode
+ version was really easy and you didn't need tens of (empty) gui_xxx()
+ functions like in the yagIRC days. Maintaining the text and GTK
+ versions separately was really easy too.
+
+ About a year later after releasing Irssi 0.7.0, I started having
+ dreams about an IRC client that would be extremely modular, like you
+ could upgrade the client to newer version ON THE FLY without needing
+ to even disconnect from the servers. I started a project codenamed
+ i2k, I took the code from Irssi, split it into more directories and
+ changed quite a lot of the code to work a bit differently.
+
+ I developed i2k quite a long, until I finally gave up with it since
+ it could do only some basic things, and Irssi 0.7 really needed
+ maintaining. After a while I got an idea, maybe I could merge the
+ code from the i2k to Irssi more easily than rewriting the whole
+ client. This was more easier than I thought. It's now been two
+ months since I started it, and Irssi 0.8 is looking absolutely
+ excellent.
+
+ 0.2 Irssi 0.8
+
+ Irssi 0.8 is my fourth try to create the perfect IRC client.
+ This time I'm concentrating to the code. I try to avoid kludges, I
+ try to make as simple code as I can, and I try to provide enough
+ easy to use functions so that extending Irssi is as simple as
+ possible. I also try to keep the "bloat" features in scripts or
+ modules instead of build-in.
+
+ I think I'm succeeded with these goals pretty well, there's some
+ small problems but everything in the big picture looks great.
+
+ 0.3 Future
+
+ What about Irssi 1.0, what will it look like?
+
+ I was thinking about the Linux kernel versioning and keeping
+ Irssi 0.8 a stable version all the time while developing new
+ features only to Irssi 0.9. After 0.9 is finished, it will be
+ called 0.10 or 1.0 depending if I think it's ready to be called 1.0.
+
+ 1.0's goal is that it has all the possible features anyone will
+ ever need. If not build-in, then in scripts or loadable modules.
+ Not very small goal :)
+
+ 0.4 This documentation
+
+ Strange, I just created the index list and started writing this.
+ I've never been too good at documentation and I usually don't like
+ writing it, but after coding so much recently and seeing that the
+ NEWS file was getting *SO* large, I thought that I had to put all
+ these features down somewhere so people (and me!) would find them.
+
+ Besides of just telling about Irssi's features and how to use them,
+ this file also contains some not so well known IRC features, some
+ of my own experiences, opinions, etc. So even if you're an
+ experienced IRCer, you might still want to browse through this file.
+
+ NOTE: my experiences are mostly IRCnet related, and Irssi is pretty
+ much IRCnet specific too, since it's the most commonly used IRC
+ network here in Finland. IRCnet has tens of servers here where as
+ other IRC networks have maybe one or two or mostly none.
+
+
+ 1. Installation
+
+ 1.1 Configuration
+
+ configure script accepts these parameters:
+
+ --with-servertest Build test irc server which you can use to
+ try crash irc clients
+ --with-socks Build with socks library
+ --with-mysql=dir Build with mysql plugin
+ --without-gtk Build without GTK frontend
+ --without-textui Build without text frontend
+ --without-bot Build without irssibot
+ --without-gnome Build without GNOME libraries
+ --without-gnome-panel Build without GNOME panel
+ --without-imlib Build without Imlib library (you can use only
+ .xpm files as backgrounds)
+ --enable-memdebug Enable memory debugging, great for finding
+ memory leaks
+ --enable-gtk-hebrew Enable Hebrew support - see README-HEBREW
+ --disable-perl Disable Perl support
+
+ In short:
+
+ ./configure
+ make
+ make install
+
+ 1.2 Command line parameters
+
+ --connect -c <server> Connect to server at startup
+ --port -p <port> - specify port
+ --noconnect -! Don't autoconnect to any servers at startup
+ --nick -n Specify what nick to use
+ --hostname -h Specify what host name to use
+ --no-applet Don't start GNOME panel applet
+
+
+ 2. Message levels
+
+
+ Message levels (or in short, levels) are used almost everywhere.
+ They describe what kind of messages we're dealing with. Here's a
+ list of them all:
+
+ CRAP - Can be almost anything
+ MSGS - Private messages
+ PUBLIC - Public messages in channel
+ NOTICES - Notices
+ SNOTES - Server notices
+ CTCPS - CTCP messages
+ ACTIONS - Actions (/me) - both private and public
+ (which is a bit problematic..)
+ JOINS - Someone joins a channel
+ PARTS - Someone parts a channel
+ QUITS - Someone quits IRC
+ KICKS - Someone gets kicked from channel
+ MODES - Channel mode is changed
+ TOPICS - Channel topic is changed
+ WALLOPS - Wallop is received
+ INVITES - Invite is received
+ NICKS - Someone changes nick
+ DCC - DCC messages
+ CLIENTNOTICES - Irssi's notices
+ CLIENTERRORS - Irssi's error messages
+ CLIENTCRAP - Some other messages from Irssi
+ HILIGHT - Hilighted text
+ NOHILIGHT - Don't use hilighting for this message
+
+
+ 3. Flood protection
+
+ 3.1 Command flood protection
+
+ Most (all?) IRC servers' flood protection works like this
+ (from RFC 1459):
+
+ --------
+ * check to see if client's `message timer' is less than
+ current time (set to be equal if it is);
+
+ * read any data present from the client;
+
+ * while the timer is less than ten seconds ahead of the current
+ time, parse any present messages and penalize the client by
+ 2 seconds for each message;
+
+ which in essence means that the client may send 1 message every 2
+ seconds without being adversely affected.
+ --------
+
+ Irssi's flood protection works the same way, except it penalizes
+ 2.2 seconds by default for each message (helps with some servers).
+ You can change it with /SET cmd_queue_speed <milliseconds>. You can
+ also change the number of commands before flood protection activates
+ (ie. the burst count) with /SET cmd_max_at_once <count>.
+
+ IRC servers also have an input buffer where the client's commands
+ are saved before processed. It's size is server specific (can be as
+ low as 1k!) If it gets full, the server kicks you out (the
+ "Excess flood" quit message). Irssi's flood protecion protects this
+ pretty well with small commands, but if you send many big commands
+ (like >400 char long messages) fast, you could get easily kicked out.
+ Normally this isn't problem, but if you have scripts sending long
+ messages, you should remember this. I'm not sure how much you should
+ wait between the long messages, but 2 seconds isn't enough.
+
+ This protection is used with all commands sent to server, so you
+ don't need to worry about it with your scripts.
+
+ 3.2 CTCP flood protection
+
+ Other people can pretty easily flood you with CTCP requests, and
+ even if you wouldn't get kicked out from the server, they could
+ easily grow your command queue. So, Irssi's CTCP flood protection
+ works like this:
+
+ First it checks how big the CTCP reply queue is, if it's longer
+ than `max_ctcp_queue', the CTCP is ignored. You can change it with
+ /SET max_ctcp_queue <count> (default is 5).
+
+ After this the CTCP reply is placed to server's "idle queue", so
+ the reply is sent "when there's extra time", this means that if
+ you are busy sending other commands, it might take a while before
+ the reply is sent.
+
+ 3.3 Detecting floods
+
+ Irssi is all the time automatically checking different flooding,
+ when flood is noticed, it sends "flood" signal. This can be easily
+ used for example to create a script for kicking channel flooders.
+ Autoignore uses this also, see section 10.2.
+
+ Flood is detected when more than `flood_max_msgs' same kind of
+ messages arrives in `flood_timecheck' milliseconds to same target
+ (channel or private msg) so it isn't flooding if same user sends a
+ message to 10 different channels you are on, but it is flooding if
+ 10 messages are sent to same channel by the same user.
+
+ Currently only messages, notices and ctcps are checked for
+ flooding.
+
+ /SET flood_max_msgs = <count>, default is 4
+ /SET flood_timecheck = <milliseconds>, default is 5 seconds
+ If either of these is 0, the flood checking is disabled.
+
+
+ 4. Configuration
+
+ 4.1 Configuration files
+
+ The configuration is saved to ~/.irssi/config file. You can edit
+ it with text editor if you want, you can also add comments to it
+ and they stay there even if /SAVE is used. Comments are the lines
+ starting with # character. Any errors in config file are displayed
+ at startup.
+
+ Irssi uses it's own config library for handling the config file.
+ The format is pretty much the same as in libPropList and should be
+ easily understandable.
+
+ You can reload the config file on the fly with /REHASH command, you
+ can also read a different config file with /REHASH <filename>.
+
+ If you change any settings, they aren't saved to file until you use
+ /SAVE. You can save the config file to different place with
+ /SAVE <filename>.
+
+ 4.2 Settings
+
+ You can view or change the settings with /SET command.
+
+ /SET without any arguments displays all the settings.
+ /SET <key> displays settings which key (partly) matches <key>
+ /SET <key> <value> sets <key> to <value>
+
+ Boolean settings accepts only values ON, OFF and TOGGLE. You can
+ also use /TOGGLE command to change them, so /TOGGLE <key> behaves
+ like /SET <key> TOGGLE. /TOGGLE also accepts arguments ON and OFF
+ when /TOGGLE behaves exactly like /SET.
+
+ Remember that changes are not saved until you use /SAVE!
+
+
+ 5. Servers
+
+ 5.1 Generic
+
+ Irssi is multi-server friendly. You can be connected to multiple
+ different servers, or the same server multiple times. Most of the
+ settings that let you specify the channel, let you also specify IRC
+ network.
+
+ Servers are referenced by a "server tag". If the server is known
+ to belong to some IRC network, the tag is the IRC network's name,
+ like "ircnet". If the IRC network is unknown, the tag is created
+ from the server's name, like irc.funet.fi -> funet. If the tag
+ already exists, a number is added to the end of it and raised until
+ unused tag is found.
+
+ Quit messages have a small problem if there's already a few
+ commands in server's input command queue. If the server's socket is
+ disconnected immediately after QUIT message is sent, it is possible
+ that the server didn't yet process the quit command and your quit
+ message will be "broken pipe" or something similiar. The right thing
+ to do is to let the server disconnect you, but what if the
+ connection to server is broken and the server never disconnects you?
+ I solved the problem by waiting a few seconds to see if the server
+ disconnects us. If it didn't, force the disconnect. This explains
+ the (a bit annoying) "waiting for servers to close connections"
+ message when quiting Irssi. Most IRC clients just ignore this whole
+ problem, but I hate it if my quit message isn't displayed right.
+
+ 5.2 IRC networks
+
+ Different IRC networks behave a bit differently, and to be as
+ efficient as possible, Irssi needs to know a few things about them
+ or the safe defaults will be used. The default configuration file
+ contains the settings for the biggest IRC networks.
+
+ /IRCNET ADD [-kicks <count>] [-msgs <count>] [-modes <count>]
+ [-whois <count>] [-cmdspeed <ms>] [-cmdmax <count>]
+ [-nick <nick>] [-user <user>] [-name <name>]
+ [-host <host>] <name>
+
+ -kicks: Maximum number of nicks in one /KICK command
+ -msgs: Maximum number of nicks in one /MSG command
+ -modes: Maximum number of mode changes in one /MODE command
+ -whois: Maximum number of nicks in one /WHOIS command
+ -cmdspeed: Same as /SET cmd_queue_speed, see section 3.1
+ -cmdmax: Same as /SET cmd_max_at_once, see section 3.1
+ -nick, -user, -name: Specify what nick/username/realname to use
+ -host: Specify what host name to use, if you have multiple
+
+ /IRCNET REMOVE <name>
+
+ 5.3 Manually connecting and disconnecting
+
+ To connect to a new server, use:
+ /CONNECT [-ircnet <ircnet>] [-host <hostname>] <address>|<ircnet>
+ [<port> [<password> [<nick>]]]
+
+ If there's no password, set it to -. You can directly connect to
+ IRC server in specified address, or you can connect to some IRC
+ network and Irssi will pick the server for you.
+
+ You don't need to specify the IRC network, password, nick, etc. if
+ you setup the server using /SERVER -add (see next section). If the
+ settings can't be found there either, Irssi will use the defaults:
+
+ /SET default_nick = <nick>, defaults to user_name
+ /SET alternate_nick = <nick>, defaults to <default_nick>_
+ /SET user_name = <user>, defaults to your login name
+ /SET real_name = <name>, taken from /etc/passwd by default
+ /SET hostname = <host>, what host name to use when connecting
+ /SET skip_motd ON|OFF|TOGGLE - Don't show server's MOTD
+
+ NOTE: /CONNECT is also a command for IRC operators to connect IRC
+ servers to other IRC servers. If you want to use it, use /SCONNECT
+ instead.
+
+ You can disconnect from the server with:
+ /DISCONNECT *|<tag> [message]
+
+ If message isn't given, Irssi will use the default quit message. You
+ can set it with /SET quit_message <message>, default is "leaving".
+
+ /SERVER disconnects the server in active window and connects to new
+ one. It will take the same arguments as /CONNECT. If you prefix the
+ address with + character, Irssi won't disconnect the active server,
+ and it will create a new window where the server is connected
+ (ie. /window new hide;/connect address)
+
+ /SERVER without any arguments displays list of connected servers.
+
+ 5.4 Server settings
+
+ /SERVER -add [-auto] [-ircnet <ircnet>] [-host <hostname>]
+ [-cmdspeed <ms>] [-cmdmax <count>] <address>
+ [<port> [<password> [<nick>]]]
+
+ -auto: Automatically connect to server at startup
+ -ircnet: Specify what IRC network this server belongs to
+ -host: Specify what host name to use, if you have multiple
+ -cmdspeed: Same as /SET cmd_queue_speed, see section 3.1
+ -cmdmax: Same as /SET cmd_max_at_once, see section 3.1
+
+ /SERVER -remove <address> [<port>]
+
+ /SERVER -list
+
+ After connected to server, Irssi can automatically change your user
+ mode. You can set it with /SET usermode <mode>, default is +i.
+
+ 5.5 Automatic reconnecting
+
+ If you get disconnected from server, Irssi will try to reconnect
+ back to some of the servers in the same IRC network. To prevent
+ flooding the server that doesn't let you in (and avoiding K-lines),
+ Irssi won't try to reconnect to the same server more often than
+ once in `server_reconnect_time' seconds. You can change it with
+ /SET server_reconnect_time <seconds>, default is 5 minutes.
+
+ After reconnected to server, Irssi will re-set your user mode, away
+ message and will join you back to the same channels where you were
+ before the connection was lost.
+
+ You can see list of the reconnections with /SERVER. The servers
+ that have tag as RECON-n are the reconnections. You can remove them
+ with /DISCONNECT <tag>, and you can reconnect to them immediately
+ with /RECONNECT <n>. /RECONNECT without any arguments will
+ disconnect from the active server and reconnect back immediately.
+
+ 5.6 Command redirections
+
+ FIXME
+
+ 5.7 Server idle command queue
+
+ There's some situations when you want to ask something from the
+ server which isn't really important. For example when connected
+ to server and you didn't get your nick, Irssi asks with /WHOIS
+ who has your nick and displays it. But if you already have a lot of
+ commands in buffer, like you just autojoined to many channels,
+ you'd rather first let the JOIN commands to be sent to server
+
+ This is where server idle queue gets into picture. Commands in
+ idle queue are sent to server when there's nothing else in the
+ normal command queue.
+
+ Idle queue works with server redirections, so you can ask something
+ from server when it has time and your function is called when the
+ reply is received.
+
+ 5.8 Net splits
+
+ Irssi keeps track of people who were lost in net splits. You can
+ get a list of them with /NETSPLIT command.
+
+ Another use for this is with bots. Channel master can op anyone in
+ the channel and the bot happily accepts it. But if the opped user
+ is lost behind a net split and in netjoin the server gives ops for
+ the user, the bot should decide if the user (who isn't in bot's user
+ database) is a malicious attacker who should be deopped, or if
+ he/she/it is just some user that already had ops before the net
+ split.
+
+ /SET hide_netsplit_quits - If ON, when detected net splits, display
+ only "Net split host1 host" message and hide all the quit
+ messages
+
+ 5.9 Lag checking
+
+ Irssi will constantly check how big the lag to the server is. It's
+ done by sending IRSSILAG CTCP replies to ourself. Using PING command
+ for this would seem more reasonable, but there was too many problems
+ with it - some servers didn't even know the whole PING command!
+
+ If the lag is too big, Irssi will reconnect to different IRC server.
+ This is sometimes useful if the connection has been stuck for 30
+ minutes but it still hasn't been closed.
+
+ /SET lag_check_time <seconds> - Specifies how often to check the
+ lag. If it is set to 0, the lag detection is disabled. Default
+ is 30 seconds.
+ /SET lag_max_before_disconnect <seconds> - Specifies how big the lag
+ can be before reconnecting to another server. Default is 5
+ minutes.
+ /SET lag_min_show <100th seconds> - Specifies the minimum lag to
+ display in status bar. Default is 1 second.
+
+ 5.10 Raw log
+
+ All data that is received or sent to server is kept in a raw log
+ buffer for a while. Also event redirections are kept there. This is
+ very useful for debugging purposes.
+
+ /RAWLOG SAVE <filename> - Save the current raw log buffer to file
+ /RAWLOG OPEN <filename> - Like /RAWLOG SAVE, but keep the log file
+ open and write all new log to it.
+ /RAWLOG CLOSE - Close the open raw log
+
+ /SET rawlog_lines <count> - Specify the number of raw log lines to
+ keep in memory.
+
+
+ 6. Channels
+
+ 6.1 Generic
+
+ There's several types of channels you can join, here's a list of
+ the ones that Irssi supports:
+
+ #channel - Normal channels, most commonly used
+ +channel - Modeless channels, channel has no modes, no channel
+ operators and no topic. This way no-one is above others
+ and there's no operator-wars etc. But on the other hand,
+ you can't kick any troublemakers..
+ &channel - Local channels, these channels aren't distributed outside
+ the IRC server. IRCNet has replaced server notices with
+ several different &channels (&ERRORS, &NOTICES, etc.)
+ !channel - New channels, currently supported only by IRCNet. These
+ channels are designed so that they can't be taken over
+ with net splits. /JOIN !channel joins to existing
+ !channel, /JOIN !!channel creates a new channel.
+
+ 6.2 Joining, parting
+
+ Channels can be joined with /JOIN command. You can join to multiple
+ channels with one /JOIN by giving it a comma-separated list of
+ channels, like /JOIN #channel1,#channel2. If you don't give the
+ channel mode character (#+&!) before the channel name, Irssi
+ automatically uses # channels.
+
+ Channel name may contain any characters except SPACE, BELL, NUL,
+ CR, LF or comma (','). You can also restrict the channel to only
+ certain users by adding the hostmask to the end of the channel
+ name separated with a ':' character, like #channel:*!*@*.fi lets
+ only people from .fi domain join the channel. This doesn't work with
+ all IRC servers and it's pretty difficult to use, since everyone
+ will have to always join the #channel:*!*@*.fi channel, #channel or
+ #channel:*!*@*.se channels are different channels. Ban exceptions
+ (+e) and especially invite lists (+I) replace this functionality
+ pretty well, see section 6.5.
+
+ If channel has a password (aka. key), you can join it with
+ /JOIN #channel pass, or multiple channels with passwords with
+
+ /JOIN #secret1,#public,#secret2 pass1,x,pass2
+
+ #public didn't have any password, so we used "x" as it's password.
+ It doesn't really matter what password you send with channels that
+ don't have passwords.
+
+ You can leave channels with /PART [<channels>] [<part message>].
+ For example "/PART byebye all" leaves the active channel with
+ "byebye all" message, or /PART #chan1,#chan2 leaves those channels.
+
+ NOTE: Sending JOIN 0 directly to server (/quote join 0) leaves all
+ the channels you are joined. There's been some jokes about joining
+ for example to #2000,0 where the server actually leaves you from all
+ channels. With Irssi this isn't really a problem, since irssi would
+ happily join to channels #2000 and #0.
+
+ 6.3 Automatic joining
+
+ Irssi can automatically join to specified channels in specified
+ IRC networks. It can also automatically send the password when
+ manually joining to channel without specifying the password.
+
+ /CHANNEL ADD [-auto] [-bots <botmasks>] [-botcmd <command>]
+ <channel> <ircnet> [<password>]
+
+ With -bots and -botcmd arguments you can automatically send
+ commands to someone in channel. This is useful for automatically
+ getting ops for channels, for example
+
+ /CHANNEL ADD -auto -bots "*!bot@bothost.org bot*!*@host2.org"
+ -botcmd "msg $0 op mypass" #channel ircnet
+
+ You can also use the -botcmd without -bots argument. The command is
+ then sent whenever you join the channel.
+
+ You can remove the channels with
+ /CHANNEL REMOVE <channel> <ircnet>
+
+ /CHANNEL LIST displays list of channels with settings.
+ /CHANNEL without any arguments displays list of channels you have
+ joined. You can also use /CHANNEL to join to channels just as with
+ /JOIN, like /CHANNEL #a.
+
+ 6.4 After-join automation
+
+ When joined to channel, Irssi asks some information about it.
+ After it has got all of it, it prints the "Channel synchronized"
+ text. The following information is asked:
+
+ - Channel mode
+ - WHO list to get nicks' hosts - useful for /BAN for example
+ - Ban list - useful for allowing /UNBAN to use wildcards
+ - Exception list, Invite list - these are asked only from servers
+ that support +I and +e modes, mostly just IRCNet and some EFNet
+ servers. These aren't really needed for anything currenty, except
+ /INVITELIST and /BANS uses them to display the lists.
+
+ If you have joined many channels at once, Irssi tries to optimize
+ the commands it sends to server. Instead of sending two commands
+ to ask two channels' mode, it just sends MODE #a,#b. Same thing with
+ WHO list and ban/except/invite lists. Some servers do not support
+ this and they reply with different kinds of error messages, Irssi
+ tries to deal with them all right and resend the commands again
+ separately. However, some strange servers sometimes use some weird
+ error replies that Irssi doesn't know about, and the channel never
+ gets synchronized. If this happens with some server you know, please
+ let the Irssi's author know about it.
+
+ 6.5 Channel modes
+
+ Irssi knows these channel modes:
+
+ i - Invite only - People can't join to channel without being
+ /INVITEd, or being in invite list (+I, see below).
+ m - Moderated - People who don't have voices (+v) can't send
+ messages to channel
+ p - Private - People who aren't joined to channel can't see it
+ for example with /WHOISing people who are in channel.
+ s - Secret - Like private, but the channel isn't displayed in
+ /LIST's output.
+ n - No external msgs - Without this mode, anyone can send messages
+ to channel without even being joined.
+ t - Topic can be changed only by channel operators.
+
+ k <key> - Channel password (aka. key) - The channel can't be joined
+ without specifying the channel key (see section 6.2).
+
+ l <count> - User limit - No more than <count> people can join to
+ channel. This can be overridden with /INVITE with some
+ servers.
+
+ This is usually used for protecting channel from join
+ flooding, like some bot allows max. 5 users to join in
+ one minute or so.
+
+ a - Anonymous - No-one's nick name, host or anything else can be
+ seen. All messages, joins, parts, modes, etc. are seen as coming
+ from nick "anonymous", this could be pretty confusing but nice
+ feature if you want total anonymity. This mode can only be set,
+ never unset. This mode isn't supported by all servers.
+
+ NOTE: there is/was one bug :) Channel operators can guess if some
+ nick might be in the channel and try to kick it. If nick was in
+ channel, everyone will see the nick that was kicked.
+
+ r - Re-op - If channel becomes opless for longer than 45 (?) minutes,
+ op everyone in the channel. This works only in !channels. This
+ mode can only be set, not unset by channel creator.
+
+ b - Set/remove ban. For example MODE #channel +b *!*@*.org bans
+ everyone from .org domain.
+
+ If someone from .org domain was already in channel before the
+ ban was set, he/she couldn't be able to write any messages to
+ channel (doesn't work with all servers).
+
+ Ban can also be overridden with /INVITE, although many stupid
+ IRC clients automatically kick the user out because they see
+ the ban and think that because of it the user shouldn't be in
+ the channel (doesn't work with all servers).
+
+ e - Ban exceptions. You could for example ban everyone from
+ *!*@*.org but set ban exception to *!*@*.host.org - works only
+ in IRCnet/EFnet servers.
+
+ I - Invite list. If channel is invite only (+i), people in this
+ list can join it without being /INVITEd - works only in
+ IRCnet/EFnet servers.
+
+ This is excellent for in-country channels that don't want
+ foreigners (spammers!) to join the channel, for example setting
+ channel's mode to +i and +I *!*@*.fi allows only finnish people
+ to join the channel. In addition to this, there's usually a bot
+ in the channels and sending /MSG bot invite command to it
+ /INVITEs you to the channel.
+
+ The ':' feature in channel modes is quite similiar, see section
+ 6.2.
+
+ O - Channel owner, the nick who creates a !channel receives this
+ mode. It isn't displayed anywhere, you can't pass it to anyone
+ else and you can't regain it again. This is needed for setting
+ +r mode in channel when it's first created.
+
+ o <nick> - Grant or revoke channel operator status from nick
+ v <nick> - Grant or revoke voice status from nick, only people with
+ +v (or +o) can talk to channel when it's moderated (+m).
+
+ You can send multiple mode changes with one mode command:
+
+ /MODE #channel +nto-o+v nick1,nick2,nick3
+
+ This would set channel's mode to +nt, give ops to nick1, take ops
+ from nick2 and give voices to nick3.
+
+ You can set only limited number of modes that requires argument in
+ one command. In IRCnet it's 3, in EFnet it's 4 and in many others
+ it's 6. If it's not known, Irssi defaults to 3. Irssi will also
+ automatically split them, so you can use /MODE +oooooo n1,n2,..
+ command to op 6 people and Irssi will split it to two commands in
+ IRCnet/EFnet.
+
+ Instead of manually setting o, v and b modes you probably want to
+ use /OP, /DEOP, /VOICE, /DEVOICE, /BAN and /UNBAN commands.
+
+ /OP, /DEOP, /VOICE and /DEVOICE commands allows wildcards as their
+ argument. So /OP ni* will op all non-opped people whose nick start
+ with "ni". /DEOP * will deop everyone else except you. /VOICE and
+ /DEVOICE work the same way.
+
+ 6.6 Bans
+
+ You can give /BAN a list of nicks or whole ban masks. /UNBAN
+ accepts wildcards, so if you have ban nick!user@reallylonghost.org,
+ you can simply unban it with /UNBAN *really*
+
+ Using /BAN <nicks>, Irssi will automatically create the mask. You
+ can change the way it's created with /BANTYPE command:
+
+ /BANTYPE normal|host|domain|custom
+
+ Normal - *!user@*.domain.net
+ Host - *!*@host.domain.net
+ Domain - *!*@*.domain.net
+ Custom [nick] [user] [host] [domain]
+ eg. /bantype custom nick domain - nick!*@*.domain.net
+ eg. /bantype custom user host - *!user@host.domain.net
+
+ Irssi has also a couple of commands to help banning people:
+
+ /KICKBAN [<channel>] <nick> <reason> - ban and kick the nick
+ /KNOCKOUT [<seconds>] <nick> <reason> - kickban the nick, unban
+ after waiting <seconds>, default is 5 minutes.
+
+ 6.7 Massjoins
+
+ Automatic opping the nick right after joined to channel is a pretty
+ commonly used. What mostly irritates me with this is that the nick
+ may be opped multiple times by different people, or after netsplits
+ when the people join back, the server will op them, but still the
+ bots op the people again, even if it was just done by the server.
+
+ Irssi has this feature that it sends a "massjoin" signal a while
+ after the real join. If someone has already opped the nick, you can
+ easily check it in the massjoin signal handler.
+
+ The default is to report maximum of 5 joins in one massjoin signal.
+ If the 5 joins don't come in 5 seconds, the signal is sent anyway.
+ You can change these with /SET massjoin_max_wait <milliseconds> and
+ /SET massjoin_max_joins <count>.
+
+
+ 7. IRC commands and features (FIXME)
+
+ 7.x Basic commands
+
+ 7.x IRC operator commands
+
+ 7.x Away features
+
+ 8. Notify list
+
+ Notify list is generally used for knowing when someone you know
+ comes to IRC or leaves from IRC. Traditionally notify list can
+ handle only a list of nicks, no nick masks etc. I lost interest to
+ traditional notify lists long time ago, since the people I know
+ are in IRC all the time. So I made a bit more featureful notify
+ list:
+
+ /NOTIFY [-list] [-away] [-idle [minutes]] <mask> [ircnet [ircnet...]]
+
+ -away: Notifies about away-status changes
+ -idle: Notifies if idle time is first larger than <minutes>
+ (default is hour) and then it drops down.
+ -list: Lists the notify list entries with all their settings
+ <mask>: Either a simple "nick" or "nick!*@*blah.org". The nick
+ can't contain wildcards, but the user/host can.
+
+ /UNNOTIFY <mask>
+
+ /NOTIFY without any arguments displays if the people in notify
+ list are online or offline.
+
+
+ 9. Text highlighting
+
+ Irssi supports highlighting lines that match the specified pattern.
+ You can also change the color of the nicks that match specified nick
+ mask, so you could for example show your friends' nicks with
+ different color.
+
+ /HILIGHT [-nick | -regexp | -word] [-color <color>]
+ [-level <level>] [-channels <channels>] <text>
+
+ -nick: Match only for nick, <text> is a nick mask
+ -regexp: <text> is a regular expression
+ -word: <text> must match to full words
+ -color: Print the reply with <color> - see below
+ -level: Match only for <level> messages, default is
+ publics,msgs,notices,actions
+ -channels: Match only in <channels>
+
+ /DEHILIGHT <ref#> | <text>
+
+ /HILIGHT without any arguments displays list of the hilights.
+
+ By default the highlighted line will be printed with white color.
+ You can change this with the -color argument. If <color> is a
+ number, Irssi will treat it as a MIRC color code. You can also use
+ bolds (^B), underlines (^_) etc. as <color> if you like.
+
+
+ 10. Ignoring
+
+ 10.1 Manual ignoring
+
+ Irssi's ignoring options should be enough for everyone :)
+
+ /IGNORE [-regexp | -word] [-pattern <pattern>] [-except]
+ [-channels <channel>] <mask> <levels> <^levels>
+
+ -regexp: <pattern> is a regular expression
+ -word: <pattern> must match to full words
+ -pattern: <pattern> must match to the message's text
+ -except: *DON'T* ignore
+ -channels: Ignore only in channels
+ <mask>: Either a nick mask or list of channels
+ <levels>: List of levels to ignore
+ <^levels>: List of levels to NOT ignore
+ (/ignore -except nick notices = /ignore nick ^notices)
+
+ /UNIGNORE <ref#> | <mask>
+
+ /IGNORE without any arguments displays list of ignores.
+
+ The best match always wins, so you can have:
+
+ /IGNORE * CTCPS
+ /IGNORE -except *!*@host.org CTCPS
+
+ 10.2 Automatic ignoring
+
+ Irssi can automatically set ignores for people who flood you.
+ Currently you can autoignore MSGS, NOTICES, CTCPS and PUBLIC.
+ Actions are placed to either MSGS or PUBLIC. See section 3.3 for
+ definition of the flood.
+
+ /SET autoignore_time <seconds> specifies how long to ignore the
+ user.
+
+ /SET autoignore_levels <levels> specifies what levels to ignore
+ automatically, default is to ignore only CTCPS.
+
+
+ 11. Logging
+
+ 11.1 Basic logging
+
+ /LOG OPEN [-noopen] [-autoopen] [-targets <targets>] [-window]
+ [-rotate hour|day|week|month] <filename> [<levels>]
+
+ -noopen: Create the entry to log list, but don't start logging
+ -autoopen: Automatically open this log file at startup
+ -targets: Log only in specified channels/nicks
+ -window: Log the active window
+ -rotate: Reopen the log file every hour, day, week or month.
+ This makes only sense if you specify date/time formats
+ to file name.
+ <filename>: File name where to log, it is parsed with
+ strftime(), so %d=day, etc. see "man strftime" for
+ more info.
+ <levels>: Defaults to ALL
+
+ /LOG CLOSE <ref#> | <fname> - Close log and remove from log list
+ /LOG START <ref#> | <fname> - Start logging to file
+ /LOG STOP <ref#> | <fname> - Stop logging to file
+ /LOG without any arguments displays the log list
+
+ /SET log_create_mode <mode> - Specifies what file mode to use with
+ the created log files. Default is 0644.
+
+ All of these are parsed with strftime():
+ /SET log_timestamp <text> - Specifies the time stamp format.
+ Default is "%H:%M ".
+ /SET log_open_string <text> - Text written to log when it's opened
+ /SET log_close_string <text> - Text written to log when it's closed
+ /SET log_day_changed <text> - Text written to log when day changes
+
+ NOTE: Log files are locked after opened, so two Irssis can't
+ accidentally try to write to the same log file.
+
+ Examples:
+
+ /LOG OPEN -targets cras ~/irclogs/cras.log MSGS
+ - Logs all messages from/to nick `cras'
+
+ /LOG OPEN -rotate day -targets #linux ~/irclogs/linux/linux-%Y-%m-%d
+ - Logs all messages in channel #linux. Log is rotated daily, so
+ logs in 1. May 2000 goes to file "linux-2000-05-01", when the
+ day is changed, Irssi closes the log and starts logging to
+ "linux-2000-05-02" etc.
+
+ 11.2 Window logging
+
+ /WINDOW LOG ON|OFF|TOGGLE [<filename>]
+
+ Start/stop logging the active window. This works exactly like
+ /LOG OPEN -window.
+
+ /WINDOW LOGFILE <filename>
+
+ Sets the default log file to use in the window, it can be
+ overridden with specifying the file name in /WINDOW LOG. If no file
+ name isn't given, Irssi defaults to ~/irc.log.<windowname> or
+ ~/irc.log.Window<ref#> if window doesn't have name.
+
+ Creates the entry to log list, same as /LOG OPEN -window -noopen.
+ Also, if /WINDOW LOG ON is used it starts logging to this file.
+
+ 11.3 Automatic logging
+
+ This is the logging method that I had been asked to implement for
+ ages, and it is really simple to use too. It logs only messages
+ that have "targets", ie. private messages and channel specific
+ messages (msgs, modes, topics, etc). WHOIS replies and such aren't
+ logged. If you with to log them too, use the /LOG command.
+
+ So, when for example a private messages comes to you from "guy"
+ nick, Irssi creates a log file ~/irclogs/guy.log for it. After few
+ minutes of inactivity, the log file is closed.
+
+ /SET AUTOLOG ON|OFF|TOGGLE - Enable/disable autolog.
+
+ /SET AUTOLOG_LEVEL <level> - Specifies what levels to log, default
+ is ALL.
+
+ /SET AUTOLOG_PATH <path> - expandos (see special_vars.txt) can be
+ used, $0 is the target. If you are using multiple servers, it makes
+ sense to use the server tag as part of the file name, for example
+ ~/irclogs/$tag/$0.log (this is the default). The directories are
+ created automatically.
+
+ 11.4 Awaylog
+
+ Irssi logs specified messages when you're away. After you set
+ yourself unaway, Irssi will display all the messages in the awaylog.
+
+ /SET awaylog_level <level> - Default is MSGS HILIGHT
+ /SET awaylog_file <filename> - Default is ~/.irssi/away.log
+
+ You can disable this feature by setting awaylog_level to NONE.
+
+
diff --git a/docs/signals.txt b/docs/signals.txt
index 09e8cac0..ad9b329f 100644
--- a/docs/signals.txt
+++ b/docs/signals.txt
@@ -95,6 +95,7 @@ server.c:
"server connecting", SERVER_REC, ulong *ip
"server looking", SERVER_REC
"server disconnected", SERVER_REC
+ "server quit", SERVER_REC, char *msg
"event connected", SERVER_REC
server-reconnect.c:
@@ -148,7 +149,7 @@ dcc.c:
flood.c:
- "flood", SERVER_REC, char *nick, char *host, char *level, char *target
+ "flood", SERVER_REC, char *nick, char *host, int level, char *target
ignore.c:
diff --git a/docs/special_vars.txt b/docs/special_vars.txt
index 4890b55a..81e30a78 100644
--- a/docs/special_vars.txt
+++ b/docs/special_vars.txt
@@ -1,5 +1,4 @@
NOTE: This is just a slightly modified file taken from EPIC's help.
-'!' at start of the line means that the feature doesn't work yet..
Special Variables and Expandos
@@ -70,7 +69,7 @@ $A .. $Z is important.
$R version of current server
$S current server name
$T target of current input (channel or QUERY nickname)
-! $U value of cutbuffer
+! $U value of cutbuffer (*DOES NOT WORK* - there is no cut buffer..)
$V client release date (numeric version string)
$W current working directory
$X your /userhost $N address (user@host)
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 7449b4d1..9a17f5ec 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -64,12 +64,12 @@ src/fe-common/core/fe-settings.c
src/fe-common/core/hilight-text.c
src/fe-common/core/keyboard.c
src/fe-common/core/module-formats.c
-src/fe-common/core/nick-hilight.c
src/fe-common/core/printtext.c
src/fe-common/core/themes.c
src/fe-common/core/translation.c
src/fe-common/core/window-items.c
src/fe-common/core/windows.c
+src/fe-common/core/window-activity.c
src/fe-common/irc/dcc/fe-dcc.c
src/fe-common/irc/dcc/module-formats.c
src/fe-common/irc/completion.c
@@ -82,20 +82,22 @@ src/fe-common/irc/fe-ignore.c
src/fe-common/irc/fe-irc-commands.c
src/fe-common/irc/fe-query.c
src/fe-common/irc/irc-hilight-text.c
-src/fe-common/irc/irc-nick-hilight.c
src/fe-common/irc/module-formats.c
src/fe-common/irc/flood/fe-flood.c
src/fe-common/irc/flood/module-formats.c
src/fe-common/irc/notifylist/fe-notifylist.c
src/fe-common/irc/notifylist/module-formats.c
+src/fe-common/irc/fe-irc-server.c
+src/fe-common/irc/irc-window-activity.c
+src/fe-common/irc/fe-netsplit.c
src/fe-none/irssi.c
src/fe-text/gui-entry.c
-src/fe-text/gui-mainwindows.c
+src/fe-text/statusbar.c
+src/fe-text/mainwindows.c
src/fe-text/gui-printtext.c
src/fe-text/gui-readline.c
src/fe-text/gui-special-vars.c
-src/fe-text/gui-statusbar-items.c
-src/fe-text/gui-statusbar.c
+src/fe-text/statusbar-items.c
src/fe-text/gui-textwidget.c
src/fe-text/irssi.c
src/fe-text/module-formats.c
diff --git a/src/common-setup.h b/src/common-setup.h
index a658e836..9bdd6eeb 100644
--- a/src/common-setup.h
+++ b/src/common-setup.h
@@ -16,9 +16,6 @@
/* How often to check for gone status of nick */
#define MAX_GONE_REFRESH_TIME 300
-/* Maximum time to wait for more JOINs before sending massjoin signal */
-#define MAX_MASSJOIN_WAIT 5000
-
/* How long to keep netsplits in memory (seconds) */
#define NETSPLIT_MAX_REMEMBER (60*30)
diff --git a/src/core/levels.c b/src/core/levels.c
index 7e55d738..9682dcdd 100644
--- a/src/core/levels.c
+++ b/src/core/levels.c
@@ -36,7 +36,6 @@ static char *levels[] =
"KICKS",
"MODES",
"TOPICS",
- "WALLS",
"WALLOPS",
"INVITES",
"NICKS",
diff --git a/src/core/levels.h b/src/core/levels.h
index f3a54507..ccaf6daa 100644
--- a/src/core/levels.h
+++ b/src/core/levels.h
@@ -20,17 +20,16 @@
#define MSGLEVEL_KICKS 0x0000400
#define MSGLEVEL_MODES 0x0000800
#define MSGLEVEL_TOPICS 0x0001000
-#define MSGLEVEL_WALLS 0x0002000
-#define MSGLEVEL_WALLOPS 0x0004000
-#define MSGLEVEL_INVITES 0x0008000
-#define MSGLEVEL_NICKS 0x0010000
-#define MSGLEVEL_DCC 0x0020000
-#define MSGLEVEL_CLIENTNOTICE 0x0040000
-#define MSGLEVEL_CLIENTCRAP 0x0080000
-#define MSGLEVEL_CLIENTERROR 0x0100000
-#define MSGLEVEL_HILIGHT 0x0200000
+#define MSGLEVEL_WALLOPS 0x0002000
+#define MSGLEVEL_INVITES 0x0004000
+#define MSGLEVEL_NICKS 0x0008000
+#define MSGLEVEL_DCC 0x0010000
+#define MSGLEVEL_CLIENTNOTICE 0x0020000
+#define MSGLEVEL_CLIENTCRAP 0x0040000
+#define MSGLEVEL_CLIENTERROR 0x0080000
+#define MSGLEVEL_HILIGHT 0x0100000
-#define MSGLEVEL_ALL 0x03fffff
+#define MSGLEVEL_ALL 0x01fffff
#define MSGLEVEL_NOHILIGHT 0x1000000 /* Don't try to hilight words in this message */
#define MSGLEVEL_NO_ACT 0x2000000 /* Don't trigger channel activity */
diff --git a/src/core/server.c b/src/core/server.c
index dcfefc5a..a600e74a 100644
--- a/src/core/server.c
+++ b/src/core/server.c
@@ -60,7 +60,9 @@ static char *server_create_address_tag(const char *address)
const char *start, *end;
/* try to generate a reasonable server tag */
- if (g_strncasecmp(address, "irc", 3) == 0 ||
+ if (strchr(address, '.') == NULL) {
+ start = end = NULL;
+ } else if (g_strncasecmp(address, "irc", 3) == 0 ||
g_strncasecmp(address, "chat", 4) == 0) {
/* irc-2.cs.hut.fi -> hut, chat.bt.net -> bt */
end = strrchr(address, '.');
@@ -224,14 +226,14 @@ SERVER_REC *server_find_tag(const char *tag)
for (tmp = servers; tmp != NULL; tmp = tmp->next) {
SERVER_REC *server = tmp->data;
- if (strcmp(server->tag, tag) == 0)
+ if (g_strcasecmp(server->tag, tag) == 0)
return server;
}
for (tmp = lookup_servers; tmp != NULL; tmp = tmp->next) {
SERVER_REC *server = tmp->data;
- if (strcmp(server->tag, tag) == 0)
+ if (g_strcasecmp(server->tag, tag) == 0)
return server;
}
@@ -249,7 +251,7 @@ SERVER_REC *server_find_ircnet(const char *ircnet)
SERVER_REC *server = tmp->data;
if (server->connrec->ircnet != NULL &&
- strcmp(server->connrec->ircnet, ircnet) == 0) return server;
+ g_strcasecmp(server->connrec->ircnet, ircnet) == 0) return server;
}
return NULL;
diff --git a/src/core/settings.c b/src/core/settings.c
index 5db3c790..a7e27a63 100644
--- a/src/core/settings.c
+++ b/src/core/settings.c
@@ -258,7 +258,11 @@ static void init_configfile(void)
if (stat(str, &statbuf) != 0) {
/* ~/.irssi not found, create it. */
if (mkdir(str, 0700) != 0)
- g_error("Couldn't create %s/.irssi directory", g_get_home_dir());
+ g_error(_("Couldn't create %s/.irssi directory"), g_get_home_dir());
+ } else {
+ if (!S_ISDIR(statbuf.st_mode)) {
+ g_error(_("%s/.irssi is not a directory.\nYou should remove it with command: rm ~/.irssi"), g_get_home_dir());
+ }
}
g_free(str);
@@ -266,7 +270,7 @@ static void init_configfile(void)
/* any errors? */
if (config_last_error(mainconfig) != NULL) {
- last_error_msg = g_strdup_printf("Ignored errors in configuration file:\n%s",
+ last_error_msg = g_strdup_printf(_("Ignored errors in configuration file:\n%s"),
config_last_error(mainconfig));
signal_add("irssi init finished", (SIGNAL_FUNC) sig_print_config_error);
}
@@ -291,7 +295,7 @@ static void cmd_rehash(const char *data)
if (config_last_error(tempconfig) != NULL) {
/* error */
- str = g_strdup_printf("Errors in configuration file:\n%s",
+ str = g_strdup_printf(_("Errors in configuration file:\n%s"),
config_last_error(tempconfig));
signal_emit("gui dialog", 2, "error", str);
g_free(str);
@@ -308,7 +312,16 @@ static void cmd_rehash(const char *data)
static void cmd_save(const char *data)
{
- config_write(mainconfig, *data == '\0' ? NULL : data, 0660);
+ char *str;
+
+ if (config_write(mainconfig, *data == '\0' ? NULL : data, 0660) == 0)
+ return;
+
+ /* error */
+ str = g_strdup_printf(_("Couldn't save configuration file: %s"),
+ config_last_error(mainconfig));
+ signal_emit("gui dialog", 2, "error", str);
+ g_free(str);
}
void settings_init(void)
diff --git a/src/fe-common/core/Makefile.am b/src/fe-common/core/Makefile.am
index 025a9dda..c8931435 100644
--- a/src/fe-common/core/Makefile.am
+++ b/src/fe-common/core/Makefile.am
@@ -17,7 +17,7 @@ libfe_common_core_la_SOURCES = \
hilight-text.c \
keyboard.c \
module-formats.c \
- nick-hilight.c \
+ window-activity.c \
printtext.c \
themes.c \
translation.c \
diff --git a/src/fe-common/core/autorun.c b/src/fe-common/core/autorun.c
index f1e5d88d..506e45ff 100644
--- a/src/fe-common/core/autorun.c
+++ b/src/fe-common/core/autorun.c
@@ -44,7 +44,7 @@ static void sig_autorun(void)
recvlen = read(f, tmpbuf, sizeof(tmpbuf));
ret = line_split(tmpbuf, recvlen, &str, &buffer);
- eval_special_string(str, "", active_win->active_server, active_win->active);
+ if (ret > 0) eval_special_string(str, "", active_win->active_server, active_win->active);
} while (ret > 0);
line_split_free(buffer);
diff --git a/src/fe-common/core/command-history.c b/src/fe-common/core/command-history.c
index 01ae46d7..fa7a1375 100644
--- a/src/fe-common/core/command-history.c
+++ b/src/fe-common/core/command-history.c
@@ -151,7 +151,7 @@ static char *special_history_func(const char *text, void *item, int *free_ret)
static void read_settings(void)
{
- window_history = settings_get_bool("toggle_window_history");
+ window_history = settings_get_bool("window_history");
}
void command_history_init(void)
@@ -159,7 +159,7 @@ void command_history_init(void)
settings_add_int("history", "max_textwidget_lines", 1000);
settings_add_int("history", "block_remove_lines", 20);
settings_add_int("history", "max_command_history", 100);
- settings_add_bool("history", "toggle_window_history", FALSE);
+ settings_add_bool("history", "window_history", FALSE);
special_history_func_set(special_history_func);
diff --git a/src/fe-common/core/fe-common-core.c b/src/fe-common/core/fe-common-core.c
index d111584d..a348583d 100644
--- a/src/fe-common/core/fe-common-core.c
+++ b/src/fe-common/core/fe-common-core.c
@@ -47,37 +47,34 @@ void fe_server_deinit(void);
void fe_settings_init(void);
void fe_settings_deinit(void);
-void nick_hilight_init(void);
-void nick_hilight_deinit(void);
+void window_activity_init(void);
+void window_activity_deinit(void);
void fe_core_commands_init(void);
void fe_core_commands_deinit(void);
void fe_common_core_init(void)
{
- settings_add_bool("lookandfeel", "toggle_show_menubar", TRUE);
- settings_add_bool("lookandfeel", "toggle_show_toolbar", FALSE);
- settings_add_bool("lookandfeel", "toggle_show_statusbar", TRUE);
- settings_add_bool("lookandfeel", "toggle_show_nicklist", TRUE);
- settings_add_bool("lookandfeel", "toggle_show_timestamps", FALSE);
- settings_add_bool("lookandfeel", "toggle_show_msgs_timestamps", FALSE);
- settings_add_bool("lookandfeel", "toggle_hide_text_style", FALSE);
- settings_add_bool("lookandfeel", "toggle_bell_beeps", FALSE);
- settings_add_bool("lookandfeel", "toggle_actlist_moves", FALSE);
- settings_add_bool("lookandfeel", "toggle_show_nickmode", TRUE);
- settings_add_bool("lookandfeel", "toggle_show_topicbar", TRUE);
-
- settings_add_bool("lookandfeel", "toggle_use_status_window", FALSE);
- settings_add_bool("lookandfeel", "toggle_use_msgs_window", TRUE);
- settings_add_bool("lookandfeel", "toggle_autoraise_msgs_window", FALSE);
- settings_add_bool("lookandfeel", "toggle_autocreate_query", TRUE);
- settings_add_bool("lookandfeel", "toggle_notifylist_popups", FALSE);
- settings_add_bool("lookandfeel", "toggle_use_tabbed_windows", TRUE);
- settings_add_int("lookandfeel", "tab_orientation", 3);
+ /*settings_add_bool("lookandfeel", "show_menubar", TRUE);
+ settings_add_bool("lookandfeel", "show_toolbar", FALSE);
+ settings_add_bool("lookandfeel", "show_statusbar", TRUE);
+ settings_add_bool("lookandfeel", "show_nicklist", TRUE);*/
+ settings_add_bool("lookandfeel", "timestamps", TRUE);
+ settings_add_bool("lookandfeel", "msgs_timestamps", FALSE);
+ settings_add_bool("lookandfeel", "hide_text_style", FALSE);
+ settings_add_bool("lookandfeel", "bell_beeps", FALSE);
+ settings_add_bool("lookandfeel", "show_nickmode", TRUE);
+
+ settings_add_bool("lookandfeel", "use_status_window", FALSE);
+ settings_add_bool("lookandfeel", "use_msgs_window", TRUE);
+ /*settings_add_bool("lookandfeel", "autoraise_msgs_window", FALSE);*/
+ settings_add_bool("lookandfeel", "autocreate_query", TRUE);
+ /*settings_add_bool("lookandfeel", "use_tabbed_windows", TRUE);
+ settings_add_int("lookandfeel", "tab_orientation", 3);*/
settings_add_str("lookandfeel", "current_theme", "default");
autorun_init();
- nick_hilight_init();
+ window_activity_init();
hilight_text_init();
command_history_init();
keyboard_init();
@@ -95,7 +92,7 @@ void fe_common_core_init(void)
void fe_common_core_deinit(void)
{
autorun_deinit();
- nick_hilight_deinit();
+ window_activity_deinit();
hilight_text_deinit();
command_history_deinit();
keyboard_deinit();
@@ -116,13 +113,15 @@ void fe_common_core_finish_init(void)
signal(SIGPIPE, SIG_IGN);
- if (settings_get_bool("toggle_use_status_window")) {
+ if (settings_get_bool("use_status_window")) {
window = window_create(NULL, TRUE);
window_set_name(window, "(status)");
- window_set_level(window, MSGLEVEL_ALL ^ (settings_get_bool("toggle_use_msgs_window") ? (MSGLEVEL_MSGS|MSGLEVEL_ACTIONS) : 0));
+ window_set_level(window, MSGLEVEL_ALL ^
+ (settings_get_bool("use_msgs_window") ?
+ (MSGLEVEL_MSGS|MSGLEVEL_ACTIONS) : 0));
}
- if (settings_get_bool("toggle_use_msgs_window")) {
+ if (settings_get_bool("use_msgs_window")) {
window = window_create(NULL, TRUE);
window_set_name(window, "(msgs)");
window_set_level(window, MSGLEVEL_MSGS|MSGLEVEL_ACTIONS);
diff --git a/src/fe-common/core/fe-core-commands.c b/src/fe-common/core/fe-core-commands.c
index b036385d..41320eed 100644
--- a/src/fe-common/core/fe-core-commands.c
+++ b/src/fe-common/core/fe-core-commands.c
@@ -23,35 +23,35 @@
#include "signals.h"
#include "commands.h"
#include "levels.h"
+#include "misc.h"
#include "line-split.h"
#include "irssi-version.h"
#include "windows.h"
-static gchar *ret_texts[] =
-{
- "Invalid parameter",
- "Not enough parameters given",
- "Not connected to IRC server yet",
- "Not joined to any channels yet",
- "Error: getsockname() failed",
- "Error: listen() failed",
- "Multiple matches found, be more specific",
- "Nick not found",
- "Not joined to such channel",
- "Server not found",
- "Channel not fully synchronized yet, try again after a while",
- "Doing this is not a good idea. Add -YES if you really mean it",
+static const char *ret_texts[] = {
+ "Invalid parameter",
+ "Not enough parameters given",
+ "Not connected to IRC server yet",
+ "Not joined to any channels yet",
+ "Error: getsockname() failed",
+ "Error: listen() failed",
+ "Multiple matches found, be more specific",
+ "Nick not found",
+ "Not joined to such channel",
+ "Server not found",
+ "Channel not fully synchronized yet, try again after a while",
+ "Doing this is not a good idea. Add -YES if you really mean it",
};
-static gint commands_compare(COMMAND_REC *rec, COMMAND_REC *rec2)
+static int commands_compare(COMMAND_REC *rec, COMMAND_REC *rec2)
{
- if (rec->category == NULL && rec2->category != NULL)
- return -1;
- if (rec2->category == NULL && rec->category != NULL)
- return 1;
+ if (rec->category == NULL && rec2->category != NULL)
+ return -1;
+ if (rec2->category == NULL && rec->category != NULL)
+ return 1;
- return strcmp(rec->cmd, rec2->cmd);
+ return strcmp(rec->cmd, rec2->cmd);
}
static void help_category(GSList *cmdlist, gint items, gint max)
@@ -118,7 +118,7 @@ static int show_help(COMMAND_REC *cmd)
recvlen = read(f, tmpbuf, sizeof(tmpbuf));
ret = line_split(tmpbuf, recvlen, &str, &buffer);
- printtext(NULL, NULL, MSGLEVEL_NEVER, str);
+ if (ret > 0) printtext(NULL, NULL, MSGLEVEL_NEVER, str);
}
while (ret > 0);
line_split_free(buffer);
@@ -227,6 +227,37 @@ static void cmd_version(char *data)
printtext(NULL, NULL, MSGLEVEL_CLIENTNOTICE, "Client: "PACKAGE" " IRSSI_VERSION);
}
+static void cmd_cat(const char *data)
+{
+ char tmpbuf[1024], *str, *fname;
+ LINEBUF_REC *buffer = NULL;
+ int f, ret, recvlen;
+
+ fname = convert_home(data);
+ f = open(fname, O_RDONLY);
+ g_free(fname);
+ if (f == -1) {
+ /* file not found */
+ printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", g_strerror(errno));
+ return;
+ }
+
+ do {
+ recvlen = read(f, tmpbuf, sizeof(tmpbuf));
+
+ ret = line_split(tmpbuf, recvlen, &str, &buffer);
+ if (ret > 0) printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "%s", str);
+ } while (ret > 0);
+ line_split_free(buffer);
+
+ close(f);
+}
+
+static void cmd_beep(void)
+{
+ printbeep();
+}
+
static void cmd_unknown(const char *data, void *server, WI_ITEM_REC *item)
{
char *cmd;
@@ -248,6 +279,8 @@ void fe_core_commands_init(void)
command_bind("help", NULL, (SIGNAL_FUNC) cmd_help);
command_bind("echo", NULL, (SIGNAL_FUNC) cmd_echo);
command_bind("version", NULL, (SIGNAL_FUNC) cmd_version);
+ command_bind("cat", NULL, (SIGNAL_FUNC) cmd_cat);
+ command_bind("beep", NULL, (SIGNAL_FUNC) cmd_beep);
signal_add("unknown command", (SIGNAL_FUNC) cmd_unknown);
signal_add("default command", (SIGNAL_FUNC) cmd_unknown);
@@ -259,6 +292,8 @@ void fe_core_commands_deinit(void)
command_unbind("help", (SIGNAL_FUNC) cmd_help);
command_unbind("echo", (SIGNAL_FUNC) cmd_echo);
command_unbind("version", (SIGNAL_FUNC) cmd_version);
+ command_unbind("cat", (SIGNAL_FUNC) cmd_cat);
+ command_unbind("beep", (SIGNAL_FUNC) cmd_beep);
signal_remove("unknown command", (SIGNAL_FUNC) cmd_unknown);
signal_remove("default command", (SIGNAL_FUNC) cmd_unknown);
diff --git a/src/fe-common/core/fe-log.c b/src/fe-common/core/fe-log.c
index 636c461b..11fe5b2f 100644
--- a/src/fe-common/core/fe-log.c
+++ b/src/fe-common/core/fe-log.c
@@ -43,16 +43,16 @@ static const char *autolog_path;
static void cmd_log_open(const char *data)
{
- /* /LOG OPEN [-noopen] [-autoopen] [-channels <channels>] [-window]
+ /* /LOG OPEN [-noopen] [-autoopen] [-targets <targets>] [-window]
[-rotate hour|day|week|month] <fname> [<levels>] */
- char *params, *args, *itemarg, *rotatearg, *fname, *levels;
+ char *params, *args, *targetarg, *rotatearg, *fname, *levels;
char window[MAX_INT_STRLEN];
LOG_REC *log;
int opened, level, rotate;
- args = "channels rotate";
+ args = "targets rotate";
params = cmd_get_params(data, 5 | PARAM_FLAG_MULTIARGS | PARAM_FLAG_GETREST,
- &args, &itemarg, &rotatearg, &fname, &levels);
+ &args, &targetarg, &rotatearg, &fname, &levels);
if (*fname == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
rotate = LOG_ROTATE_NEVER;
@@ -67,10 +67,10 @@ static void cmd_log_open(const char *data)
if (stristr(args, "-window")) {
/* log by window ref# */
ltoa(window, active_win->refnum);
- itemarg = window;
+ targetarg = window;
}
- log = log_create_rec(fname, level, itemarg);
+ log = log_create_rec(fname, level, targetarg);
if (log != NULL && log->handle == -1 && stristr(args, "-noopen") == NULL) {
/* start logging */
opened = log_start_logging(log);
@@ -193,7 +193,7 @@ static void cmd_window_log(const char *data)
open_log = log == NULL;
close_log = log != NULL;
} else {
- printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NOT_TOGGLE);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOT_TOGGLE);
g_free(params);
return;
}
@@ -230,17 +230,34 @@ static void cmd_window_logfile(const char *data)
log = log_find_item(window);
if (log != NULL) {
- printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_WINDOWLOG_FILE_LOGGING);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_WINDOWLOG_FILE_LOGGING);
return;
}
log = log_create_rec(data, MSGLEVEL_ALL, window);
if (log == NULL)
- printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_WINDOWLOG_FILE, data);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_WINDOWLOG_FILE, data);
else
log_update(log);
}
+/* window's refnum changed - update the logs to log the new window refnum */
+static void sig_window_refnum_changed(WINDOW_REC *window, gpointer old_refnum)
+{
+ char winnum[MAX_INT_STRLEN];
+ LOG_REC *log;
+
+ ltoa(winnum, GPOINTER_TO_INT(old_refnum));
+ log = log_find_item(winnum);
+
+ if (log != NULL) {
+ ltoa(winnum, window->refnum);
+
+ g_strfreev(log->items);
+ log->items = g_strsplit(winnum, " ", -1);
+ }
+}
+
static void autologs_close_all(void)
{
GSList *tmp, *next;
@@ -379,6 +396,7 @@ void fe_log_init(void)
command_bind("window logfile", NULL, (SIGNAL_FUNC) cmd_window_logfile);
signal_add_first("print text stripped", (SIGNAL_FUNC) sig_printtext_stripped);
signal_add("window item remove", (SIGNAL_FUNC) sig_window_item_remove);
+ signal_add("window refnum changed", (SIGNAL_FUNC) sig_window_refnum_changed);
signal_add("log locked", (SIGNAL_FUNC) sig_log_locked);
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
}
@@ -397,6 +415,7 @@ void fe_log_deinit(void)
command_unbind("window logfile", (SIGNAL_FUNC) cmd_window_logfile);
signal_remove("print text stripped", (SIGNAL_FUNC) sig_printtext_stripped);
signal_remove("window item remove", (SIGNAL_FUNC) sig_window_item_remove);
+ signal_remove("window refnum changed", (SIGNAL_FUNC) sig_window_refnum_changed);
signal_remove("log locked", (SIGNAL_FUNC) sig_log_locked);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
}
diff --git a/src/fe-common/core/fe-server.c b/src/fe-common/core/fe-server.c
index 960b94f9..fff3d1fc 100644
--- a/src/fe-common/core/fe-server.c
+++ b/src/fe-common/core/fe-server.c
@@ -77,6 +77,14 @@ static void sig_server_disconnected(SERVER_REC *server)
IRCTXT_CONNECTION_LOST, server->connrec->address);
}
+static void sig_server_quit(SERVER_REC *server, const char *msg)
+{
+ g_return_if_fail(server != NULL);
+
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_SERVER_QUIT, server->connrec->address, msg);
+}
+
void fe_server_init(void)
{
signal_add("server looking", (SIGNAL_FUNC) sig_server_looking);
@@ -84,6 +92,7 @@ void fe_server_init(void)
signal_add("server connected", (SIGNAL_FUNC) sig_server_connected);
signal_add("server connect failed", (SIGNAL_FUNC) sig_connect_failed);
signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
+ signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
}
void fe_server_deinit(void)
@@ -93,4 +102,5 @@ void fe_server_deinit(void)
signal_remove("server connected", (SIGNAL_FUNC) sig_server_connected);
signal_remove("server connect failed", (SIGNAL_FUNC) sig_connect_failed);
signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
+ signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
}
diff --git a/src/fe-common/core/fe-settings.c b/src/fe-common/core/fe-settings.c
index 5e4b6df6..f05faad0 100644
--- a/src/fe-common/core/fe-settings.c
+++ b/src/fe-common/core/fe-settings.c
@@ -23,6 +23,7 @@
#include "signals.h"
#include "commands.h"
#include "server.h"
+#include "misc.h"
#include "lib-config/iconfig.h"
#include "settings.h"
@@ -66,19 +67,17 @@ static void cmd_set(char *data)
{
GSList *sets, *tmp;
char *params, *key, *value, *last_section;
- int keylen, found;
+ int found;
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &key, &value);
- keylen = strlen(key);
last_section = ""; found = 0;
-
sets = settings_get_sorted();
for (tmp = sets; tmp != NULL; tmp = tmp->next) {
SETTINGS_REC *rec = tmp->data;
if ((*value != '\0' && g_strcasecmp(rec->key, key) != 0) ||
- (*value == '\0' && keylen != 0 && g_strncasecmp(rec->key, key, keylen) != 0))
+ (*value == '\0' && *key != '\0' && stristr(rec->key, key) == NULL))
continue;
if (strcmp(last_section, rec->section) != 0) {
@@ -140,7 +139,7 @@ static void show_aliases(const char *alias)
GSList *tmp;
int aliaslen;
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_ALIASLIST_HEADER);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_ALIASLIST_HEADER);
node = iconfig_node_traverse("aliases", FALSE);
tmp = node == NULL ? NULL : node->value;
@@ -155,11 +154,11 @@ static void show_aliases(const char *alias)
if (aliaslen != 0 && g_strncasecmp(node->key, alias, aliaslen) != 0)
continue;
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_ALIASLIST_LINE,
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_ALIASLIST_LINE,
node->key, node->value);
}
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_ALIASLIST_FOOTER);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_ALIASLIST_FOOTER);
}
static void alias_remove(const char *alias)
diff --git a/src/fe-common/core/hilight-text.c b/src/fe-common/core/hilight-text.c
index a96f7395..61156e01 100644
--- a/src/fe-common/core/hilight-text.c
+++ b/src/fe-common/core/hilight-text.c
@@ -314,7 +314,7 @@ static void cmd_dehilight(const char *data)
if (is_numeric(data, ' ')) {
/* with index number */
- tmp = g_slist_nth(hilights, atol(data)-1);
+ tmp = g_slist_nth(hilights, atoi(data)-1);
rec = tmp == NULL ? NULL : tmp->data;
} else {
/* with mask */
diff --git a/src/fe-common/core/module-formats.c b/src/fe-common/core/module-formats.c
index e8287a98..358f467c 100644
--- a/src/fe-common/core/module-formats.c
+++ b/src/fe-common/core/module-formats.c
@@ -31,8 +31,13 @@ FORMAT_REC fecommon_core_formats[] =
{ "line_start", "%B-%W!%B-%n ", 0 },
{ "line_start_irssi", "%B-%W!%B- %WIrssi:%n ", 0 },
{ "timestamp", "[$[-2.0]3:$[-2.0]4] ", 6, { 1, 1, 1, 1, 1, 1 } },
- { "daychange", "Day changed to $[-2.0]1-$[-2.0]0 $2", 3, { 1, 1, 1 } },
+ { "daychange", "Day changed to ${[-2.0]1}-$[-2.0]0 $2", 3, { 1, 1, 1 } },
{ "talking_with", "You are now talking with %_$0%_", 1, { 0 } },
+ { "refnum_too_low", "Window number must be greater than 1", 0 },
+ { "refnum_not_found", "No such window: $0", 1, { 0 } },
+ { "windowlist_header", "Ref Name Active item Server Level", 0 },
+ { "windowlist_line", "$[3]0 %|$[20]1 $[15]2 $[15]3 $4", 5, { 1, 0, 0, 0, 0 } },
+ { "windowlist_footer", "", 0 },
/* ---- */
{ NULL, "Server", 0 },
@@ -42,6 +47,7 @@ FORMAT_REC fecommon_core_formats[] =
{ "connection_established", "Connection to %_$0%_ established", 1, { 0 } },
{ "cant_connect", "Unable to connect server %_$0%_ port %_$1%_ %K[%n$2%K]", 3, { 0, 1, 0 } },
{ "connection_lost", "Connection lost to %_$0%_", 1, { 0 } },
+ { "server_quit", "Disconnecting from server $0: %K[%n$1%K]", 2, { 0, 0 } },
{ "server_changed", "Changed to %_$2%_ server %_$1%_", 3, { 0, 0, 0 } },
{ "unknown_server_tag", "Unknown server tag %_$0%_", 1, { 0 } },
diff --git a/src/fe-common/core/module-formats.h b/src/fe-common/core/module-formats.h
index 6730f413..db94140e 100644
--- a/src/fe-common/core/module-formats.h
+++ b/src/fe-common/core/module-formats.h
@@ -10,6 +10,11 @@ enum {
IRCTXT_TIMESTAMP,
IRCTXT_DAYCHANGE,
IRCTXT_TALKING_WITH,
+ IRCTXT_REFNUM_TOO_LOW,
+ IRCTXT_REFNUM_NOT_FOUND,
+ IRCTXT_WINDOWLIST_HEADER,
+ IRCTXT_WINDOWLIST_LINE,
+ IRCTXT_WINDOWLIST_FOOTER,
IRCTXT_FILL_2,
@@ -18,6 +23,7 @@ enum {
IRCTXT_CONNECTION_ESTABLISHED,
IRCTXT_CANT_CONNECT,
IRCTXT_CONNECTION_LOST,
+ IRCTXT_SERVER_QUIT,
IRCTXT_SERVER_CHANGED,
IRCTXT_UNKNOWN_SERVER_TAG,
diff --git a/src/fe-common/core/printtext.c b/src/fe-common/core/printtext.c
index a80177b6..7152e910 100644
--- a/src/fe-common/core/printtext.c
+++ b/src/fe-common/core/printtext.c
@@ -1,7 +1,7 @@
/*
printtext.c : irssi
- Copyright (C) 1999 Timo Sirainen
+ Copyright (C) 1999-2000 Timo Sirainen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@
#include "themes.h"
#include "windows.h"
-static gboolean toggle_show_timestamps, toggle_show_msgs_timestamps, toggle_hide_text_style;
+static gboolean timestamps, msgs_timestamps, hide_text_style;
static gint printtag;
static gchar ansitab[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
@@ -108,7 +108,7 @@ static char *convert_ansi(char *str, int *fgcolor, int *bgcolor, int *flags)
if (*str == 'm')
{
- if (!toggle_hide_text_style)
+ if (!hide_text_style)
{
*fgcolor = fg;
*bgcolor = bg == -1 ? -1 : bg;
@@ -410,7 +410,7 @@ static void add_timestamp(WINDOW_REC *window, GString *out, void *server, const
struct tm *tm;
GString *tmp;
- if (!(level != MSGLEVEL_NEVER && (toggle_show_timestamps || (toggle_show_msgs_timestamps && (level & MSGLEVEL_MSGS) != 0))))
+ if (!(level != MSGLEVEL_NEVER && (timestamps || (msgs_timestamps && (level & MSGLEVEL_MSGS) != 0))))
return;
t = time(NULL);
@@ -574,6 +574,7 @@ static void sig_print_text(void *server, const char *target, gpointer level, con
flags = 0; fgcolor = -1; bgcolor = -1; type = '\0';
+ window->last_line = time(NULL);
newline(window);
out = g_string_new(text);
@@ -612,7 +613,7 @@ static void sig_print_text(void *server, const char *target, gpointer level, con
if (type == 7)
{
/* bell */
- if (settings_get_bool("toggle_bell_beeps"))
+ if (settings_get_bool("bell_beeps"))
flags |= PRINTFLAG_BEEP;
}
if (*str != '\0' || flags & PRINTFLAG_BEEP)
@@ -628,12 +629,12 @@ static void sig_print_text(void *server, const char *target, gpointer level, con
{
case 2:
/* bold */
- if (!toggle_hide_text_style)
+ if (!hide_text_style)
flags ^= PRINTFLAG_BOLD;
break;
case 6:
/* blink */
- if (!toggle_hide_text_style)
+ if (!hide_text_style)
flags ^= PRINTFLAG_BLINK;
break;
case 15:
@@ -643,12 +644,12 @@ static void sig_print_text(void *server, const char *target, gpointer level, con
break;
case 22:
/* reverse */
- if (!toggle_hide_text_style)
+ if (!hide_text_style)
flags ^= PRINTFLAG_REVERSE;
break;
case 31:
/* underline */
- if (!toggle_hide_text_style)
+ if (!hide_text_style)
flags ^= PRINTFLAG_UNDERLINE;
case 27:
/* ansi color code */
@@ -711,7 +712,7 @@ static void sig_print_text(void *server, const char *target, gpointer level, con
}
/* MIRC color */
- if (toggle_hide_text_style)
+ if (hide_text_style)
{
/* don't show them. */
if (isdigit((gint) *ptr))
@@ -776,7 +777,7 @@ static int sig_check_daychange(void)
time_t t;
struct tm *tm;
- if (!toggle_show_timestamps)
+ if (!timestamps)
{
/* display day change notice only when using timestamps */
return TRUE;
@@ -800,6 +801,9 @@ static int sig_check_daychange(void)
{
WINDOW_REC *win = tmp->data;
+ if (win->active == NULL)
+ continue; /* FIXME: how to print in these windows? */
+
printformat(win->active->server, win->active->name, MSGLEVEL_NEVER,
IRCTXT_DAYCHANGE, tm->tm_mday, tm->tm_mon+1, 1900+tm->tm_year);
}
@@ -833,9 +837,9 @@ static void sig_gui_dialog(const char *type, const char *text)
static void read_settings(void)
{
- toggle_show_timestamps = settings_get_bool("toggle_show_timestamps");
- toggle_show_msgs_timestamps = settings_get_bool("toggle_show_msgs_timestamps");
- toggle_hide_text_style = settings_get_bool("toggle_hide_text_style");
+ timestamps = settings_get_bool("timestamps");
+ msgs_timestamps = settings_get_bool("msgs_timestamps");
+ hide_text_style = settings_get_bool("hide_text_style");
}
void printtext_init(void)
@@ -852,7 +856,6 @@ void printtext_init(void)
signal_add("print text", (SIGNAL_FUNC) sig_print_text);
signal_add("gui dialog", (SIGNAL_FUNC) sig_gui_dialog);
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
- command_bind("beep", NULL, (SIGNAL_FUNC) printbeep);
}
void printtext_deinit(void)
@@ -861,5 +864,4 @@ void printtext_deinit(void)
signal_remove("print text", (SIGNAL_FUNC) sig_print_text);
signal_remove("gui dialog", (SIGNAL_FUNC) sig_gui_dialog);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
- command_unbind("beep", (SIGNAL_FUNC) printbeep);
}
diff --git a/src/fe-common/core/printtext.h b/src/fe-common/core/printtext.h
index 6c32522e..18f3246e 100644
--- a/src/fe-common/core/printtext.h
+++ b/src/fe-common/core/printtext.h
@@ -56,6 +56,9 @@ void printtext(void *server, const char *channel, int level, const char *str, ..
void printtext_multiline(void *server, const char *channel, int level, const char *format, const char *text);
void printbeep(void);
+/* strip all color (etc.) codes from `input'. returns newly allocated string. */
+char *strip_codes(const char *input);
+
void printtext_init(void);
void printtext_deinit(void);
diff --git a/src/fe-common/core/nick-hilight.c b/src/fe-common/core/window-activity.c
index 8244ff50..ba3adb13 100644
--- a/src/fe-common/core/nick-hilight.c
+++ b/src/fe-common/core/window-activity.c
@@ -1,5 +1,5 @@
/*
- nick-hilight.c : irssi
+ window-activity.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
@@ -57,6 +57,7 @@ static void sig_dehilight(WINDOW_REC *window, WI_ITEM_REC *item)
static void sig_dehilight_window(WINDOW_REC *window)
{
+ GSList *tmp;
int oldlevel;
g_return_if_fail(window != NULL);
@@ -71,7 +72,8 @@ static void sig_dehilight_window(WINDOW_REC *window)
}
signal_emit("window activity", 2, window, GINT_TO_POINTER(oldlevel));
- g_slist_foreach(window->items, (GFunc) sig_dehilight, NULL);
+ for (tmp = window->items; tmp != NULL; tmp = tmp->next)
+ sig_dehilight(window, tmp->data);
}
static void sig_hilight_window_item(WI_ITEM_REC *item)
@@ -96,7 +98,7 @@ static void sig_hilight_window_item(WI_ITEM_REC *item)
signal_emit("window activity", 2, window, GINT_TO_POINTER(oldlevel));
}
-void nick_hilight_init(void)
+void window_activity_init(void)
{
signal_add("print text", (SIGNAL_FUNC) sig_hilight_text);
signal_add("window item changed", (SIGNAL_FUNC) sig_dehilight);
@@ -105,7 +107,7 @@ void nick_hilight_init(void)
signal_add("window item hilight", (SIGNAL_FUNC) sig_hilight_window_item);
}
-void nick_hilight_deinit(void)
+void window_activity_deinit(void)
{
signal_remove("print text", (SIGNAL_FUNC) sig_hilight_text);
signal_remove("window item changed", (SIGNAL_FUNC) sig_dehilight);
diff --git a/src/fe-common/core/windows.c b/src/fe-common/core/windows.c
index 3a88833b..6587a4e8 100644
--- a/src/fe-common/core/windows.c
+++ b/src/fe-common/core/windows.c
@@ -24,6 +24,7 @@
#include "signals.h"
#include "commands.h"
#include "server.h"
+#include "misc.h"
#include "settings.h"
#include "levels.h"
@@ -32,7 +33,8 @@
#include "windows.h"
#include "window-items.h"
-GSList *windows;
+GSList *windows; /* first in the list is the active window,
+ next is the last active, etc. */
WINDOW_REC *active_win;
static int window_get_new_refnum(void)
@@ -65,7 +67,7 @@ WINDOW_REC *window_create(WI_ITEM_REC *item, int automatic)
rec = g_new0(WINDOW_REC, 1);
rec->refnum = window_get_new_refnum();
- windows = g_slist_append(windows, rec);
+ windows = g_slist_prepend(windows, rec);
signal_emit("window created", 2, rec, GINT_TO_POINTER(automatic));
if (item != NULL) window_add_item(rec, item, automatic);
@@ -77,8 +79,26 @@ WINDOW_REC *window_create(WI_ITEM_REC *item, int automatic)
return rec;
}
+/* removed_refnum was removed from the windows list, pack the windows so
+ there won't be any holes. If there is any holes after removed_refnum,
+ leave the windows behind it alone. */
+static void windows_pack(int removed_refnum)
+{
+ WINDOW_REC *window;
+ int refnum;
+
+ for (refnum = removed_refnum+1;; refnum++) {
+ window = window_find_refnum(refnum);
+ if (window == NULL) break;
+
+ window_set_refnum(window, refnum-1);
+ }
+}
+
void window_destroy(WINDOW_REC *window)
{
+ int refnum;
+
g_return_if_fail(window != NULL);
if (window->destroying) return;
@@ -93,29 +113,25 @@ void window_destroy(WINDOW_REC *window)
g_slist_foreach(window->waiting_channels, (GFunc) g_free, NULL);
g_slist_free(window->waiting_channels);
+ refnum = window->refnum;
g_free_not_null(window->name);
g_free(window);
-}
-void window_set_active_num(int number)
-{
- GSList *win;
-
- win = g_slist_nth(windows, number);
- if (win == NULL) return;
+ if (active_win == window && windows != NULL)
+ window_set_active(windows->data);
- active_win = win->data;
- signal_emit("window changed", 1, active_win);
+ windows_pack(refnum);
}
void window_set_active(WINDOW_REC *window)
{
- int number;
-
- number = g_slist_index(windows, window);
- if (number == -1) return;
+ if (window == active_win)
+ return;
active_win = window;
+ windows = g_slist_remove(windows, active_win);
+ windows = g_slist_prepend(windows, active_win);
+
signal_emit("window changed", 1, active_win);
}
@@ -125,6 +141,30 @@ void window_change_server(WINDOW_REC *window, void *server)
signal_emit("window server changed", 2, window, server);
}
+void window_set_refnum(WINDOW_REC *window, int refnum)
+{
+ GSList *tmp;
+ int old_refnum;
+
+ g_return_if_fail(window != NULL);
+ g_return_if_fail(refnum >= 1);
+ if (window->refnum == refnum) return;
+
+ for (tmp = windows; tmp != NULL; tmp = tmp->next) {
+ WINDOW_REC *rec = tmp->data;
+
+ if (rec->refnum == refnum) {
+ rec->refnum = window->refnum;
+ signal_emit("window refnum changed", 2, rec, GINT_TO_POINTER(refnum));
+ break;
+ }
+ }
+
+ old_refnum = window->refnum;
+ window->refnum = refnum;
+ signal_emit("window refnum changed", 2, window, GINT_TO_POINTER(old_refnum));
+}
+
void window_set_name(WINDOW_REC *window, const char *name)
{
g_free_not_null(window->name);
@@ -182,6 +222,68 @@ WINDOW_REC *window_find_closest(void *server, const char *name, int level)
return active_win;
}
+WINDOW_REC *window_find_refnum(int refnum)
+{
+ GSList *tmp;
+
+ for (tmp = windows; tmp != NULL; tmp = tmp->next) {
+ WINDOW_REC *rec = tmp->data;
+
+ if (rec->refnum == refnum)
+ return rec;
+ }
+
+ return NULL;
+}
+
+static int windows_refnum_last(void)
+{
+ GSList *tmp;
+ int max;
+
+ max = -1;
+ for (tmp = windows; tmp != NULL; tmp = tmp->next) {
+ WINDOW_REC *rec = tmp->data;
+
+ if (rec->refnum > max)
+ max = rec->refnum;
+ }
+
+ return max;
+}
+
+static int window_refnum_prev(int refnum)
+{
+ GSList *tmp;
+ int max;
+
+ max = -1;
+ for (tmp = windows; tmp != NULL; tmp = tmp->next) {
+ WINDOW_REC *rec = tmp->data;
+
+ if (rec->refnum < refnum && (max == -1 || rec->refnum > max))
+ max = rec->refnum;
+ }
+
+ return max;
+}
+
+static int window_refnum_next(int refnum)
+{
+ GSList *tmp;
+ int min;
+
+ min = -1;
+ for (tmp = windows; tmp != NULL; tmp = tmp->next) {
+ WINDOW_REC *rec = tmp->data;
+
+ if (rec->refnum > refnum && (min == -1 || rec->refnum < min))
+ min = rec->refnum;
+ }
+
+ return min;
+}
+
static void cmd_window(const char *data, void *server, WI_ITEM_REC *item)
{
command_runsub("window", data, server, item);
@@ -194,7 +296,7 @@ static void cmd_window_new(const char *data, void *server, WI_ITEM_REC *item)
g_return_if_fail(data != NULL);
- type = (g_strcasecmp(data, "hide") == 0 || g_strcasecmp(data, "tab") == 0) ? 1 :
+ type = (g_strncasecmp(data, "hid", 3) == 0 || g_strcasecmp(data, "tab") == 0) ? 1 :
(g_strcasecmp(data, "split") == 0 ? 2 : 0);
signal_emit("gui window create override", 1, GINT_TO_POINTER(type));
@@ -210,13 +312,15 @@ static void cmd_window_close(const char *data)
}
/* return the first window number with the highest activity */
-static int window_highest_activity(WINDOW_REC *window)
+static WINDOW_REC *window_highest_activity(WINDOW_REC *window)
{
- WINDOW_REC *rec;
+ WINDOW_REC *rec, *max_win;
GSList *tmp;
- int max_num, max_act, through;
+ int max_act, through;
+
+ g_return_val_if_fail(window != NULL, NULL);
- max_num = 0; max_act = 0; through = FALSE;
+ max_win = NULL; max_act = 0; through = FALSE;
tmp = g_slist_find(windows, window);
for (;; tmp = tmp->next) {
@@ -232,20 +336,41 @@ static int window_highest_activity(WINDOW_REC *window)
if (rec->new_data && max_act < rec->new_data) {
max_act = rec->new_data;
- max_num = g_slist_index(windows, rec)+1;
+ max_win = rec;
}
}
- return max_num;
+ return max_win;
}
-/* channel name - first try channel from same server */
-static int window_find_name(WINDOW_REC *window, const char *name)
+WINDOW_REC *window_find_name(const char *name)
{
+ GSList *tmp;
+
+ g_return_val_if_fail(name != NULL, NULL);
+
+ for (tmp = windows; tmp != NULL; tmp = tmp->next) {
+ WINDOW_REC *rec = tmp->data;
+
+ if (rec->name != NULL && g_strcasecmp(rec->name, name) == 0)
+ return rec;
+ }
+
+ return NULL;
+}
+
+WINDOW_REC *window_find_item(WINDOW_REC *window, const char *name)
+{
+ WINDOW_REC *rec;
WI_ITEM_REC *item;
- int num;
- item = window_item_find(window->active_server, name);
+ g_return_val_if_fail(name != NULL, NULL);
+
+ rec = window_find_name(name);
+ if (rec != NULL) return rec;
+
+ item = window == NULL ? NULL :
+ window_item_find(window->active_server, name);
if (item == NULL && window->active_server != NULL) {
/* not found from the active server - any server? */
item = window_item_find(NULL, name);
@@ -257,7 +382,8 @@ static int window_find_name(WINDOW_REC *window, const char *name)
/* still nothing? maybe user just left the # in front of
channel, try again with it.. */
chan = g_strdup_printf("#%s", name);
- item = window_item_find(window->active_server, chan);
+ item = window == NULL ? NULL :
+ window_item_find(window->active_server, chan);
if (item == NULL) item = window_item_find(NULL, chan);
g_free(chan);
}
@@ -265,48 +391,63 @@ static int window_find_name(WINDOW_REC *window, const char *name)
if (item == NULL)
return 0;
- /* get the window number */
- window = MODULE_DATA(item);
- if (window == NULL) return 0;
+ return MODULE_DATA(item);
+}
- num = g_slist_index(windows, window);
- return num < 0 ? 0 : num+1;
+static void cmd_window_refnum(const char *data)
+{
+ WINDOW_REC *window;
+
+ if (!is_numeric(data, 0)) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_REFNUM_NOT_FOUND, data);
+ return;
+ }
+
+ window = window_find_refnum(atoi(data));
+ if (window == NULL)
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_REFNUM_NOT_FOUND, data);
+ else
+ window_set_active(window);
}
static void cmd_window_goto(const char *data)
{
- int num;
+ WINDOW_REC *window;
g_return_if_fail(data != NULL);
- num = 0;
+ if (is_numeric(data, 0)) {
+ cmd_window_refnum(data);
+ return;
+ }
+
if (g_strcasecmp(data, "active") == 0)
- num = window_highest_activity(active_win);
- else if (isdigit(*data))
- num = atol(data);
+ window = window_highest_activity(active_win);
else
- num = window_find_name(active_win, data);
+ window = window_find_item(active_win, data);
- if (num > 0)
- window_set_active_num(num-1);
+ if (window != NULL)
+ window_set_active(window);
}
-static void cmd_window_next(const char *data)
+static void cmd_window_next(void)
{
int num;
- num = g_slist_index(windows, active_win)+1;
- if (num >= g_slist_length(windows)) num = 0;
- window_set_active_num(num);
+ num = window_refnum_next(active_win->refnum);
+ if (num < 1) num = windows_refnum_last();
+
+ window_set_active(window_find_refnum(num));
}
-static void cmd_window_prev(const char *data)
+static void cmd_window_prev(void)
{
int num;
- num = g_slist_index(windows, active_win)-1;
- if (num < 0) num = g_slist_length(windows)-1;
- window_set_active_num(num);
+ num = window_refnum_prev(active_win->refnum);
+ if (num < 1) num = window_refnum_next(0);
+
+ window_set_active(window_find_refnum(num));
}
static void cmd_window_level(const char *data)
@@ -392,11 +533,155 @@ static void cmd_window_item_next(const char *data, void *server, WI_ITEM_REC *it
window_item_set_active(window, next);
}
+static void cmd_window_number(const char *data)
+{
+ int num;
+
+ num = atoi(data);
+ if (num < 1)
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_REFNUM_TOO_LOW);
+ else
+ window_set_refnum(active_win, num);
+}
+
static void cmd_window_name(const char *data)
{
window_set_name(active_win, data);
}
+/* we're moving the first window to last - move the first contiguous block
+ of refnums to left. Like if there's windows 1..5 and 7..10, move 1 to
+ 11, 2..5 to 1..4 and leave 7..10 alone */
+static void windows_move_left(WINDOW_REC *move_window)
+{
+ WINDOW_REC *window;
+ int refnum;
+
+ window_set_refnum(move_window, windows_refnum_last()+1);
+ for (refnum = 2;; refnum++) {
+ window = window_find_refnum(refnum);
+ if (window == NULL) break;
+
+ window_set_refnum(window, refnum-1);
+ }
+}
+
+/* we're moving the last window to first - make some space so we can use the
+ refnum 1 */
+static void windows_move_right(WINDOW_REC *move_window)
+{
+ WINDOW_REC *window;
+ int refnum;
+
+ /* find the first unused refnum, like if there's windows
+ 1..5 and 7..10, we only need to move 1..5 to 2..6 */
+ refnum = 1;
+ while (window_find_refnum(refnum) != NULL) refnum++;
+
+ refnum--;
+ while (refnum > 0) {
+ window = window_find_refnum(refnum);
+ g_return_if_fail(window != NULL);
+ window_set_refnum(window, window == move_window ? 1 : refnum+1);
+
+ refnum--;
+ }
+}
+
+static void cmd_window_move_left(void)
+{
+ int refnum;
+
+ refnum = window_refnum_prev(active_win->refnum);
+ if (refnum != -1) {
+ window_set_refnum(active_win, active_win->refnum-1);
+ return;
+ }
+
+ windows_move_left(active_win);
+}
+
+static void cmd_window_move_right(void)
+{
+ int refnum;
+
+ refnum = window_refnum_next(active_win->refnum);
+ if (refnum != -1) {
+ window_set_refnum(active_win, active_win->refnum+1);
+ return;
+ }
+
+ windows_move_right(active_win);
+}
+
+static void cmd_window_move(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
+{
+ int new_refnum, refnum;
+
+ if (!is_numeric(data, 0)) {
+ command_runsub("window move", data, server, item);
+ return;
+ }
+
+ new_refnum = atoi(data);
+ if (new_refnum > active_win->refnum) {
+ for (;;) {
+ refnum = window_refnum_next(active_win->refnum);
+ if (refnum == -1 || refnum > new_refnum)
+ break;
+
+ window_set_refnum(active_win, refnum);
+ }
+ } else {
+ for (;;) {
+ refnum = window_refnum_prev(active_win->refnum);
+ if (refnum == -1 || refnum < new_refnum)
+ break;
+
+ window_set_refnum(active_win, refnum);
+ }
+ }
+}
+
+static int windows_compare(WINDOW_REC *w1, WINDOW_REC *w2)
+{
+ return w1->refnum < w2->refnum ? -1 : 1;
+}
+
+GSList *windows_get_sorted(void)
+{
+ GSList *tmp, *list;
+
+ list = NULL;
+ for (tmp = windows; tmp != NULL; tmp = tmp->next) {
+ list = g_slist_insert_sorted(list, tmp->data, (GCompareFunc) windows_compare);
+ }
+
+ return list;
+}
+
+static void cmd_window_list(void)
+{
+ GSList *tmp, *sorted;
+ char *levelstr;
+
+ sorted = windows_get_sorted();
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_WINDOWLIST_HEADER);
+ for (tmp = sorted; tmp != NULL; tmp = tmp->next) {
+ WINDOW_REC *rec = tmp->data;
+
+ levelstr = bits2level(rec->level);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_WINDOWLIST_LINE,
+ rec->refnum, rec->name == NULL ? "" : rec->name,
+ rec->active == NULL ? "" : rec->active->name,
+ rec->active_server == NULL ? "" : ((SERVER_REC *) rec->active_server)->tag,
+ levelstr);
+ g_free(levelstr);
+ }
+ g_slist_free(sorted);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_WINDOWLIST_FOOTER);
+}
+
static void sig_server_looking(void *server)
{
GSList *tmp;
@@ -434,14 +719,21 @@ void windows_init(void)
command_bind("window", NULL, (SIGNAL_FUNC) cmd_window);
command_bind("window new", NULL, (SIGNAL_FUNC) cmd_window_new);
command_bind("window close", NULL, (SIGNAL_FUNC) cmd_window_close);
+ command_bind("window kill", NULL, (SIGNAL_FUNC) cmd_window_close);
command_bind("window server", NULL, (SIGNAL_FUNC) cmd_window_server);
+ command_bind("window refnum", NULL, (SIGNAL_FUNC) cmd_window_refnum);
command_bind("window goto", NULL, (SIGNAL_FUNC) cmd_window_goto);
command_bind("window prev", NULL, (SIGNAL_FUNC) cmd_window_prev);
command_bind("window next", NULL, (SIGNAL_FUNC) cmd_window_next);
command_bind("window level", NULL, (SIGNAL_FUNC) cmd_window_level);
command_bind("window item prev", NULL, (SIGNAL_FUNC) cmd_window_item_prev);
command_bind("window item next", NULL, (SIGNAL_FUNC) cmd_window_item_next);
+ command_bind("window number", NULL, (SIGNAL_FUNC) cmd_window_number);
command_bind("window name", NULL, (SIGNAL_FUNC) cmd_window_name);
+ command_bind("window move", NULL, (SIGNAL_FUNC) cmd_window_move);
+ command_bind("window move left", NULL, (SIGNAL_FUNC) cmd_window_move_left);
+ command_bind("window move right", NULL, (SIGNAL_FUNC) cmd_window_move_right);
+ command_bind("window list", NULL, (SIGNAL_FUNC) cmd_window_list);
signal_add("server looking", (SIGNAL_FUNC) sig_server_looking);
signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
signal_add("server connect failed", (SIGNAL_FUNC) sig_server_disconnected);
@@ -452,14 +744,21 @@ void windows_deinit(void)
command_unbind("window", (SIGNAL_FUNC) cmd_window);
command_unbind("window new", (SIGNAL_FUNC) cmd_window_new);
command_unbind("window close", (SIGNAL_FUNC) cmd_window_close);
+ command_unbind("window kill", (SIGNAL_FUNC) cmd_window_close);
command_unbind("window server", (SIGNAL_FUNC) cmd_window_server);
+ command_unbind("window refnum", (SIGNAL_FUNC) cmd_window_refnum);
command_unbind("window goto", (SIGNAL_FUNC) cmd_window_goto);
command_unbind("window prev", (SIGNAL_FUNC) cmd_window_prev);
command_unbind("window next", (SIGNAL_FUNC) cmd_window_next);
command_unbind("window level", (SIGNAL_FUNC) cmd_window_level);
command_unbind("window item prev", (SIGNAL_FUNC) cmd_window_item_prev);
command_unbind("window item next", (SIGNAL_FUNC) cmd_window_item_next);
+ command_unbind("window number", (SIGNAL_FUNC) cmd_window_number);
command_unbind("window name", (SIGNAL_FUNC) cmd_window_name);
+ command_unbind("window move", (SIGNAL_FUNC) cmd_window_move);
+ command_unbind("window move left", (SIGNAL_FUNC) cmd_window_move_left);
+ command_unbind("window move right", (SIGNAL_FUNC) cmd_window_move_right);
+ command_unbind("window list", (SIGNAL_FUNC) cmd_window_list);
signal_remove("server looking", (SIGNAL_FUNC) sig_server_looking);
signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
signal_remove("server connect failed", (SIGNAL_FUNC) sig_server_disconnected);
diff --git a/src/fe-common/core/windows.h b/src/fe-common/core/windows.h
index f279e888..a3b06d86 100644
--- a/src/fe-common/core/windows.h
+++ b/src/fe-common/core/windows.h
@@ -41,6 +41,7 @@ typedef struct {
int level;
int new_data;
time_t last_timestamp; /* When was last timestamp printed */
+ time_t last_line; /* When was last line printed */
gpointer gui_data;
} WINDOW_REC;
@@ -55,11 +56,15 @@ void window_set_active_num(int number);
void window_set_active(WINDOW_REC *window);
void window_change_server(WINDOW_REC *window, void *server);
+void window_set_refnum(WINDOW_REC *window, int refnum);
void window_set_name(WINDOW_REC *window, const char *name);
void window_set_level(WINDOW_REC *window, int level);
WINDOW_REC *window_find_level(void *server, int level);
WINDOW_REC *window_find_closest(void *server, const char *name, int level);
+WINDOW_REC *window_find_refnum(int refnum);
+WINDOW_REC *window_find_name(const char *name);
+WINDOW_REC *window_find_item(WINDOW_REC *window, const char *name);
void windows_init(void);
void windows_deinit(void);
diff --git a/src/fe-common/irc/Makefile.am b/src/fe-common/irc/Makefile.am
index 440f14bd..d4ca3f70 100644
--- a/src/fe-common/irc/Makefile.am
+++ b/src/fe-common/irc/Makefile.am
@@ -15,13 +15,15 @@ libfe_common_irc_la_SOURCES = \
completion.c \
fe-channels.c \
fe-irc-commands.c \
+ fe-irc-server.c \
fe-ctcp.c \
fe-events.c \
fe-events-numeric.c \
fe-ignore.c \
+ fe-netsplit.c \
fe-query.c \
fe-common-irc.c \
- irc-nick-hilight.c \
+ irc-window-activity.c \
irc-hilight-text.c \
module-formats.c
diff --git a/src/fe-common/irc/dcc/module-formats.h b/src/fe-common/irc/dcc/module-formats.h
index 40d6f090..bc58035e 100644
--- a/src/fe-common/irc/dcc/module-formats.h
+++ b/src/fe-common/irc/dcc/module-formats.h
@@ -6,9 +6,9 @@ enum {
IRCTXT_FILL_1,
IRCTXT_OWN_DCC,
- IRCTXT_DCC_MSG,
IRCTXT_OWN_DCC_ME,
IRCTXT_OWN_DCC_CTCP,
+ IRCTXT_DCC_MSG,
IRCTXT_ACTION_DCC,
IRCTXT_DCC_CTCP,
IRCTXT_DCC_CHAT,
diff --git a/src/fe-common/irc/fe-channels.c b/src/fe-common/irc/fe-channels.c
index c95e6411..6403412a 100644
--- a/src/fe-common/irc/fe-channels.c
+++ b/src/fe-common/irc/fe-channels.c
@@ -24,9 +24,12 @@
#include "signals.h"
#include "commands.h"
#include "levels.h"
+#include "misc.h"
#include "irc.h"
#include "channels.h"
+#include "channels-setup.h"
+#include "nicklist.h"
#include "windows.h"
#include "window-items.h"
@@ -100,6 +103,134 @@ static void cmd_wjoin(const char *data, void *server, WI_ITEM_REC *item)
signal_remove("channel created", (SIGNAL_FUNC) signal_channel_created_curwin);
}
+static void cmd_channel_list_joined(void)
+{
+ CHANNEL_REC *channel;
+ GString *nicks;
+ GSList *nicklist, *tmp, *ntmp;
+ char *mode;
+
+ if (channels == NULL) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOT_IN_CHANNELS);
+ return;
+ }
+
+ /* print active channel */
+ channel = irc_item_channel(active_win->active);
+ if (channel != NULL)
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CURRENT_CHANNEL, channel->name);
+
+ /* print list of all channels, their modes, server tags and nicks */
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_CHANLIST_HEADER);
+ for (tmp = channels; tmp != NULL; tmp = tmp->next) {
+ channel = tmp->data;
+
+ nicklist = nicklist_getnicks(channel);
+ mode = channel_get_mode(channel);
+ nicks = g_string_new(NULL);
+ for (ntmp = nicklist; ntmp != NULL; ntmp = ntmp->next) {
+ NICK_REC *rec = ntmp->data;
+
+ g_string_sprintfa(nicks, "%s ", rec->nick);
+ }
+
+ g_string_truncate(nicks, nicks->len-1);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_CHANLIST_LINE,
+ channel->name, mode, channel->server->tag, nicks->str);
+
+ g_free(mode);
+ g_slist_free(nicklist);
+ g_string_free(nicks, TRUE);
+ }
+}
+
+static void cmd_channel_list(void)
+{
+ GString *str;
+ GSList *tmp;
+
+ str = g_string_new(NULL);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_CHANSETUP_HEADER);
+ for (tmp = setupchannels; tmp != NULL; tmp = tmp->next) {
+ SETUP_CHANNEL_REC *rec = tmp->data;
+
+ g_string_truncate(str, 0);
+ if (rec->autojoin)
+ g_string_append(str, "autojoin ");
+ if (rec->botmasks != NULL && *rec->botmasks != '\0')
+ g_string_sprintfa(str, "bots: %s ", rec->botmasks);
+ if (rec->autosendcmd != NULL && *rec->autosendcmd != '\0')
+ g_string_sprintfa(str, "botcmd: %s ", rec->autosendcmd);
+
+ g_string_truncate(str, str->len-1);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_CHANSETUP_LINE,
+ rec->name, rec->ircnet == NULL ? "" : rec->ircnet,
+ rec->password == NULL ? "" : rec->password, str->str);
+ }
+ g_string_free(str, TRUE);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_CHANSETUP_FOOTER);
+}
+
+static void cmd_channel(const char *data, IRC_SERVER_REC *server, WI_ITEM_REC *item)
+{
+ if (ischannel(*data)) {
+ signal_emit("command join", 2, data, server);
+ return;
+ }
+
+ command_runsub("channel", data, server, item);
+}
+
+static void cmd_channel_add(const char *data)
+{
+ char *params, *args, *botarg, *botcmdarg, *ircnet, *channel, *password;
+ SETUP_CHANNEL_REC *rec;
+
+ args = "bots botcmd";
+ params = cmd_get_params(data, 6 | PARAM_FLAG_MULTIARGS, &args,
+ &botarg, &botcmdarg, &channel, &ircnet, &password);
+
+ if (*ircnet == '\0' || *channel == '\0')
+ cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+ rec = channels_setup_find(channel, ircnet);
+ if (rec == NULL) {
+ rec = g_new0(SETUP_CHANNEL_REC, 1);
+ rec->name = g_strdup(channel);
+ rec->ircnet = g_strdup(ircnet);
+ } else {
+ g_free_not_null(rec->botmasks);
+ g_free_not_null(rec->autosendcmd);
+ g_free_not_null(rec->password);
+ }
+ rec->autojoin = stristr(args, "-auto") != NULL;
+ rec->botmasks = *botarg == '\0' ? NULL : g_strdup(botarg);
+ rec->autosendcmd = *botcmdarg == '\0' ? NULL : g_strdup(botcmdarg);
+ rec->password = *password == '\0' ? NULL : g_strdup(password);
+ channels_setup_create(rec);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CHANSETUP_ADDED, channel, ircnet);
+
+ g_free(params);
+}
+
+static void cmd_channel_remove(const char *data)
+{
+ char *params, *ircnet, *channel;
+ SETUP_CHANNEL_REC *rec;
+
+ params = cmd_get_params(data, 2, &channel, &ircnet);
+ if (*ircnet == '\0' || *channel == '\0')
+ cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ rec = channels_setup_find(channel, ircnet);
+ if (rec == NULL)
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CHANSETUP_NOT_FOUND, channel, ircnet);
+ else {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CHANSETUP_REMOVED, channel, ircnet);
+ channels_setup_destroy(rec);
+ }
+ g_free(params);
+}
+
void fe_channels_init(void)
{
signal_add("channel created", (SIGNAL_FUNC) signal_channel_created);
@@ -109,6 +240,11 @@ void fe_channels_init(void)
signal_add_last("server disconnected", (SIGNAL_FUNC) sig_disconnected);
command_bind("wjoin", NULL, (SIGNAL_FUNC) cmd_wjoin);
+ command_bind("channel ", NULL, (SIGNAL_FUNC) cmd_channel_list_joined);
+ command_bind("channel", NULL, (SIGNAL_FUNC) cmd_channel);
+ command_bind("channel add", NULL, (SIGNAL_FUNC) cmd_channel_add);
+ command_bind("channel remove", NULL, (SIGNAL_FUNC) cmd_channel_remove);
+ command_bind("channel list", NULL, (SIGNAL_FUNC) cmd_channel_list);
}
void fe_channels_deinit(void)
@@ -120,4 +256,9 @@ void fe_channels_deinit(void)
signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
command_unbind("wjoin", (SIGNAL_FUNC) cmd_wjoin);
+ command_unbind("channel", (SIGNAL_FUNC) cmd_channel);
+ command_unbind("channel ", (SIGNAL_FUNC) cmd_channel_list_joined);
+ command_unbind("channel add", (SIGNAL_FUNC) cmd_channel_add);
+ command_unbind("channel remove", (SIGNAL_FUNC) cmd_channel_remove);
+ command_unbind("channel list", (SIGNAL_FUNC) cmd_channel_list);
}
diff --git a/src/fe-common/irc/fe-common-irc.c b/src/fe-common/irc/fe-common-irc.c
index b8166f5e..bde1d9fe 100644
--- a/src/fe-common/irc/fe-common-irc.c
+++ b/src/fe-common/irc/fe-common-irc.c
@@ -35,6 +35,9 @@ void fe_channels_deinit(void);
void fe_irc_commands_init(void);
void fe_irc_commands_deinit(void);
+void fe_irc_server_init(void);
+void fe_irc_server_deinit(void);
+
void fe_ctcp_init(void);
void fe_ctcp_deinit(void);
@@ -53,8 +56,8 @@ void fe_ignore_deinit(void);
void fe_query_init(void);
void fe_query_deinit(void);
-void irc_nick_hilight_init(void);
-void irc_nick_hilight_deinit(void);
+void irc_window_activity_init(void);
+void irc_window_activity_deinit(void);
void fe_notifylist_init(void);
void fe_notifylist_deinit(void);
@@ -62,6 +65,9 @@ void fe_notifylist_deinit(void);
void fe_flood_init(void);
void fe_flood_deinit(void);
+void fe_netsplit_init(void);
+void fe_netsplit_deinit(void);
+
static char *autocon_server;
static char *autocon_password;
static int autocon_port;
@@ -96,6 +102,7 @@ void fe_common_irc_init(void)
fe_channels_init();
fe_irc_commands_init();
+ fe_irc_server_init();
fe_ctcp_init();
fe_dcc_init();
fe_events_init();
@@ -103,15 +110,17 @@ void fe_common_irc_init(void)
fe_ignore_init();
fe_notifylist_init();
fe_flood_init();
+ fe_netsplit_init();
fe_query_init();
completion_init();
- irc_nick_hilight_init();
+ irc_window_activity_init();
}
void fe_common_irc_deinit(void)
{
fe_channels_deinit();
fe_irc_commands_deinit();
+ fe_irc_server_deinit();
fe_ctcp_deinit();
fe_dcc_deinit();
fe_events_deinit();
@@ -119,9 +128,10 @@ void fe_common_irc_deinit(void)
fe_ignore_deinit();
fe_notifylist_deinit();
fe_flood_deinit();
+ fe_netsplit_deinit();
fe_query_deinit();
completion_deinit();
- irc_nick_hilight_deinit();
+ irc_window_activity_deinit();
}
void fe_common_irc_finish_init(void)
@@ -162,7 +172,7 @@ void fe_common_irc_finish_init(void)
if (*rec->ircnet != '\0')
ircnets = g_slist_append(ircnets, rec->ircnet);
- str = g_strdup_printf("%s %d", rec->server, rec->port);
+ str = g_strdup_printf("%s %d", rec->address, rec->port);
signal_emit("command connect", 1, str);
g_free(str);
}
diff --git a/src/fe-common/irc/fe-events-numeric.c b/src/fe-common/irc/fe-events-numeric.c
index 44169fe8..5b692e58 100644
--- a/src/fe-common/irc/fe-events-numeric.c
+++ b/src/fe-common/irc/fe-events-numeric.c
@@ -607,7 +607,7 @@ static void event_motd(gchar *data, SERVER_REC *server, gchar *nick, gchar *addr
/* numeric event. */
gchar *params, *args, *ptr;
- if (settings_get_bool("toggle_skip_motd"))
+ if (settings_get_bool("skip_motd"))
return;
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, NULL, &args);
diff --git a/src/fe-common/irc/fe-events.c b/src/fe-common/irc/fe-events.c
index c846211a..f6a2557c 100644
--- a/src/fe-common/irc/fe-events.c
+++ b/src/fe-common/irc/fe-events.c
@@ -32,6 +32,7 @@
#include "query.h"
#include "nicklist.h"
#include "ignore.h"
+#include "netsplit.h"
#include "irc-hilight-text.h"
#include "windows.h"
@@ -83,7 +84,7 @@ static void event_privmsg(gchar *data, IRC_SERVER_REC *server, gchar *nick, gcha
color = irc_hilight_find_nick(target, nick, addr);
nickrec = chanrec == NULL ? NULL : nicklist_find(chanrec, nick);
- nickmode = !settings_get_bool("toggle_show_nickmode") || nickrec == NULL ? "" :
+ nickmode = !settings_get_bool("show_nickmode") || nickrec == NULL ? "" :
nickrec->op ? "@" : nickrec->voice ? "+" : " ";
window = chanrec == NULL ? NULL : window_item_window((WI_ITEM_REC *) chanrec);
@@ -125,7 +126,7 @@ static void event_privmsg(gchar *data, IRC_SERVER_REC *server, gchar *nick, gcha
else
{
/* private message */
- if (settings_get_bool("toggle_autocreate_query") && query_find(server, nick) == NULL)
+ if (settings_get_bool("autocreate_query") && query_find(server, nick) == NULL)
item = (WI_ITEM_REC *) query_create(server, nick, TRUE);
else
item = (WI_ITEM_REC *) query_find(server, nick);
@@ -183,7 +184,7 @@ static void ctcp_action_msg(gchar *data, IRC_SERVER_REC *server, gchar *nick, gc
else
{
/* private action */
- if (settings_get_bool("toggle_autocreate_query") && query_find(server, nick) == NULL)
+ if (settings_get_bool("autocreate_query") && query_find(server, nick) == NULL)
item = (WI_ITEM_REC *) query_create(server, nick, TRUE);
else
item = (WI_ITEM_REC *) channel_find(server, nick);
@@ -280,6 +281,9 @@ static void event_quit(const char *data, IRC_SERVER_REC *server, const char *nic
if (ignore_check(server, nick, addr, NULL, data, MSGLEVEL_QUITS))
return;
+ if (settings_get_bool("hide_netsplit_quits") && quitmsg_is_split(data))
+ return;
+
print_channel = NULL;
once = settings_get_bool("show_quit_once");
chans = !once ? NULL : g_string_new(NULL);
@@ -558,46 +562,46 @@ static void event_ban_type_changed(gchar *bantype)
static void sig_server_lag_disconnected(IRC_SERVER_REC *server)
{
- g_return_if_fail(server != NULL);
+ g_return_if_fail(server != NULL);
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
- IRCTXT_LAG_DISCONNECTED, server->connrec->address, time(NULL)-server->lag_sent);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_LAG_DISCONNECTED, server->connrec->address, time(NULL)-server->lag_sent);
}
static void sig_server_reconnect_removed(RECONNECT_REC *reconnect)
{
- g_return_if_fail(reconnect != NULL);
+ g_return_if_fail(reconnect != NULL);
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
- IRCTXT_RECONNECT_REMOVED, reconnect->conn->address, reconnect->conn->port,
- reconnect->conn->ircnet == NULL ? "" : reconnect->conn->ircnet);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_RECONNECT_REMOVED, reconnect->conn->address, reconnect->conn->port,
+ reconnect->conn->ircnet == NULL ? "" : reconnect->conn->ircnet);
}
static void sig_server_reconnect_not_found(gchar *tag)
{
- g_return_if_fail(tag != NULL);
+ g_return_if_fail(tag != NULL);
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
- IRCTXT_RECONNECT_NOT_FOUND, tag);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_RECONNECT_NOT_FOUND, tag);
}
static void event_received(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *addr)
{
- g_return_if_fail(data != NULL);
+ char *params, *cmd, *args, *ptr;
- if (!isdigit((gint) *data))
- printtext(server, NULL, MSGLEVEL_CRAP, "%s", data);
- else
- {
- /* numeric event. */
- gchar *params, *cmd, *args, *ptr;
+ g_return_if_fail(data != NULL);
- params = event_get_params(data, 3 | PARAM_FLAG_GETREST, &cmd, NULL, &args);
- ptr = strstr(args, " :");
+ if (!isdigit((gint) *data)) {
+ printtext(server, NULL, MSGLEVEL_CRAP, "%s", data);
+ return;
+ }
+
+ /* numeric event. */
+ params = event_get_params(data, 3 | PARAM_FLAG_GETREST, &cmd, NULL, &args);
+ ptr = strstr(args, " :");
if (ptr != NULL) *(ptr+1) = ' ';
printtext(server, NULL, MSGLEVEL_CRAP, "%s", args);
g_free(params);
- }
}
static void sig_empty(void)
@@ -612,6 +616,7 @@ static void read_settings(void)
void fe_events_init(void)
{
+ settings_add_bool("misc", "hide_netsplit_quits", TRUE);
beep_msg_level = 0;
read_settings();
diff --git a/src/fe-common/irc/fe-ignore.c b/src/fe-common/irc/fe-ignore.c
index 35da7c84..db91826e 100644
--- a/src/fe-common/irc/fe-ignore.c
+++ b/src/fe-common/irc/fe-ignore.c
@@ -191,7 +191,7 @@ static void cmd_ignore(const char *data)
else {
key = ignore_get_key(rec);
levels = ignore_get_levels(rec->level, rec->except_level);
- printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_IGNORED, key, levels);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_IGNORED, key, levels);
g_free(key);
g_free(levels);
}
@@ -212,7 +212,7 @@ static void cmd_unignore(const char *data)
if (is_numeric(data, ' ')) {
/* with index number */
- tmp = g_slist_nth(ignores, atol(data)-1);
+ tmp = g_slist_nth(ignores, atoi(data)-1);
rec = tmp == NULL ? NULL : tmp->data;
} else {
/* with mask */
diff --git a/src/fe-common/irc/fe-irc-commands.c b/src/fe-common/irc/fe-irc-commands.c
index bc6097cf..dc844346 100644
--- a/src/fe-common/irc/fe-irc-commands.c
+++ b/src/fe-common/irc/fe-irc-commands.c
@@ -28,7 +28,6 @@
#include "levels.h"
#include "irc.h"
#include "server.h"
-#include "server-reconnect.h"
#include "mode-lists.h"
#include "nicklist.h"
#include "channels.h"
@@ -37,66 +36,6 @@
#include "windows.h"
#include "window-items.h"
-static void cmd_server(const char *data)
-{
- if (*data == '+' && data[1] != '\0')
- window_create(NULL, FALSE);
-}
-
-static void print_servers(void)
-{
- GSList *tmp;
-
- for (tmp = servers; tmp != NULL; tmp = tmp->next) {
- IRC_SERVER_REC *rec = tmp->data;
-
- printformat(NULL, NULL, MSGLEVEL_CRAP, IRCTXT_SERVER_LIST,
- rec->tag, rec->connrec->address, rec->connrec->port,
- rec->connrec->ircnet == NULL ? "" : rec->connrec->ircnet, rec->connrec->nick);
- }
-}
-
-static void print_lookup_servers(void)
-{
- GSList *tmp;
- for (tmp = lookup_servers; tmp != NULL; tmp = tmp->next) {
- IRC_SERVER_REC *rec = tmp->data;
-
- printformat(NULL, NULL, MSGLEVEL_CRAP, IRCTXT_SERVER_LOOKUP_LIST,
- rec->tag, rec->connrec->address, rec->connrec->port,
- rec->connrec->ircnet == NULL ? "" : rec->connrec->ircnet, rec->connrec->nick);
- }
-}
-
-static void print_reconnects(void)
-{
- GSList *tmp;
- char *tag, *next_connect;
- int left;
-
- for (tmp = reconnects; tmp != NULL; tmp = tmp->next) {
- RECONNECT_REC *rec = tmp->data;
- IRC_SERVER_CONNECT_REC *conn = rec->conn;
-
- tag = g_strdup_printf("RECON-%d", rec->tag);
- left = rec->next_connect-time(NULL);
- next_connect = g_strdup_printf("%02d:%02d", left/60, left%60);
- printformat(NULL, NULL, MSGLEVEL_CRAP, IRCTXT_SERVER_RECONNECT_LIST,
- tag, conn->address, conn->port,
- conn->ircnet == NULL ? "" : conn->ircnet,
- conn->nick, next_connect);
- g_free(next_connect);
- g_free(tag);
- }
-}
-
-static void cmd_servers(void)
-{
- print_servers();
- print_lookup_servers();
- print_reconnects();
-}
-
static void cmd_unquery(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
{
QUERY_REC *query;
@@ -196,7 +135,7 @@ static void cmd_msg(gchar *data, IRC_SERVER_REC *server, WI_ITEM_REC *item)
{
/* msg to channel */
nickrec = channel == NULL ? NULL : nicklist_find(channel, server->nick);
- nickmode = !settings_get_bool("toggle_show_nickmode") || nickrec == NULL ? "" :
+ nickmode = !settings_get_bool("show_nickmode") || nickrec == NULL ? "" :
nickrec->op ? "@" : nickrec->voice ? "+" : " ";
window = channel == NULL ? NULL : window_item_window((WI_ITEM_REC *) channel);
@@ -329,8 +268,8 @@ static void cmd_ban(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
GSList *tmp;
g_return_if_fail(data != NULL);
- if (*data == '\0')
- return; /* setting ban - don't handle here */
+ if (*data != '\0')
+ return; /* setting ban - don't handle here */
if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED);
@@ -415,52 +354,6 @@ static void cmd_join(const char *data, IRC_SERVER_REC *server)
}
}
-static void cmd_channel(const char *data, IRC_SERVER_REC *server)
-{
- CHANNEL_REC *channel;
- GString *nicks;
- GSList *nicklist, *tmp, *ntmp;
- char *mode;
-
- if (*data != '\0') {
- cmd_join(data, server);
- return;
- }
-
- if (channels == NULL) {
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOT_IN_CHANNELS);
- return;
- }
-
- /* print active channel */
- channel = irc_item_channel(active_win->active);
- if (channel != NULL)
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CURRENT_CHANNEL, channel->name);
-
- /* print list of all channels, their modes, server tags and nicks */
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CHANLIST_HEADER);
- for (tmp = channels; tmp != NULL; tmp = tmp->next) {
- channel = tmp->data;
-
- nicklist = nicklist_getnicks(channel);
- mode = channel_get_mode(channel);
- nicks = g_string_new(NULL);
- for (ntmp = nicklist; ntmp != NULL; ntmp = ntmp->next) {
- NICK_REC *rec = ntmp->data;
-
- g_string_sprintfa(nicks, "%s ", rec->nick);
- }
-
- g_string_truncate(nicks, nicks->len-1);
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CHANLIST_LINE,
- channel->name, mode, channel->server->tag, nicks->str);
-
- g_free(mode);
- g_slist_free(nicklist);
- g_string_free(nicks, TRUE);
- }
-}
-
static void cmd_nick(const char *data, IRC_SERVER_REC *server)
{
g_return_if_fail(data != NULL);
@@ -506,8 +399,6 @@ static void cmd_ts(const char *data)
void fe_irc_commands_init(void)
{
- command_bind("server", NULL, (SIGNAL_FUNC) cmd_server);
- command_bind("servers", NULL, (SIGNAL_FUNC) cmd_servers);
command_bind("query", NULL, (SIGNAL_FUNC) cmd_query);
command_bind("unquery", NULL, (SIGNAL_FUNC) cmd_unquery);
command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg);
@@ -519,7 +410,6 @@ void fe_irc_commands_init(void)
command_bind("ban", NULL, (SIGNAL_FUNC) cmd_ban);
command_bind("invitelist", NULL, (SIGNAL_FUNC) cmd_invitelist);
command_bind("join", NULL, (SIGNAL_FUNC) cmd_join);
- command_bind("channel", NULL, (SIGNAL_FUNC) cmd_channel);
command_bind("nick", NULL, (SIGNAL_FUNC) cmd_nick);
command_bind("ver", NULL, (SIGNAL_FUNC) cmd_ver);
command_bind("ts", NULL, (SIGNAL_FUNC) cmd_ts);
@@ -527,8 +417,6 @@ void fe_irc_commands_init(void)
void fe_irc_commands_deinit(void)
{
- command_unbind("server", (SIGNAL_FUNC) cmd_server);
- command_unbind("servers", (SIGNAL_FUNC) cmd_servers);
command_unbind("query", (SIGNAL_FUNC) cmd_query);
command_unbind("unquery", (SIGNAL_FUNC) cmd_unquery);
command_unbind("msg", (SIGNAL_FUNC) cmd_msg);
@@ -540,7 +428,6 @@ void fe_irc_commands_deinit(void)
command_unbind("ban", (SIGNAL_FUNC) cmd_ban);
command_unbind("invitelist", (SIGNAL_FUNC) cmd_invitelist);
command_unbind("join", (SIGNAL_FUNC) cmd_join);
- command_unbind("channel", (SIGNAL_FUNC) cmd_channel);
command_unbind("nick", (SIGNAL_FUNC) cmd_nick);
command_unbind("ver", (SIGNAL_FUNC) cmd_ver);
command_unbind("ts", (SIGNAL_FUNC) cmd_ts);
diff --git a/src/fe-common/irc/fe-irc-server.c b/src/fe-common/irc/fe-irc-server.c
new file mode 100644
index 00000000..30e09886
--- /dev/null
+++ b/src/fe-common/irc/fe-irc-server.c
@@ -0,0 +1,215 @@
+/*
+ fe-irc-server.c : irssi
+
+ Copyright (C) 1999-2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "module-formats.h"
+#include "signals.h"
+#include "commands.h"
+#include "misc.h"
+
+#include "levels.h"
+#include "irc-server.h"
+#include "server-reconnect.h"
+#include "server-setup.h"
+
+#include "windows.h"
+
+static void print_servers(void)
+{
+ GSList *tmp;
+
+ for (tmp = servers; tmp != NULL; tmp = tmp->next) {
+ IRC_SERVER_REC *rec = tmp->data;
+
+ printformat(NULL, NULL, MSGLEVEL_CRAP, IRCTXT_SERVER_LIST,
+ rec->tag, rec->connrec->address, rec->connrec->port,
+ rec->connrec->ircnet == NULL ? "" : rec->connrec->ircnet, rec->connrec->nick);
+ }
+}
+
+static void print_lookup_servers(void)
+{
+ GSList *tmp;
+ for (tmp = lookup_servers; tmp != NULL; tmp = tmp->next) {
+ IRC_SERVER_REC *rec = tmp->data;
+
+ printformat(NULL, NULL, MSGLEVEL_CRAP, IRCTXT_SERVER_LOOKUP_LIST,
+ rec->tag, rec->connrec->address, rec->connrec->port,
+ rec->connrec->ircnet == NULL ? "" : rec->connrec->ircnet, rec->connrec->nick);
+ }
+}
+
+static void print_reconnects(void)
+{
+ GSList *tmp;
+ char *tag, *next_connect;
+ int left;
+
+ for (tmp = reconnects; tmp != NULL; tmp = tmp->next) {
+ RECONNECT_REC *rec = tmp->data;
+ IRC_SERVER_CONNECT_REC *conn = rec->conn;
+
+ tag = g_strdup_printf("RECON-%d", rec->tag);
+ left = rec->next_connect-time(NULL);
+ next_connect = g_strdup_printf("%02d:%02d", left/60, left%60);
+ printformat(NULL, NULL, MSGLEVEL_CRAP, IRCTXT_SERVER_RECONNECT_LIST,
+ tag, conn->address, conn->port,
+ conn->ircnet == NULL ? "" : conn->ircnet,
+ conn->nick, next_connect);
+ g_free(next_connect);
+ g_free(tag);
+ }
+}
+
+static void server_add(const char *data)
+{
+ SETUP_SERVER_REC *rec;
+ char *params, *args, *ircnet, *host, *cmdspeed, *cmdmax;
+ char *addr, *portstr, *password, *nick;
+ int port;
+
+ args = "ircnet host cmdspeed cmdmax";
+ params = cmd_get_params(data, 9 | PARAM_FLAG_MULTIARGS,
+ &args, &ircnet, &host, &cmdspeed, &cmdmax,
+ &addr, &portstr, &password, &nick);
+ if (*addr == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+ port = *portstr == '\0' ? 6667 : atoi(portstr);
+
+ rec = server_setup_find(addr, port);
+ if (rec == NULL) {
+ rec = g_new0(SETUP_SERVER_REC, 1);
+ rec->address = g_strdup(addr);
+ rec->port = port;
+ } else {
+ g_free_and_null(rec->ircnet);
+ g_free_and_null(rec->password);
+ g_free_and_null(rec->own_host);
+ }
+
+ rec->autoconnect = stristr(args, "-auto") != NULL;
+ if (*ircnet != '\0') rec->ircnet = g_strdup(ircnet);
+ if (*password != '\0') rec->password = g_strdup(password);
+ if (*host != '\0') rec->own_host = g_strdup(host);
+ rec->cmd_queue_speed = atoi(cmdspeed);
+ rec->max_cmds_at_once = atoi(cmdmax);
+
+ server_setup_add(rec);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_SETUPSERVER_ADDED, addr, port);
+
+ g_free(params);
+}
+
+static void server_remove(const char *data)
+{
+ SETUP_SERVER_REC *rec;
+ char *params, *args, *addr, *portstr;
+ int port;
+
+ params = cmd_get_params(data, 3 | PARAM_FLAG_OPTARGS, &args, &addr, &portstr);
+ if (*addr == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+ port = *portstr == '\0' ? 6667 : atoi(portstr);
+
+ rec = server_setup_find(addr, port);
+ if (rec == NULL)
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_SETUPSERVER_NOT_FOUND, addr, port);
+ else {
+ server_setup_remove(rec);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_SETUPSERVER_REMOVED, addr, port);
+ }
+
+ g_free(params);
+}
+
+static void server_list(const char *data)
+{
+ GString *str;
+ GSList *tmp;
+
+ str = g_string_new(NULL);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_SETUPSERVER_HEADER);
+ for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
+ SETUP_SERVER_REC *rec = tmp->data;
+
+ g_string_truncate(str, 0);
+ if (rec->password != NULL)
+ g_string_append(str, "(pass) ");
+ if (rec->autoconnect)
+ g_string_append(str, "autoconnect ");
+ if (rec->max_cmds_at_once > 0)
+ g_string_sprintfa(str, "cmdmax: %d ", rec->max_cmds_at_once);
+ if (rec->cmd_queue_speed > 0)
+ g_string_sprintfa(str, "cmdspeed: %d ", rec->cmd_queue_speed);
+ if (rec->own_host != NULL)
+ g_string_sprintfa(str, "host: %s ", rec->own_host);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_SETUPSERVER_LINE,
+ rec->address, rec->port,
+ rec->ircnet == NULL ? "" : rec->ircnet,
+ str->str);
+ }
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_SETUPSERVER_FOOTER);
+ g_string_free(str, TRUE);
+}
+
+static void cmd_server(const char *data)
+{
+ char *params, *args, *ircnetarg, *hostarg, *addr;
+
+ if (*data == '\0') {
+ print_servers();
+ print_lookup_servers();
+ print_reconnects();
+
+ signal_stop();
+ return;
+ }
+
+ args = "ircnet host";
+ params = cmd_get_params(data, 4 | PARAM_FLAG_MULTIARGS,
+ &args, &ircnetarg, &hostarg, &addr);
+
+ if (stristr(args, "-list") != NULL) {
+ server_list(data);
+ signal_stop();
+ } else if (stristr(args, "-add") != NULL) {
+ if (*addr == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+ server_add(data);
+ signal_stop();
+ } else if (stristr(args, "-remove") != NULL) {
+ if (*addr == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+ server_remove(data);
+ signal_stop();
+ } else {
+ if (*addr == '\0' || strcmp(addr, "+") == 0)
+ cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+ if (*addr == '+') window_create(NULL, FALSE);
+ }
+
+ g_free(params);
+}
+
+void fe_irc_server_init(void)
+{
+ command_bind("server", NULL, (SIGNAL_FUNC) cmd_server);
+}
+
+void fe_irc_server_deinit(void)
+{
+ command_unbind("server", (SIGNAL_FUNC) cmd_server);
+}
diff --git a/src/fe-common/irc/fe-netsplit.c b/src/fe-common/irc/fe-netsplit.c
new file mode 100644
index 00000000..b13ae437
--- /dev/null
+++ b/src/fe-common/irc/fe-netsplit.c
@@ -0,0 +1,69 @@
+/*
+ fe-netsplit.c : irssi
+
+ Copyright (C) 2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "module-formats.h"
+#include "signals.h"
+#include "commands.h"
+
+#include "levels.h"
+#include "netsplit.h"
+
+static void sig_netsplit_servers(NETSPLIT_SERVER_REC *rec)
+{
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NETSPLIT, rec->server, rec->destserver);
+}
+
+static void split_print(const char *nick, NETSPLIT_REC *rec)
+{
+ NETSPLIT_CHAN_REC *chan;
+
+ chan = rec->channels->data;
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NETSPLITS_LINE,
+ rec->nick, chan == NULL ? "" : chan->name,
+ rec->server->server, rec->server->destserver);
+}
+
+static void cmd_netsplit(const char *data, IRC_SERVER_REC *server)
+{
+ if (server == NULL || !server->connected)
+ cmd_return_error(CMDERR_NOT_CONNECTED);
+
+ if (server->split_servers == NULL) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NO_NETSPLITS);
+ return;
+ }
+
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NETSPLITS_HEADER);
+ g_hash_table_foreach(server->splits, (GHFunc) split_print, NULL);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NETSPLITS_FOOTER);
+}
+
+void fe_netsplit_init(void)
+{
+ signal_add("netsplit new server", (SIGNAL_FUNC) sig_netsplit_servers);
+ command_bind("netsplit", NULL, (SIGNAL_FUNC) cmd_netsplit);
+}
+
+void fe_netsplit_deinit(void)
+{
+ signal_remove("netsplit new server", (SIGNAL_FUNC) sig_netsplit_servers);
+ command_unbind("netsplit", (SIGNAL_FUNC) cmd_netsplit);
+}
diff --git a/src/fe-common/irc/fe-query.c b/src/fe-common/irc/fe-query.c
index be46ea0b..5444a031 100644
--- a/src/fe-common/irc/fe-query.c
+++ b/src/fe-common/irc/fe-query.c
@@ -23,6 +23,7 @@
#include "modules.h"
#include "signals.h"
#include "commands.h"
+#include "settings.h"
#include "irc.h"
#include "levels.h"
@@ -31,6 +32,8 @@
#include "windows.h"
#include "window-items.h"
+static int queryclose_tag, query_auto_close;
+
static void signal_query_created(QUERY_REC *query, gpointer automatic)
{
window_item_create((WI_ITEM_REC *) query, GPOINTER_TO_INT(automatic));
@@ -110,12 +113,67 @@ static void cmd_wquery(const char *data, void *server, WI_ITEM_REC *item)
signal_remove("query created", (SIGNAL_FUNC) signal_query_created_curwin);
}
+static void sig_window_changed(WINDOW_REC *window)
+{
+ GSList *tmp;
+
+ if (query_auto_close <= 0)
+ return;
+
+ for (tmp = window->items; tmp != NULL; tmp = tmp->next) {
+ if (irc_item_query(tmp->data))
+ break;
+ }
+ if (tmp == NULL) return; /* no queries in window */
+
+ /* reset the window's last_line timestamp so that query doesn't get
+ closed immediately after switched to the window. */
+ window->last_line = time(NULL);
+}
+
+static int sig_query_autoclose(void)
+{
+ WINDOW_REC *window;
+ GSList *tmp, *next;
+ time_t now;
+
+ now = time(NULL);
+ for (tmp = queries; tmp != NULL; tmp = next) {
+ QUERY_REC *rec = tmp->data;
+
+ next = tmp->next;
+ window = window_item_window((WI_ITEM_REC *) rec);
+ if (window != active_win && rec->new_data == 0 &&
+ now-window->last_line > query_auto_close)
+ query_destroy(rec);
+ }
+ return 1;
+}
+
+static void read_settings(void)
+{
+ query_auto_close = settings_get_int("query_auto_close");
+ if (query_auto_close > 0 && queryclose_tag == -1)
+ queryclose_tag = g_timeout_add(5000, (GSourceFunc) sig_query_autoclose, NULL);
+ else if (query_auto_close <= 0 && queryclose_tag != -1) {
+ g_source_remove(queryclose_tag);
+ queryclose_tag = -1;
+ }
+}
+
void fe_query_init(void)
{
+ settings_add_int("lookandfeel", "query_auto_close", 0);
+
+ queryclose_tag = -1;
+ read_settings();
+
signal_add("query created", (SIGNAL_FUNC) signal_query_created);
signal_add("query destroyed", (SIGNAL_FUNC) signal_query_destroyed);
signal_add("window item remove", (SIGNAL_FUNC) signal_window_item_removed);
signal_add("server connected", (SIGNAL_FUNC) sig_server_connected);
+ signal_add("window changed", (SIGNAL_FUNC) sig_window_changed);
+ signal_add("setup changed", (SIGNAL_FUNC) read_settings);
command_bind("wquery", NULL, (SIGNAL_FUNC) cmd_wquery);
command_bind("window server", NULL, (SIGNAL_FUNC) cmd_window_server);
@@ -123,10 +181,14 @@ void fe_query_init(void)
void fe_query_deinit(void)
{
+ if (queryclose_tag != -1) g_source_remove(queryclose_tag);
+
signal_remove("query created", (SIGNAL_FUNC) signal_query_created);
signal_remove("query destroyed", (SIGNAL_FUNC) signal_query_destroyed);
signal_remove("window item remove", (SIGNAL_FUNC) signal_window_item_removed);
signal_remove("server connected", (SIGNAL_FUNC) sig_server_connected);
+ signal_remove("window changed", (SIGNAL_FUNC) sig_window_changed);
+ signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
command_unbind("wquery", (SIGNAL_FUNC) cmd_wquery);
command_unbind("window server", (SIGNAL_FUNC) cmd_window_server);
diff --git a/src/fe-common/irc/irc-nick-hilight.c b/src/fe-common/irc/irc-window-activity.c
index 0d790822..5a9aa86f 100644
--- a/src/fe-common/irc/irc-nick-hilight.c
+++ b/src/fe-common/irc/irc-window-activity.c
@@ -1,5 +1,5 @@
/*
- irc-nick-hilight.c : irssi
+ irc-window-activity.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
@@ -78,12 +78,12 @@ static void event_privmsg(const char *data, IRC_SERVER_REC *server, const char *
g_free(params);
}
-void irc_nick_hilight_init(void)
+void irc_window_activity_init(void)
{
signal_add_last("event privmsg", (SIGNAL_FUNC) event_privmsg);
}
-void irc_nick_hilight_deinit(void)
+void irc_window_activity_deinit(void)
{
signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg);
}
diff --git a/src/fe-common/irc/module-formats.c b/src/fe-common/irc/module-formats.c
index 4b46959c..b1040d40 100644
--- a/src/fe-common/irc/module-formats.c
+++ b/src/fe-common/irc/module-formats.c
@@ -36,6 +36,17 @@ FORMAT_REC fecommon_irc_formats[] =
{ "server_reconnect_removed", "Removed reconnection to server %_$0%_ port %_$1%_", 3, { 0, 1, 0 } },
{ "server_reconnect_not_found", "Reconnection tag %_$0%_ not found", 1, { 0 } },
{ "query_server_changed", "Query with %_$2%_ changed to server %_$1%_", 3, { 0, 0, 0 } },
+ { "setupserver_added", "Server $0 saved", 2, { 0, 0 } },
+ { "setupserver_removed", "Server $0 removed", 2, { 0, 0 } },
+ { "setupserver_not_found", "Server $0 not found", 2, { 0, 0 } },
+ { "setupserver_header", "Server Port IRC Net Settings", 0 },
+ { "setupserver_line", "%|$[!20]0 $[5]1 $[10]2 $3", 4, { 0, 1, 0, 0 } },
+ { "setupserver_footer", "", 0 },
+ { "netsplit", "%RNetsplit%n detected between servers %_$0%_ and %_$1%_%:Use /NETSPLIT to see who left", 2, { 0, 0 } },
+ { "no_netsplits", "There are no net splits", 0 },
+ { "netsplits_header", "Nick Channel Server Splitted server", 0 },
+ { "netsplits_line", "$[9]0 $[10]1 $[20]2 $3", 4, { 0, 0, 0, 0 } },
+ { "netsplits_footer", "", 0 },
/* ---- */
{ NULL, "Channels", 0 },
@@ -73,11 +84,17 @@ FORMAT_REC fecommon_irc_formats[] =
{ "ebanlist_long", "%_$0%_: ban exception %c$1 %K[%nby %_$2%_, $3 secs ago%K]", 4, { 0, 0, 0, 1 } },
{ "invitelist", "%_$0%_: invite %c$1", 2, { 0, 0 } },
{ "no_such_channel", "$0: No such channel", 1, { 0 } },
+ { "channel_synced", "Join to %_$0%_ was synced in %_$1%_ secs", 2, { 0, 2 } },
{ "not_in_channels", "You are not on any channels", 0 },
{ "current_channel", "Current channel $0", 1, { 0 } },
{ "chanlist_header", "You are on the following channels:", 0 },
{ "chanlist_line", "$[-10]0 %|+$1 ($2): $3", 4, { 0, 0, 0, 0 } },
- { "channel_synced", "Join to %_$0%_ was synced in %_$1%_ secs", 2, { 0, 2 } },
+ { "chansetup_not_found", "Channel $0 not found", 2, { 0, 0 } },
+ { "chansetup_added", "Channel $0 saved", 2, { 0, 0 } },
+ { "chansetup_removed", "Channel $0 removed", 2, { 0, 0 } },
+ { "chansetup_header", "Channel IRC net Password Settings", 0 },
+ { "chansetup_line", "$[15]0 %|$[10]1 $[10]2 $3", 4, { 0, 0, 0, 0 } },
+ { "chansetup_footer", "", 0 },
/* ---- */
{ NULL, "Nick", 0 },
diff --git a/src/fe-common/irc/module-formats.h b/src/fe-common/irc/module-formats.h
index 325d3f4a..c7dc5bf8 100644
--- a/src/fe-common/irc/module-formats.h
+++ b/src/fe-common/irc/module-formats.h
@@ -13,6 +13,17 @@ enum {
IRCTXT_RECONNECT_REMOVED,
IRCTXT_RECONNECT_NOT_FOUND,
IRCTXT_QUERY_SERVER_CHANGED,
+ IRCTXT_SETUPSERVER_ADDED,
+ IRCTXT_SETUPSERVER_REMOVED,
+ IRCTXT_SETUPSERVER_NOT_FOUND,
+ IRCTXT_SETUPSERVER_HEADER,
+ IRCTXT_SETUPSERVER_LINE,
+ IRCTXT_SETUPSERVER_FOOTER,
+ IRCTXT_NETSPLIT,
+ IRCTXT_NO_NETSPLITS,
+ IRCTXT_NETSPLITS_HEADER,
+ IRCTXT_NETSPLITS_LINE,
+ IRCTXT_NETSPLITS_FOOTER,
IRCTXT_FILL_2,
@@ -49,11 +60,17 @@ enum {
IRCTXT_EBANLIST_LONG,
IRCTXT_INVITELIST,
IRCTXT_NO_SUCH_CHANNEL,
+ IRCTXT_CHANNEL_SYNCED,
IRCTXT_NOT_IN_CHANNELS,
IRCTXT_CURRENT_CHANNEL,
IRCTXT_CHANLIST_HEADER,
IRCTXT_CHANLIST_LINE,
- IRCTXT_CHANNEL_SYNCED,
+ IRCTXT_CHANSETUP_NOT_FOUND,
+ IRCTXT_CHANSETUP_ADDED,
+ IRCTXT_CHANSETUP_REMOVED,
+ IRCTXT_CHANSETUP_HEADER,
+ IRCTXT_CHANSETUP_LINE,
+ IRCTXT_CHANSETUP_FOOTER,
IRCTXT_FILL_4,
diff --git a/src/fe-none/.cvsignore b/src/fe-none/.cvsignore
index 8553e9e9..59b736b5 100644
--- a/src/fe-none/.cvsignore
+++ b/src/fe-none/.cvsignore
@@ -6,3 +6,4 @@
Makefile
Makefile.in
so_locations
+irssi-bot
diff --git a/src/fe-text/Makefile.am b/src/fe-text/Makefile.am
index c651cf0e..0120a4d9 100644
--- a/src/fe-text/Makefile.am
+++ b/src/fe-text/Makefile.am
@@ -20,12 +20,12 @@ irssi_text_LDADD = \
irssi_text_SOURCES = \
gui-entry.c \
- gui-mainwindows.c \
+ mainwindows.c \
gui-printtext.c \
gui-readline.c \
gui-special-vars.c \
- gui-statusbar.c \
- gui-statusbar-items.c \
+ statusbar.c \
+ statusbar-items.c \
gui-textwidget.c \
gui-windows.c \
irssi.c \
@@ -34,12 +34,11 @@ irssi_text_SOURCES = \
noinst_HEADERS = \
gui-entry.h \
- gui-mainwindows.h \
+ mainwindows.h \
gui-printtext.h \
gui-readline.h \
gui-special-vars.h \
- gui-statusbar.h \
- gui-statusbar-items.h \
+ statusbar.h \
gui-textwidget.h \
gui-windows.h \
module-formats.h \
diff --git a/src/fe-text/gui-entry.c b/src/fe-text/gui-entry.c
index d4505195..5f96d30f 100644
--- a/src/fe-text/gui-entry.c
+++ b/src/fe-text/gui-entry.c
@@ -23,7 +23,7 @@
#include "screen.h"
static GString *entry;
-static int promptlen, pos, scrstart, scrpos;
+static int promptlen, permanent_prompt, pos, scrstart, scrpos;
static char *prompt;
static void entry_screenpos(void)
@@ -71,14 +71,11 @@ static void entry_update(void)
void gui_entry_set_prompt(const char *str)
{
if (str != NULL) {
- if (prompt != NULL) g_free(prompt);
- prompt = g_strdup(str);
+ if (permanent_prompt) return;
+ g_free_not_null(prompt);
+ prompt = g_strdup(str);
promptlen = strlen(prompt);
- if (promptlen > 20) {
- promptlen = 20;
- prompt[20] = '\0';
- }
}
set_color(0);
@@ -88,6 +85,23 @@ void gui_entry_set_prompt(const char *str)
entry_update();
}
+void gui_entry_set_perm_prompt(const char *str)
+{
+ g_return_if_fail(str != NULL);
+
+ g_free_not_null(prompt);
+ prompt = g_strdup(str);
+ promptlen = strlen(prompt);
+
+ permanent_prompt = TRUE;
+ gui_entry_set_prompt(NULL);
+}
+
+void gui_entry_remove_perm_prompt(void)
+{
+ permanent_prompt = FALSE;
+}
+
void gui_entry_set_text(const char *str)
{
g_return_if_fail(str != NULL);
@@ -166,8 +180,10 @@ void gui_entry_redraw(void)
void gui_entry_init(void)
{
entry = g_string_new(NULL);
+
pos = scrpos = 0;
prompt = NULL; promptlen = 0;
+ permanent_prompt = FALSE;
}
void gui_entry_deinit(void)
diff --git a/src/fe-text/gui-entry.h b/src/fe-text/gui-entry.h
index 443d2509..4fbf5c16 100644
--- a/src/fe-text/gui-entry.h
+++ b/src/fe-text/gui-entry.h
@@ -3,6 +3,10 @@
void gui_entry_set_prompt(const char *str);
+/* permanent prompt can't be overwritten with gui_entry_set_prompt() */
+void gui_entry_set_perm_prompt(const char *str);
+void gui_entry_remove_perm_prompt(void);
+
void gui_entry_set_text(const char *str);
char *gui_entry_get_text(void);
diff --git a/src/fe-text/gui-mainwindows.c b/src/fe-text/gui-mainwindows.c
deleted file mode 100644
index d5d66c1d..00000000
--- a/src/fe-text/gui-mainwindows.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- gui-mainwindows.c : irssi
-
- Copyright (C) 1999 Timo Sirainen
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "module.h"
-#include "signals.h"
-
-#include "windows.h"
-#include "gui-mainwindows.h"
-
-GList *mainwindows;
-
-MAIN_WINDOW_REC *gui_mainwindow_create(void)
-{
- MAIN_WINDOW_REC *window;
-
- window = g_new0(MAIN_WINDOW_REC, 1);
- mainwindows = g_list_append(mainwindows, window);
-
- return window;
-}
-
-void gui_mainwindow_destroy(MAIN_WINDOW_REC *window)
-{
- g_return_if_fail(window != NULL);
- if (window->destroying) return;
-
- mainwindows = g_list_remove(mainwindows, window);
-
- window->destroying = TRUE;
- while (window->children != NULL)
- window_destroy(window->children->data);
- window->destroying = FALSE;
-
- g_free(window);
-
- if (mainwindows == NULL)
- signal_emit("gui exit", 0);
-}
-
-void gui_mainwindows_init(void)
-{
- mainwindows = NULL;
-}
-
-void gui_mainwindows_deinit(void)
-{
- while (mainwindows != NULL)
- gui_mainwindow_destroy(mainwindows->data);
-}
diff --git a/src/fe-text/gui-mainwindows.h b/src/fe-text/gui-mainwindows.h
deleted file mode 100644
index b91f35a9..00000000
--- a/src/fe-text/gui-mainwindows.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __GUI_MAINWINDOWS_H
-#define __GUI_MAINWINDOWS_H
-
-#include "windows.h"
-
-typedef struct {
- WINDOW_REC *active;
- GList *children;
-
- int destroying;
-} MAIN_WINDOW_REC;
-
-extern GList *mainwindows;
-
-void gui_mainwindows_init(void);
-void gui_mainwindows_deinit(void);
-
-MAIN_WINDOW_REC *gui_mainwindow_create(void);
-void gui_mainwindow_destroy(MAIN_WINDOW_REC *window);
-
-#endif
diff --git a/src/fe-text/gui-printtext.c b/src/fe-text/gui-printtext.c
index 1ef4aa32..59e00d52 100644
--- a/src/fe-text/gui-printtext.c
+++ b/src/fe-text/gui-printtext.c
@@ -28,7 +28,6 @@
#include "themes.h"
#include "screen.h"
-#include "gui-mainwindows.h"
#include "gui-windows.h"
#define TEXT_CHUNK_USABLE_SIZE (LINE_TEXT_CHUNK_SIZE-2-sizeof(char*))
@@ -46,6 +45,9 @@ static LINE_REC *create_line(GUI_WINDOW_REC *gui, gint level)
gui->cur_line->level = (gint32) GPOINTER_TO_INT(level);
gui->cur_line->time = time(NULL);
+ /* temporarily mark the end of line. */
+ memcpy(gui->cur_text->buffer+gui->cur_text->pos, "\0\x80", 2);
+
gui->last_color = -1;
gui->last_flags = 0;
@@ -67,6 +69,8 @@ static TEXT_CHUNK_REC *create_text_chunk(GUI_WINDOW_REC *gui)
g_return_val_if_fail(gui != NULL, NULL);
rec = g_new(TEXT_CHUNK_REC, 1);
+ rec->overflow[0] = 0;
+ rec->overflow[1] = (char) LINE_CMD_OVERFLOW;
rec->pos = 0;
rec->lines = 0;
@@ -268,7 +272,7 @@ static void gui_printtext(WINDOW_REC *window, gpointer fgcolor, gpointer bgcolor
if (visible)
{
/* draw the line to screen. */
- lines = gui_window_line_draw(gui, line, first_text_line+gui->ypos, gui->last_subline, -1);
+ lines = gui_window_line_draw(gui, line, gui->parent->first_line+gui->ypos, gui->last_subline, -1);
}
else
{
@@ -289,7 +293,7 @@ static void cmd_clear(gchar *data)
if (is_window_visible(active_win))
{
- for (n = first_text_line; n < last_text_line; n++)
+ for (n = gui->parent->first_line; n <= gui->parent->last_line; n++)
{
move(n, 0);
clrtoeol();
@@ -300,7 +304,7 @@ static void cmd_clear(gchar *data)
gui->ypos = -1;
gui->bottom_startline = gui->startline = g_list_last(gui->lines);
gui->bottom_subline = gui->subline = gui->last_subline+1;
- gui->empty_linecount = last_text_line-first_text_line;
+ gui->empty_linecount = gui->parent->last_line-gui->parent->first_line+1;
gui->bottom = TRUE;
}
diff --git a/src/fe-text/gui-readline.c b/src/fe-text/gui-readline.c
index 39608119..0171dc8d 100644
--- a/src/fe-text/gui-readline.c
+++ b/src/fe-text/gui-readline.c
@@ -31,25 +31,71 @@
#include "screen.h"
#include "gui-entry.h"
-#include "gui-mainwindows.h"
#include "gui-windows.h"
#include <signal.h>
-static gint readtag, sigint_count = 0;
+typedef void (*ENTRY_REDIRECT_KEY_FUNC) (int key, void *data, SERVER_REC *server, WI_ITEM_REC *item);
+typedef void (*ENTRY_REDIRECT_ENTRY_FUNC) (const char *line, void *data, SERVER_REC *server, WI_ITEM_REC *item);
+
+typedef struct {
+ SIGNAL_FUNC func;
+ int key;
+ void *data;
+} ENTRY_REDIRECT_REC;
+
+static ENTRY_REDIRECT_REC *redir;
+
+static int readtag, sigint_count = 0;
static time_t idle_time;
+static void handle_key_redirect(int key)
+{
+ ENTRY_REDIRECT_KEY_FUNC func;
+ void *data;
+
+ func = (ENTRY_REDIRECT_KEY_FUNC) redir->func;
+ data = redir->data;
+ g_free_and_null(redir);
+
+ if (func != NULL)
+ func(key, data, active_win->active_server, active_win->active);
+
+ gui_entry_remove_perm_prompt();
+ window_update_prompt(active_win);
+}
+
+static void handle_entry_redirect(const char *line)
+{
+ ENTRY_REDIRECT_ENTRY_FUNC func;
+ void *data;
+
+ func = (ENTRY_REDIRECT_ENTRY_FUNC) redir->func;
+ data = redir->data;
+ g_free_and_null(redir);
+
+ if (func != NULL)
+ func(line, data, active_win->active_server, active_win->active);
+
+ gui_entry_remove_perm_prompt();
+ window_update_prompt(active_win);
+}
+
static void window_prev_page(void)
{
- gui_window_scroll(active_win, -(last_text_line-first_text_line)/2);
+ GUI_WINDOW_REC *gui = WINDOW_GUI(active_win);
+
+ gui_window_scroll(active_win, -(gui->parent->last_line-gui->parent->first_line)/2);
}
static void window_next_page(void)
{
- gui_window_scroll(active_win, (last_text_line-first_text_line)/2);
+ GUI_WINDOW_REC *gui = WINDOW_GUI(active_win);
+
+ gui_window_scroll(active_win, (gui->parent->last_line-gui->parent->first_line)/2);
}
-static char *get_key_name(int key)
+static const char *get_key_name(int key)
{
static char str[MAX_INT_STRLEN];
@@ -76,157 +122,163 @@ static char *get_key_name(int key)
}
}
-void handle_key(gint key)
+void handle_key(int key)
{
- const char *text;
- char *str;
- int c;
-
- /* Quit if we get 5 CTRL-C's in a row. */
- if (key != 3)
- sigint_count = 0;
- else if (++sigint_count >= 5)
- raise(SIGTERM);
-
- idle_time = time(NULL);
- switch (key)
- {
- case 27:
- c = getch();
- if (c == toupper(c) && c != tolower(c))
- str = g_strdup_printf("ALT-SHIFT-%c", c);
- else {
- if (c < 256)
- str = g_strdup_printf("ALT-%c", toupper(c));
- else
- str = g_strdup_printf("ALT-%s", get_key_name(c));
- }
- key_pressed(str, NULL);
- g_free(str);
- break;
+ const char *text;
+ char *str;
+ int c;
+
+ /* Quit if we get 5 CTRL-C's in a row. */
+ if (key != 3)
+ sigint_count = 0;
+ else if (++sigint_count >= 5)
+ raise(SIGTERM);
+
+ idle_time = time(NULL);
+
+ if (redir != NULL && redir->key) {
+ handle_key_redirect(key);
+ return;
+ }
+
+ switch (key)
+ {
+ case 27:
+ c = getch();
+ if (c == toupper(c) && c != tolower(c))
+ str = g_strdup_printf("ALT-SHIFT-%c", c);
+ else {
+ if (c < 256)
+ str = g_strdup_printf("ALT-%c", toupper(c));
+ else
+ str = g_strdup_printf("ALT-%s", get_key_name(c));
+ }
+ key_pressed(str, NULL);
+ g_free(str);
+ break;
case KEY_HOME:
- /* home */
- gui_entry_set_pos(0);
- gui_entry_move_pos(0);
- break;
- case KEY_END:
- /* end */
- gui_entry_set_pos(strlen(gui_entry_get_text()));
- gui_entry_move_pos(0);
- break;
- case KEY_PPAGE:
- /* page up */
- window_prev_page();
- break;
- case KEY_NPAGE:
- /* page down */
- window_next_page();
- break;
-
- case KEY_UP:
- /* up */
- text = command_history_prev(active_win, gui_entry_get_text());
- gui_entry_set_text(text);
- break;
- case KEY_DOWN:
- /* down */
- text = command_history_next(active_win, gui_entry_get_text());
- gui_entry_set_text(text);
- break;
- case KEY_RIGHT:
- /* right */
- gui_entry_move_pos(1);
- break;
- case KEY_LEFT:
- /* left */
- gui_entry_move_pos(-1);
- break;
+ /* home */
+ gui_entry_set_pos(0);
+ gui_entry_move_pos(0);
+ break;
+ case KEY_END:
+ /* end */
+ gui_entry_set_pos(strlen(gui_entry_get_text()));
+ gui_entry_move_pos(0);
+ break;
+ case KEY_PPAGE:
+ /* page up */
+ window_prev_page();
+ break;
+ case KEY_NPAGE:
+ /* page down */
+ window_next_page();
+ break;
+
+ case KEY_UP:
+ /* up */
+ text = command_history_prev(active_win, gui_entry_get_text());
+ gui_entry_set_text(text);
+ break;
+ case KEY_DOWN:
+ /* down */
+ text = command_history_next(active_win, gui_entry_get_text());
+ gui_entry_set_text(text);
+ break;
+ case KEY_RIGHT:
+ /* right */
+ gui_entry_move_pos(1);
+ break;
+ case KEY_LEFT:
+ /* left */
+ gui_entry_move_pos(-1);
+ break;
case 21:
- /* Ctrl-U, clear line */
- gui_entry_set_text("");
- break;
+ /* Ctrl-U, clear line */
+ gui_entry_set_text("");
+ break;
case 9:
- key_pressed("Tab", NULL);
- break;
+ key_pressed("Tab", NULL);
+ break;
case 8:
case 127:
- case KEY_BACKSPACE:
- gui_entry_erase(1);
- break;
-
- case KEY_DC:
- if (gui_entry_get_pos() < strlen(gui_entry_get_text()))
- {
- gui_entry_move_pos(1);
- gui_entry_erase(1);
- }
- break;
+ case KEY_BACKSPACE:
+ gui_entry_erase(1);
+ break;
+
+ case KEY_DC:
+ if (gui_entry_get_pos() < strlen(gui_entry_get_text())) {
+ gui_entry_move_pos(1);
+ gui_entry_erase(1);
+ }
+ break;
case 0:
- /* Ctrl-space - ignore */
- break;
- case 1:
- /* C-A, home */
- gui_entry_set_pos(0);
- gui_entry_move_pos(0);
- break;
- case 5:
- /* C-E, end */
- gui_entry_set_pos(strlen(gui_entry_get_text()));
- gui_entry_move_pos(0);
- break;
-
- case '\n':
+ /* Ctrl-space - ignore */
+ break;
+ case 1:
+ /* C-A, home */
+ gui_entry_set_pos(0);
+ gui_entry_move_pos(0);
+ break;
+ case 5:
+ /* C-E, end */
+ gui_entry_set_pos(strlen(gui_entry_get_text()));
+ gui_entry_move_pos(0);
+ break;
+
+ case '\n':
case 13:
- key_pressed("Return", NULL);
+ key_pressed("Return", NULL);
- str = gui_entry_get_text();
- if (*str == '\0') break;
+ str = gui_entry_get_text();
+ if (*str == '\0') break;
- translate_output(str);
- signal_emit("send command", 3, str, active_win->active_server, active_win->active);
+ translate_output(str);
- command_history_add(active_win, gui_entry_get_text(), FALSE);
- gui_entry_set_text("");
- command_history_clear_pos(active_win);
- break;
+ if (redir == NULL)
+ signal_emit("send command", 3, str, active_win->active_server, active_win->active);
+ else
+ handle_entry_redirect(str);
- default:
- if (key > 0 && key < 32)
- {
- str = g_strdup_printf("CTRL-%c", key == 31 ? '-' : key+'A'-1);
- key_pressed(str, NULL);
- g_free(str);
+ command_history_add(active_win, gui_entry_get_text(), FALSE);
+ gui_entry_set_text("");
+ command_history_clear_pos(active_win);
break;
- }
-
- if (key < 256)
- {
- gchar str[2];
- str[0] = toupper(key); str[1] = '\0';
- key_pressed(str, NULL);
- gui_entry_insert_char((gchar) key);
- }
- break;
- }
+ default:
+ if (key > 0 && key < 32) {
+ str = g_strdup_printf("CTRL-%c", key == 31 ? '-' : key+'A'-1);
+ key_pressed(str, NULL);
+ g_free(str);
+ break;
+ }
+
+ if (key < 256) {
+ char str[2];
+
+ str[0] = toupper(key); str[1] = '\0';
+ key_pressed(str, NULL);
+ gui_entry_insert_char((char) key);
+ }
+ break;
+ }
}
void readline(void)
{
- gint key;
+ int key;
- for (;;)
- {
- key = getch();
- if (key == ERR) break;
+ for (;;) {
+ key = getch();
+ if (key == ERR) break;
- handle_key(key);
- }
+ handle_key(key);
+ }
}
time_t get_idle_time(void)
@@ -236,147 +288,169 @@ time_t get_idle_time(void)
static void sig_prev_page(void)
{
- window_prev_page();
+ window_prev_page();
}
static void sig_next_page(void)
{
- window_next_page();
+ window_next_page();
}
-static void sig_change_window(gchar *data)
+static void sig_change_window(const char *data)
{
- signal_emit("command window goto", 3, data, active_win->active_server, active_win->active);
+ signal_emit("command window goto", 3, data, active_win->active_server, active_win->active);
}
static void sig_completion(void)
{
- gchar *line;
- gint pos;
-
- pos = gui_entry_get_pos();
-
- line = completion_line(active_win, gui_entry_get_text(), &pos);
- if (line != NULL)
- {
- gui_entry_set_text(line);
- gui_entry_set_pos(pos);
- g_free(line);
- }
+ char *line;
+ int pos;
+
+ pos = gui_entry_get_pos();
+
+ line = completion_line(active_win, gui_entry_get_text(), &pos);
+ if (line != NULL) {
+ gui_entry_set_text(line);
+ gui_entry_set_pos(pos);
+ g_free(line);
+ }
}
static void sig_replace(void)
{
- gchar *line;
- gint pos;
-
- pos = gui_entry_get_pos();
-
- line = auto_completion(gui_entry_get_text(), &pos);
- if (line != NULL)
- {
- gui_entry_set_text(line);
- gui_entry_set_pos(pos);
- g_free(line);
- }
+ char *line;
+ int pos;
+
+ pos = gui_entry_get_pos();
+
+ line = auto_completion(gui_entry_get_text(), &pos);
+ if (line != NULL) {
+ gui_entry_set_text(line);
+ gui_entry_set_pos(pos);
+ g_free(line);
+ }
}
static void sig_prev_window(void)
{
- signal_emit("command window prev", 3, "", active_win->active_server, active_win->active);
+ signal_emit("command window prev", 3, "", active_win->active_server, active_win->active);
}
static void sig_next_window(void)
{
- signal_emit("command window next", 3, "", active_win->active_server, active_win->active);
+ signal_emit("command window next", 3, "", active_win->active_server, active_win->active);
+}
+
+static void sig_up_window(void)
+{
+ signal_emit("command window up", 3, "", active_win->active_server, active_win->active);
+}
+
+static void sig_down_window(void)
+{
+ signal_emit("command window down", 3, "", active_win->active_server, active_win->active);
}
static void sig_window_goto_active(void)
{
- signal_emit("command window goto", 3, "active", active_win->active_server, active_win->active);
+ signal_emit("command window goto", 3, "active", active_win->active_server, active_win->active);
}
-static void sig_prev_channel(void)
+static void sig_prev_window_item(void)
{
- signal_emit("command channel prev", 3, "", active_win->active_server, active_win->active);
+ signal_emit("command window item prev", 3, "", active_win->active_server, active_win->active);
}
-static void sig_next_channel(void)
+static void sig_next_window_item(void)
{
- signal_emit("command channel next", 3, "", active_win->active_server, active_win->active);
+ signal_emit("command window item next", 3, "", active_win->active_server, active_win->active);
}
-static void sig_addchar(gchar *data)
+static void sig_addchar(const char *data)
{
- gui_entry_insert_char(*data);
+ gui_entry_insert_char(*data);
}
-static void signal_window_auto_changed(WINDOW_REC *window)
+static void sig_window_auto_changed(WINDOW_REC *window)
{
command_history_next(active_win, gui_entry_get_text());
gui_entry_set_text("");
}
+static void sig_gui_entry_redirect(SIGNAL_FUNC func, const char *entry, gpointer key, void *data)
+{
+ redir = g_new0(ENTRY_REDIRECT_REC, 1);
+ redir->func = func;
+ redir->key = key != NULL;
+ redir->data = data;
+
+ gui_entry_set_perm_prompt(entry);
+}
+
void gui_readline_init(void)
{
- static gchar changekeys[] = "1234567890QWERTYUIO";
- gchar *key, *data;
- gint n;
-
- idle_time = time(NULL);
- readtag = g_input_add(0, G_INPUT_READ, (GInputFunction) readline, NULL);
-
- key_bind("completion", NULL, "Nick completion", "Tab", (SIGNAL_FUNC) sig_completion);
- key_bind("check replaces", NULL, "Check word replaces", " ", (SIGNAL_FUNC) sig_replace);
- key_bind("check replaces", NULL, NULL, "Return", (SIGNAL_FUNC) sig_replace);
- key_bind("window prev", NULL, "Previous window", "CTRL-P", (SIGNAL_FUNC) sig_prev_window);
- key_bind("window prev", NULL, NULL, "ALT-Left", (SIGNAL_FUNC) sig_prev_window);
- key_bind("window next", NULL, "Next window", "CTRL-N", (SIGNAL_FUNC) sig_next_window);
- key_bind("window next", NULL, NULL, "ALT-Right", (SIGNAL_FUNC) sig_next_window);
- key_bind("window active", NULL, "Go to next window with the highest activity", "ALT-A", (SIGNAL_FUNC) sig_window_goto_active);
- key_bind("channel next", NULL, "Next channel", "CTRL-X", (SIGNAL_FUNC) sig_next_channel);
- key_bind("channel prev", NULL, "Next channel", NULL, (SIGNAL_FUNC) sig_prev_channel);
-
- key_bind("redraw", NULL, "Redraw window", "CTRL-L", (SIGNAL_FUNC) irssi_redraw);
- key_bind("prev page", NULL, "Previous page", "ALT-P", (SIGNAL_FUNC) sig_prev_page);
- key_bind("next page", NULL, "Next page", "ALT-N", (SIGNAL_FUNC) sig_next_page);
-
- key_bind("special char", "\x02", "Insert special character", "CTRL-B", (SIGNAL_FUNC) sig_addchar);
- key_bind("special char", "\x1f", NULL, "CTRL--", (SIGNAL_FUNC) sig_addchar);
- key_bind("special char", "\x03", NULL, "CTRL-C", (SIGNAL_FUNC) sig_addchar);
- key_bind("special char", "\x16", NULL, "CTRL-V", (SIGNAL_FUNC) sig_addchar);
- key_bind("special char", "\x07", NULL, "CTRL-G", (SIGNAL_FUNC) sig_addchar);
- key_bind("special char", "\x0f", NULL, "CTRL-O", (SIGNAL_FUNC) sig_addchar);
-
- for (n = 0; changekeys[n] != '\0'; n++)
- {
- key = g_strdup_printf("ALT-%c", changekeys[n]);
- data = g_strdup_printf("%d", n+1);
- key_bind("change window", data, "Change window", key, (SIGNAL_FUNC) sig_change_window);
- g_free(data); g_free(key);
- }
-
- signal_add("window changed automatic", (SIGNAL_FUNC) signal_window_auto_changed);
+ static char changekeys[] = "1234567890QWERTYUIO";
+ char *key, data[MAX_INT_STRLEN];
+ int n;
+
+ redir = NULL;
+ idle_time = time(NULL);
+ readtag = g_input_add(0, G_INPUT_READ, (GInputFunction) readline, NULL);
+
+ key_bind("completion", NULL, "Nick completion", "Tab", (SIGNAL_FUNC) sig_completion);
+ key_bind("check replaces", NULL, "Check word replaces", " ", (SIGNAL_FUNC) sig_replace);
+ key_bind("check replaces", NULL, NULL, "Return", (SIGNAL_FUNC) sig_replace);
+ key_bind("window prev", NULL, "Previous window", "CTRL-P", (SIGNAL_FUNC) sig_prev_window);
+ key_bind("window prev", NULL, NULL, "ALT-Left", (SIGNAL_FUNC) sig_prev_window);
+ key_bind("window next", NULL, "Next window", "CTRL-N", (SIGNAL_FUNC) sig_next_window);
+ key_bind("window next", NULL, NULL, "ALT-Right", (SIGNAL_FUNC) sig_next_window);
+ key_bind("window up", NULL, "Upper window", "ALT-Up", (SIGNAL_FUNC) sig_up_window);
+ key_bind("window down", NULL, "Lower window", "ALT-Down", (SIGNAL_FUNC) sig_down_window);
+ key_bind("window active", NULL, "Go to next window with the highest activity", "ALT-A", (SIGNAL_FUNC) sig_window_goto_active);
+ key_bind("window item next", NULL, "Next channel", "CTRL-X", (SIGNAL_FUNC) sig_next_window_item);
+ key_bind("window item prev", NULL, "Next channel", NULL, (SIGNAL_FUNC) sig_prev_window_item);
+
+ key_bind("redraw", NULL, "Redraw window", "CTRL-L", (SIGNAL_FUNC) irssi_redraw);
+ key_bind("prev page", NULL, "Previous page", "ALT-P", (SIGNAL_FUNC) sig_prev_page);
+ key_bind("next page", NULL, "Next page", "ALT-N", (SIGNAL_FUNC) sig_next_page);
+
+ key_bind("special char", "\x02", "Insert special character", "CTRL-B", (SIGNAL_FUNC) sig_addchar);
+ key_bind("special char", "\x1f", NULL, "CTRL--", (SIGNAL_FUNC) sig_addchar);
+ key_bind("special char", "\x03", NULL, "CTRL-C", (SIGNAL_FUNC) sig_addchar);
+ key_bind("special char", "\x16", NULL, "CTRL-V", (SIGNAL_FUNC) sig_addchar);
+ key_bind("special char", "\x07", NULL, "CTRL-G", (SIGNAL_FUNC) sig_addchar);
+ key_bind("special char", "\x0f", NULL, "CTRL-O", (SIGNAL_FUNC) sig_addchar);
+
+ for (n = 0; changekeys[n] != '\0'; n++) {
+ key = g_strdup_printf("ALT-%c", changekeys[n]);
+ ltoa(data, n+1);
+ key_bind("change window", data, "Change window", key, (SIGNAL_FUNC) sig_change_window);
+ g_free(key);
+ }
+
+ signal_add("window changed automatic", (SIGNAL_FUNC) sig_window_auto_changed);
+ signal_add("gui entry redirect", (SIGNAL_FUNC) sig_gui_entry_redirect);
}
void gui_readline_deinit(void)
{
- g_source_remove(readtag);
+ g_source_remove(readtag);
- key_unbind("completion", (SIGNAL_FUNC) sig_completion);
- key_unbind("check replaces", (SIGNAL_FUNC) sig_replace);
- key_unbind("window prev", (SIGNAL_FUNC) sig_prev_window);
- key_unbind("window next", (SIGNAL_FUNC) sig_next_window);
- key_unbind("window active", (SIGNAL_FUNC) sig_window_goto_active);
- key_unbind("channel next", (SIGNAL_FUNC) sig_next_channel);
- key_unbind("channel prev", (SIGNAL_FUNC) sig_prev_channel);
+ key_unbind("completion", (SIGNAL_FUNC) sig_completion);
+ key_unbind("check replaces", (SIGNAL_FUNC) sig_replace);
+ key_unbind("window prev", (SIGNAL_FUNC) sig_prev_window);
+ key_unbind("window next", (SIGNAL_FUNC) sig_next_window);
+ key_unbind("window active", (SIGNAL_FUNC) sig_window_goto_active);
+ key_unbind("window item next", (SIGNAL_FUNC) sig_next_window_item);
+ key_unbind("window item prev", (SIGNAL_FUNC) sig_prev_window_item);
- key_unbind("redraw", (SIGNAL_FUNC) irssi_redraw);
- key_unbind("prev page", (SIGNAL_FUNC) sig_prev_page);
- key_unbind("next page", (SIGNAL_FUNC) sig_next_page);
+ key_unbind("redraw", (SIGNAL_FUNC) irssi_redraw);
+ key_unbind("prev page", (SIGNAL_FUNC) sig_prev_page);
+ key_unbind("next page", (SIGNAL_FUNC) sig_next_page);
- key_unbind("special char", (SIGNAL_FUNC) sig_addchar);
- key_unbind("change window", (SIGNAL_FUNC) sig_change_window);
+ key_unbind("special char", (SIGNAL_FUNC) sig_addchar);
+ key_unbind("change window", (SIGNAL_FUNC) sig_change_window);
- signal_remove("window changed automatic", (SIGNAL_FUNC) signal_window_auto_changed);
+ signal_remove("window changed automatic", (SIGNAL_FUNC) sig_window_auto_changed);
+ signal_remove("gui entry redirect", (SIGNAL_FUNC) sig_gui_entry_redirect);
}
diff --git a/src/fe-text/gui-statusbar-items.h b/src/fe-text/gui-statusbar-items.h
deleted file mode 100644
index f71415f0..00000000
--- a/src/fe-text/gui-statusbar-items.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __GUI_STATUSBAR_ITEMS_H
-#define __GUI_STATUSBAR_ITEMS_H
-
-void gui_statusbar_items_init(void);
-void gui_statusbar_items_deinit(void);
-
-#endif
diff --git a/src/fe-text/gui-statusbar.h b/src/fe-text/gui-statusbar.h
deleted file mode 100644
index bdaba584..00000000
--- a/src/fe-text/gui-statusbar.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __GUI_STATUSBAR_H
-#define __GUI_STATUSBAR_H
-
-typedef void (*STATUSBAR_FUNC) (gint xpos, gint ypos, gint size);
-
-/* create new statusbar, return position */
-gint gui_statusbar_create(gboolean up);
-void gui_statusbar_delete(gboolean up, gint ypos);
-
-/* allocate area in statusbar, returns tag or -1 if failed */
-gint gui_statusbar_allocate(gint size, gboolean right_justify, gboolean up, gint ypos, STATUSBAR_FUNC func);
-void gui_statusbar_resize(gint tag, gint size);
-void gui_statusbar_remove(gint tag);
-
-/* redraw item, -1 = all */
-void gui_statusbar_redraw(gint tag);
-
-void gui_statusbar_init(void);
-void gui_statusbar_deinit(void);
-
-#endif
diff --git a/src/fe-text/gui-textwidget.c b/src/fe-text/gui-textwidget.c
index c4d6d2f4..a380322b 100644
--- a/src/fe-text/gui-textwidget.c
+++ b/src/fe-text/gui-textwidget.c
@@ -29,7 +29,6 @@
#include "windows.h"
#include "screen.h"
-#include "gui-mainwindows.h"
#include "gui-windows.h"
static gchar *gui_window_line2text(LINE_REC *line)
@@ -178,7 +177,7 @@ static void cmd_lastlog(const char *data)
countstr = text;
text = "";
}
- count = atol(countstr);
+ count = atoi(countstr);
if (count == 0) count = -1;
level = lastlog_parse_args(args, &flags);
@@ -188,7 +187,7 @@ static void cmd_lastlog(const char *data)
printformat(NULL, NULL, MSGLEVEL_LASTLOG, IRCTXT_LASTLOG_START);
list = gui_window_find_text(active_win, text, startline, flags & LASTLOG_FLAG_REGEXP, flags & LASTLOG_FLAG_WORD);
- tmp = lastlog_find_startline(list, count, atol(start), level);
+ tmp = lastlog_find_startline(list, count, atoi(start), level);
for (; tmp != NULL && (count < 0 || count > 0); tmp = tmp->next, count--) {
LINE_REC *rec = tmp->data;
@@ -197,13 +196,13 @@ static void cmd_lastlog(const char *data)
continue;
text = gui_window_line2text(rec);
- if (settings_get_bool("toggle_show_timestamps"))
- printtext(NULL, NULL, MSGLEVEL_LASTLOG, text);
+ if (settings_get_bool("timestamps"))
+ printtext(NULL, NULL, MSGLEVEL_LASTLOG, "%s", text);
else {
tm = localtime(&rec->time);
str = g_strdup_printf("[%02d:%02d] %s", tm->tm_hour, tm->tm_min, text);
- printtext(NULL, NULL, MSGLEVEL_LASTLOG, str);
+ printtext(NULL, NULL, MSGLEVEL_LASTLOG, "%s", str);
g_free(str);
}
g_free(text);
@@ -249,7 +248,7 @@ static void scrollback_goto_pos(WINDOW_REC *window, GList *pos)
gui->bottom = TRUE;
gui->startline = gui->bottom_startline;
gui->subline = gui->bottom_subline;
- gui->ypos = last_text_line-first_text_line-1;
+ gui->ypos = gui->parent->last_line-gui->parent->first_line-1;
}
if (is_window_visible(window))
@@ -362,7 +361,7 @@ static void cmd_scrollback_end(gchar *data)
gui->bottom = TRUE;
gui->startline = gui->bottom_startline;
gui->subline = gui->bottom_subline;
- gui->ypos = last_text_line-first_text_line-1;
+ gui->ypos = gui->parent->last_line-gui->parent->first_line-1;
if (is_window_visible(active_win))
gui_window_redraw(active_win);
diff --git a/src/fe-text/gui-windows.c b/src/fe-text/gui-windows.c
index bdcfa916..df1ba8ec 100644
--- a/src/fe-text/gui-windows.c
+++ b/src/fe-text/gui-windows.c
@@ -30,14 +30,13 @@
#include "screen.h"
#include "gui-entry.h"
-#include "gui-mainwindows.h"
#include "gui-windows.h"
#include <regex.h>
#define DEFAULT_INDENT_POS 10
-int first_text_line = 0, last_text_line = 0;
+static int window_create_override;
static GUI_WINDOW_REC *gui_window_init(WINDOW_REC *window, MAIN_WINDOW_REC *parent)
{
@@ -49,7 +48,7 @@ static GUI_WINDOW_REC *gui_window_init(WINDOW_REC *window, MAIN_WINDOW_REC *pare
gui->bottom = TRUE;
gui->line_chunk = g_mem_chunk_new("line chunk", sizeof(LINE_REC),
sizeof(LINE_REC)*100, G_ALLOC_AND_FREE);
- gui->empty_linecount = last_text_line-first_text_line-1;
+ gui->empty_linecount = parent->last_line-parent->first_line;
return gui;
}
@@ -65,19 +64,31 @@ static void gui_window_deinit(GUI_WINDOW_REC *gui)
g_free(gui);
}
+static void sig_window_create_override(gpointer tab)
+{
+ window_create_override = GPOINTER_TO_INT(tab);
+}
+
static void gui_window_created(WINDOW_REC *window)
{
- MAIN_WINDOW_REC *parent;
+ MAIN_WINDOW_REC *parent;
- g_return_if_fail(window != NULL);
+ g_return_if_fail(window != NULL);
- parent = (active_win == NULL || WINDOW_GUI(active_win) == NULL) ?
- gui_mainwindow_create() : WINDOW_GUI(active_win)->parent;
- if (parent->children == NULL) parent->active = window;
- parent->children = g_list_append(parent->children, window);
+ parent = window_create_override != 0 &&
+ active_win != NULL && WINDOW_GUI(active_win) != NULL ?
+ WINDOW_GUI(active_win)->parent : mainwindow_create();
+ if (parent == NULL) {
+ /* not enough space for new window, but we really can't
+ abort creation of the window anymore, so create hidden
+ window instead. */
+ parent = WINDOW_GUI(active_win)->parent;
+ }
+ window_create_override = -1;
- window->gui_data = gui_window_init(window, parent);
- signal_emit("gui window created", 1, window);
+ if (parent->active == NULL) parent->active = window;
+ window->gui_data = gui_window_init(window, parent);
+ signal_emit("gui window created", 1, window);
}
static void gui_window_destroyed(WINDOW_REC *window)
@@ -89,39 +100,35 @@ static void gui_window_destroyed(WINDOW_REC *window)
gui = WINDOW_GUI(window);
parent = gui->parent;
- parent->children = g_list_remove(parent->children, window);
signal_emit("gui window destroyed", 1, window);
gui_window_deinit(gui);
window->gui_data = NULL;
- if (parent->children == NULL)
- gui_mainwindow_destroy(parent);
-
- if (windows != NULL && active_win == window && !quitting)
- window_set_active(windows->data);
+ if (mainwindows->next != NULL && parent->active == window)
+ mainwindow_destroy(parent);
}
void gui_window_clear(WINDOW_REC *window)
{
- MAIN_WINDOW_REC *parent;
+ MAIN_WINDOW_REC *parent;
- g_return_if_fail(window != NULL);
+ g_return_if_fail(window != NULL);
- parent = WINDOW_GUI(window)->parent;
- gui_window_deinit(WINDOW_GUI(window));
- window->gui_data = gui_window_init(window, parent);
+ parent = WINDOW_GUI(window)->parent;
+ gui_window_deinit(WINDOW_GUI(window));
+ window->gui_data = gui_window_init(window, parent);
- window->lines = 0;
+ window->lines = 0;
- if (is_window_visible(window))
- gui_window_redraw(window);
+ if (is_window_visible(window))
+ gui_window_redraw(window);
}
-gint gui_window_update_bottom(GUI_WINDOW_REC *gui, gint lines)
+int gui_window_update_bottom(GUI_WINDOW_REC *gui, int lines)
{
- gint linecount, last_linecount;
+ int linecount, last_linecount;
if (gui->bottom_startline == NULL)
return -1;
@@ -173,7 +180,7 @@ void gui_window_newline(GUI_WINDOW_REC *gui, gboolean visible)
g_return_if_fail(gui != NULL);
gui->xpos = 0;
- last_line = gui->ypos >= last_text_line-first_text_line-1;
+ last_line = gui->ypos >= gui->parent->last_line-gui->parent->first_line;
if (gui->empty_linecount > 0)
{
@@ -211,8 +218,8 @@ void gui_window_newline(GUI_WINDOW_REC *gui, gboolean visible)
if (visible)
{
- scroll_up(first_text_line, last_text_line-1);
- move(last_text_line-1, 0); clrtoeol();
+ scroll_up(gui->parent->first_line, gui->parent->last_line);
+ move(gui->parent->last_line, 0); clrtoeol();
}
}
}
@@ -240,6 +247,8 @@ gint gui_window_get_linecount(GUI_WINDOW_REC *gui, LINE_REC *line)
ptr++;
switch ((guchar) *ptr)
{
+ case LINE_CMD_OVERFLOW:
+ g_error("buffer overflow!");
case LINE_CMD_EOL:
return lines;
case LINE_CMD_CONTINUE:
@@ -306,6 +315,8 @@ gint gui_window_line_draw(GUI_WINDOW_REC *gui, LINE_REC *line, gint ypos, gint s
}
else switch ((guchar) *ptr)
{
+ case LINE_CMD_OVERFLOW:
+ g_error("buffer overflow!");
case LINE_CMD_EOL:
return lines;
case LINE_CMD_CONTINUE:
@@ -365,7 +376,7 @@ gint gui_window_line_draw(GUI_WINDOW_REC *gui, LINE_REC *line, gint ypos, gint s
else
{
gui_window_newline(gui, TRUE);
- ypos = first_text_line+gui->ypos;
+ ypos = gui->parent->first_line+gui->ypos;
}
lines++;
}
@@ -409,7 +420,7 @@ void gui_window_redraw(WINDOW_REC *window)
gui = WINDOW_GUI(window);
- for (ypos = first_text_line; ypos < last_text_line; ypos++)
+ for (ypos = gui->parent->first_line; ypos <= gui->parent->last_line; ypos++)
{
set_color(0);
move(ypos, 0);
@@ -417,12 +428,12 @@ void gui_window_redraw(WINDOW_REC *window)
}
skip = gui->subline;
- ypos = first_text_line;
+ ypos = gui->parent->first_line;
for (line = gui->startline; line != NULL; line = line->next)
{
LINE_REC *rec = line->data;
- max = last_text_line - ypos-1;
+ max = gui->parent->last_line - ypos;
if (max < 0) break;
lines = gui_window_line_draw(gui, rec, ypos, skip, max);
@@ -460,7 +471,7 @@ static void gui_window_scroll_up(GUI_WINDOW_REC *gui, gint lines)
gui->ypos -= -count;
}
- gui->bottom = (gui->ypos >= -1 && gui->ypos <= last_text_line-first_text_line-1);
+ gui->bottom = (gui->ypos >= -1 && gui->ypos <= gui->parent->last_line-gui->parent->first_line);
}
static void gui_window_scroll_down(GUI_WINDOW_REC *gui, gint lines)
@@ -507,28 +518,28 @@ static void gui_window_scroll_down(GUI_WINDOW_REC *gui, gint lines)
gui->startline = gui->startline->next;
}
- gui->bottom = (gui->ypos >= -1 && gui->ypos <= last_text_line-first_text_line-1);
+ gui->bottom = (gui->ypos >= -1 && gui->ypos <= gui->parent->last_line-gui->parent->first_line);
}
-void gui_window_scroll(WINDOW_REC *window, gint lines)
+void gui_window_scroll(WINDOW_REC *window, int lines)
{
- GUI_WINDOW_REC *gui;
+ GUI_WINDOW_REC *gui;
- g_return_if_fail(window != NULL);
+ g_return_if_fail(window != NULL);
- gui = WINDOW_GUI(window);
+ gui = WINDOW_GUI(window);
- if (lines < 0)
- gui_window_scroll_up(gui, -lines);
- else
- gui_window_scroll_down(gui, lines);
+ if (lines < 0)
+ gui_window_scroll_up(gui, -lines);
+ else
+ gui_window_scroll_down(gui, lines);
- if (is_window_visible(window))
- gui_window_redraw(window);
- signal_emit("gui page scrolled", 1, window);
+ if (is_window_visible(window))
+ gui_window_redraw(window);
+ signal_emit("gui page scrolled", 1, window);
}
-static void window_update_prompt(WINDOW_REC *window)
+void window_update_prompt(WINDOW_REC *window)
{
WI_ITEM_REC *item;
char *text, *str;
@@ -551,11 +562,34 @@ static void window_update_prompt(WINDOW_REC *window)
if (*str != '\0') g_free(str);
}
+void gui_window_reparent(WINDOW_REC *window, MAIN_WINDOW_REC *parent)
+{
+ MAIN_WINDOW_REC *oldparent;
+ int ychange;
+
+ oldparent = WINDOW_GUI(window)->parent;
+ ychange = (parent->last_line - parent->first_line) -
+ (oldparent->last_line - oldparent->first_line);
+
+ WINDOW_GUI(window)->parent = parent;
+ if (ychange != 0) gui_window_resize(window, ychange, FALSE);
+}
+
static void signal_window_changed(WINDOW_REC *window)
{
g_return_if_fail(window != NULL);
- WINDOW_GUI(window)->parent->active = window;
+ if (is_window_visible(window)) {
+ /* already visible, great! */
+ active_mainwin = WINDOW_GUI(window)->parent;
+ } else {
+ /* move it to active main window */
+ if (active_mainwin == NULL)
+ active_mainwin = WINDOW_GUI(window)->parent;
+ else
+ gui_window_reparent(window, active_mainwin);
+ active_mainwin->active = window;
+ }
screen_refresh_freeze();
window_update_prompt(window);
@@ -565,15 +599,6 @@ static void signal_window_changed(WINDOW_REC *window)
static void signal_window_item_update(WINDOW_REC *window)
{
- CHANNEL_REC *channel;
-
- channel = irc_item_channel(window->active);
- if (channel != NULL) {
- /* redraw channel widgets */
- signal_emit("channel topic changed", 1, channel);
- signal_emit("channel mode changed", 1, channel);
- }
-
window_update_prompt(window);
}
@@ -625,6 +650,8 @@ GList *gui_window_find_text(WINDOW_REC *window, gchar *text, GList *startline, i
}
else if ((guchar) *ptr == LINE_CMD_EOL)
break;
+ else if ((guchar) *ptr == LINE_CMD_OVERFLOW)
+ g_error("buffer overflow!");
}
}
str[n] = '\0';
@@ -645,138 +672,89 @@ GList *gui_window_find_text(WINDOW_REC *window, gchar *text, GList *startline, i
static void gui_window_horiz_resize(WINDOW_REC *window)
{
- GUI_WINDOW_REC *gui;
- gint linecount;
+ GUI_WINDOW_REC *gui;
+ int linecount;
- gui = WINDOW_GUI(window);
- if (gui->lines == NULL) return;
+ gui = WINDOW_GUI(window);
+ if (gui->lines == NULL) return;
- linecount = gui_window_get_linecount(gui, g_list_last(gui->lines)->data);
- gui->last_subline = linecount-1;
+ linecount = gui_window_get_linecount(gui, g_list_last(gui->lines)->data);
+ gui->last_subline = linecount-1;
- /* fake a /CLEAR and scroll window up one page */
- gui->ypos = -1;
- gui->bottom = TRUE;
- gui->empty_linecount = last_text_line-first_text_line-1;
+ /* fake a /CLEAR and scroll window up one page */
+ gui->ypos = -1;
+ gui->bottom = TRUE;
+ gui->empty_linecount = gui->parent->last_line-gui->parent->first_line;
- gui->bottom_startline = gui->startline = g_list_last(gui->lines);
- gui->bottom_subline = gui->subline = gui->last_subline+1;
- gui_window_scroll(window, -gui->empty_linecount-1);
+ gui->bottom_startline = gui->startline = g_list_last(gui->lines);
+ gui->bottom_subline = gui->subline = gui->last_subline+1;
+ gui_window_scroll(window, -gui->empty_linecount-1);
- gui->bottom_startline = gui->startline;
- gui->bottom_subline = gui->subline;
+ gui->bottom_startline = gui->startline;
+ gui->bottom_subline = gui->subline;
- /* remove the empty lines from the end */
- if (gui->bottom && gui->startline == gui->lines)
- gui->empty_linecount = (last_text_line-first_text_line-1);
- else
- gui->empty_linecount = 0;
+ /* remove the empty lines from the end */
+ if (gui->bottom && gui->startline == gui->lines)
+ gui->empty_linecount = (gui->parent->last_line-gui->parent->first_line);
+ else
+ gui->empty_linecount = 0;
}
-void gui_windows_resize(gint ychange, gboolean xchange)
+void gui_window_resize(WINDOW_REC *window, int ychange, int xchange)
{
- GUI_WINDOW_REC *gui;
- WINDOW_REC *window;
- GSList *tmp;
-
- screen_refresh_freeze();
- for (tmp = windows; tmp != NULL; tmp = tmp->next)
- {
- window = tmp->data;
+ GUI_WINDOW_REC *gui;
gui = WINDOW_GUI(window);
- if (xchange)
- {
- /* window width changed, we'll need to recalculate a few things.. */
- gui_window_horiz_resize(window);
- continue;
+ if (xchange) {
+ /* window width changed, we'll need to recalculate a few things.. */
+ gui_window_horiz_resize(window);
+ return;
}
- if (ychange < 0 && gui->empty_linecount > 0)
- {
- /* empty space at the bottom of the screen - just eat it. */
- gui->empty_linecount += ychange;
- if (gui->empty_linecount < 0)
- gui->empty_linecount = 0;
- }
- else if (gui->bottom && gui->startline == gui->lines && ychange > 0)
- {
- /* less than screenful of text, add empty space */
- gui->empty_linecount += ychange;
- }
- else
- {
- gui_window_update_bottom(WINDOW_GUI(window), -ychange);
- gui_window_scroll(window, -ychange);
+ if (ychange < 0 && gui->empty_linecount > 0) {
+ /* empty space at the bottom of the screen - just eat it. */
+ gui->empty_linecount += ychange;
+ if (gui->empty_linecount >= 0)
+ ychange = 0;
+ else {
+ ychange -= gui->empty_linecount;
+ gui->empty_linecount = 0;
+ }
}
- }
-
- irssi_redraw();
- screen_refresh_thaw();
-}
-
-static void cmd_window_move(gchar *data)
-{
- GSList *w1, *w2;
- WINDOW_REC *window;
- g_return_if_fail(data != NULL);
-
- window = active_win;
- w1 = g_slist_find(windows, window);
- if (g_strcasecmp(data, "LEFT") == 0 || g_strncasecmp(data, "PREV", 4) == 0)
- {
- w2 = g_slist_nth(windows, g_slist_index(windows, window)-1);
- if (w2 == NULL)
- {
- window = w1->data;
- windows = g_slist_remove(windows, window);
- windows = g_slist_append(windows, window);
- w2 = g_slist_last(windows);
- }
- }
- else if (g_strcasecmp(data, "RIGHT") == 0 || g_strcasecmp(data, "NEXT") == 0)
- {
- w2 = w1->next;
- if (w2 == NULL)
- {
- window = w1->data;
- windows = g_slist_remove(windows, window);
- windows = g_slist_prepend(windows, window);
+ if (gui->bottom && gui->startline == gui->lines && ychange > 0) {
+ /* less than screenful of text, add empty space */
+ gui->empty_linecount += ychange;
+ } else {
+ gui_window_update_bottom(WINDOW_GUI(window), -ychange);
+ gui_window_scroll(window, -ychange);
}
- }
- else
- return;
-
- if (w2 != NULL)
- {
- window = w1->data;
- w1->data = w2->data;
- w2->data = window;
- }
-
- window_set_active(window);
}
void gui_windows_init(void)
{
- signal_add("window created", (SIGNAL_FUNC) gui_window_created);
- signal_add("window destroyed", (SIGNAL_FUNC) gui_window_destroyed);
- signal_add("window changed", (SIGNAL_FUNC) signal_window_changed);
- signal_add("window item changed", (SIGNAL_FUNC) signal_window_item_update);
- signal_add("window name changed", (SIGNAL_FUNC) signal_window_item_update);
- signal_add("window item remove", (SIGNAL_FUNC) signal_window_item_update);
- command_bind("window move", NULL, (SIGNAL_FUNC) cmd_window_move);
+ window_create_override = -1;
+
+ signal_add("gui window create override", (SIGNAL_FUNC) sig_window_create_override);
+ signal_add("window created", (SIGNAL_FUNC) gui_window_created);
+ signal_add("window destroyed", (SIGNAL_FUNC) gui_window_destroyed);
+ signal_add_first("window changed", (SIGNAL_FUNC) signal_window_changed);
+ signal_add("window item changed", (SIGNAL_FUNC) signal_window_item_update);
+ signal_add("window name changed", (SIGNAL_FUNC) signal_window_item_update);
+ signal_add("window item remove", (SIGNAL_FUNC) signal_window_item_update);
}
void gui_windows_deinit(void)
{
- signal_remove("window created", (SIGNAL_FUNC) gui_window_created);
- signal_remove("window destroyed", (SIGNAL_FUNC) gui_window_destroyed);
- signal_remove("window changed", (SIGNAL_FUNC) signal_window_changed);
- signal_remove("window item changed", (SIGNAL_FUNC) signal_window_item_update);
- signal_remove("window name changed", (SIGNAL_FUNC) signal_window_item_update);
- signal_remove("window item remove", (SIGNAL_FUNC) signal_window_item_update);
- command_unbind("window move", (SIGNAL_FUNC) cmd_window_move);
+ while (windows != NULL)
+ window_destroy(windows->data);
+
+ signal_remove("gui window create override", (SIGNAL_FUNC) sig_window_create_override);
+ signal_remove("window created", (SIGNAL_FUNC) gui_window_created);
+ signal_remove("window destroyed", (SIGNAL_FUNC) gui_window_destroyed);
+ signal_remove("window changed", (SIGNAL_FUNC) signal_window_changed);
+ signal_remove("window item changed", (SIGNAL_FUNC) signal_window_item_update);
+ signal_remove("window name changed", (SIGNAL_FUNC) signal_window_item_update);
+ signal_remove("window item remove", (SIGNAL_FUNC) signal_window_item_update);
}
diff --git a/src/fe-text/gui-windows.h b/src/fe-text/gui-windows.h
index 14a3a982..28dde1e9 100644
--- a/src/fe-text/gui-windows.h
+++ b/src/fe-text/gui-windows.h
@@ -2,7 +2,7 @@
#define __GUI_WINDOWS_H
#include "server.h"
-#include "gui-mainwindows.h"
+#include "mainwindows.h"
#define WINDOW_GUI(a) ((GUI_WINDOW_REC *) ((a)->gui_data))
@@ -12,63 +12,57 @@
#define LINE_TEXT_CHUNK_SIZE 2048
/* 7 first bits of LINE_REC's info byte. */
-enum
-{
- LINE_CMD_EOL=0x80, /* line ends here. */
- LINE_CMD_CONTINUE, /* line continues in next block */
- LINE_CMD_COLOR8, /* change to dark grey, normally 8 = bold black */
- LINE_CMD_UNDERLINE, /* enable/disable underlining */
- LINE_CMD_BEEP, /* beep */
- LINE_CMD_INDENT /* if line is split, indent it at this position */
+enum {
+ LINE_CMD_EOL=0x80, /* line ends here. */
+ LINE_CMD_CONTINUE, /* line continues in next block */
+ LINE_CMD_OVERFLOW, /* buffer overflow! */
+ LINE_CMD_COLOR8, /* change to dark grey, normally 8 = bold black */
+ LINE_CMD_UNDERLINE, /* enable/disable underlining */
+ LINE_CMD_BEEP, /* beep */
+ LINE_CMD_INDENT /* if line is split, indent it at this position */
};
-typedef struct
-{
- gchar *text; /* text in the line. \0 means that the next char will be a
- color or command. <= 127 = color or if 8.bit is set, the
- first 7 bits are the command. See LINE_CMD_xxxx. */
-
- gint32 level;
- time_t time;
-}
-LINE_REC;
-
-typedef struct
-{
- gchar buffer[LINE_TEXT_CHUNK_SIZE];
- gint pos;
- gint lines;
-}
-TEXT_CHUNK_REC;
-
-typedef struct
-{
- MAIN_WINDOW_REC *parent;
-
- GMemChunk *line_chunk;
- GSList *text_chunks;
- GList *lines;
-
- LINE_REC *cur_line;
- TEXT_CHUNK_REC *cur_text;
-
- gint xpos, ypos; /* cursor position in screen */
- GList *startline; /* line at the top of the screen */
- gint subline; /* number of "real lines" to skip from `startline' */
-
- GList *bottom_startline; /* marks the bottom of the text buffer */
- gint bottom_subline;
- gint empty_linecount; /* how many empty lines are in screen.
- a screenful when started or used /CLEAR */
- gboolean bottom; /* window is at the bottom of the text buffer */
-
- /* for gui-printtext.c */
- gint last_subline;
- gint last_color, last_flags;
-}
-GUI_WINDOW_REC;
-
-extern gint first_text_line, last_text_line;
+typedef struct {
+ /* text in the line. \0 means that the next char will be a
+ color or command. <= 127 = color or if 8.bit is set, the
+ first 7 bits are the command. See LINE_CMD_xxxx. */
+ char *text;
+
+ int level;
+ time_t time;
+} LINE_REC;
+
+typedef struct {
+ char buffer[LINE_TEXT_CHUNK_SIZE];
+ char overflow[2];
+ int pos;
+ int lines;
+} TEXT_CHUNK_REC;
+
+typedef struct {
+ MAIN_WINDOW_REC *parent;
+
+ GMemChunk *line_chunk;
+ GSList *text_chunks;
+ GList *lines;
+
+ LINE_REC *cur_line;
+ TEXT_CHUNK_REC *cur_text;
+
+ int xpos, ypos; /* cursor position in screen */
+ GList *startline; /* line at the top of the screen */
+ int subline; /* number of "real lines" to skip from `startline' */
+
+ GList *bottom_startline; /* marks the bottom of the text buffer */
+ int bottom_subline;
+ int empty_linecount; /* how many empty lines are in screen.
+ a screenful when started or used /CLEAR */
+ int bottom; /* window is at the bottom of the text buffer */
+
+ /* for gui-printtext.c */
+ int last_subline;
+ int last_color, last_flags;
+} GUI_WINDOW_REC;
void gui_windows_init(void);
void gui_windows_deinit(void);
@@ -76,18 +70,20 @@ void gui_windows_deinit(void);
WINDOW_REC *gui_window_create(MAIN_WINDOW_REC *parent);
void gui_window_set_server(WINDOW_REC *window, SERVER_REC *server);
-GList *gui_window_find_text(WINDOW_REC *window, gchar *text, GList *startline, int regexp, int fullword);
+GList *gui_window_find_text(WINDOW_REC *window, char *text, GList *startline, int regexp, int fullword);
/* get number of real lines that line record takes */
-gint gui_window_get_linecount(GUI_WINDOW_REC *gui, LINE_REC *line);
-gint gui_window_line_draw(GUI_WINDOW_REC *gui, LINE_REC *line, gint ypos, gint skip, gint max);
+int gui_window_get_linecount(GUI_WINDOW_REC *gui, LINE_REC *line);
+int gui_window_line_draw(GUI_WINDOW_REC *gui, LINE_REC *line, int ypos, int skip, int max);
void gui_window_clear(WINDOW_REC *window);
void gui_window_redraw(WINDOW_REC *window);
-void gui_windows_resize(gint ychange, gboolean xchange);
+void gui_window_resize(WINDOW_REC *window, int ychange, int xchange);
+void gui_window_reparent(WINDOW_REC *window, MAIN_WINDOW_REC *parent);
+void window_update_prompt(WINDOW_REC *window);
void gui_window_newline(GUI_WINDOW_REC *gui, gboolean visible);
-gint gui_window_update_bottom(GUI_WINDOW_REC *gui, gint lines);
-void gui_window_scroll(WINDOW_REC *window, gint lines);
+int gui_window_update_bottom(GUI_WINDOW_REC *gui, int lines);
+void gui_window_scroll(WINDOW_REC *window, int lines);
#endif
diff --git a/src/fe-text/irssi.c b/src/fe-text/irssi.c
index d427a208..2c95b87d 100644
--- a/src/fe-text/irssi.c
+++ b/src/fe-text/irssi.c
@@ -29,12 +29,11 @@
#include "screen.h"
#include "gui-entry.h"
-#include "gui-mainwindows.h"
+#include "mainwindows.h"
#include "gui-printtext.h"
#include "gui-readline.h"
#include "gui-special-vars.h"
-#include "gui-statusbar.h"
-#include "gui-statusbar-items.h"
+#include "statusbar.h"
#include "gui-textwidget.h"
#include "gui-windows.h"
@@ -59,109 +58,103 @@ static void sig_exit(void)
/* redraw irssi's screen.. */
void irssi_redraw(void)
{
- clear();
-
- /* current window */
- gui_window_redraw(active_win);
- /* statusbar */
- gui_statusbar_redraw(-1);
- /* entry line */
- gui_entry_redraw();
+ clear();
+
+ /* windows */
+ mainwindows_redraw();
+ /* statusbar */
+ statusbar_redraw(NULL);
+ /* entry line */
+ gui_entry_redraw();
}
static void textui_init(void)
{
- static struct poptOption options[] = {
- POPT_AUTOHELP
- { NULL, '\0', 0, NULL }
- };
-
- args_register(options);
-
- irssi_gui = IRSSI_GUI_TEXT;
- core_init();
- irc_init();
- fe_common_core_init();
- fe_common_irc_init();
- signal_add("gui exit", (SIGNAL_FUNC) sig_exit);
+ static struct poptOption options[] = {
+ POPT_AUTOHELP
+ { NULL, '\0', 0, NULL }
+ };
+
+ args_register(options);
+
+ irssi_gui = IRSSI_GUI_TEXT;
+ core_init();
+ irc_init();
+ fe_common_core_init();
+ fe_common_irc_init();
+ signal_add("gui exit", (SIGNAL_FUNC) sig_exit);
}
static void textui_finish_init(void)
{
- quitting = FALSE;
-
- screen_refresh_freeze();
- gui_entry_init();
- gui_mainwindows_init();
- gui_printtext_init();
- gui_readline_init();
- gui_special_vars_init();
- gui_textwidget_init();
- gui_windows_init();
-
- fe_common_core_finish_init();
- fe_common_irc_finish_init();
-
- gui_statusbar_init();
- gui_statusbar_items_init();
-
- signal_emit("irssi init finished", 0);
+ quitting = FALSE;
+
+ screen_refresh_freeze();
+ gui_entry_init();
+ mainwindows_init();
+ gui_printtext_init();
+ gui_readline_init();
+ gui_special_vars_init();
+ gui_textwidget_init();
+ gui_windows_init();
+ statusbar_init();
+
+ fe_common_core_finish_init();
+ fe_common_irc_finish_init();
+
+ signal_emit("irssi init finished", 0);
#ifdef HAVE_PERL
- irssi_perl_init();
+ irssi_perl_init();
#endif
- screen_refresh_thaw();
+ screen_refresh_thaw();
}
static void textui_deinit(void)
{
- quitting = TRUE;
- signal(SIGINT, SIG_DFL);
+ quitting = TRUE;
+ signal(SIGINT, SIG_DFL);
- signal_remove("gui exit", (SIGNAL_FUNC) sig_exit);
+ signal_remove("gui exit", (SIGNAL_FUNC) sig_exit);
#ifdef HAVE_PERL
- irssi_perl_deinit();
+ irssi_perl_deinit();
#endif
- gui_textwidget_deinit();
- gui_special_vars_deinit();
- gui_statusbar_items_deinit();
- gui_statusbar_deinit();
- gui_printtext_deinit();
- gui_readline_deinit();
- gui_mainwindows_deinit();
- gui_windows_deinit();
- gui_entry_deinit();
- deinit_screen();
-
- fe_common_irc_deinit();
- fe_common_core_deinit();
- irc_deinit();
- core_deinit();
+ gui_textwidget_deinit();
+ gui_special_vars_deinit();
+ statusbar_deinit();
+ gui_printtext_deinit();
+ gui_readline_deinit();
+ mainwindows_deinit();
+ gui_windows_deinit();
+ gui_entry_deinit();
+ deinit_screen();
+
+ fe_common_irc_deinit();
+ fe_common_core_deinit();
+ irc_deinit();
+ core_deinit();
}
int main(int argc, char **argv)
{
#ifdef HAVE_SOCKS
- SOCKSinit(argv[0]);
+ SOCKSinit(argv[0]);
#endif
- textui_init();
- args_execute(argc, argv);
+ textui_init();
+ args_execute(argc, argv);
- if (!init_screen())
- {
- printf("Can't initialize screen handling, quitting.\n");
- return 1;
- }
+ if (!init_screen())
+ g_error(_("Can't initialize screen handling, quitting.\n"));
- textui_finish_init();
- main_loop = g_main_new(TRUE);
- g_main_run(main_loop);
- g_main_destroy(main_loop);
- textui_deinit();
+ textui_finish_init();
+ main_loop = g_main_new(TRUE);
+ g_main_run(main_loop);
+ g_main_destroy(main_loop);
+ textui_deinit();
#ifdef MEM_DEBUG
- ig_mem_profile();
+ ig_mem_profile();
#endif
- return 0;
+ return 0;
}
diff --git a/src/fe-text/mainwindows.c b/src/fe-text/mainwindows.c
new file mode 100644
index 00000000..35bf4ecd
--- /dev/null
+++ b/src/fe-text/mainwindows.c
@@ -0,0 +1,606 @@
+/*
+ gui-mainwindows.c : irssi
+
+ Copyright (C) 1999 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "module-formats.h"
+#include "signals.h"
+#include "commands.h"
+#include "levels.h"
+#include "misc.h"
+
+#include "screen.h"
+#include "statusbar.h"
+#include "gui-windows.h"
+
+#define WINDOW_MIN_SIZE 2
+#define NEW_WINDOW_SIZE (WINDOW_MIN_SIZE + 1)
+
+#define window_size(window) \
+ ((window)->last_line - (window)->first_line+1)
+
+GSList *mainwindows;
+MAIN_WINDOW_REC *active_mainwin;
+
+static int reserved_up, reserved_down;
+
+static MAIN_WINDOW_REC *find_window_with_room(void)
+{
+ MAIN_WINDOW_REC *biggest_rec;
+ GSList *tmp;
+ int space, biggest;
+
+ biggest = 0; biggest_rec = NULL;
+ for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+
+ space = window_size(rec);
+ if (space >= WINDOW_MIN_SIZE+NEW_WINDOW_SIZE && space > biggest) {
+ biggest = space;
+ biggest_rec = rec;
+ }
+ }
+
+ return biggest_rec;
+}
+
+static void mainwindow_resize(MAIN_WINDOW_REC *window, int ychange, int xchange)
+{
+ GSList *tmp;
+
+ if (ychange == 0 && !xchange) return;
+
+ for (tmp = windows; tmp != NULL; tmp = tmp->next) {
+ WINDOW_REC *rec = tmp->data;
+
+ if (rec->gui_data != NULL && WINDOW_GUI(rec)->parent == window)
+ gui_window_resize(rec, ychange, xchange);
+ }
+
+ signal_emit("mainwindow resized", 1, window);
+}
+
+MAIN_WINDOW_REC *mainwindow_create(void)
+{
+ MAIN_WINDOW_REC *rec, *parent;
+ int space;
+
+ rec = g_new0(MAIN_WINDOW_REC, 1);
+ rec->statusbar_lines = 1;
+
+ if (mainwindows == NULL) {
+ active_mainwin = rec;
+
+ rec->first_line = reserved_up;
+ rec->last_line = LINES-1-reserved_down-rec->statusbar_lines;
+ } else {
+ parent = WINDOW_GUI(active_win)->parent;
+ if (window_size(parent) < WINDOW_MIN_SIZE+NEW_WINDOW_SIZE)
+ parent = find_window_with_room();
+ if (parent == NULL)
+ return NULL; /* not enough space */
+
+ space = (window_size(parent)-parent->statusbar_lines)/2;
+ rec->first_line = parent->first_line;
+ rec->last_line = rec->first_line + space-rec->statusbar_lines;
+ parent->first_line = rec->last_line+1+rec->statusbar_lines;
+
+ mainwindow_resize(parent, -space-1, FALSE);
+ }
+
+ mainwindows = g_slist_append(mainwindows, rec);
+ signal_emit("mainwindow created", 1, rec);
+ return rec;
+}
+
+static MAIN_WINDOW_REC *mainwindows_find_lower(int line)
+{
+ MAIN_WINDOW_REC *best;
+ GSList *tmp;
+
+ best = NULL;
+ for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+
+ if (rec->first_line > line &&
+ (best == NULL || rec->first_line < best->first_line))
+ best = rec;
+ }
+
+ return best;
+}
+
+static MAIN_WINDOW_REC *mainwindows_find_upper(int line)
+{
+ MAIN_WINDOW_REC *best;
+ GSList *tmp;
+
+ best = NULL;
+ for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+
+ if (rec->last_line < line &&
+ (best == NULL || rec->last_line > best->last_line))
+ best = rec;
+ }
+
+ return best;
+}
+
+static void mainwindows_add_space(int first_line, int last_line)
+{
+ MAIN_WINDOW_REC *rec;
+ int size;
+
+ if (last_line < first_line)
+ return;
+
+ size = last_line-first_line+1;
+
+ rec = mainwindows_find_lower(last_line);
+ if (rec != NULL) {
+ rec->first_line = first_line;
+ mainwindow_resize(rec, size, FALSE);
+ return;
+ }
+
+ rec = mainwindows_find_upper(first_line);
+ if (rec != NULL) {
+ rec->last_line = last_line-rec->statusbar_lines;
+ mainwindow_resize(rec, size, FALSE);
+ }
+}
+
+static void gui_windows_remove_parent(MAIN_WINDOW_REC *window)
+{
+ MAIN_WINDOW_REC *new_parent;
+ GSList *tmp;
+
+ new_parent = mainwindows->data;
+ for (tmp = windows; tmp != NULL; tmp = tmp->next) {
+ WINDOW_REC *rec = tmp->data;
+
+ if (rec->gui_data != NULL && WINDOW_GUI(rec)->parent == window)
+ gui_window_reparent(rec, new_parent);
+ }
+}
+
+void mainwindow_destroy(MAIN_WINDOW_REC *window)
+{
+ g_return_if_fail(window != NULL);
+
+ mainwindows = g_slist_remove(mainwindows, window);
+ signal_emit("mainwindow destroyed", 1, window);
+
+ if (!quitting && mainwindows != NULL) {
+ gui_windows_remove_parent(window);
+ mainwindows_add_space(window->first_line, window->last_line+window->statusbar_lines);
+
+ mainwindows_redraw();
+ statusbar_redraw(NULL);
+ }
+ g_free(window);
+
+ if (active_mainwin == window) active_mainwin = NULL;
+}
+
+void mainwindows_redraw(void)
+{
+ GSList *tmp;
+
+ screen_refresh_freeze();
+ for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+
+ gui_window_redraw(rec->active);
+ }
+ screen_refresh_thaw();
+}
+
+static int mainwindows_compare(MAIN_WINDOW_REC *w1, MAIN_WINDOW_REC *w2)
+{
+ return w1->first_line < w2->first_line ? -1 : 1;
+}
+
+static int mainwindows_compare_reverse(MAIN_WINDOW_REC *w1, MAIN_WINDOW_REC *w2)
+{
+ return w1->first_line < w2->first_line ? 1 : -1;
+}
+
+static GSList *mainwindows_get_sorted(int reverse)
+{
+ GSList *tmp, *list;
+
+ list = NULL;
+ for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
+ list = g_slist_insert_sorted(list, tmp->data, (GCompareFunc)
+ (reverse ? mainwindows_compare_reverse : mainwindows_compare));
+ }
+
+ return list;
+}
+
+static void mainwindows_resize_too_small(int ychange, int xchange)
+{
+ GSList *sorted, *tmp;
+ int space, moved;
+
+ /* terminal is too small - just take the space whereever possible */
+ sorted = mainwindows_get_sorted(FALSE);
+ moved = 0;
+ for (tmp = sorted; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+
+ space = window_size(rec);
+ if (ychange == 0 || space <= 0) {
+ if (moved > 0) {
+ rec->first_line -= moved;
+ rec->last_line -= moved;
+ signal_emit("mainwindow moved", 1, rec);
+ }
+ continue;
+ }
+
+ if (space > -ychange) space = -ychange;
+ ychange += space;
+ rec->first_line -= moved;
+ moved += space;
+ rec->last_line -= space;
+ mainwindow_resize(rec, -space, xchange);
+ }
+ g_slist_free(sorted);
+}
+
+static void mainwindows_resize_smaller(int ychange, int xchange)
+{
+ GSList *sorted, *tmp;
+ int space;
+
+ space = 0;
+ for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+
+ space += window_size(rec)-WINDOW_MIN_SIZE;
+ }
+
+ if (space < -ychange) {
+ /* not enough space, use different algorithm */
+ mainwindows_resize_too_small(ychange, xchange);
+ return;
+ }
+
+ /* resize windows that have space */
+ sorted = mainwindows_get_sorted(TRUE);
+ for (tmp = sorted; tmp != NULL && ychange < 0; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+
+ space = window_size(rec)-WINDOW_MIN_SIZE;
+ if (space <= 0) {
+ rec->first_line += ychange;
+ rec->last_line += ychange;
+ signal_emit("mainwindow moved", 1, rec);
+ continue;
+ }
+
+ if (space <= 0) space = 1;
+ if (space > -ychange) space = -ychange;
+ rec->last_line += ychange;
+ ychange += space;
+ rec->first_line += ychange;
+
+ mainwindow_resize(rec, -space, xchange);
+ }
+ g_slist_free(sorted);
+}
+
+static void mainwindows_resize_bigger(int ychange, int xchange)
+{
+ GSList *sorted, *tmp;
+ int moved, space;
+
+ sorted = mainwindows_get_sorted(FALSE);
+ moved = 0;
+ for (tmp = sorted; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+
+ space = window_size(rec)-WINDOW_MIN_SIZE;
+ if (ychange == 0 || (space >= 0 && tmp->next != NULL)) {
+ if (moved > 0) {
+ rec->first_line += moved;
+ rec->last_line += moved;
+ signal_emit("mainwindow moved", 1, rec);
+ }
+ continue;
+ }
+
+ if (space < 0 && tmp->next != NULL) {
+ /* space below minimum */
+ space = -space;
+ if (space > ychange) space = ychange;
+ } else {
+ /* lowest window - give all the extra space for it */
+ space = ychange;
+ }
+ ychange -= space;
+ rec->first_line += moved;
+ moved += space;
+ rec->last_line += moved;
+
+ mainwindow_resize(rec, space, xchange);
+ }
+ g_slist_free(sorted);
+}
+
+void mainwindows_resize(int ychange, int xchange)
+{
+ screen_refresh_freeze();
+ if (ychange < 0)
+ mainwindows_resize_smaller(ychange, xchange);
+ else if (ychange > 0)
+ mainwindows_resize_bigger(ychange, xchange);
+
+ irssi_redraw();
+ screen_refresh_thaw();
+}
+
+int mainwindows_reserve_lines(int count, int up)
+{
+ MAIN_WINDOW_REC *window;
+ int ret;
+
+ if (up) {
+ g_return_val_if_fail(count > 0 || reserved_up > count, -1);
+
+ ret = reserved_up;
+ reserved_up += count;
+
+ window = mainwindows_find_lower(-1);
+ if (window != NULL) window->first_line += count;
+ } else {
+ g_return_val_if_fail(count > 0 || reserved_down > count, -1);
+
+ ret = reserved_down;
+ reserved_down += count;
+
+ window = mainwindows_find_upper(LINES);
+ if (window != NULL) window->last_line -= count;
+ }
+
+ if (window != NULL)
+ mainwindow_resize(window, -count, FALSE);
+
+ return ret;
+}
+
+static void mainwindows_resize_two(MAIN_WINDOW_REC *grow_win, MAIN_WINDOW_REC *shrink_win, int count)
+{
+ mainwindow_resize(grow_win, count, FALSE);
+ mainwindow_resize(shrink_win, -count, FALSE);
+ gui_window_redraw(grow_win->active);
+ gui_window_redraw(shrink_win->active);
+ statusbar_redraw(grow_win->statusbar);
+ statusbar_redraw(shrink_win->statusbar);
+}
+
+static void cmd_window_grow(const char *data)
+{
+ MAIN_WINDOW_REC *window, *shrink_win;
+ int count;
+
+ count = *data == '\0' ? 1 : atoi(data);
+ window = WINDOW_GUI(active_win)->parent;
+
+ /* shrink lower window */
+ shrink_win = mainwindows_find_lower(window->last_line);
+ if (shrink_win != NULL && window_size(shrink_win)-count >= WINDOW_MIN_SIZE) {
+ window->last_line += count;
+ shrink_win->first_line += count;
+ } else {
+ /* shrink upper window */
+ shrink_win = mainwindows_find_upper(window->first_line);
+ if (shrink_win != NULL && window_size(shrink_win)-count >= WINDOW_MIN_SIZE) {
+ window->first_line -= count;
+ shrink_win->last_line -= count;
+ } else {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_WINDOW_TOO_SMALL);
+ return;
+ }
+ }
+
+ mainwindows_resize_two(window, shrink_win, count);
+}
+
+static void cmd_window_shrink(const char *data)
+{
+ MAIN_WINDOW_REC *window, *grow_win;
+ int count;
+
+ count = *data == '\0' ? 1 : atoi(data);
+
+ window = WINDOW_GUI(active_win)->parent;
+ if (window_size(window)-count < WINDOW_MIN_SIZE) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_WINDOW_TOO_SMALL);
+ return;
+ }
+
+ grow_win = mainwindows_find_lower(window->last_line);
+ if (grow_win != NULL) {
+ window->last_line -= count;
+ grow_win->first_line -= count;
+ } else {
+ grow_win = mainwindows_find_upper(window->first_line);
+ if (grow_win == NULL) return;
+
+ window->first_line += count;
+ grow_win->last_line += count;
+ }
+
+ mainwindows_resize_two(grow_win, window, count);
+}
+
+static void cmd_window_size(const char *data)
+{
+ char sizestr[MAX_INT_STRLEN];
+ int size;
+
+ if (!is_numeric(data, 0)) return;
+ size = atoi(data);
+
+ size -= window_size(WINDOW_GUI(active_win)->parent);
+ if (size == 0) return;
+
+ ltoa(sizestr, size < 0 ? -size : size);
+ if (size < 0)
+ cmd_window_shrink(sizestr);
+ else
+ cmd_window_grow(sizestr);
+}
+
+static void cmd_window_balance(void)
+{
+ GSList *sorted, *tmp;
+ int avail_size, unit_size, bigger_units;
+ int windows, last_line, old_size;
+
+ windows = g_slist_length(mainwindows);
+ if (windows == 1) return;
+
+ avail_size = LINES-reserved_up-reserved_down;
+ unit_size = avail_size/windows;
+ bigger_units = avail_size%windows;
+
+ sorted = mainwindows_get_sorted(FALSE);
+ last_line = 0;
+ for (tmp = sorted; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+
+ old_size = window_size(rec);
+ rec->first_line = last_line+1;
+ rec->last_line = rec->first_line-1 + unit_size -
+ rec->statusbar_lines;
+
+ if (bigger_units > 0) {
+ rec->last_line++;
+ bigger_units--;
+ }
+ last_line = rec->last_line + rec->statusbar_lines;
+
+ mainwindow_resize(rec, window_size(rec)-old_size, FALSE);
+ }
+ g_slist_free(sorted);
+
+ mainwindows_redraw();
+ statusbar_redraw(NULL);
+}
+
+static void cmd_window_hide(const char *data)
+{
+ WINDOW_REC *window;
+
+ if (mainwindows->next == NULL) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CANT_HIDE_LAST);
+ return;
+ }
+
+ if (*data == '\0')
+ window = active_win;
+ else if (is_numeric(data, 0))
+ window = window_find_refnum(atoi(data));
+ else
+ window = window_find_item(active_win, data);
+
+ if (window == NULL) return;
+ if (!is_window_visible(window)) return;
+
+ mainwindow_destroy(WINDOW_GUI(window)->parent);
+
+ if (active_mainwin == NULL) {
+ active_mainwin = WINDOW_GUI(active_win)->parent;
+ window_set_active(active_mainwin->active);
+ }
+}
+
+static void cmd_window_show(const char *data)
+{
+ WINDOW_REC *window;
+
+ if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ window = is_numeric(data, 0) ?
+ window_find_refnum(atoi(data)) :
+ window_find_item(active_win, data);
+
+ if (window == NULL) return;
+ if (is_window_visible(window)) return;
+
+ WINDOW_GUI(window)->parent = mainwindow_create();
+ WINDOW_GUI(window)->parent->active = window;
+
+ active_mainwin = NULL;
+ window_set_active(window);
+}
+
+static void cmd_window_up(void)
+{
+ MAIN_WINDOW_REC *rec;
+
+ rec = mainwindows_find_upper(active_mainwin->first_line);
+ if (rec != NULL)
+ window_set_active(rec->active);
+}
+
+static void cmd_window_down(void)
+{
+ MAIN_WINDOW_REC *rec;
+
+ rec = mainwindows_find_lower(active_mainwin->last_line);
+ if (rec != NULL)
+ window_set_active(rec->active);
+}
+
+void mainwindows_init(void)
+{
+ mainwindows = NULL;
+ active_mainwin = NULL;
+ reserved_up = reserved_down = 0;
+
+ /* for entry line */
+ mainwindows_reserve_lines(1, FALSE);
+
+ command_bind("window grow", NULL, (SIGNAL_FUNC) cmd_window_grow);
+ command_bind("window shrink", NULL, (SIGNAL_FUNC) cmd_window_shrink);
+ command_bind("window size", NULL, (SIGNAL_FUNC) cmd_window_size);
+ command_bind("window balance", NULL, (SIGNAL_FUNC) cmd_window_balance);
+ command_bind("window hide", NULL, (SIGNAL_FUNC) cmd_window_hide);
+ command_bind("window show", NULL, (SIGNAL_FUNC) cmd_window_show);
+ command_bind("window up", NULL, (SIGNAL_FUNC) cmd_window_up);
+ command_bind("window down", NULL, (SIGNAL_FUNC) cmd_window_down);
+}
+
+void mainwindows_deinit(void)
+{
+ command_unbind("window grow", (SIGNAL_FUNC) cmd_window_grow);
+ command_unbind("window shrink", (SIGNAL_FUNC) cmd_window_shrink);
+ command_unbind("window size", (SIGNAL_FUNC) cmd_window_size);
+ command_unbind("window balance", (SIGNAL_FUNC) cmd_window_balance);
+ command_unbind("window hide", (SIGNAL_FUNC) cmd_window_hide);
+ command_unbind("window show", (SIGNAL_FUNC) cmd_window_show);
+ command_unbind("window up", (SIGNAL_FUNC) cmd_window_up);
+ command_unbind("window down", (SIGNAL_FUNC) cmd_window_down);
+}
diff --git a/src/fe-text/mainwindows.h b/src/fe-text/mainwindows.h
new file mode 100644
index 00000000..467add2d
--- /dev/null
+++ b/src/fe-text/mainwindows.h
@@ -0,0 +1,29 @@
+#ifndef __MAINWINDOWS_H
+#define __MAINWINDOWS_H
+
+#include "windows.h"
+
+typedef struct {
+ WINDOW_REC *active;
+
+ int first_line, last_line;
+ int statusbar_lines;
+ void *statusbar;
+ void *statusbar_channel_item;
+} MAIN_WINDOW_REC;
+
+extern GSList *mainwindows;
+extern MAIN_WINDOW_REC *active_mainwin;
+
+void mainwindows_init(void);
+void mainwindows_deinit(void);
+
+MAIN_WINDOW_REC *mainwindow_create(void);
+void mainwindow_destroy(MAIN_WINDOW_REC *window);
+
+void mainwindows_redraw(void);
+void mainwindows_resize(int ychange, int xchange);
+
+int mainwindows_reserve_lines(int count, int up);
+
+#endif
diff --git a/src/fe-text/module-formats.c b/src/fe-text/module-formats.c
index a7576de9..9b38fecb 100644
--- a/src/fe-text/module-formats.c
+++ b/src/fe-text/module-formats.c
@@ -27,4 +27,7 @@ FORMAT_REC gui_text_formats[] =
{ "lastlog_start", "%_Lastlog:", 0 },
{ "lastlog_end", "%_End of Lastlog", 0 },
+
+ { "window_too_small", "Not enough room to resize this window", 0 },
+ { "cant_hide_last", "You can't hide the last window", 0 }
};
diff --git a/src/fe-text/module-formats.h b/src/fe-text/module-formats.h
index d8f7a3b8..32f219e2 100644
--- a/src/fe-text/module-formats.h
+++ b/src/fe-text/module-formats.h
@@ -1,10 +1,13 @@
#include "printtext.h"
enum {
- IRCTXT_MODULE_NAME,
+ IRCTXT_MODULE_NAME,
- IRCTXT_LASTLOG_START,
- IRCTXT_LASTLOG_END
+ IRCTXT_LASTLOG_START,
+ IRCTXT_LASTLOG_END,
+
+ IRCTXT_WINDOW_TOO_SMALL,
+ IRCTXT_CANT_HIDE_LAST
};
extern FORMAT_REC gui_text_formats[];
diff --git a/src/fe-text/screen.c b/src/fe-text/screen.c
index 19c79f5a..5f197028 100644
--- a/src/fe-text/screen.c
+++ b/src/fe-text/screen.c
@@ -1,8 +1,7 @@
/*
- screen.c : All virtual screen management, real screen management is in
- con_???.c files.
+ screen.c : irssi
- Copyright (C) 1999 Timo Sirainen
+ Copyright (C) 1999-2000 Timo Sirainen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,7 +24,7 @@
#include "screen.h"
#include "gui-readline.h"
-#include "gui-windows.h"
+#include "mainwindows.h"
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
@@ -38,52 +37,50 @@
#define MIN_SCREEN_WIDTH 20
-static gint scrx, scry;
-gboolean use_colors;
-static gint freeze_refresh;
+static int scrx, scry;
+static int use_colors;
+static int freeze_refresh;
#ifdef SIGWINCH
static void sig_winch(int p)
{
#ifdef TIOCGWINSZ
- struct winsize ws;
- gint ychange, xchange;
+ struct winsize ws;
+ int ychange, xchange;
- /* Get new window size */
- if (ioctl(0, TIOCGWINSZ, &ws) < 0)
- return;
+ /* Get new window size */
+ if (ioctl(0, TIOCGWINSZ, &ws) < 0)
+ return;
- if (ws.ws_row == LINES && ws.ws_col == COLS)
- {
- /* Same size, abort. */
- return;
- }
+ if (ws.ws_row == LINES && ws.ws_col == COLS) {
+ /* Same size, abort. */
+ return;
+ }
- if (ws.ws_col < MIN_SCREEN_WIDTH)
- ws.ws_col = MIN_SCREEN_WIDTH;
+ if (ws.ws_col < MIN_SCREEN_WIDTH)
+ ws.ws_col = MIN_SCREEN_WIDTH;
- /* Resize curses terminal */
- ychange = ws.ws_row-LINES;
- xchange = ws.ws_col-COLS;
+ /* Resize curses terminal */
+ ychange = ws.ws_row-LINES;
+ xchange = ws.ws_col-COLS;
#ifdef HAVE_CURSES_RESIZETERM
- resizeterm(ws.ws_row, ws.ws_col);
+ resizeterm(ws.ws_row, ws.ws_col);
#else
- deinit_screen();
- init_screen();
+ deinit_screen();
+ init_screen();
#endif
- last_text_line += ychange;
- gui_windows_resize(ychange, xchange != 0);
+ mainwindows_resize(ychange, xchange != 0);
#endif
}
#endif
-/* SIGINT != ^C .. any better way to make this work? */
+/* FIXME: SIGINT != ^C .. any better way to make this work? */
void sigint_handler(int p)
{
- ungetch(3);
- readline();
+ ungetch(3);
+ readline();
}
static void read_settings(void)
@@ -93,162 +90,141 @@ static void read_settings(void)
}
/* Initialize screen, detect screen length */
-gint init_screen(void)
+int init_screen(void)
{
- gchar ansi_tab[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
- gint num;
+ char ansi_tab[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+ int num;
- if (!initscr()) return 0;
+ if (!initscr()) return 0;
- if (COLS < MIN_SCREEN_WIDTH)
- COLS = MIN_SCREEN_WIDTH;
+ if (COLS < MIN_SCREEN_WIDTH)
+ COLS = MIN_SCREEN_WIDTH;
- signal(SIGINT, sigint_handler);
- cbreak(); noecho(); idlok(stdscr, 1);
+ signal(SIGINT, sigint_handler);
+ cbreak(); noecho(); idlok(stdscr, 1);
#ifdef HAVE_CURSES_IDCOK
- idcok(stdscr, 1);
+ idcok(stdscr, 1);
#endif
- intrflush(stdscr, FALSE); halfdelay(1); keypad(stdscr, 1);
+ intrflush(stdscr, FALSE); halfdelay(1); keypad(stdscr, 1);
- settings_add_bool("lookandfeel", "colors", TRUE);
+ settings_add_bool("lookandfeel", "colors", TRUE);
- use_colors = settings_get_bool("colors") && has_colors();
- if (has_colors()) start_color();
+ use_colors = settings_get_bool("colors") && has_colors();
+ if (has_colors()) start_color();
#ifdef HAVE_NCURSES_USE_DEFAULT_COLORS
- /* this lets us to use the "default" background color for colors <= 7 so
- background pixmaps etc. show up right */
- use_default_colors();
+ /* this lets us to use the "default" background color for colors <= 7 so
+ background pixmaps etc. show up right */
+ use_default_colors();
- for (num = 1; num < COLOR_PAIRS; num++)
- init_pair(num, ansi_tab[num & 7], num <= 7 ? -1 : ansi_tab[num >> 3]);
+ for (num = 1; num < COLOR_PAIRS; num++)
+ init_pair(num, ansi_tab[num & 7], num <= 7 ? -1 : ansi_tab[num >> 3]);
- init_pair(63, 0, -1); /* hm.. not THAT good idea, but probably more people
- want dark grey than white on white.. */
+ init_pair(63, 0, -1); /* hm.. not THAT good idea, but probably more
+ people want dark grey than white on white.. */
#else
- for (num = 1; num < COLOR_PAIRS; num++)
- init_pair(num, ansi_tab[num & 7], ansi_tab[num >> 3]);
- init_pair(63, 0, 0);
+ for (num = 1; num < COLOR_PAIRS; num++)
+ init_pair(num, ansi_tab[num & 7], ansi_tab[num >> 3]);
+ init_pair(63, 0, 0);
#endif
- scrx = scry = 0;
- if (last_text_line == 0)
- {
- first_text_line = 0;
- last_text_line = LINES-1;
- }
+ scrx = scry = 0;
#ifdef SIGWINCH
- signal(SIGWINCH, sig_winch);
+ signal(SIGWINCH, sig_winch);
#endif
- freeze_refresh = 0;
- clear();
+ freeze_refresh = 0;
+ clear();
- signal_add("setup changed", (SIGNAL_FUNC) read_settings);
- return 1;
+ signal_add("setup changed", (SIGNAL_FUNC) read_settings);
+ return 1;
}
/* Deinitialize screen */
void deinit_screen(void)
{
- signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
- endwin();
+ signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
+ endwin();
}
-void set_color(gint col)
+void set_color(int col)
{
- gint attr;
-
- if (!use_colors)
- {
- if ((col & 0x70) != 0)
- attr = A_REVERSE;
- else
- attr = 0;
- }
- else
- {
- if (col & ATTR_COLOR8)
- attr = A_DIM | COLOR_PAIR(63);
- else
- attr = COLOR_PAIR((col&7) + (col&0x70)/2);
- }
-
- if (col & 0x08) attr |= A_BOLD;
- if (col & 0x80) attr |= A_BLINK;
-
- if (col & ATTR_UNDERLINE) attr |= A_UNDERLINE;
- if (col & ATTR_REVERSE) attr |= A_REVERSE;
-
- attrset(attr);
+ int attr;
+
+ if (!use_colors)
+ attr = (col & 0x70) ? A_REVERSE : 0;
+ else {
+ attr = (col & ATTR_COLOR8) ?
+ (A_DIM | COLOR_PAIR(63)) :
+ (COLOR_PAIR((col&7) + (col&0x70)/2));
+ }
+
+ if (col & 0x08) attr |= A_BOLD;
+ if (col & 0x80) attr |= A_BLINK;
+
+ if (col & ATTR_UNDERLINE) attr |= A_UNDERLINE;
+ if (col & ATTR_REVERSE) attr |= A_REVERSE;
+
+ attrset(attr);
}
-void set_bg(gint col)
+void set_bg(int col)
{
- gint attr;
-
- if (!use_colors)
- {
- if ((col & 0x70) != 0)
- attr = A_REVERSE;
- else
- attr = 0;
- }
- else
- {
- if (col == 8)
- attr = A_DIM | COLOR_PAIR(63);
- else
- attr = COLOR_PAIR((col&7) + (col&0x70)/2);
- }
-
- if (col & 0x08) attr |= A_BOLD;
- if (col & 0x80) attr |= A_BLINK;
-
- bkgdset(' ' | attr);
+ int attr;
+
+ if (!use_colors)
+ attr = (col & 0x70) ? A_REVERSE : 0;
+ else {
+ attr = (col == 8) ?
+ (A_DIM | COLOR_PAIR(63)) :
+ (COLOR_PAIR((col&7) + (col&0x70)/2));
+ }
+
+ if (col & 0x08) attr |= A_BOLD;
+ if (col & 0x80) attr |= A_BLINK;
+
+ bkgdset(' ' | attr);
}
/* Scroll area up */
-void scroll_up(gint y1, gint y2)
+void scroll_up(int y1, int y2)
{
- scrollok(stdscr, TRUE);
- setscrreg(y1, y2); scrl(1);
- scrollok(stdscr, FALSE);
+ scrollok(stdscr, TRUE);
+ setscrreg(y1, y2); scrl(1);
+ scrollok(stdscr, FALSE);
}
/* Scroll area down */
-void scroll_down(gint y1, gint y2)
+void scroll_down(int y1, int y2)
{
- scrollok(stdscr, TRUE);
- setscrreg(y1, y2); scrl(-1);
- scrollok(stdscr, FALSE);
+ scrollok(stdscr, TRUE);
+ setscrreg(y1, y2); scrl(-1);
+ scrollok(stdscr, FALSE);
}
-void move_cursor(gint y, gint x)
+void move_cursor(int y, int x)
{
- scry = y;
- scrx = x;
+ scry = y;
+ scrx = x;
}
void screen_refresh_freeze(void)
{
- freeze_refresh++;
+ freeze_refresh++;
}
void screen_refresh_thaw(void)
{
- if (freeze_refresh > 0)
- {
- freeze_refresh--;
- if (freeze_refresh == 0) screen_refresh();
- }
+ if (freeze_refresh > 0) {
+ freeze_refresh--;
+ if (freeze_refresh == 0) screen_refresh();
+ }
}
void screen_refresh(void)
{
- if (freeze_refresh == 0)
- {
- move(scry, scrx);
- refresh();
- }
+ if (freeze_refresh == 0) {
+ move(scry, scrx);
+ refresh();
+ }
}
diff --git a/src/fe-text/gui-statusbar-items.c b/src/fe-text/statusbar-items.c
index 1cb3740e..8b55f263 100644
--- a/src/fe-text/gui-statusbar-items.c
+++ b/src/fe-text/statusbar-items.c
@@ -31,10 +31,11 @@
#include "nicklist.h"
#include "windows.h"
+#include "window-items.h"
#include "screen.h"
-#include "gui-statusbar.h"
-#include "gui-mainwindows.h"
+#include "printtext.h"
+#include "statusbar.h"
#include "gui-windows.h"
/* how often to redraw lagging time */
@@ -43,72 +44,78 @@
the lag */
#define MAX_LAG_UNKNOWN_TIME 30
+static STATUSBAR_REC *mainbar;
+static MAIN_WINDOW_REC *mainbar_window;
+static int use_colors;
+
/* clock */
-static int clock_tag, clock_timetag;
+static SBAR_ITEM_REC *clock_item;
+static int clock_timetag;
static time_t clock_last;
/* nick */
-static int nick_tag;
+static SBAR_ITEM_REC *nick_item;
/* channel */
-static int channel_tag;
+static SBAR_ITEM_REC *channel_item;
/* activity */
-static int activity_tag;
+static SBAR_ITEM_REC *activity_item;
static GList *activity_list;
/* more */
-static int more_tag;
+static SBAR_ITEM_REC *more_item;
/* lag */
-static int lag_tag, lag_timetag, lag_min_show;
+static SBAR_ITEM_REC *lag_item;
+static int lag_timetag, lag_min_show;
static time_t lag_last_draw;
/* topic */
-static int topic_tag;
+static SBAR_ITEM_REC *topic_item;
+static STATUSBAR_REC *topic_bar;
/* redraw clock */
-static void statusbar_clock(int xpos, int ypos, int size)
+static void statusbar_clock(SBAR_ITEM_REC *item, int ypos)
{
- struct tm *tm;
- gchar str[5];
+ struct tm *tm;
+ char str[6];
- clock_last = time(NULL);
- tm = localtime(&clock_last);
+ clock_last = time(NULL);
+ tm = localtime(&clock_last);
- sprintf(str, "%02d:%02d", tm->tm_hour, tm->tm_min);
+ g_snprintf(str, sizeof(str), "%02d:%02d", tm->tm_hour, tm->tm_min);
- move(ypos, xpos);
- set_color((1 << 4)+3); addch('[');
- set_color((1 << 4)+15); addstr(str);
- set_color((1 << 4)+3); addch(']');
+ move(ypos, item->xpos);
+ set_color((1 << 4)+3); addch('[');
+ set_color((1 << 4)+15); addstr(str);
+ set_color((1 << 4)+3); addch(']');
- screen_refresh();
+ screen_refresh();
}
/* check if we need to redraw clock.. */
static int statusbar_clock_timeout(void)
{
- struct tm *tm;
- time_t t;
- int min;
+ struct tm *tm;
+ time_t t;
+ int min;
- tm = localtime(&clock_last);
- min = tm->tm_min;
+ tm = localtime(&clock_last);
+ min = tm->tm_min;
- t = time(NULL);
- tm = localtime(&t);
+ t = time(NULL);
+ tm = localtime(&t);
- if (tm->tm_min != min)
- {
- /* minute changed, redraw! */
- gui_statusbar_redraw(clock_tag);
- }
- return 1;
+ if (tm->tm_min != min) {
+ /* minute changed, redraw! */
+ statusbar_item_redraw(clock_item);
+ }
+ return 1;
}
/* redraw nick */
-static void statusbar_nick(int xpos, int ypos, int size)
+static void statusbar_nick(SBAR_ITEM_REC *item, int ypos)
{
CHANNEL_REC *channel;
IRC_SERVER_REC *server;
@@ -140,15 +147,15 @@ static void statusbar_nick(int xpos, int ypos, int size)
(server != NULL && server->usermode_away ? 7 : 0) +
(nickrec != NULL && (nickrec->op || nickrec->voice) ? 1 : 0); /* @ + */
- if (size != size_needed)
+ if (item->size != size_needed)
{
/* we need more (or less..) space! */
- gui_statusbar_resize(nick_tag, size_needed);
+ statusbar_item_resize(item, size_needed);
return;
}
/* size ok, draw the nick */
- move(ypos, xpos);
+ move(ypos, item->xpos);
set_color((1 << 4)+3); addch('[');
if (nickrec != NULL && (nickrec->op || nickrec->voice))
@@ -175,41 +182,57 @@ static void statusbar_nick(int xpos, int ypos, int size)
static void sig_statusbar_nick_redraw(void)
{
- gui_statusbar_redraw(nick_tag);
+ statusbar_item_redraw(nick_item);
+}
+
+static WINDOW_REC *mainwindow_find_sbar(SBAR_ITEM_REC *item)
+{
+ GSList *tmp;
+
+ for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+
+ if (rec->statusbar_channel_item == item)
+ return rec->active;
+ }
+
+ return active_win;
}
/* redraw channel */
-static void statusbar_channel(int xpos, int ypos, int size)
+static void statusbar_channel(SBAR_ITEM_REC *item, int ypos)
{
- WI_ITEM_REC *item;
+ WINDOW_REC *window;
+ WI_ITEM_REC *witem;
CHANNEL_REC *channel;
SERVER_REC *server;
- gchar channame[21], window[MAX_INT_STRLEN], *mode;
+ gchar channame[21], winnum[MAX_INT_STRLEN], *mode;
int size_needed;
int mode_size;
- server = active_win == NULL ? NULL : active_win->active_server;
+ window = item->bar->pos != STATUSBAR_POS_MIDDLE ? active_win :
+ mainwindow_find_sbar(item);
+ server = window == NULL ? NULL : window->active_server;
- ltoa(window, active_win == NULL ? 0 :
- g_slist_index(windows, active_win)+1);
+ ltoa(winnum, window == NULL ? 0 : window->refnum);
- item = active_win != NULL && irc_item_check(active_win->active) ?
- active_win->active : NULL;
- if (item == NULL)
+ witem = window != NULL && irc_item_check(window->active) ?
+ window->active : NULL;
+ if (witem == NULL)
{
/* display server tag */
channame[0] = '\0';
mode = NULL;
mode_size = 0;
- size_needed = 3 + strlen(window) + (server == NULL ? 0 : strlen(server->tag));
+ size_needed = 3 + strlen(winnum) + (server == NULL ? 0 : strlen(server->tag));
}
else
{
/* display channel + mode */
- strncpy(channame, item->name, 20); channame[20] = '\0';
+ strncpy(channame, witem->name, 20); channame[20] = '\0';
- channel = irc_item_channel(item);
+ channel = irc_item_channel(witem);
if (channel == NULL) {
mode_size = 0;
mode = NULL;
@@ -219,22 +242,22 @@ static void statusbar_channel(int xpos, int ypos, int size)
if (mode_size > 0) mode_size += 3; /* (+) */
}
- size_needed = 3 + strlen(window) + strlen(channame) + mode_size;
+ size_needed = 3 + strlen(winnum) + strlen(channame) + mode_size;
}
- if (size != size_needed)
+ if (item->size != size_needed)
{
/* we need more (or less..) space! */
- gui_statusbar_resize(channel_tag, size_needed);
+ statusbar_item_resize(item, size_needed);
if (mode != NULL) g_free(mode);
return;
}
- move(ypos, xpos);
+ move(ypos, item->xpos);
set_color((1 << 4)+3); addch('[');
/* window number */
- set_color((1 << 4)+7); addstr(window);
+ set_color((1 << 4)+7); addstr(winnum);
set_color((1 << 4)+3); addch(':');
if (channame[0] == '\0' && server != NULL)
@@ -262,14 +285,29 @@ static void statusbar_channel(int xpos, int ypos, int size)
static void sig_statusbar_channel_redraw(void)
{
- gui_statusbar_redraw(channel_tag);
+ statusbar_item_redraw(channel_item);
+}
+
+static void sig_statusbar_channel_redraw_window(WINDOW_REC *window)
+{
+ if (is_window_visible(window))
+ statusbar_item_redraw(channel_item);
+}
+
+static void sig_statusbar_channel_redraw_window_item(WI_ITEM_REC *item)
+{
+ WINDOW_REC *window;
+
+ window = window_item_window(item);
+ if (window->active == item && is_window_visible(window))
+ statusbar_item_redraw(channel_item);
}
static void draw_activity(gchar *title, gboolean act, gboolean det)
{
WINDOW_REC *window;
GList *tmp;
- gchar str[(sizeof(int) * CHAR_BIT + 2) / 3 + 1];
+ gchar str[MAX_INT_STRLEN];
gboolean first, is_det;
set_color((1 << 4)+7); addstr(title);
@@ -291,7 +329,7 @@ static void draw_activity(gchar *title, gboolean act, gboolean det)
addch(',');
}
- sprintf(str, "%d", g_slist_index(windows, window)+1);
+ ltoa(str, window->refnum);
switch (window->new_data)
{
case NEWDATA_TEXT:
@@ -309,7 +347,7 @@ static void draw_activity(gchar *title, gboolean act, gboolean det)
}
/* redraw activity */
-static void statusbar_activity(int xpos, int ypos, int size)
+static void statusbar_activity(SBAR_ITEM_REC *item, int ypos)
{
WINDOW_REC *window;
GList *tmp;
@@ -322,7 +360,7 @@ static void statusbar_activity(int xpos, int ypos, int size)
{
window = tmp->data;
- size_needed += 1+g_snprintf(str, sizeof(str), "%d", g_slist_index(windows, window)+1);
+ size_needed += 1+ltoa(str, window->refnum);
if (!use_colors && window->new_data == NEWDATA_MSG_FORYOU)
det = TRUE;
@@ -334,17 +372,17 @@ static void statusbar_activity(int xpos, int ypos, int size)
if (det) size_needed += 6; /* [Det: ], -1 */
if (act && det) size_needed--;
- if (size != size_needed)
+ if (item->size != size_needed)
{
/* we need more (or less..) space! */
- gui_statusbar_resize(activity_tag, size_needed);
+ statusbar_item_resize(item, size_needed);
return;
}
- if (size == 0)
+ if (item->size == 0)
return;
- move(ypos, xpos);
+ move(ypos, item->xpos);
set_color((1 << 4)+3); addch('[');
if (act) draw_activity("Act: ", TRUE, !det);
if (act && det) addch(' ');
@@ -356,19 +394,19 @@ static void statusbar_activity(int xpos, int ypos, int size)
static void sig_statusbar_activity_hilight(WINDOW_REC *window, gpointer oldlevel)
{
- int pos, inspos;
GList *tmp;
+ int inspos;
g_return_if_fail(window != NULL);
- if (settings_get_bool("toggle_actlist_moves"))
+ if (settings_get_bool("actlist_moves"))
{
/* Move the window to the first in the activity list */
if (g_list_find(activity_list, window) != NULL)
activity_list = g_list_remove(activity_list, window);
if (window->new_data != 0)
activity_list = g_list_prepend(activity_list, window);
- gui_statusbar_redraw(activity_tag);
+ statusbar_item_redraw(activity_item);
return;
}
@@ -379,12 +417,12 @@ static void sig_statusbar_activity_hilight(WINDOW_REC *window, gpointer oldlevel
{
/* remove from activity list */
activity_list = g_list_remove(activity_list, window);
- gui_statusbar_redraw(activity_tag);
+ statusbar_item_redraw(activity_item);
}
else if (window->new_data != GPOINTER_TO_INT(oldlevel))
{
/* different level as last time, just redraw it. */
- gui_statusbar_redraw(activity_tag);
+ statusbar_item_redraw(activity_item);
}
return;
}
@@ -393,12 +431,12 @@ static void sig_statusbar_activity_hilight(WINDOW_REC *window, gpointer oldlevel
return;
/* add window to activity list .. */
- pos = g_slist_index(windows, window);
-
inspos = 0;
for (tmp = activity_list; tmp != NULL; tmp = tmp->next, inspos++)
{
- if (pos < g_slist_index(windows, tmp->data))
+ WINDOW_REC *rec = tmp->data;
+
+ if (window->refnum < rec->refnum)
{
activity_list = g_list_insert(activity_list, window, inspos);
break;
@@ -407,7 +445,7 @@ static void sig_statusbar_activity_hilight(WINDOW_REC *window, gpointer oldlevel
if (tmp == NULL)
activity_list = g_list_append(activity_list, window);
- gui_statusbar_redraw(activity_tag);
+ statusbar_item_redraw(activity_item);
}
static void sig_statusbar_activity_window_destroyed(WINDOW_REC *window)
@@ -417,54 +455,50 @@ static void sig_statusbar_activity_window_destroyed(WINDOW_REC *window)
if (g_list_find(activity_list, window) != NULL)
{
activity_list = g_list_remove(activity_list, window);
- gui_statusbar_redraw(activity_tag);
+ statusbar_item_redraw(activity_item);
}
}
/* redraw -- more -- */
-static void statusbar_more(int xpos, int ypos, int size)
+static void statusbar_more(SBAR_ITEM_REC *item, int ypos)
{
- if (size != 10) return;
+ if (item->size != 10) return;
- move(ypos, xpos);
+ move(ypos, item->xpos);
set_color((1 << 4)+15); addstr("-- more --");
screen_refresh();
}
static void sig_statusbar_more_check_remove(WINDOW_REC *window)
{
- g_return_if_fail(window != NULL);
+ g_return_if_fail(window != NULL);
- if (!is_window_visible(window))
- return;
+ if (!is_window_visible(window))
+ return;
- if (more_tag != -1 && WINDOW_GUI(window)->bottom)
- {
- gui_statusbar_remove(more_tag);
- more_tag = -1;
- }
+ if (more_item != NULL && WINDOW_GUI(window)->bottom) {
+ statusbar_item_remove(more_item);
+ more_item = NULL;
+ }
}
static void sig_statusbar_more_check(WINDOW_REC *window)
{
- g_return_if_fail(window != NULL);
+ g_return_if_fail(window != NULL);
- if (WINDOW_GUI(window)->parent->active != window)
- return;
+ if (!is_window_visible(window))
+ return;
- if (!WINDOW_GUI(window)->bottom)
- {
- if (more_tag == -1)
- more_tag = gui_statusbar_allocate(10, FALSE, FALSE, 0, statusbar_more);
- }
- else if (more_tag != -1)
- {
- gui_statusbar_remove(more_tag);
- more_tag = -1;
- }
+ if (!WINDOW_GUI(window)->bottom) {
+ if (more_item == NULL)
+ more_item = statusbar_item_create(mainbar, 10, FALSE, statusbar_more);
+ } else if (more_item != NULL) {
+ statusbar_item_remove(more_item);
+ more_item = NULL;
+ }
}
-static void statusbar_lag(int xpos, int ypos, int size)
+static void statusbar_lag(SBAR_ITEM_REC *item, int ypos)
{
IRC_SERVER_REC *server;
GString *str;
@@ -494,18 +528,18 @@ static void statusbar_lag(int xpos, int ypos, int size)
size_needed = str->len+7;
}
- if (size != size_needed)
+ if (item->size != size_needed)
{
/* we need more (or less..) space! */
- gui_statusbar_resize(lag_tag, size_needed);
+ statusbar_item_resize(item, size_needed);
g_string_free(str, TRUE);
return;
}
- if (size != 0)
+ if (item->size != 0)
{
lag_last_draw = now;
- move(ypos, xpos);
+ move(ypos, item->xpos);
set_color((1 << 4)+3); addch('[');
set_color((1 << 4)+7); addstr("Lag: ");
@@ -519,7 +553,7 @@ static void statusbar_lag(int xpos, int ypos, int size)
static void sig_statusbar_lag_redraw(void)
{
- gui_statusbar_redraw(lag_tag);
+ statusbar_item_redraw(lag_item);
}
static int statusbar_lag_timeout(void)
@@ -528,23 +562,23 @@ static int statusbar_lag_timeout(void)
if (time(NULL)-lag_last_draw < LAG_REFRESH_TIME)
return 1;
- gui_statusbar_redraw(lag_tag);
+ statusbar_item_redraw(lag_item);
return 1;
}
-static void statusbar_topic(int xpos, int ypos, int size)
+static void statusbar_topic(SBAR_ITEM_REC *item, int ypos)
{
CHANNEL_REC *channel;
QUERY_REC *query;
char *str, *topic;
- if (size != COLS-2) {
+ if (item->size != COLS-2) {
/* get all space for topic */
- gui_statusbar_resize(topic_tag, COLS-2);
+ statusbar_item_resize(item, COLS-2);
return;
}
- move(ypos, xpos);
+ move(ypos, item->xpos);
set_bg((1<<4)+7); clrtoeol(); set_bg(0);
if (active_win == NULL)
@@ -557,51 +591,156 @@ static void statusbar_topic(int xpos, int ypos, int size)
if (query != NULL && query->address != NULL) topic = query->address;
if (topic == NULL) return;
- str = g_strdup_printf("%.*s", size, topic);
+ topic = strip_codes(topic);
+ str = g_strdup_printf("%.*s", item->size, topic);
set_color((1<<4)+15); addstr(str);
g_free(str);
+ g_free(topic);
screen_refresh();
}
static void sig_statusbar_topic_redraw(void)
{
- gui_statusbar_redraw(topic_tag);
+ if (topic_item != NULL) statusbar_item_redraw(topic_item);
}
-static void read_settings(void)
+static void sig_sidebars_redraw(void)
{
- int ypos;
-
- if (topic_tag == -1 && settings_get_bool("toggle_show_topicbar")) {
- ypos = gui_statusbar_create(TRUE);
- topic_tag = gui_statusbar_allocate(0, FALSE, TRUE, ypos, statusbar_topic);
- signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
- signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
- signal_add("channel topic changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
- signal_add("query address changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
- } else if (topic_tag != -1 && !settings_get_bool("toggle_show_topicbar")) {
- gui_statusbar_delete(TRUE, 0);
- topic_tag = -1;
- signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
- signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
- signal_remove("channel topic changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
- signal_remove("query address changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
+ GSList *tmp;
+
+ for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+
+ if (rec->statusbar_channel_item != NULL)
+ statusbar_item_redraw(rec->statusbar_channel_item);
}
+}
+
+static void topicbar_create(void)
+{
+ if (topic_bar != NULL)
+ return;
+
+ topic_bar = statusbar_create(STATUSBAR_POS_UP, 0);
+ topic_item = statusbar_item_create(topic_bar, 0, FALSE, statusbar_topic);
+ statusbar_redraw(topic_bar);
+
+ signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
+ signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
+ signal_add("channel topic changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
+ signal_add("query address changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
+}
+
+static void topicbar_destroy(void)
+{
+ if (topic_bar == NULL)
+ return;
+
+ statusbar_destroy(topic_bar);
+ topic_item = NULL;
+ topic_bar = NULL;
+
+ signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
+ signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
+ signal_remove("channel topic changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
+ signal_remove("query address changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
+}
+
+static void mainbar_remove_items(void)
+{
+ statusbar_item_remove(clock_item);
+ statusbar_item_remove(nick_item);
+ statusbar_item_remove(channel_item);
+ statusbar_item_remove(activity_item);
+ statusbar_item_remove(lag_item);
+}
+
+static void mainbar_add_items(MAIN_WINDOW_REC *window)
+{
+ mainbar = window->statusbar;
+ mainbar_window = window;
+
+ clock_item = statusbar_item_create(mainbar, 7, FALSE, statusbar_clock);
+ nick_item = statusbar_item_create(mainbar, 2, FALSE, statusbar_nick);
+ channel_item = statusbar_item_create(mainbar, 2, FALSE, statusbar_channel);
+ activity_item = statusbar_item_create(mainbar, 0, FALSE, statusbar_activity);
+ lag_item = statusbar_item_create(mainbar, 0, FALSE, statusbar_lag);
+}
+
+static void sidebar_add_items(MAIN_WINDOW_REC *window)
+{
+ window->statusbar_channel_item =
+ statusbar_item_create(window->statusbar, 3, FALSE, statusbar_channel);
+}
+
+static void sidebar_remove_items(MAIN_WINDOW_REC *window)
+{
+ if (window->statusbar_channel_item != NULL) {
+ statusbar_item_remove(window->statusbar_channel_item);
+ window->statusbar_channel_item = NULL;
+ }
+}
+
+static void sig_mainwindow_created(MAIN_WINDOW_REC *window)
+{
+ window->statusbar = statusbar_create(STATUSBAR_POS_MIDDLE, window->last_line+1);
+ sidebar_add_items(window);
+}
+
+static void sig_mainwindow_destroyed(MAIN_WINDOW_REC *window)
+{
+ if (window == mainbar_window) {
+ mainbar = NULL;
+ mainbar_window = NULL;
+ }
+
+ if (window->statusbar != NULL)
+ statusbar_destroy(window->statusbar);
+}
+
+static void sig_main_statusbar_changed(WINDOW_REC *window)
+{
+ MAIN_WINDOW_REC *parent;
+
+ if (window == NULL)
+ return;
+
+ parent = WINDOW_GUI(window)->parent;
+ if (mainbar == parent->statusbar)
+ return;
+
+ if (mainbar != NULL) {
+ mainbar_remove_items();
+ sidebar_add_items(mainbar_window);
+ }
+ sidebar_remove_items(parent);
+ mainbar_add_items(parent);
+}
+
+static void read_settings(void)
+{
+ use_colors = settings_get_bool("colors");
+ if (settings_get_bool("topicbar"))
+ topicbar_create();
+ else if (!settings_get_bool("topicbar"))
+ topicbar_destroy();
lag_min_show = settings_get_int("lag_min_show")*10;
}
-void gui_statusbar_items_init(void)
+void statusbar_items_init(void)
{
+ GSList *tmp;
+
settings_add_int("misc", "lag_min_show", 100);
+ settings_add_bool("lookandfeel", "topicbar", TRUE);
+ settings_add_bool("lookandfeel", "actlist_moves", FALSE);
/* clock */
- clock_tag = gui_statusbar_allocate(7, FALSE, FALSE, 0, statusbar_clock);
clock_timetag = g_timeout_add(1000, (GSourceFunc) statusbar_clock_timeout, NULL);
/* nick */
- nick_tag = gui_statusbar_allocate(2, FALSE, FALSE, 0, statusbar_nick);
signal_add("server connected", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
signal_add("channel wholist", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
@@ -613,45 +752,53 @@ void gui_statusbar_items_init(void)
signal_add("away mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
/* channel */
- channel_tag = gui_statusbar_allocate(2, FALSE, FALSE, 0, statusbar_channel);
signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
- signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
- signal_add("channel mode changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
- signal_add("window server changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
+ signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window);
+ signal_add("channel mode changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window_item);
+ signal_add("window server changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window);
+ signal_add("window refnum changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window);
/* activity */
activity_list = NULL;
- activity_tag = gui_statusbar_allocate(0, FALSE, FALSE, 0, statusbar_activity);
signal_add("window activity", (SIGNAL_FUNC) sig_statusbar_activity_hilight);
signal_add("window destroyed", (SIGNAL_FUNC) sig_statusbar_activity_window_destroyed);
/* more */
- more_tag = -1;
+ more_item = NULL;
signal_add("gui page scrolled", (SIGNAL_FUNC) sig_statusbar_more_check_remove);
signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_more_check);
signal_add("gui print text", (SIGNAL_FUNC) sig_statusbar_more_check);
/* lag */
- lag_tag = gui_statusbar_allocate(0, FALSE, FALSE, 0, statusbar_lag);
lag_timetag = g_timeout_add(1000*LAG_REFRESH_TIME, (GSourceFunc) statusbar_lag_timeout, NULL);
signal_add("server lag", (SIGNAL_FUNC) sig_statusbar_lag_redraw);
signal_add("window server changed", (SIGNAL_FUNC) sig_statusbar_lag_redraw);
- /* topic bar */
- topic_tag = -1;
+ /* topic */
+ topic_item = NULL; topic_bar = NULL;
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
read_settings();
+ statusbar_redraw(NULL);
+
+ /* middle bars */
+ signal_add("mainwindow created", (SIGNAL_FUNC) sig_mainwindow_created);
+ signal_add("mainwindow destroyed", (SIGNAL_FUNC) sig_mainwindow_destroyed);
+ signal_add("window changed", (SIGNAL_FUNC) sig_main_statusbar_changed);
+ signal_add("window refnum changed", (SIGNAL_FUNC) sig_sidebars_redraw);
+
+ /* add statusbars to existing windows */
+ for (tmp = mainwindows; tmp != NULL; tmp = tmp->next)
+ sig_mainwindow_created(tmp->data);
+ sig_main_statusbar_changed(active_win);
}
-void gui_statusbar_items_deinit(void)
+void statusbar_items_deinit(void)
{
/* clock */
- gui_statusbar_remove(clock_tag);
+ g_source_remove(clock_timetag);
/* nick */
- gui_statusbar_remove(nick_tag);
- g_source_remove(clock_timetag);
signal_remove("server connected", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
signal_remove("channel wholist", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
@@ -663,31 +810,34 @@ void gui_statusbar_items_deinit(void)
signal_remove("away mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
/* channel */
- gui_statusbar_remove(channel_tag);
signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
- signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
- signal_remove("channel mode changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
- signal_remove("window server changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
+ signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window);
+ signal_remove("channel mode changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window_item);
+ signal_remove("window server changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window);
+ signal_remove("window refnum changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window);
/* activity */
- gui_statusbar_remove(activity_tag);
signal_remove("window activity", (SIGNAL_FUNC) sig_statusbar_activity_hilight);
signal_remove("window destroyed", (SIGNAL_FUNC) sig_statusbar_activity_window_destroyed);
g_list_free(activity_list);
/* more */
- if (more_tag != -1) gui_statusbar_remove(more_tag);
signal_remove("gui page scrolled", (SIGNAL_FUNC) sig_statusbar_more_check_remove);
signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_more_check);
signal_remove("gui print text", (SIGNAL_FUNC) sig_statusbar_more_check);
/* lag */
- gui_statusbar_remove(lag_tag);
g_source_remove(lag_timetag);
signal_remove("server lag", (SIGNAL_FUNC) sig_statusbar_lag_redraw);
signal_remove("window server changed", (SIGNAL_FUNC) sig_statusbar_lag_redraw);
/* topic */
- if (topic_tag != -1) gui_statusbar_delete(TRUE, 0);
+ topicbar_destroy();
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
+
+ /* middle bars */
+ signal_remove("mainwindow created", (SIGNAL_FUNC) sig_mainwindow_created);
+ signal_remove("mainwindow destroyed", (SIGNAL_FUNC) sig_mainwindow_destroyed);
+ signal_remove("window changed", (SIGNAL_FUNC) sig_main_statusbar_changed);
+ signal_remove("window refnum changed", (SIGNAL_FUNC) sig_sidebars_redraw);
}
diff --git a/src/fe-text/statusbar.c b/src/fe-text/statusbar.c
new file mode 100644
index 00000000..24e89107
--- /dev/null
+++ b/src/fe-text/statusbar.c
@@ -0,0 +1,266 @@
+/*
+ gui-statusbar.c : irssi
+
+ Copyright (C) 1999 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "signals.h"
+#include "server.h"
+
+#include "windows.h"
+
+#include "screen.h"
+#include "statusbar.h"
+#include "gui-windows.h"
+
+void statusbar_items_init(void);
+void statusbar_items_deinit(void);
+
+static GSList *statusbars;
+static int sbar_uppest, sbar_lowest, sbars_up, sbars_down;
+
+static void statusbar_item_destroy(SBAR_ITEM_REC *rec)
+{
+ rec->bar->items = g_slist_remove(rec->bar->items, rec);
+ g_free(rec);
+}
+
+static void statusbar_redraw_line(STATUSBAR_REC *bar)
+{
+ static int recurses = 0, resized = FALSE;
+ STATUSBAR_FUNC func;
+ GSList *tmp;
+ int xpos, rxpos, old_resized;
+
+ old_resized = resized;
+ resized = FALSE;
+ recurses++;
+
+ xpos = 1;
+ for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
+ SBAR_ITEM_REC *rec = tmp->data;
+
+ if (!rec->right_justify && xpos+rec->size < COLS) {
+ rec->xpos = xpos;
+
+ func = rec->func;
+ func(rec, bar->ypos);
+
+ if (resized) break;
+ if (rec->size > 0) xpos += rec->size+1;
+ }
+ }
+
+ rxpos = COLS-1;
+ for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
+ SBAR_ITEM_REC *rec = tmp->data;
+
+ if (rec->right_justify && rxpos-rec->size > xpos) {
+ rec->xpos = rxpos-rec->size;
+
+ func = rec->func;
+ func(rec, bar->ypos);
+
+ if (resized) break;
+ if (rec->size > 0) rxpos -= rec->size+1;
+ }
+ }
+
+ resized = old_resized;
+ if (--recurses > 0) resized = TRUE;
+}
+
+static void statusbar_redraw_all(void)
+{
+ GSList *tmp;
+
+ screen_refresh_freeze();
+
+ for (tmp = statusbars; tmp != NULL; tmp = tmp->next)
+ statusbar_redraw(tmp->data);
+
+ screen_refresh_thaw();
+}
+
+STATUSBAR_REC *statusbar_find(int pos, int line)
+{
+ GSList *tmp;
+
+ for (tmp = statusbars; tmp != NULL; tmp = tmp->next) {
+ STATUSBAR_REC *rec = tmp->data;
+
+ if (rec->pos == pos && rec->line == line)
+ return rec;
+ }
+
+ return NULL;
+}
+
+void statusbar_redraw(STATUSBAR_REC *bar)
+{
+ if (bar == NULL) {
+ statusbar_redraw_all();
+ return;
+ }
+
+ set_bg((1<<4)+15);
+ move(bar->ypos, 0); clrtoeol();
+ set_bg(0);
+
+ statusbar_redraw_line(bar);
+}
+
+void statusbar_item_redraw(SBAR_ITEM_REC *item)
+{
+ STATUSBAR_FUNC func;
+
+ g_return_if_fail(item != NULL);
+
+ func = item->func;
+ func(item, item->bar->ypos);
+}
+
+/* ypos is used only when pos == STATUSBAR_POS_MIDDLE */
+STATUSBAR_REC *statusbar_create(int pos, int ypos)
+{
+ STATUSBAR_REC *rec;
+
+ rec = g_new0(STATUSBAR_REC, 1);
+ statusbars = g_slist_append(statusbars, rec);
+
+ rec->pos = pos;
+ rec->line = pos == STATUSBAR_POS_MIDDLE ? ypos :
+ mainwindows_reserve_lines(1, pos == STATUSBAR_POS_UP);
+ rec->ypos = pos == STATUSBAR_POS_MIDDLE ? ypos :
+ pos == STATUSBAR_POS_UP ? rec->line : LINES-1-rec->line;
+
+ if (pos == STATUSBAR_POS_UP) {
+ if (sbars_up == 0) sbar_uppest = rec->line;
+ sbars_up++;
+ rec->line -= sbar_uppest;
+ } else if (pos == STATUSBAR_POS_DOWN) {
+ if (sbars_down == 0) sbar_lowest = rec->line;
+ sbars_down++;
+ rec->line -= sbar_lowest;
+ }
+
+ set_bg((1<<4)+15);
+ move(rec->ypos, 0); clrtoeol();
+ set_bg(0);
+
+ return rec;
+}
+
+static void statusbars_pack(int pos, int line)
+{
+ GSList *tmp;
+
+ for (tmp = statusbars; tmp != NULL; tmp = tmp->next) {
+ STATUSBAR_REC *rec = tmp->data;
+
+ if (rec->pos == pos && rec->line > line) {
+ rec->line--;
+ rec->ypos += pos == STATUSBAR_POS_UP ? -1 : 1;
+ }
+ }
+}
+
+void statusbar_destroy(STATUSBAR_REC *bar)
+{
+ g_return_if_fail(bar != NULL);
+
+ if (bar->pos != STATUSBAR_POS_MIDDLE)
+ mainwindows_reserve_lines(-1, bar->pos == STATUSBAR_POS_UP);
+
+ if (bar->pos == STATUSBAR_POS_UP) sbars_up--;
+ if (bar->pos == STATUSBAR_POS_DOWN) sbars_down--;
+ statusbars = g_slist_remove(statusbars, bar);
+
+ while (bar->items != NULL)
+ statusbar_item_destroy(bar->items->data);
+
+ if (bar->pos != STATUSBAR_POS_MIDDLE)
+ statusbars_pack(bar->pos, bar->pos);
+ g_free(bar);
+
+ if (!quitting) statusbar_redraw_all();
+}
+
+SBAR_ITEM_REC *statusbar_item_create(STATUSBAR_REC *bar, int size, int right_justify, STATUSBAR_FUNC func)
+{
+ SBAR_ITEM_REC *rec;
+
+ g_return_val_if_fail(bar != NULL, NULL);
+ g_return_val_if_fail(func != NULL, NULL);
+
+ rec = g_new0(SBAR_ITEM_REC, 1);
+ rec->bar = bar;
+ bar->items = g_slist_append(bar->items, rec);
+
+ rec->xpos = -1;
+ rec->size = size;
+ rec->right_justify = right_justify;
+ rec->func = func;
+
+ return rec;
+}
+
+void statusbar_item_resize(SBAR_ITEM_REC *item, int size)
+{
+ g_return_if_fail(item != NULL);
+
+ item->size = size;
+ statusbar_redraw_all();
+}
+
+void statusbar_item_remove(SBAR_ITEM_REC *item)
+{
+ g_return_if_fail(item != NULL);
+
+ statusbar_item_destroy(item);
+ if (!quitting) statusbar_redraw_all();
+}
+
+static void sig_mainwindow_resized(MAIN_WINDOW_REC *window)
+{
+ STATUSBAR_REC *rec;
+
+ rec = window->statusbar;
+ rec->ypos = window->last_line+1;
+}
+
+void statusbar_init(void)
+{
+ statusbars = NULL;
+ sbars_up = sbars_down = 0;
+
+ statusbar_items_init();
+ signal_add("mainwindow resized", (SIGNAL_FUNC) sig_mainwindow_resized);
+ signal_add("mainwindow moved", (SIGNAL_FUNC) sig_mainwindow_resized);
+}
+
+void statusbar_deinit(void)
+{
+ statusbar_items_deinit();
+
+ while (statusbars != NULL)
+ statusbar_destroy(statusbars->data);
+
+ signal_remove("mainwindow resized", (SIGNAL_FUNC) sig_mainwindow_resized);
+ signal_remove("mainwindow moved", (SIGNAL_FUNC) sig_mainwindow_resized);
+}
diff --git a/src/fe-text/statusbar.h b/src/fe-text/statusbar.h
new file mode 100644
index 00000000..3ca133ef
--- /dev/null
+++ b/src/fe-text/statusbar.h
@@ -0,0 +1,45 @@
+#ifndef __STATUSBAR_H
+#define __STATUSBAR_H
+
+enum {
+ STATUSBAR_POS_UP,
+ STATUSBAR_POS_MIDDLE,
+ STATUSBAR_POS_DOWN
+};
+
+typedef struct {
+ int pos;
+ int line;
+
+ int ypos; /* real position in screen at the moment */
+ GSList *items;
+} STATUSBAR_REC;
+
+typedef struct {
+ STATUSBAR_REC *bar;
+
+ int xpos, size;
+ int right_justify;
+ void *func;
+} SBAR_ITEM_REC;
+
+typedef void (*STATUSBAR_FUNC) (SBAR_ITEM_REC *item, int ypos);
+
+/* ypos is used only when pos == STATUSBAR_POS_MIDDLE */
+STATUSBAR_REC *statusbar_create(int pos, int ypos);
+void statusbar_destroy(STATUSBAR_REC *bar);
+
+STATUSBAR_REC *statusbar_find(int pos, int line);
+
+SBAR_ITEM_REC *statusbar_item_create(STATUSBAR_REC *bar, int size, gboolean right_justify, STATUSBAR_FUNC func);
+void statusbar_item_resize(SBAR_ITEM_REC *item, int size);
+void statusbar_item_remove(SBAR_ITEM_REC *item);
+
+/* redraw statusbar, NULL = all */
+void statusbar_redraw(STATUSBAR_REC *bar);
+void statusbar_item_redraw(SBAR_ITEM_REC *item);
+
+void statusbar_init(void);
+void statusbar_deinit(void);
+
+#endif
diff --git a/src/irc/core/bans.c b/src/irc/core/bans.c
index 962c3c8d..4108f1bd 100644
--- a/src/irc/core/bans.c
+++ b/src/irc/core/bans.c
@@ -55,7 +55,7 @@ char *ban_get_mask(CHANNEL_REC *channel, const char *nick)
host = strchr(++user, '@');
if (host == NULL) return str;
- if ((int) (host-user) < 10) {
+ if ((int) (host-user) > 10) {
/* too long user mask */
user[9] = '*';
g_memmove(user+10, host, strlen(host)+1);
@@ -112,7 +112,7 @@ void ban_set_type(const char *type)
void ban_set(CHANNEL_REC *channel, const char *bans)
{
GString *str;
- char **ban, **banlist;
+ char **ban, **banlist, *realban;
g_return_if_fail(bans != NULL);
@@ -121,19 +121,20 @@ void ban_set(CHANNEL_REC *channel, const char *bans)
for (ban = banlist; *ban != NULL; ban++) {
if (strchr(*ban, '!') != NULL) {
/* explicit ban */
- g_string_sprintfa(str, " %s", *ban);
+ g_string_sprintfa(str, "%s ", *ban);
continue;
}
/* ban nick */
- *ban = ban_get_mask(channel, *ban);
- if (*ban != NULL) {
- g_string_sprintfa(str, " %s", *ban);
- g_free(*ban);
+ realban = ban_get_mask(channel, *ban);
+ if (realban != NULL) {
+ g_string_sprintfa(str, "%s ", realban);
+ g_free(realban);
}
}
g_strfreev(banlist);
+ g_string_truncate(str, str->len-1);
channel_set_singlemode(channel->server, channel->name, str->str, "+b");
g_string_free(str, TRUE);
}
@@ -169,7 +170,7 @@ static void command_set_ban(const char *data, IRC_SERVER_REC *server, WI_IRC_REC
if (server == NULL || !server->connected || !irc_server_check(server))
cmd_return_error(CMDERR_NOT_CONNECTED);
- params = cmd_get_params(data, 3 | PARAM_FLAG_OPTCHAN | PARAM_FLAG_GETREST,
+ params = cmd_get_params(data, 2 | PARAM_FLAG_OPTCHAN | PARAM_FLAG_GETREST,
item, &channel, &nicks);
if (!ischannel(*channel)) cmd_param_error(CMDERR_NOT_JOINED);
if (*nicks == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
diff --git a/src/irc/core/channel-events.c b/src/irc/core/channel-events.c
index 8f11ee47..8de80cbd 100644
--- a/src/irc/core/channel-events.c
+++ b/src/irc/core/channel-events.c
@@ -95,6 +95,27 @@ static void event_topic(const char *data, IRC_SERVER_REC *server)
g_free(params);
}
+/* Find any unjoined channel that matches `channel'. Long channel names are
+ also a bit problematic, so find a channel where start of the name matches. */
+static CHANNEL_REC *channel_find_unjoined(IRC_SERVER_REC *server, const char *channel)
+{
+ GSList *tmp;
+ int len;
+
+ len = strlen(channel);
+ for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
+ CHANNEL_REC *rec = tmp->data;
+
+ if (rec->joined) continue;
+
+ if (g_strncasecmp(channel, rec->name, len) == 0 &&
+ (len > 20 || rec->name[len] == '\0'))
+ return rec;
+ }
+
+ return NULL;
+}
+
static void event_join(const char *data, IRC_SERVER_REC *server, const char *nick, const char *address)
{
char *params, *channel, *tmp;
@@ -120,10 +141,8 @@ static void event_join(const char *data, IRC_SERVER_REC *server, const char *nic
!channel here to !ABCDEchannel */
char *shortchan;
- shortchan = g_strdup(channel);
- sprintf(shortchan, "!%s", channel+6);
-
- chanrec = channel_find(server, shortchan);
+ shortchan = g_strdup_printf("!%s", channel+6);
+ chanrec = channel_find_unjoined(server, shortchan);
if (chanrec != NULL) {
g_free(chanrec->name);
chanrec->name = g_strdup(channel);
@@ -132,11 +151,16 @@ static void event_join(const char *data, IRC_SERVER_REC *server, const char *nic
g_free(shortchan);
}
- chanrec = channel_find(server, channel);
+ chanrec = channel_find_unjoined(server, channel);
if (chanrec == NULL) {
/* didn't get here with /join command.. */
chanrec = channel_create(server, channel, TRUE);
}
+ chanrec->joined = TRUE;
+ if (strcmp(chanrec->name, channel) != 0) {
+ g_free(chanrec->name);
+ chanrec->name = g_strdup(channel);
+ }
g_free(params);
}
diff --git a/src/irc/core/channels-query.c b/src/irc/core/channels-query.c
index 0691d3ef..d8516ff6 100644
--- a/src/irc/core/channels-query.c
+++ b/src/irc/core/channels-query.c
@@ -232,7 +232,7 @@ static void channel_send_query(IRC_SERVER_REC *server, int query)
for (tmp = chans; tmp != NULL; tmp = tmp->next) {
chanrec = tmp->data;
- server_redirect_event((SERVER_REC *) server, chanrec->name, 4,
+ server_redirect_event((SERVER_REC *) server, chanrec->name, 2,
"event 403", "chanquery mode abort", 1,
"event 349", "chanquery eban end", 1,
"event 348", "chanquery eban", 1, NULL);
@@ -244,7 +244,7 @@ static void channel_send_query(IRC_SERVER_REC *server, int query)
for (tmp = chans; tmp != NULL; tmp = tmp->next) {
chanrec = tmp->data;
- server_redirect_event((SERVER_REC *) server, chanrec->name, 4,
+ server_redirect_event((SERVER_REC *) server, chanrec->name, 2,
"event 403", "chanquery mode abort", 1,
"event 347", "chanquery ilist end", 1,
"event 346", "chanquery ilist", 1, NULL);
diff --git a/src/irc/core/channels-setup.c b/src/irc/core/channels-setup.c
index c8400d4e..2991a8bc 100644
--- a/src/irc/core/channels-setup.c
+++ b/src/irc/core/channels-setup.c
@@ -26,6 +26,7 @@
#include "nicklist.h"
#include "irc-server.h"
#include "server-setup.h"
+#include "special-vars.h"
#include "lib-config/iconfig.h"
#include "settings.h"
@@ -33,30 +34,52 @@
GSList *setupchannels;
#define ircnet_match(a, b) \
- ((a[0]) == '\0' || (b != NULL && g_strcasecmp(a, b) == 0))
+ ((a) == NULL || (a[0]) == '\0' || (b != NULL && g_strcasecmp(a, b) == 0))
-SETUP_CHANNEL_REC *channels_setup_find(const char *channel, IRC_SERVER_REC *server)
+static void channel_config_add(SETUP_CHANNEL_REC *channel)
{
- GSList *tmp;
+ CONFIG_NODE *node;
- g_return_val_if_fail(channel != NULL, NULL);
- g_return_val_if_fail(server != NULL, NULL);
+ node = iconfig_node_traverse("(channels", TRUE);
+ node = config_node_section(node, NULL, NODE_TYPE_BLOCK);
+
+ config_node_set_str(node, "name", channel->name);
+ config_node_set_str(node, "ircnet", channel->ircnet);
+ if (channel->autojoin)
+ config_node_set_bool(node, "autojoin", TRUE);
+ config_node_set_str(node, "password", channel->password);
+ config_node_set_str(node, "botmasks", channel->botmasks);
+ config_node_set_str(node, "autosendcmd", channel->autosendcmd);
+ config_node_set_str(node, "background", channel->background);
+ config_node_set_str(node, "font", channel->font);
+}
- for (tmp = setupchannels; tmp != NULL; tmp = tmp->next) {
- SETUP_CHANNEL_REC *rec = tmp->data;
+static void channel_config_remove(SETUP_CHANNEL_REC *channel)
+{
+ CONFIG_NODE *node;
- if (g_strcasecmp(rec->name, channel) == 0 &&
- ircnet_match(rec->ircnet, server->connrec->ircnet))
- return rec;
+ node = iconfig_node_traverse("channels", FALSE);
+ if (node != NULL) config_node_list_remove(node, g_slist_index(setupchannels, channel));
+}
+
+void channels_setup_create(SETUP_CHANNEL_REC *channel)
+{
+ if (g_slist_find(setupchannels, channel) != NULL) {
+ channel_config_remove(channel);
+ setupchannels = g_slist_remove(setupchannels, channel);
}
+ setupchannels = g_slist_append(setupchannels, channel);
- return NULL;
+ channel_config_add(channel);
}
void channels_setup_destroy(SETUP_CHANNEL_REC *channel)
{
g_return_if_fail(channel != NULL);
+ channel_config_remove(channel);
+ setupchannels = g_slist_remove(setupchannels, channel);
+
g_free(channel->name);
g_free(channel->ircnet);
g_free_not_null(channel->password);
@@ -65,16 +88,30 @@ void channels_setup_destroy(SETUP_CHANNEL_REC *channel)
g_free_not_null(channel->background);
g_free_not_null(channel->font);
g_free(channel);
+}
- setupchannels = g_slist_remove(setupchannels, channel);
+SETUP_CHANNEL_REC *channels_setup_find(const char *channel, const char *ircnet)
+{
+ GSList *tmp;
+
+ g_return_val_if_fail(channel != NULL, NULL);
+
+ for (tmp = setupchannels; tmp != NULL; tmp = tmp->next) {
+ SETUP_CHANNEL_REC *rec = tmp->data;
+
+ if (g_strcasecmp(rec->name, channel) == 0 &&
+ ircnet_match(rec->ircnet, ircnet))
+ return rec;
+ }
+
+ return NULL;
}
/* connected to server, autojoin to channels. */
static void event_connected(IRC_SERVER_REC *server)
{
- GString *chans, *keys;
+ GString *chans;
GSList *tmp;
- int use_keys;
g_return_if_fail(server != NULL);
@@ -83,9 +120,6 @@ static void event_connected(IRC_SERVER_REC *server)
/* join to the channels marked with autojoin in setup */
chans = g_string_new(NULL);
- keys = g_string_new(NULL);
-
- use_keys = FALSE;
for (tmp = setupchannels; tmp != NULL; tmp = tmp->next) {
SETUP_CHANNEL_REC *rec = tmp->data;
@@ -93,21 +127,14 @@ static void event_connected(IRC_SERVER_REC *server)
continue;
g_string_sprintfa(chans, "%s,", rec->name);
- g_string_sprintfa(keys, "%s,", rec->password == NULL ? "x" : rec->password);
- if (rec->password != NULL)
- use_keys = TRUE;
}
if (chans->len > 0) {
g_string_truncate(chans, chans->len-1);
- g_string_truncate(keys, keys->len-1);
- if (use_keys) g_string_sprintfa(chans, " %s", keys->str);
-
channels_join(server, chans->str, TRUE);
}
g_string_free(chans, TRUE);
- g_string_free(keys, TRUE);
}
/* channel wholist received: send the auto send command */
@@ -115,17 +142,17 @@ static void channel_wholist(CHANNEL_REC *channel)
{
SETUP_CHANNEL_REC *rec;
NICK_REC *nick;
- char **bots, **bot, *str;
+ char **bots, **bot;
g_return_if_fail(channel != NULL);
- rec = channels_setup_find(channel->name, channel->server);
+ rec = channels_setup_find(channel->name, channel->server->connrec->ircnet);
if (rec == NULL || rec->autosendcmd == NULL || !*rec->autosendcmd)
return;
if (rec->botmasks == NULL || !*rec->botmasks) {
/* just send the command. */
- signal_emit("send command", 3, rec->autosendcmd, channel->server, channel);
+ eval_special_string(rec->autosendcmd, "", channel->server, channel);
}
/* find first available bot.. */
@@ -136,9 +163,7 @@ static void channel_wholist(CHANNEL_REC *channel)
continue;
/* got one! */
- str = g_strdup_printf(rec->autosendcmd, nick->nick);
- signal_emit("send command", 3, str, channel->server, channel);
- g_free(str);
+ eval_special_string(rec->autosendcmd, nick->nick, channel->server, channel);
break;
}
g_strfreev(bots);
diff --git a/src/irc/core/channels-setup.h b/src/irc/core/channels-setup.h
index 0556019a..9cd2472c 100644
--- a/src/irc/core/channels-setup.h
+++ b/src/irc/core/channels-setup.h
@@ -20,8 +20,9 @@ extern GSList *setupchannels;
void channels_setup_init(void);
void channels_setup_deinit(void);
+void channels_setup_create(SETUP_CHANNEL_REC *channel);
void channels_setup_destroy(SETUP_CHANNEL_REC *channel);
-SETUP_CHANNEL_REC *channels_setup_find(const char *channel, IRC_SERVER_REC *server);
+SETUP_CHANNEL_REC *channels_setup_find(const char *channel, const char *ircnet);
#endif
diff --git a/src/irc/core/channels.c b/src/irc/core/channels.c
index 9f01d57a..4c50ab7b 100644
--- a/src/irc/core/channels.c
+++ b/src/irc/core/channels.c
@@ -156,10 +156,12 @@ char *channel_get_mode(CHANNEL_REC *channel)
void channels_join(IRC_SERVER_REC *server, const char *data, int automatic)
{
+ SETUP_CHANNEL_REC *schannel;
CHANNEL_REC *chanrec;
GString *outchans, *outkeys;
char *params, *channels, *keys;
char **chanlist, **keylist, **tmp, **tmpkey, *channel;
+ int use_keys;
g_return_if_fail(data != NULL);
if (server == NULL || !server->connected || !irc_server_check(server))
@@ -174,19 +176,24 @@ void channels_join(IRC_SERVER_REC *server, const char *data, int automatic)
outchans = g_string_new(NULL);
outkeys = g_string_new(NULL);
+ use_keys = *keys != '\0';
tmpkey = keylist;
for (tmp = chanlist; *tmp != NULL; tmp++) {
channel = ischannel(**tmp) ? g_strdup(*tmp) :
g_strdup_printf("#%s", *tmp);
chanrec = channel_find(server, channel);
- if (chanrec != NULL) {
- /* already joined this channel */
- signal_emit("gui channel open", 1, chanrec);
- } else {
+ if (chanrec == NULL) {
+ schannel = channels_setup_find(channel, server->connrec->ircnet);
+
g_string_sprintfa(outchans, "%s,", channel);
- if (*keys != '\0')
+ if (schannel == NULL || schannel->password == NULL)
g_string_sprintfa(outkeys, "%s,", get_join_key(*tmpkey));
+ else {
+ /* get password from setup record */
+ use_keys = TRUE;
+ g_string_sprintfa(outkeys, "%s,", schannel->password);
+ }
channel_create(server, channel + (channel[0] == '!' && channel[1] == '!'), automatic);
}
@@ -197,7 +204,7 @@ void channels_join(IRC_SERVER_REC *server, const char *data, int automatic)
}
if (outchans->len > 0) {
- irc_send_cmdv(server, *keys == '\0' ? "JOIN %s" : "JOIN %s %s",
+ irc_send_cmdv(server, use_keys ? "JOIN %s %s" : "JOIN %s",
outchans->str, outkeys->str);
}
diff --git a/src/irc/core/channels.h b/src/irc/core/channels.h
index 5cf53aa5..03ae1a6e 100644
--- a/src/irc/core/channels.h
+++ b/src/irc/core/channels.h
@@ -41,6 +41,7 @@ typedef struct {
int wholist:1; /* WHO list got */
int synced:1; /* Channel synced - all queries done */
+ int joined:1; /* Have we even received JOIN event for this channel? */
int left:1; /* You just left the channel */
int kicked:1; /* You just got kicked */
int destroying:1;
diff --git a/src/irc/core/ctcp.c b/src/irc/core/ctcp.c
index 5265c2be..55df8098 100644
--- a/src/irc/core/ctcp.c
+++ b/src/irc/core/ctcp.c
@@ -52,7 +52,7 @@ void ctcp_send_reply(IRC_SERVER_REC *server, const char *data)
if (g_slist_length(server->ctcpqueue) < settings_get_int("max_ctcp_queue")) {
/* Add to first in idle queue */
- tag = server_idle_add_first(server, data, NULL, 0, NULL);
+ tag = server_idle_add(server, data, NULL, 0, NULL);
server->ctcpqueue = g_slist_append(server->ctcpqueue, GINT_TO_POINTER(tag));
}
}
diff --git a/src/irc/core/ignore.c b/src/irc/core/ignore.c
index ab817ae1..274a8646 100644
--- a/src/irc/core/ignore.c
+++ b/src/irc/core/ignore.c
@@ -251,6 +251,7 @@ static void read_ignores(void)
IGNORE_REC *rec;
CONFIG_NODE *node;
GSList *tmp;
+ char *str;
while (ignores != NULL)
ignore_destroy(ignores->data);
@@ -269,8 +270,8 @@ static void read_ignores(void)
rec->mask = g_strdup(config_node_get_str(node, "mask", NULL));
rec->pattern = g_strdup(config_node_get_str(node, "pattern", NULL));
- rec->level = level2bits(config_node_get_str(node, "level", 0));
- rec->except_level = level2bits(config_node_get_str(node, "except_level", 0));
+ rec->level = level2bits(config_node_get_str(node, "level", ""));
+ rec->except_level = level2bits(config_node_get_str(node, "except_level", ""));
rec->regexp = config_node_get_bool(node, "regexp", FALSE);
rec->fullword = config_node_get_bool(node, "fullword", FALSE);
diff --git a/src/irc/core/irc-commands.c b/src/irc/core/irc-commands.c
index 8fcd4259..b06d9371 100644
--- a/src/irc/core/irc-commands.c
+++ b/src/irc/core/irc-commands.c
@@ -19,6 +19,7 @@
*/
#include "module.h"
+#include "network.h"
#include "commands.h"
#include "misc.h"
#include "special-vars.h"
@@ -46,23 +47,35 @@ static IRC_SERVER_REC *connect_server(const char *data)
{
IRC_SERVER_CONNECT_REC *conn;
IRC_SERVER_REC *server;
- char *params, *addr, *portstr, *password, *nick;
- int port;
+ char *params, *args, *ircnet, *host, *addr, *portstr, *password, *nick;
g_return_val_if_fail(data != NULL, NULL);
- params = cmd_get_params(data, 4, &addr, &portstr, &password, &nick);
+ args = "ircnet host";
+ params = cmd_get_params(data, 7 | PARAM_FLAG_MULTIARGS,
+ &args, &ircnet, &host, &addr,
+ &portstr, &password, &nick);
+ if (*addr == '+') addr++;
if (*addr == '\0') return NULL;
if (strcmp(password, "-") == 0)
*password = '\0';
- port = 6667;
- if (*portstr != '\0')
- sscanf(portstr, "%d", &port);
-
/* connect to server */
- conn = irc_server_create_conn(addr, port, password, nick);
+ conn = irc_server_create_conn(addr, atoi(portstr), password, nick);
+ if (*ircnet != '\0') {
+ g_free_not_null(conn->ircnet);
+ conn->ircnet = g_strdup(ircnet);
+ }
+ if (*host != '\0') {
+ IPADDR ip;
+
+ if (net_gethostname(host, &ip) == 0) {
+ if (conn->own_ip == NULL)
+ conn->own_ip = g_new(IPADDR, 1);
+ memcpy(conn->own_ip, &ip, sizeof(IPADDR));
+ }
+ }
server = irc_server_connect(conn);
g_free(params);
@@ -92,6 +105,9 @@ static void cmd_disconnect(const char *data, IRC_SERVER_REC *server)
if (server == NULL || !irc_server_check(server))
cmd_param_error(CMDERR_NOT_CONNECTED);
+ if (*msg == '\0') msg = (char *) settings_get_str("quit_message");
+ signal_emit("server quit", 2, server, msg);
+
ircserver = (IRC_SERVER_REC *) server;
if (ircserver->handle != -1 && ircserver->buffer != NULL) {
/* flush transmit queue */
@@ -100,8 +116,6 @@ static void cmd_disconnect(const char *data, IRC_SERVER_REC *server)
ircserver->cmdqueue = NULL;
ircserver->cmdcount = 0;
- /* then send quit message */
- if (*msg == '\0') msg = (char *) settings_get_str("default_quit_message");
irc_send_cmdv(ircserver, "QUIT :%s", msg);
}
g_free(params);
@@ -111,12 +125,20 @@ static void cmd_disconnect(const char *data, IRC_SERVER_REC *server)
static void cmd_server(const char *data, IRC_SERVER_REC *server)
{
+ char *params, *args, *ircnetarg, *hostarg, *addr;
char *channels, *away_reason, *usermode, *ircnet;
+ int no_old_server;
g_return_if_fail(data != NULL);
- if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
- if (*data == '+' || server == NULL) {
+ args = "ircnet host";
+ params = cmd_get_params(data, 4 | PARAM_FLAG_MULTIARGS,
+ &args, &ircnetarg, &hostarg, &addr);
+ if (*addr == '\0' || strcmp(addr, "+") == 0)
+ cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ no_old_server = server == NULL;
+ if (*addr == '+' || server == NULL) {
channels = away_reason = usermode = ircnet = NULL;
} else {
ircnet = g_strdup(server->connrec->ircnet);
@@ -129,20 +151,21 @@ static void cmd_server(const char *data, IRC_SERVER_REC *server)
cmd_disconnect("* Changing server", server);
}
- server = connect_server(data + (*data == '+' ? 1 : 0));
- if (*data == '+' || server == NULL ||
+ server = connect_server(data);
+ if (*addr == '+' || server == NULL ||
(ircnet != NULL && server->connrec->ircnet != NULL &&
g_strcasecmp(ircnet, server->connrec->ircnet) != 0)) {
g_free_not_null(channels);
g_free_not_null(usermode);
g_free_not_null(away_reason);
- } else if (server != NULL) {
+ } else if (server != NULL && !no_old_server) {
server->connrec->reconnection = TRUE;
server->connrec->channels = channels;
server->connrec->usermode = usermode;
server->connrec->away_reason = away_reason;
}
g_free_not_null(ircnet);
+ g_free(params);
}
static void cmd_quit(const char *data)
@@ -154,7 +177,7 @@ static void cmd_quit(const char *data)
g_return_if_fail(data != NULL);
quitmsg = *data != '\0' ? data :
- settings_get_str("default_quit_message");
+ settings_get_str("quit_message");
/* disconnect from every server */
for (tmp = servers; tmp != NULL; tmp = next) {
@@ -646,7 +669,7 @@ static void cmd_knockout(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *i
if (is_numeric(data, ' ')) {
/* first argument is the timeout */
params = cmd_get_params(data, 3 | PARAM_FLAG_GETREST, &timeoutstr, &nick, &reason);
- timeleft = atol(timeoutstr);
+ timeleft = atoi(timeoutstr);
} else {
timeleft = 0;
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &nick, &reason);
@@ -749,7 +772,7 @@ void irc_commands_init(void)
{
tmpstr = g_string_new(NULL);
- settings_add_str("misc", "default_quit_message", "leaving");
+ settings_add_str("misc", "quit_message", "leaving");
settings_add_int("misc", "knockout_time", 300);
knockout_tag = g_timeout_add(KNOCKOUT_TIMECHECK, (GSourceFunc) knockout_timeout, NULL);
diff --git a/src/irc/core/irc-log.c b/src/irc/core/irc-log.c
index 3c9ef760..9871ee64 100644
--- a/src/irc/core/irc-log.c
+++ b/src/irc/core/irc-log.c
@@ -90,8 +90,8 @@ static void event_unaway(const char *data, IRC_SERVER_REC *server)
void irc_log_init(void)
{
- settings_add_str("misc", "awaylog_file", "~/.irssi/away.log");
- settings_add_str("misc", "awaylog_level", "msgs hilight");
+ settings_add_str("log", "awaylog_file", "~/.irssi/away.log");
+ settings_add_str("log", "awaylog_level", "msgs hilight");
signal_add("print text stripped", (SIGNAL_FUNC) sig_log);
signal_add("event 306", (SIGNAL_FUNC) event_away);
diff --git a/src/irc/core/irc-server.c b/src/irc/core/irc-server.c
index 2f9e9fb1..a21d9a1f 100644
--- a/src/irc/core/irc-server.c
+++ b/src/irc/core/irc-server.c
@@ -335,7 +335,7 @@ static int sig_set_user_mode(IRC_SERVER_REC *server)
if (g_slist_find(servers, server) == NULL)
return 0; /* got disconnected */
- mode = settings_get_str("default_user_mode");
+ mode = settings_get_str("usermode");
newmode = server->usermode == NULL ? NULL :
modes_join(server->usermode, mode);
if (server->usermode == NULL || strcmp(newmode, server->usermode) != 0)
@@ -369,7 +369,7 @@ static void event_connected(const char *data, IRC_SERVER_REC *server, const char
if (!server->connrec->reconnection) {
/* wait a second and then send the user mode */
- mode = settings_get_str("default_user_mode");
+ mode = settings_get_str("usermode");
if (*mode != '\0')
g_timeout_add(1000, (GSourceFunc) sig_set_user_mode, server);
}
@@ -414,7 +414,7 @@ static void event_empty(void)
void irc_servers_init(void)
{
- settings_add_str("misc", "default_user_mode", DEFAULT_USER_MODE);
+ settings_add_str("misc", "usermode", DEFAULT_USER_MODE);
settings_add_int("flood", "cmd_queue_speed", DEFAULT_CMD_QUEUE_SPEED);
settings_add_int("flood", "cmds_max_at_once", DEFAULT_CMDS_MAX_AT_ONCE);
diff --git a/src/irc/core/irc-server.h b/src/irc/core/irc-server.h
index 21e3e73c..11172bea 100644
--- a/src/irc/core/irc-server.h
+++ b/src/irc/core/irc-server.h
@@ -120,6 +120,7 @@ typedef struct {
GSList *lastmsgs; /* List of nicks who last send you msg */
GHashTable *splits; /* For keeping track of netsplits */
+ GSList *split_servers; /* Servers that are currently in split */
time_t lag_sent; /* 0 or time when last lag query was sent to server */
time_t lag_last_check; /* last time we checked lag */
diff --git a/src/irc/core/irc.c b/src/irc/core/irc.c
index c25f32b6..4e37d474 100644
--- a/src/irc/core/irc.c
+++ b/src/irc/core/irc.c
@@ -48,6 +48,7 @@ static void cmd_send(IRC_SERVER_REC *server, const char *cmd, int send_now, int
/* just check that we don't send any longer commands than 512 bytes.. */
strncpy(str, cmd, 510);
len = strlen(cmd);
+ if (len > 510) len = 510;
str[len++] = 13; str[len++] = 10; str[len] = '\0';
ptr = str;
diff --git a/src/irc/core/ircnet-setup.c b/src/irc/core/ircnet-setup.c
index 0e19f3a5..8296a7e8 100644
--- a/src/irc/core/ircnet-setup.c
+++ b/src/irc/core/ircnet-setup.c
@@ -104,6 +104,7 @@ static void read_ircnets(void)
void ircnets_setup_init(void)
{
+ read_ircnets();
signal_add("setup reread", (SIGNAL_FUNC) read_ircnets);
}
diff --git a/src/irc/core/massjoin.c b/src/irc/core/massjoin.c
index 3cd0d31a..51831a1a 100644
--- a/src/irc/core/massjoin.c
+++ b/src/irc/core/massjoin.c
@@ -20,7 +20,7 @@
#include "module.h"
#include "signals.h"
-#include "common-setup.h"
+#include "settings.h"
#include "channels.h"
#include "irc.h"
@@ -28,6 +28,7 @@
#include "irc-server.h"
static int massjoin_tag;
+static int massjoin_max_joins;
/* Massjoin support - really useful when trying to do things (like op/deop)
to people after netjoins. It sends
@@ -210,7 +211,7 @@ static void server_check_massjoins(IRC_SERVER_REC *server, time_t max)
continue;
if (rec->massjoin_start < max || /* We've waited long enough */
- rec->massjoins-5 < rec->last_massjoins) { /* Less than 5 joins since last check */
+ rec->massjoins-massjoin_max_joins < rec->last_massjoins) { /* Less than x joins since last check */
/* send them */
massjoin_send(rec);
} else {
@@ -226,21 +227,30 @@ static int sig_massjoin_timeout(void)
GSList *tmp;
time_t max;
- max = time(NULL)-MAX_MASSJOIN_WAIT;
+ max = time(NULL)-settings_get_int("massjoin_max_wait");
for (tmp = servers; tmp != NULL; tmp = tmp->next)
server_check_massjoins(tmp->data, max);
return 1;
}
+static void read_settings(void)
+{
+ massjoin_max_joins = settings_get_int("massjoin_max_joins");
+}
+
void massjoin_init(void)
{
+ settings_add_int("misc", "massjoin_max_wait", 5000);
+ settings_add_int("misc", "massjoin_max_joins", 3);
massjoin_tag = g_timeout_add(1000, (GSourceFunc) sig_massjoin_timeout, NULL);
+ read_settings();
signal_add("event join", (SIGNAL_FUNC) event_join);
signal_add("event part", (SIGNAL_FUNC) event_part);
signal_add("event kick", (SIGNAL_FUNC) event_kick);
signal_add("event quit", (SIGNAL_FUNC) event_quit);
+ signal_add("setup changed", (SIGNAL_FUNC) read_settings);
}
void massjoin_deinit(void)
@@ -251,4 +261,5 @@ void massjoin_deinit(void)
signal_remove("event part", (SIGNAL_FUNC) event_part);
signal_remove("event kick", (SIGNAL_FUNC) event_kick);
signal_remove("event quit", (SIGNAL_FUNC) event_quit);
+ signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
}
diff --git a/src/irc/core/modes.c b/src/irc/core/modes.c
index 9b5c8027..bd31d3ab 100644
--- a/src/irc/core/modes.c
+++ b/src/irc/core/modes.c
@@ -103,7 +103,7 @@ void parse_channel_modes(CHANNEL_REC *channel, const char *setby, const char *mo
ptr = cmd_get_param(&modestr);
if (*ptr == '\0') break;
- if (strcmp(channel->server->nick, ptr) == 0)
+ if (g_strcasecmp(channel->server->nick, ptr) == 0)
channel->chanop = type == '+' ? TRUE : FALSE;
nick_mode_change(channel, ptr, '@', type == '+');
break;
@@ -297,6 +297,9 @@ void channel_set_singlemode(IRC_SERVER_REC *server, const char *channel, const c
nicklist = g_strsplit(nicks, " ", -1);
for (nick = nicklist; *nick != NULL; nick++) {
+ if (*nick == '\0')
+ continue;
+
if (num == 0)
{
g_string_sprintf(str, "MODE %s %s", channel, mode);
@@ -373,28 +376,94 @@ void channel_set_mode(IRC_SERVER_REC *server, const char *channel, const char *m
g_free(orig);
}
-static void cmd_op(gchar *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
+static char *get_nicks(WI_IRC_REC *item, const char *data, int op, int voice)
+{
+ GString *str;
+ GSList *nicks, *tmp;
+ char **matches, **match, *ret;
+
+ str = g_string_new(NULL);
+ matches = g_strsplit(data, " ", -1);
+ for (match = matches; *match != NULL; match++) {
+ if (strchr(*match, '*') == NULL && strchr(*match, '?') == NULL) {
+ /* no wildcards */
+ g_string_sprintfa(str, "%s ", *match);
+ continue;
+ }
+
+ /* wildcards */
+ nicks = nicklist_find_multiple((CHANNEL_REC *) item, data);
+ for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
+ NICK_REC *rec = tmp->data;
+
+ if ((op == 1 && !rec->op) || (op == 0 && rec->op) ||
+ (voice == 1 && !rec->voice) || (voice == 0 && rec->voice))
+ continue;
+
+ if (g_strcasecmp(rec->nick, item->server->nick) == 0)
+ continue;
+
+ g_string_sprintfa(str, "%s ", rec->nick);
+ }
+ g_slist_free(nicks);
+ }
+
+ g_string_truncate(str, str->len-1);
+ ret = str->str;
+ g_string_free(str, FALSE);
+ return ret;
+}
+
+static void cmd_op(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
{
- if (!irc_item_channel(item)) return;
- channel_set_singlemode(server, item->name, data, "+o");
+ char *nicks;
+
+ if (!irc_item_channel(item))
+ return;
+
+ nicks = get_nicks(item, data, 0, -1);
+ if (*nicks != '\0')
+ channel_set_singlemode(server, item->name, nicks, "+o");
+ g_free(nicks);
}
static void cmd_deop(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
{
- if (!irc_item_channel(item)) return;
- channel_set_singlemode(server, item->name, data, "-o");
+ char *nicks;
+
+ if (!irc_item_channel(item))
+ return;
+
+ nicks = get_nicks(item, data, 1, -1);
+ if (*nicks != '\0')
+ channel_set_singlemode(server, item->name, nicks, "-o");
+ g_free(nicks);
}
static void cmd_voice(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
{
- if (!irc_item_channel(item)) return;
- channel_set_singlemode(server, item->name, data, "+v");
+ char *nicks;
+
+ if (!irc_item_channel(item))
+ return;
+
+ nicks = get_nicks(item, data, 0, 0);
+ if (*nicks != '\0')
+ channel_set_singlemode(server, item->name, nicks, "+v");
+ g_free(nicks);
}
static void cmd_devoice(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
{
- if (!irc_item_channel(item)) return;
- channel_set_singlemode(server, item->name, data, "-v");
+ char *nicks;
+
+ if (!irc_item_channel(item))
+ return;
+
+ nicks = get_nicks(item, data, 0, 1);
+ if (*nicks != '\0')
+ channel_set_singlemode(server, item->name, nicks, "-v");
+ g_free(nicks);
}
static void cmd_mode(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
diff --git a/src/irc/core/netsplit.c b/src/irc/core/netsplit.c
index b455f740..c5a4ff49 100644
--- a/src/irc/core/netsplit.c
+++ b/src/irc/core/netsplit.c
@@ -29,6 +29,46 @@
static int split_tag;
+static NETSPLIT_SERVER_REC *netsplit_server_find(IRC_SERVER_REC *server, const char *servername, const char *destserver)
+{
+ GSList *tmp;
+
+ for (tmp = server->split_servers; tmp != NULL; tmp = tmp->next) {
+ NETSPLIT_SERVER_REC *rec = tmp->data;
+
+ if (g_strcasecmp(rec->server, servername) == 0 &&
+ g_strcasecmp(rec->destserver, destserver) == 0)
+ return rec;
+ }
+
+ return NULL;
+}
+
+static NETSPLIT_SERVER_REC *netsplit_server_create(IRC_SERVER_REC *server, const char *servername, const char *destserver)
+{
+ NETSPLIT_SERVER_REC *rec;
+
+ rec = netsplit_server_find(server, servername, destserver);
+ if (rec != NULL) return rec;
+
+ rec = g_new0(NETSPLIT_SERVER_REC, 1);
+ rec->server = g_strdup(servername);
+ rec->destserver = g_strdup(destserver);
+
+ server->split_servers = g_slist_append(server->split_servers, rec);
+ signal_emit("netsplit new server", 1, rec);
+ return rec;
+}
+
+static void netsplit_destroy_server(IRC_SERVER_REC *server, NETSPLIT_SERVER_REC *rec)
+{
+ server->split_servers = g_slist_remove(server->split_servers, rec);
+
+ g_free(rec->server);
+ g_free(rec->destserver);
+ g_free(rec);
+}
+
static NETSPLIT_REC *netsplit_add(IRC_SERVER_REC *server, const char *nick, const char *address, const char *servers)
{
NETSPLIT_REC *rec;
@@ -41,6 +81,7 @@ static NETSPLIT_REC *netsplit_add(IRC_SERVER_REC *server, const char *nick, cons
g_return_val_if_fail(nick != NULL, NULL);
g_return_val_if_fail(address != NULL, NULL);
+ /* get splitted servers */
dupservers = g_strdup(servers);
p = strchr(dupservers, ' ');
if (p == NULL) {
@@ -54,9 +95,8 @@ static NETSPLIT_REC *netsplit_add(IRC_SERVER_REC *server, const char *nick, cons
rec->address = g_strdup(address);
rec->destroy = time(NULL)+NETSPLIT_MAX_REMEMBER;
- /* get splitted servers */
- rec->server = g_strdup(dupservers);
- rec->destserver = g_strdup(p);
+ rec->server = netsplit_server_create(server, dupservers, p);
+ rec->server->count++;
g_free(dupservers);
/* copy the channel nick records.. */
@@ -75,11 +115,12 @@ static NETSPLIT_REC *netsplit_add(IRC_SERVER_REC *server, const char *nick, cons
}
g_hash_table_insert(server->splits, rec->nick, rec);
+
signal_emit("netsplit add", 1, rec);
return rec;
}
-static void netsplit_destroy(NETSPLIT_REC *rec)
+static void netsplit_destroy(IRC_SERVER_REC *server, NETSPLIT_REC *rec)
{
GSList *tmp;
@@ -93,16 +134,17 @@ static void netsplit_destroy(NETSPLIT_REC *rec)
g_free(rec);
}
- g_free(rec->server);
- g_free(rec->destserver);
+ if (--rec->server->count == 0)
+ netsplit_destroy_server(server, rec->server);
+
g_free(rec->nick);
g_free(rec->address);
g_free(rec);
}
-static void netsplit_destroy_hash(gpointer key, NETSPLIT_REC *rec)
+static void netsplit_destroy_hash(void *key, NETSPLIT_REC *rec, IRC_SERVER_REC *server)
{
- netsplit_destroy(rec);
+ netsplit_destroy(server, rec);
}
NETSPLIT_REC *netsplit_find(IRC_SERVER_REC *server, const char *nick, const char *address)
@@ -136,13 +178,15 @@ NICK_REC *netsplit_find_channel(IRC_SERVER_REC *server, const char *nick, const
return NULL;
}
-static int is_split(const char *msg)
+int quitmsg_is_split(const char *msg)
{
char *params, *host1, *host2, *p;
int ok;
g_return_val_if_fail(msg != NULL, FALSE);
+ if (msg[strlen(msg)-1] == ' ') msg[strlen(msg)-1] = '\0'; /*FIXME: remove - for debugging!*/
+
/* must have only two words */
p = strchr(msg, ' ');
if (p == NULL || strchr(p+1, ' ') != NULL) return FALSE;
@@ -171,19 +215,19 @@ static int is_split(const char *msg)
return ok;
}
-static void split_set_timeout(gpointer key, NETSPLIT_REC *rec, NETSPLIT_REC *orig)
+static void split_set_timeout(void *key, NETSPLIT_REC *rec, NETSPLIT_REC *orig)
{
if (rec == orig) {
/* original nick, destroy it in a few seconds.. */
rec->destroy = time(NULL)+4;
- } else if (g_strcasecmp(rec->server, orig->server) == 0 &&
- g_strcasecmp(rec->destserver, orig->destserver) == 0) {
+ } else if (g_strcasecmp(rec->server->server, orig->server->server) == 0 &&
+ g_strcasecmp(rec->server->destserver, orig->server->destserver) == 0) {
/* same servers -> split over -> destroy old records sooner.. */
rec->destroy = time(NULL)+60;
}
}
-static void event_join(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *address)
+static void event_join(const char *data, IRC_SERVER_REC *server, const char *nick, const char *address)
{
NETSPLIT_REC *rec;
@@ -202,7 +246,7 @@ static void event_join(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *
} else {
/* back from different address.. just destroy it. */
g_hash_table_remove(server->splits, rec->nick);
- netsplit_destroy(rec);
+ netsplit_destroy(server, rec);
}
}
@@ -211,7 +255,7 @@ static void event_quit(const char *data, IRC_SERVER_REC *server, const char *nic
g_return_if_fail(data != NULL);
if (*data == ':') data++;
- if (g_strcasecmp(nick, server->nick) != 0 && is_split(data)) {
+ if (g_strcasecmp(nick, server->nick) != 0 && quitmsg_is_split(data)) {
/* netsplit! */
netsplit_add(server, nick, address, data);
}
@@ -221,17 +265,17 @@ static void sig_disconnected(IRC_SERVER_REC *server)
{
g_return_if_fail(server != NULL);
- g_hash_table_foreach(server->splits, (GHFunc) netsplit_destroy_hash, NULL);
+ g_hash_table_foreach(server->splits, (GHFunc) netsplit_destroy_hash, server);
g_hash_table_destroy(server->splits);
}
-static int split_server_check(gpointer key, NETSPLIT_REC *rec, IRC_SERVER_REC *server)
+static int split_server_check(void *key, NETSPLIT_REC *rec, IRC_SERVER_REC *server)
{
/* Check if this split record is too old.. */
if (rec->destroy > time(NULL))
return FALSE;
- netsplit_destroy(rec);
+ netsplit_destroy(server, rec);
return TRUE;
}
diff --git a/src/irc/core/netsplit.h b/src/irc/core/netsplit.h
index c2d221da..c95b5c6f 100644
--- a/src/irc/core/netsplit.h
+++ b/src/irc/core/netsplit.h
@@ -4,10 +4,16 @@
#include "nicklist.h"
typedef struct {
- char *nick;
- char *address;
char *server;
char *destserver;
+ int count;
+} NETSPLIT_SERVER_REC;
+
+typedef struct {
+ NETSPLIT_SERVER_REC *server;
+
+ char *nick;
+ char *address;
GSList *channels;
time_t destroy;
@@ -24,4 +30,6 @@ void netsplit_deinit(void);
NETSPLIT_REC *netsplit_find(IRC_SERVER_REC *server, const char *nick, const char *address);
NICK_REC *netsplit_find_channel(IRC_SERVER_REC *server, const char *nick, const char *address, const char *channel);
+int quitmsg_is_split(const char *msg);
+
#endif
diff --git a/src/irc/core/nicklist.c b/src/irc/core/nicklist.c
index a275d43e..b8947ee6 100644
--- a/src/irc/core/nicklist.c
+++ b/src/irc/core/nicklist.c
@@ -87,6 +87,22 @@ static NICK_REC *nicklist_find_wildcards(CHANNEL_REC *channel, const char *mask)
return tmp == NULL ? NULL : nick;
}
+GSList *nicklist_find_multiple(CHANNEL_REC *channel, const char *mask)
+{
+ GSList *nicks, *tmp, *next;
+
+ nicks = nicklist_getnicks(channel);
+ for (tmp = nicks; tmp != NULL; tmp = next) {
+ NICK_REC *nick = tmp->data;
+
+ next = tmp->next;
+ if (!irc_mask_match_address(mask, nick->nick, nick->host == NULL ? "" : nick->host))
+ nicks = g_slist_remove(nicks, tmp->data);
+ }
+
+ return nicks;
+}
+
/* Find nick record from list */
NICK_REC *nicklist_find(CHANNEL_REC *channel, const char *mask)
{
@@ -230,7 +246,7 @@ static void event_names_list(const char *data, IRC_SERVER_REC *server)
while (*names != '\0' && *names != ' ') names++;
if (*names != '\0') *names++ = '\0';
- if (*ptr == '@' && strcmp(server->nick, ptr+1) == 0)
+ if (*ptr == '@' && g_strcasecmp(server->nick, ptr+1) == 0)
chanrec->chanop = TRUE;
nicklist_insert(chanrec, ptr+isnickflag(*ptr), *ptr == '@', *ptr == '+', FALSE);
@@ -390,7 +406,8 @@ static void event_nick_in_use(const char *data, IRC_SERVER_REC *server)
}
/* nick already in use - need to change it .. */
- if (strcmp(server->nick, server->connrec->nick) == 0) {
+ if (strcmp(server->nick, server->connrec->nick) == 0 &&
+ server->connrec->alternate_nick != NULL) {
/* first try, so try the alternative nick.. */
g_free(server->nick);
server->nick = g_strdup(server->connrec->alternate_nick);
diff --git a/src/irc/core/nicklist.h b/src/irc/core/nicklist.h
index 8e83e97f..b5250d18 100644
--- a/src/irc/core/nicklist.h
+++ b/src/irc/core/nicklist.h
@@ -25,6 +25,8 @@ NICK_REC *nicklist_insert(CHANNEL_REC *channel, const char *nick, int op, int vo
void nicklist_remove(CHANNEL_REC *channel, NICK_REC *nick);
/* Find nick record from list */
NICK_REC *nicklist_find(CHANNEL_REC *channel, const char *mask);
+/* Get list of nicks that match the mask */
+GSList *nicklist_find_multiple(CHANNEL_REC *channel, const char *mask);
/* Get list of nicks */
GSList *nicklist_getnicks(CHANNEL_REC *channel);
/* Get all the nick records of `nick'. Returns channel, nick, channel, ... */
diff --git a/src/irc/core/server-reconnect.c b/src/irc/core/server-reconnect.c
index a00b32cf..3e1b993f 100644
--- a/src/irc/core/server-reconnect.c
+++ b/src/irc/core/server-reconnect.c
@@ -85,7 +85,7 @@ static int server_reconnect_timeout(void)
static void sserver_connect(SETUP_SERVER_REC *rec, IRC_SERVER_CONNECT_REC *conn)
{
- conn->address = g_strdup(rec->server);
+ conn->address = g_strdup(rec->address);
conn->port = rec->port;
conn->password = rec->password == NULL ? NULL :
g_strdup(rec->password);
@@ -143,7 +143,6 @@ static void sig_reconnect(IRC_SERVER_REC *server)
return;
conn = g_new0(IRC_SERVER_CONNECT_REC, 1);
- conn->reconnection = TRUE;
server_connect_copy_skeleton(conn, server->connrec);
/* save the server status */
@@ -152,6 +151,7 @@ static void sig_reconnect(IRC_SERVER_REC *server)
conn->away_reason = g_strdup(server->connrec->away_reason);
conn->usermode = g_strdup(server->connrec->usermode);
} else {
+ conn->reconnection = TRUE;
conn->channels = irc_server_get_channels(server);
conn->away_reason = !server->usermode_away ? NULL :
g_strdup(server->away_reason);
@@ -213,7 +213,7 @@ static void sig_reconnect(IRC_SERVER_REC *server)
for (tmp = setupservers; tmp != NULL; ) {
SETUP_SERVER_REC *rec = tmp->data;
- if (!found && g_strcasecmp(rec->server, server->connrec->address) == 0 &&
+ if (!found && g_strcasecmp(rec->address, server->connrec->address) == 0 &&
server->connrec->port == rec->port)
found = TRUE;
else if (found && rec->ircnet != NULL && g_strcasecmp(conn->ircnet, rec->ircnet) == 0) {
@@ -286,24 +286,36 @@ static RECONNECT_REC *reconnect_find_tag(int tag)
}
/* Try to reconnect immediately */
-static void cmd_reconnect(const char *data)
+static void cmd_reconnect(const char *data, IRC_SERVER_REC *server)
{
IRC_SERVER_CONNECT_REC *conn;
RECONNECT_REC *rec;
+ char *str;
int tag;
+ if (*data == '\0') {
+ /* reconnect back to same server */
+ if (server == NULL) cmd_return_error(CMDERR_NOT_CONNECTED);
+ str = g_strdup_printf("%s %d %s %s", server->connrec->address,
+ server->connrec->port, server->connrec->password,
+ server->connrec->nick);
+ signal_emit("command server", 2, str, server);
+ g_free(str);
+ return;
+ }
+
if (g_strncasecmp(data, "RECON-", 6) == 0)
data += 6;
- rec = sscanf(data, "%d", &tag) == 1 && tag > 0 ?
- reconnect_find_tag(tag) : NULL;
+ tag = atoi(data);
+ rec = tag <= 0 ? NULL : reconnect_find_tag(tag);
if (rec == NULL)
signal_emit("server reconnect not found", 1, data);
else {
conn = rec->conn;
server_reconnect_destroy(rec, FALSE);
- irc_server_connect(rec->conn);
+ irc_server_connect(conn);
}
}
diff --git a/src/irc/core/server-setup.c b/src/irc/core/server-setup.c
index f56d839f..62c856cb 100644
--- a/src/irc/core/server-setup.c
+++ b/src/irc/core/server-setup.c
@@ -74,7 +74,7 @@ create_addr_conn(const char *address, int port, const char *password,
conn->realname = g_strdup(settings_get_str("real_name"));
/* proxy settings */
- if (settings_get_bool("toggle_use_ircproxy")) {
+ if (settings_get_bool("use_ircproxy")) {
conn->proxy = g_strdup(settings_get_str("proxy_address"));
conn->proxy_port = settings_get_int("proxy_port");
conn->proxy_string = g_strdup(settings_get_str("proxy_string"));
@@ -91,6 +91,25 @@ create_addr_conn(const char *address, int port, const char *password,
sserver = server_setup_find(address, -1);
if (sserver == NULL) return conn;
+ if (sserver->own_ip != NULL) {
+ /* use already resolved IP */
+ if (conn->own_ip == NULL)
+ conn->own_ip = g_new(IPADDR, 1);
+ memcpy(conn->own_ip, sserver->own_ip, sizeof(IPADDR));
+ } else if (sserver->own_host != NULL) {
+ /* resolve the IP and use it */
+ IPADDR ip;
+
+ if (net_gethostname(sserver->own_host, &ip) == 0) {
+ if (conn->own_ip == NULL)
+ conn->own_ip = g_new(IPADDR, 1);
+ memcpy(conn->own_ip, &ip, sizeof(IPADDR));
+
+ sserver->own_ip = g_new(IPADDR, 1);
+ memcpy(sserver->own_ip, &ip, sizeof(IPADDR));
+ }
+ }
+
sserver->last_connect = time(NULL);
if (sserver->ircnet) conn->ircnet = g_strdup(sserver->ircnet);
@@ -151,7 +170,7 @@ irc_server_create_conn(const char *dest, int port, const char *password, const c
continue;
if (n == 1 || !rec->last_failed || rec->last_connect < now-FAILED_RECONNECT_WAIT)
- return create_addr_conn(rec->server, port, password, nick);
+ return create_addr_conn(rec->address, port, password, nick);
}
}
@@ -168,7 +187,7 @@ SETUP_SERVER_REC *server_setup_find(const char *address, int port)
for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
SETUP_SERVER_REC *rec = tmp->data;
- if (g_strcasecmp(rec->server, address) == 0 &&
+ if (g_strcasecmp(rec->address, address) == 0 &&
(port == -1 || rec->port == port)) return rec;
}
@@ -223,19 +242,88 @@ static void init_userinfo(void)
iconfig_set_str("settings", "alternate_nick", str);
g_free(str);
}
+
+ /* host name */
+ set = settings_get_str("hostname");
+ if (set == NULL || *set == '\0') {
+ str = g_getenv("IRCHOST");
+ if (str != NULL) {
+ iconfig_set_str("settings", "hostname", str);
+ g_free(str);
+ }
+ }
+}
+
+void setupserver_config_add(SETUP_SERVER_REC *rec)
+{
+ CONFIG_NODE *node;
+
+ node = iconfig_node_traverse("(servers", TRUE);
+ node = config_node_section(node, NULL, NODE_TYPE_BLOCK);
+
+ config_node_set_str(node, "address", rec->address);
+ config_node_set_str(node, "ircnet", rec->ircnet);
+
+ config_node_set_int(node, "port", rec->port);
+ config_node_set_str(node, "password", rec->password);
+ config_node_set_str(node, "own_host", rec->own_host);
+
+ if (rec->autoconnect)
+ config_node_set_bool(node, "autoconnect", TRUE);
+
+ if (rec->max_cmds_at_once > 0)
+ config_node_set_int(node, "cmds_max_at_once", rec->max_cmds_at_once);
+ if (rec->cmd_queue_speed > 0)
+ config_node_set_int(node, "cmd_queue_speed", rec->cmd_queue_speed);
+}
+
+void setupserver_config_remove(SETUP_SERVER_REC *rec)
+{
+ CONFIG_NODE *node;
+
+ node = iconfig_node_traverse("servers", FALSE);
+ if (node != NULL) config_node_list_remove(node, g_slist_index(setupservers, rec));
+}
+
+static void setupserver_destroy(SETUP_SERVER_REC *rec)
+{
+ setupservers = g_slist_remove(setupservers, rec);
+
+ g_free_not_null(rec->own_host);
+ g_free_not_null(rec->own_ip);
+ g_free(rec->ircnet);
+ g_free(rec->address);
+ g_free(rec->password);
+ g_free(rec);
+}
+
+void server_setup_add(SETUP_SERVER_REC *rec)
+{
+ if (g_slist_find(setupservers, rec) != NULL) {
+ setupserver_config_remove(rec);
+ setupservers = g_slist_append(setupservers, rec);
+ }
+
+ setupservers = g_slist_append(setupservers, rec);
+ setupserver_config_add(rec);
}
-static SETUP_SERVER_REC *setupserver_add(CONFIG_NODE *node)
+void server_setup_remove(SETUP_SERVER_REC *rec)
+{
+ setupserver_config_remove(rec);
+ setupserver_destroy(rec);
+}
+
+static SETUP_SERVER_REC *setupserver_add_node(CONFIG_NODE *node)
{
SETUP_SERVER_REC *rec;
- char *ircnet, *server;
+ char *server;
int port;
g_return_val_if_fail(node != NULL, NULL);
- ircnet = config_node_get_str(node, "ircnet", NULL);
- server = config_node_get_str(node, "server", NULL);
- if (ircnet == NULL || server == NULL) return NULL;
+ server = config_node_get_str(node, "address", NULL);
+ if (server == NULL) return NULL;
port = config_node_get_int(node, "port", 6667);
if (server_setup_find(server, port) != NULL) {
@@ -245,28 +333,19 @@ static SETUP_SERVER_REC *setupserver_add(CONFIG_NODE *node)
}
rec = g_new0(SETUP_SERVER_REC, 1);
- rec->ircnet = g_strdup(ircnet);
- rec->server = g_strdup(server);
- rec->password = g_strdup(config_node_get_str(node, "password", ""));
+ rec->ircnet = g_strdup(config_node_get_str(node, "ircnet", NULL));
+ rec->address = g_strdup(server);
+ rec->password = g_strdup(config_node_get_str(node, "password", NULL));
rec->port = port;
rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE);
rec->max_cmds_at_once = config_node_get_int(node, "cmds_max_at_once", 0);
rec->cmd_queue_speed = config_node_get_int(node, "cmd_queue_speed", 0);
+ rec->own_host = g_strdup(config_node_get_str(node, "own_host", 0));
setupservers = g_slist_append(setupservers, rec);
return rec;
}
-static void setupserver_destroy(SETUP_SERVER_REC *rec)
-{
- setupservers = g_slist_remove(setupservers, rec);
-
- g_free(rec->ircnet);
- g_free(rec->server);
- g_free(rec->password);
- g_free(rec);
-}
-
static void read_servers(void)
{
CONFIG_NODE *node;
@@ -276,10 +355,10 @@ static void read_servers(void)
setupserver_destroy(setupservers->data);
/* Read servers */
- node = iconfig_node_traverse("(setupservers", FALSE);
+ node = iconfig_node_traverse("servers", FALSE);
if (node != NULL) {
for (tmp = node->value; tmp != NULL; tmp = tmp->next)
- setupserver_add(tmp->data);
+ setupserver_add_node(tmp->data);
}
}
@@ -290,14 +369,14 @@ void servers_setup_init(void)
settings_add_int("server", "server_reconnect_time", 300);
settings_add_str("server", "hostname", "");
- settings_add_bool("server", "toggle_skip_motd", FALSE);
+ settings_add_bool("server", "skip_motd", FALSE);
settings_add_str("server", "default_nick", NULL);
settings_add_str("server", "alternate_nick", NULL);
settings_add_str("server", "user_name", NULL);
settings_add_str("server", "real_name", NULL);
- settings_add_bool("ircproxy", "toggle_use_ircproxy", FALSE);
+ settings_add_bool("ircproxy", "use_ircproxy", FALSE);
settings_add_str("ircproxy", "proxy_address", "");
settings_add_int("ircproxy", "proxy_port", 6667);
settings_add_str("ircproxy", "proxy_string", "CONNECT %s %d");
diff --git a/src/irc/core/server-setup.h b/src/irc/core/server-setup.h
index a3a3d4ff..5c893044 100644
--- a/src/irc/core/server-setup.h
+++ b/src/irc/core/server-setup.h
@@ -5,7 +5,7 @@
/* servers */
typedef struct {
- char *server;
+ char *address;
int port;
char *ircnet;
@@ -14,8 +14,8 @@ typedef struct {
int max_cmds_at_once; /* override the default if > 0 */
int cmd_queue_speed; /* override the default if > 0 */
- char *own_address; /* address to use when connecting this server */
- IPADDR *own_ip; /* resolved own_address or full of zeros */
+ char *own_host; /* address to use when connecting this server */
+ IPADDR *own_ip; /* resolved own_address if not NULL */
time_t last_connect; /* to avoid reconnecting too fast.. */
int last_failed; /* if last connection attempt failed */
@@ -31,6 +31,9 @@ extern gboolean source_host_ok; /* Use source_host_ip .. */
IRC_SERVER_CONNECT_REC *
irc_server_create_conn(const char *dest, int port, const char *password, const char *nick);
+void server_setup_add(SETUP_SERVER_REC *rec);
+void server_setup_remove(SETUP_SERVER_REC *rec);
+
/* Find matching server from setup. Set port to -1 if you don't care about it */
SETUP_SERVER_REC *server_setup_find(const char *address, int port);
diff --git a/src/irc/dcc/Makefile.am b/src/irc/dcc/Makefile.am
index b7cd30e9..6e2b68c7 100644
--- a/src/irc/dcc/Makefile.am
+++ b/src/irc/dcc/Makefile.am
@@ -9,6 +9,4 @@ libirc_dcc_la_SOURCES = \
dcc-files.c
noinst_HEADERS = \
- dcc.h \
- dcc-chat.h \
- dcc-files.h
+ dcc.h
diff --git a/src/irc/dcc/dcc-chat.c b/src/irc/dcc/dcc-chat.c
index 5cddddfa..c01077d3 100644
--- a/src/irc/dcc/dcc-chat.c
+++ b/src/irc/dcc/dcc-chat.c
@@ -307,7 +307,7 @@ static void cmd_dcc_chat(gchar *data, IRC_SERVER_REC *server)
if (server == NULL || !server->connected)
cmd_return_error(CMDERR_NOT_CONNECTED);
- if (!net_getsockname(server->handle, &addr, NULL))
+ if (net_getsockname(server->handle, &addr, NULL) == -1)
cmd_return_error(CMDERR_GETSOCKNAME);
port = settings_get_int("dcc_port");
diff --git a/src/irc/dcc/dcc-chat.h b/src/irc/dcc/dcc-chat.h
deleted file mode 100644
index 9ae9503f..00000000
--- a/src/irc/dcc/dcc-chat.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __DCC_CHAT_H
-#define __DCC_CHAT_H
-
-void dcc_chat_init(void);
-void dcc_chat_deinit(void);
-
-#endif
diff --git a/src/irc/dcc/dcc-files.c b/src/irc/dcc/dcc-files.c
index 23b1cdce..da395196 100644
--- a/src/irc/dcc/dcc-files.c
+++ b/src/irc/dcc/dcc-files.c
@@ -432,7 +432,7 @@ static void dcc_send_init(DCC_REC *dcc)
g_source_remove(dcc->tagread);
close(dcc->handle);
- dcc->fastsend = settings_get_bool("toggle_dcc_fast_send");
+ dcc->fastsend = settings_get_bool("dcc_fast_send");
dcc->handle = handle;
memcpy(&dcc->addr, &addr, sizeof(IPADDR));
net_ip2host(&dcc->addr, dcc->addrstr);
diff --git a/src/irc/dcc/dcc-files.h b/src/irc/dcc/dcc-files.h
deleted file mode 100644
index 3d12ffc1..00000000
--- a/src/irc/dcc/dcc-files.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __DCC_FILES_H
-#define __DCC_FILES_H
-
-void dcc_files_init(void);
-void dcc_files_deinit(void);
-
-#endif
diff --git a/src/irc/dcc/dcc.c b/src/irc/dcc/dcc.c
index 41833744..1c02e65a 100644
--- a/src/irc/dcc/dcc.c
+++ b/src/irc/dcc/dcc.c
@@ -30,6 +30,12 @@
#include "dcc.h"
+void dcc_chat_init(void);
+void dcc_chat_deinit(void);
+
+void dcc_files_init(void);
+void dcc_files_deinit(void);
+
#define DCC_TYPES 5
static gchar *dcc_types[] =
@@ -55,7 +61,7 @@ DCC_REC *dcc_create(gint type, gint handle, gchar *nick, gchar *arg, IRC_SERVER_
dcc = g_new0(DCC_REC, 1);
dcc->type = type == DCC_TYPE_CHAT ? module_get_uniq_id("IRC", WI_IRC_DCC_CHAT) : -1;
- dcc->mirc_ctcp = settings_get_bool("toggle_dcc_mirc_ctcp");
+ dcc->mirc_ctcp = settings_get_bool("dcc_mirc_ctcp");
dcc->created = time(NULL);
dcc->chat = chat;
dcc->dcc_type = type;
@@ -307,7 +313,7 @@ static void dcc_ctcp_msg(gchar *data, IRC_SERVER_REC *server, gchar *sender, gch
case DCC_TYPE_GET:
cstr = settings_get_str("dcc_autoget_masks");
/* check that autoget masks match */
- if (settings_get_bool("toggle_dcc_autoget") && (*cstr == '\0' || irc_masks_match(cstr, sender, sendaddr)) &&
+ if (settings_get_bool("dcc_autoget") && (*cstr == '\0' || irc_masks_match(cstr, sender, sendaddr)) &&
/* check file size limit, FIXME: it's possible to send a bogus file size and then just send what ever sized file.. */
(settings_get_int("dcc_max_autoget_size") <= 0 || (settings_get_int("dcc_max_autoget_size") > 0 && size <= settings_get_int("dcc_max_autoget_size")*1024)))
{
@@ -507,19 +513,19 @@ void dcc_init(void)
dcc_conns = NULL;
dcc_timeouttag = g_timeout_add(1000, (GSourceFunc) dcc_timeout_func, NULL);
- settings_add_bool("dcc", "toggle_dcc_autorename", FALSE);
- settings_add_bool("dcc", "toggle_dcc_autogete", FALSE);
+ settings_add_bool("dcc", "dcc_autorename", FALSE);
+ settings_add_bool("dcc", "dcc_autoget", FALSE);
settings_add_int("dcc", "dcc_max_autoget_size", 1000);
settings_add_str("dcc", "dcc_download_path", "~");
settings_add_int("dcc", "dcc_file_create_mode", 644);
settings_add_str("dcc", "dcc_autoget_masks", "");
settings_add_str("dcc", "dcc_autochat_masks", "");
- settings_add_bool("dcc", "toggle_dcc_fast_send", TRUE);
+ settings_add_bool("dcc", "dcc_fast_send", TRUE);
settings_add_str("dcc", "dcc_upload_path", "~");
- settings_add_bool("dcc", "toggle_dcc_mirc_ctcp", FALSE);
- settings_add_bool("dcc", "toggle_dcc_autodisplay_dialog", TRUE);
+ settings_add_bool("dcc", "dcc_mirc_ctcp", FALSE);
+ settings_add_bool("dcc", "dcc_autodisplay_dialog", TRUE);
settings_add_int("dcc", "dcc_block_size", 2048);
settings_add_int("dcc", "dcc_port", 0);
settings_add_int("dcc", "dcc_timeout", 300);
@@ -531,10 +537,16 @@ void dcc_init(void)
command_bind("dcc", NULL, (SIGNAL_FUNC) cmd_dcc);
command_bind("dcc close", NULL, (SIGNAL_FUNC) cmd_dcc_close);
signal_add("event 401", (SIGNAL_FUNC) event_no_such_nick);
+
+ dcc_chat_init();
+ dcc_files_init();
}
void dcc_deinit(void)
{
+ dcc_chat_deinit();
+ dcc_files_deinit();
+
signal_remove("server connected", (SIGNAL_FUNC) dcc_server_connected);
signal_remove("server disconnected", (SIGNAL_FUNC) dcc_server_disconnected);
signal_remove("ctcp reply dcc", (SIGNAL_FUNC) dcc_ctcp_reply);
diff --git a/src/irc/flood/autoignore.c b/src/irc/flood/autoignore.c
index 528ac618..da384dd9 100644
--- a/src/irc/flood/autoignore.c
+++ b/src/irc/flood/autoignore.c
@@ -217,11 +217,11 @@ int autoignore_remove(IRC_SERVER_REC *server, const char *mask, int level)
return FALSE;
}
-static void sig_flood(IRC_SERVER_REC *server, const char *nick, const char *host, const char *levelstr)
+static void sig_flood(IRC_SERVER_REC *server, const char *nick, const char *host, gpointer levelp)
{
int level, check_level;
- level = level2bits(levelstr);
+ level = GPOINTER_TO_INT(levelp);
check_level = level2bits(settings_get_str("autoignore_levels"));
if (level & check_level)
diff --git a/src/irc/flood/flood.c b/src/irc/flood/flood.c
index 5522243e..7fb4773d 100644
--- a/src/irc/flood/flood.c
+++ b/src/irc/flood/flood.c
@@ -1,8 +1,7 @@
/*
+ flood.c : Flood protection
- flood.c : Flood protection (see also ctcp.c)
-
- Copyright (C) 1999 Timo Sirainen
+ Copyright (C) 1999-2000 Timo Sirainen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -32,36 +31,59 @@
#include "ignore.h"
typedef struct {
- char *nick;
+ char *target;
int level;
+
int msgcount;
+ time_t first;
+} FLOOD_ITEM_REC;
+
+typedef struct {
+ char *nick;
+ GSList *items;
} FLOOD_REC;
static int flood_tag;
-static int flood_max_msgs;
+static int flood_max_msgs, flood_timecheck;
-static int flood_hash_deinit(const char *key, FLOOD_REC *rec)
+static int flood_hash_deinit(const char *key, FLOOD_REC *flood, gpointer nowp)
{
+ GSList *tmp, *next;
+ time_t now;
+
g_return_val_if_fail(key != NULL, FALSE);
- g_return_val_if_fail(rec != NULL, FALSE);
+ g_return_val_if_fail(flood != NULL, FALSE);
+
+ now = (time_t) GPOINTER_TO_INT(nowp);
+ for (tmp = flood->items; tmp != NULL; tmp = next) {
+ FLOOD_ITEM_REC *rec = tmp->data;
- g_free(rec->nick);
- g_free(rec);
+ next = tmp->next;
+ if (now-rec->first >= flood_timecheck)
+ flood->items = g_slist_remove(flood->items, rec);
+ }
+
+ if (flood->items != NULL)
+ return FALSE;
+
+ g_free(flood->nick);
+ g_free(flood);
return TRUE;
}
-/* timeout function: flood protection */
static int flood_timeout(void)
{
MODULE_SERVER_REC *mserver;
GSList *tmp;
+ time_t now;
- /* remove everyone from flood list */
+ /* remove the old people from flood lists */
+ now = time(NULL);
for (tmp = servers; tmp != NULL; tmp = tmp->next) {
IRC_SERVER_REC *rec = tmp->data;
mserver = MODULE_DATA(rec);
- g_hash_table_foreach_remove(mserver->floodlist, (GHRFunc) flood_hash_deinit, NULL);
+ g_hash_table_foreach_remove(mserver->floodlist, (GHRFunc) flood_hash_deinit, GINT_TO_POINTER((int) now));
}
return 1;
}
@@ -88,6 +110,8 @@ static void flood_deinit_server(IRC_SERVER_REC *server)
mserver = MODULE_DATA(server);
if (mserver != NULL && mserver->floodlist != NULL) {
+ flood_timecheck = 0;
+
g_hash_table_freeze(mserver->floodlist);
g_hash_table_foreach(mserver->floodlist, (GHFunc) flood_hash_deinit, NULL);
g_hash_table_thaw(mserver->floodlist);
@@ -96,34 +120,55 @@ static void flood_deinit_server(IRC_SERVER_REC *server)
g_free(mserver);
}
+static FLOOD_ITEM_REC *flood_find(FLOOD_REC *flood, int level, const char *target)
+{
+ GSList *tmp;
+
+ for (tmp = flood->items; tmp != NULL; tmp = tmp->next) {
+ FLOOD_ITEM_REC *rec = tmp->data;
+
+ if (rec->level == level && g_strcasecmp(rec->target, target) == 0)
+ return rec;
+ }
+
+ return NULL;
+}
+
/* All messages should go through here.. */
static void flood_newmsg(IRC_SERVER_REC *server, int level, const char *nick, const char *host, const char *target)
{
MODULE_SERVER_REC *mserver;
- FLOOD_REC *rec;
- char *levelstr;
+ FLOOD_REC *flood;
+ FLOOD_ITEM_REC *rec;
g_return_if_fail(server != NULL);
g_return_if_fail(nick != NULL);
mserver = MODULE_DATA(server);
- rec = g_hash_table_lookup(mserver->floodlist, nick);
+ flood = g_hash_table_lookup(mserver->floodlist, nick);
+
+ rec = flood == NULL ? NULL : flood_find(flood, level, target);
if (rec != NULL) {
if (++rec->msgcount > flood_max_msgs) {
/* flooding! */
- levelstr = bits2level(rec->level);
- signal_emit("flood", 5, server, nick, host, levelstr, target);
- g_free(levelstr);
+ signal_emit("flood", 5, server, nick, host, GINT_TO_POINTER(rec->level), target);
}
return;
}
- rec = g_new(FLOOD_REC, 1);
+ if (flood == NULL) {
+ flood = g_new0(FLOOD_REC, 1);
+ flood->nick = g_strdup(nick);
+ g_hash_table_insert(mserver->floodlist, flood->nick, flood);
+ }
+
+ rec = g_new0(FLOOD_ITEM_REC, 1);
rec->level = level;
+ rec->first = time(NULL);
rec->msgcount = 1;
- rec->nick = g_strdup(nick);
+ rec->target = g_strdup(target);
- g_hash_table_insert(mserver->floodlist, rec->nick, rec);
+ flood->items = g_slist_append(flood->items, rec);
}
static void flood_privmsg(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr)
@@ -141,7 +186,7 @@ static void flood_privmsg(const char *data, IRC_SERVER_REC *server, const char *
params = event_get_params(data, 2, &target, &text);
- if (*text == 1) {
+ if (*text == 1 && g_strncasecmp(text+1, "ACTION", 6) != 0) {
/* CTCP */
if (!ignore_check(server, nick, addr, target, text, MSGLEVEL_CTCPS))
flood_newmsg(server, MSGLEVEL_CTCPS, nick, addr, target);
@@ -176,24 +221,37 @@ static void flood_notice(const char *data, IRC_SERVER_REC *server, const char *n
static void read_settings(void)
{
- if (flood_tag != -1) g_source_remove(flood_tag);
- flood_tag = g_timeout_add(settings_get_int("flood_timecheck"), (GSourceFunc) flood_timeout, NULL);
+ int time;
+ flood_timecheck = settings_get_int("flood_timecheck");
flood_max_msgs = settings_get_int("flood_max_msgs");
+
+ time = flood_timecheck > 500 ? 500 :
+ (flood_timecheck > 0 && flood_timecheck < 100) ? 100 :
+ flood_timecheck;
+
+ if (flood_tag != -1) {
+ g_source_remove(flood_tag);
+ flood_tag = -1;
+ }
+
+ if (time > 0 && flood_max_msgs > 0) {
+ flood_tag = g_timeout_add(time, (GSourceFunc) flood_timeout, NULL);
+ signal_add("event privmsg", (SIGNAL_FUNC) flood_privmsg);
+ signal_add("event notice", (SIGNAL_FUNC) flood_notice);
+ }
}
void flood_init(void)
{
- settings_add_int("flood", "flood_timecheck", 1000);
- settings_add_int("flood", "flood_max_msgs", 5);
+ settings_add_int("flood", "flood_timecheck", 5000);
+ settings_add_int("flood", "flood_max_msgs", 4);
flood_tag = -1;
read_settings();
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
signal_add_first("server connected", (SIGNAL_FUNC) flood_init_server);
signal_add("server disconnected", (SIGNAL_FUNC) flood_deinit_server);
- signal_add("event privmsg", (SIGNAL_FUNC) flood_privmsg);
- signal_add("event notice", (SIGNAL_FUNC) flood_notice);
autoignore_init();
}
@@ -202,11 +260,13 @@ void flood_deinit(void)
{
autoignore_deinit();
- if (flood_tag != -1) g_source_remove(flood_tag);
+ if (flood_tag != -1) {
+ g_source_remove(flood_tag);
+ signal_remove("event privmsg", (SIGNAL_FUNC) flood_privmsg);
+ signal_remove("event notice", (SIGNAL_FUNC) flood_notice);
+ }
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
signal_remove("server connected", (SIGNAL_FUNC) flood_init_server);
signal_remove("server disconnected", (SIGNAL_FUNC) flood_deinit_server);
- signal_remove("event privmsg", (SIGNAL_FUNC) flood_privmsg);
- signal_remove("event notice", (SIGNAL_FUNC) flood_notice);
}
diff --git a/src/irc/notifylist/notify-commands.c b/src/irc/notifylist/notify-commands.c
index 9ae5a076..af022dcd 100644
--- a/src/irc/notifylist/notify-commands.c
+++ b/src/irc/notifylist/notify-commands.c
@@ -42,7 +42,7 @@ static void cmd_notify(gchar *data)
if (stristr(args, "-idle") == NULL)
idle_check_time = 0;
else {
- idle_check_time = is_numeric(idletime, 0) ? (atol(idletime)*60) :
+ idle_check_time = is_numeric(idletime, 0) ? (atoi(idletime)*60) :
(settings_get_int("notify_idle_time")*60);
}
diff --git a/src/irc/notifylist/notify-whois.c b/src/irc/notifylist/notify-whois.c
index 439a8af8..c8191b57 100644
--- a/src/irc/notifylist/notify-whois.c
+++ b/src/irc/notifylist/notify-whois.c
@@ -78,7 +78,7 @@ static void event_whois_idle(const char *data, IRC_SERVER_REC *server)
g_return_if_fail(data != NULL);
params = event_get_params(data, 3, NULL, &nick, &secstr);
- secs = atol(secstr);
+ secs = atoi(secstr);
notify = notifylist_find(nick, server->connrec->ircnet);
nickrec = notify_nick_find(server, nick);
diff --git a/src/perl/irssi-perl.c b/src/perl/irssi-perl.c
index 49373684..e4f616e9 100644
--- a/src/perl/irssi-perl.c
+++ b/src/perl/irssi-perl.c
@@ -68,7 +68,9 @@ static void perl_signal_destroy(PERL_SIGNAL_REC *rec)
{
GHashTable *table;
GSList *siglist;
- void *signal_idp;
+ void *signal_idp;
+
+ g_return_if_fail(rec != NULL);
table = rec->last ? last_signals : first_signals;
signal_idp = GINT_TO_POINTER(rec->signal_id);
@@ -138,13 +140,14 @@ static void irssi_perl_start(void)
static void signal_destroy_hash(void *key, GSList *list)
{
- GSList *next;
-
while (list != NULL) {
- next = list->next;
+ PERL_SIGNAL_REC *rec = list->data;
+
+ list = g_slist_remove(list, rec);
- perl_signal_destroy(list->data);
- list = next;
+ g_free(rec->signal);
+ g_free(rec->func);
+ g_free(rec);
}
}
@@ -154,6 +157,17 @@ static void irssi_perl_stop(void)
g_hash_table_destroy(first_signals);
g_hash_table_foreach(last_signals, (GHFunc) signal_destroy_hash, NULL);
g_hash_table_destroy(last_signals);
+ first_signals = last_signals = NULL;
+
+ if (signal_grabbed) {
+ signal_grabbed = FALSE;
+ signal_remove("signal", (SIGNAL_FUNC) sig_signal);
+ }
+
+ if (siglast_grabbed) {
+ siglast_grabbed = FALSE;
+ signal_remove("last signal", (SIGNAL_FUNC) sig_lastsignal);
+ }
while (perl_timeouts != NULL)
perl_timeout_destroy(perl_timeouts->data);
@@ -222,12 +236,37 @@ static void cmd_flush(const char *data)
irssi_perl_start();
}
+static int perl_signal_find(const char *signal, const char *func, int last)
+{
+ GHashTable *table;
+ GSList *siglist;
+ int signal_id;
+
+ table = last ? last_signals : first_signals;
+
+ signal_id = module_get_uniq_id_str("signals", signal);
+ siglist = g_hash_table_lookup(table, GINT_TO_POINTER(signal_id));
+
+ while (siglist != NULL) {
+ PERL_SIGNAL_REC *rec = siglist->data;
+
+ if (strcmp(rec->func, func) == 0)
+ return TRUE;
+ siglist = siglist->next;
+ }
+
+ return FALSE;
+}
+
static void perl_signal_to(const char *signal, const char *func, int last)
{
PERL_SIGNAL_REC *rec;
GHashTable *table;
GSList *siglist;
- void *signal_idp;
+ void *signal_idp;
+
+ if (perl_signal_find(signal, func, last))
+ return;
rec = g_new(PERL_SIGNAL_REC, 1);
rec->signal_id = module_get_uniq_id_str("signals", signal);
diff --git a/src/perl/xs/Irssi-core.xs b/src/perl/xs/Irssi-core.xs
index b7cdcb6d..324637ae 100644
--- a/src/perl/xs/Irssi-core.xs
+++ b/src/perl/xs/Irssi-core.xs
@@ -88,8 +88,18 @@ command_bind(cmd, category, func)
char *func
CODE:
char *signal;
+ GSList *tmp;
- command_bind(cmd, *category ? category : "Perl scripts' commands", NULL);
+ /* Don't add the command twice */
+ if (*category == '\0') category = "Perl scripts' commands";
+ for (tmp = commands; tmp != NULL; tmp = tmp->next) {
+ COMMAND_REC *rec = tmp->data;
+
+ if (g_strcasecmp(rec->cmd, cmd) == 0 &&
+ g_strcasecmp(rec->category, category) == 0)
+ break;
+ }
+ if (tmp == NULL) command_bind(cmd, category, NULL);
signal = g_strconcat("command ", cmd, NULL);
perl_signal_add(signal, func);
g_free(signal);
@@ -101,7 +111,6 @@ command_unbind(cmd, func)
CODE:
char *signal;
- command_unbind(cmd, NULL);
signal = g_strconcat("command ", cmd, NULL);
perl_signal_remove(signal, func);
g_free(signal);
diff --git a/src/perl/xs/Irssi-netsplit.xs b/src/perl/xs/Irssi-netsplit.xs
index 0c1e998f..428cb61a 100644
--- a/src/perl/xs/Irssi-netsplit.xs
+++ b/src/perl/xs/Irssi-netsplit.xs
@@ -22,13 +22,30 @@ void
values(netsplit)
Irssi::Netsplit netsplit
PREINIT:
- HV *hv;
+ HV *hv, *stash;
PPCODE:
hv = newHV();
hv_store(hv, "nick", 4, new_pv(netsplit->nick), 0);
hv_store(hv, "address", 7, new_pv(netsplit->address), 0);
- hv_store(hv, "server", 6, new_pv(netsplit->server), 0);
- hv_store(hv, "destserver", 10, new_pv(netsplit->destserver), 0);
hv_store(hv, "destroy", 7, newSViv(netsplit->destroy), 0);
+
+ stash = gv_stashpv("Irssi::Netsplitserver", 0);
+ hv_store(hv, "server", 6, sv_bless(newRV_noinc(newSViv(GPOINTER_TO_INT(netsplit->server))), stash), 0);
/*FIXME: add GSList *channels;*/
XPUSHs(sv_2mortal(newRV_noinc((SV*)hv)));
+
+#*******************************
+MODULE = Irssi PACKAGE = Irssi::Netsplitserver
+#*******************************
+
+void
+values(rec)
+ Irssi::Netsplitserver rec
+PREINIT:
+ HV *hv;
+PPCODE:
+ hv = newHV();
+ hv_store(hv, "server", 6, new_pv(rec->server), 0);
+ hv_store(hv, "destserver", 10, new_pv(rec->destserver), 0);
+ hv_store(hv, "count", 5, newSViv(rec->count), 0);
+ XPUSHs(sv_2mortal(newRV_noinc((SV*)hv)));
diff --git a/src/perl/xs/Irssi-server.xs b/src/perl/xs/Irssi-server.xs
index 326b8d99..f53527ec 100644
--- a/src/perl/xs/Irssi-server.xs
+++ b/src/perl/xs/Irssi-server.xs
@@ -53,7 +53,7 @@ void
values(server)
Irssi::Server server
PREINIT:
- HV *hv, *stash;
+ HV *hv;
char *type;
PPCODE:
type = "IRC";
diff --git a/src/perl/xs/module.h b/src/perl/xs/module.h
index 350f3de0..3a55f787 100644
--- a/src/perl/xs/module.h
+++ b/src/perl/xs/module.h
@@ -44,6 +44,7 @@ typedef RECONNECT_REC *Irssi__Reconnect;
typedef NICK_REC *Irssi__Nick;
typedef BAN_REC *Irssi__Ban;
typedef NETSPLIT_REC *Irssi__Netsplit;
+typedef NETSPLIT_SERVER_REC *Irssi__Netsplitserver;
typedef IGNORE_REC *Irssi__Ignore;
typedef DCC_REC *Irssi__Dcc;
diff --git a/src/perl/xs/typemap b/src/perl/xs/typemap
index 0e61ce06..5173ebe4 100644
--- a/src/perl/xs/typemap
+++ b/src/perl/xs/typemap
@@ -9,6 +9,7 @@ Irssi::Nick T_PTROBJ
Irssi::Ban T_PTROBJ
Irssi::Dcc T_PTROBJ
Irssi::Netsplit T_PTROBJ
+Irssi::Netsplitserver T_PTROBJ
Irssi::Autoignore T_PTROBJ
Irssi::Log T_PTROBJ
Irssi::Rawlog T_PTROBJ