Some biographical details here.


Published:

IRSSI + XMPP + OTR on FreeBSD

Yesterday evening I found myself wanting to consolidate some of the services I used for online chat sessions. Typically, I am on a desktop environment with numerous applications running, but I always end up using my terminal client most. So, I decided to move everything I could into the terminal.

I know about Bitlbee, but I wanted to stay away from it for now. I decided to keep everything in irssi and get my Gtalk session and OTR plugged into it for every day use.

I am running FreeBSD 9.2-RELEASE currently on my personal shell server, so these instructions will be for anyone looking to get irssi + xmpp + OTR installed on FreeBSD using the current ports available.

Installation

First, we need to install irssi with the plugins we believe are necessary. I always start with irssi-fish because I often find myself using blowfish encryption in certain chat channels.

Locate the port for irssi-fish within our ports directive, enter it's directory and compile it.

[[email protected] ~]$ find /usr/ports -name "irssi-fish"
/usr/ports/irc/irssi-fish
[[email protected] ~]$ cd /usr/ports/irc/ircci-fish && make install clean

Next, we want to compile XMPP for irssi, which we can do via ports as well. We follow the same procedure, locate it within our ports collection, enter it's directory and compile.

[[email protected] /usr/ports/irc/irssi-fish]$ find /usr/ports -name "xmpp"
/usr/ports/irc/irssi-xmpp
[[email protected] /usr/ports/irc/irssi-fish]$ cd ../../irssi-xmpp && make install clean

Because we were already in /usr/ports/irc/irssi-fish we just went up two spots in our directory tree and entered irssi-xmpp, hence the ../../.

Now that we have irssi-fish and irssi-xmpp compiled, it is time to compile irssi-otr. We follow the same procedure, but this time I am not going to show you how to find the port or how to cd. You should get that by now.

[[email protected] /usr/ports/irc/irssi-otr]$ make install clean

It is now compiled and we are good to go on software. Let's get everything configured.

Configure IRSSI

Configuring irssi is very easy. When you launch irssi for the first time, it will create a folder within your ~ (home directory) named .irssi/ which is where it stores all of its configuration, themes, plugins, etc.

[[email protected] ~]$ irssi

Once irssi is open, just type /save and then /quit to close it again. We just wanted to create the appropriate directory structure and config file.

[[email protected] ~]$ cd ~/.irssi
[[email protected] ~/.irssi]$ ls
config          config.autosave default.theme   otr             startup  

You may not see all of the same files I have in my ~/.irssi folder, but you should have config. That is the file we care to modify for now. Open it with your favorite editor (vim, vi, nano, whatever..)

~/.irssi/config explanation

The top of this configuration file contains an object block named servers which are the individual servers that make up specific chat networks. You should see something similar to:

servers = (  
  {
    address = "irc.efnet.org";
    chatnet = "EFNet";
    port = "6667";
    autoconnect = "yes";
  },
  { address = "irc.synirc.net"; chatnet = "SynIRC"; port = "6667"; autoconnect = "no"; },

Typically, irssi loads your config up with most of the major networks, EFNet, Dalnet, Undernet, FreeNode, QuakeNet, etc.. Since I do not use most of these networks, I remove them. I keep EFNet, SynIRC and some private IRCDs that I connect to every day. The format should be fairly self-explanatory. If you need to add additional ircds, do so now. But keep note of the chatnet you associate it with, because you will need this next.

The next section of the irssi config file belongs to chatnets, which is a blog that outlines an actual network and some properties for your client to use. It will look similar to:

chatnets = {  
  EFNet = {
    type = "IRC";
    max_kicks = "4";
    max_msgs = "3";
    max_whois = "1";
  };
  SynIRC = {
    type = "IRC";
    max_kicks = "4";
    max_msgs = "3";
    max_whois = "30";
  };
};

You should have a block for each Chatnet you created in the servers section of the configuration. The rest of the configuration file consists of a bit of themeing, colors, core settings, module settings, etc. I may go into those later, but for now we are going to save this config and open irssi again to load it. Once we load it up, we will quit irssi again. Just checking to make sure there are not any errors in our syntax.

You might discover an issue with your servers block or chatnets block, but this is likely due to a missing , or misplaced ;. As a heads up, your servers segment should have { }, wrapping each server and the last one should not contain a ,. As for the chatnets section, each network block (Efnet, Synirc, Etc) should be wrapped in { }; and make sure it ends with a ;. These entries are not comma delimited.

Adding OTR and XMPP to irssi

Now that you verified your config is okay, it is time to add the modules for OTR (off-the-record) and XMPP (Jabber) that will allow us to use Google Talk for chat.

Open your config file for irssi again.

First, we will be adding a server block for Gtalk:

{
    address = "talk.google.com";
    use_ssl = "yes";
    chatnet = "Gtalk";
    password = "";
    autoconnect = "yes";
  }

Then, we need to create a chatnet for gtalk:

Gtalk = { type = "XMPP"; nick = "[email protected]"; };

Personally, I do not like notifying other google talk users that I am writing them a message. You know, that silly pencil that pops up in their GUI and tells them we are composing something. So, I am going to disable it. If you would like to disable it as well, scroll down in your config until you find the settings = { block.

After "fe-text" = { actlist_sort ="refum"; }; add:

 "fe-common/xmpp" = {
    xmpp_status_window = "yes";
    xmpp_send_composing = "no";
  };
  "xmpp/core" = { xmpp_set_nick_as_username = "yes"; };

Let's create a status window within irssi for Gtalk as well. After your current settings block ends, add this:

windows = {  
  1 = {
    immortal = "yes";
    name = "(Status)";
    level = "ALL";
    sticky = "yes";
  };
  2 = { sticky = "yes"; name = "(Gtalk)"; parent = "1"; };

That will create a window (1) for Status and (2) for Gtalk status. You will see what I mean once you're in irssi again. To give you an idea of what my entire ~/.irssi/config looks like, here you go:

servers = (  
  {
    address = "irc.efnet.org";
    chatnet = "EFNet";
    port = "6667";
    autoconnect = "yes";
  },
  {
    address = "talk.google.com";
    use_ssl = "yes";
    chatnet = "Gtalk";
    password = "##PASSWORD##";
    autoconnect = "yes";
  }
);

chatnets = {  
  EFNet = {
    type = "IRC";
    max_kicks = "4";
    max_msgs = "3";
    max_whois = "1";
  };
  Gtalk = { type = "XMPP"; nick = "[email protected]"; };
};

channels = (  
  { name = "#fbsd"; chatnet = "EFNet"; autojoin = "yes"; },
);

aliases = {  
  J = "join";
  WJOIN = "join -window";
  WQUERY = "query -window";
  LEAVE = "part";
  BYE = "quit";
  EXIT = "quit";
  SIGNOFF = "quit";
  DESCRIBE = "action";
  DATE = "time";
  HOST = "userhost";
  LAST = "lastlog";
  SAY = "msg *";
  WI = "whois";
  WII = "whois $0 $0";
  WW = "whowas";
  W = "who";
  N = "names";
  M = "msg";
  T = "topic";
  C = "clear";
  CL = "clear";
  K = "kick";
  KB = "kickban";
  KN = "knockout";
  BANS = "ban";
  B = "ban";
  MUB = "unban *";
  UB = "unban";
  IG = "ignore";
  UNIG = "unignore";
  SB = "scrollback";
  UMODE = "mode $N";
  WC = "window close";
  WN = "window new hide";
  SV = "say Irssi $J ($V) - http://irssi.org/";
  GOTO = "sb goto";
  CHAT = "dcc chat";
  RUN = "SCRIPT LOAD";
  CALC = "exec - if command -v bc >/dev/null 2>&1\\; then printf '%s=' '$*'\\; echo '$*' | bc -l\\; else echo bc was not found\\; fi";
  SBAR = "STATUSBAR";
  INVITELIST = "mode $C +I";
  Q = "QUERY";
  "MANUAL-WINDOWS" = "set use_status_window off;set autocreate_windows off;set autocreate_query_level none;set autoclose_windows off;set reuse_unused_windows on;save";
  EXEMPTLIST = "mode $C +e";
  ATAG = "WINDOW SERVER";
  UNSET = "set -clear";
  RESET = "set -default";
};

statusbar = {  
  # formats:
  # when using {templates}, the template is shown only if it's argument isn't
  # empty unless no argument is given. for example {sb} is printed always,
  # but {sb $T} is printed only if $T isn't empty.

  items = {
    # start/end text in statusbars
    barstart = "{sbstart}";
    barend = "{sbend}";

    topicbarstart = "{topicsbstart}";
    topicbarend = "{topicsbend}";

    # treated "normally", you could change the time/user name to whatever
    time = "{sb $Z}";
    user = "{sb {sbnickmode $cumode}$N{sbmode $usermode}{sbaway $A}}";

    # treated specially .. window is printed with non-empty windows,
    # window_empty is printed with empty windows
    window = "{sb $winref:$tag/$itemname{sbmode $M}}";
    window_empty = "{sb $winref{sbservertag $tag}}";
    prompt = "{prompt $[.15]itemname}";
    prompt_empty = "{prompt $winname}";
    topic = " $topic";
    topic_empty = " Irssi v$J - http://www.irssi.org";

    # all of these treated specially, they're only displayed when needed
    lag = "{sb Lag: $0-}";
    act = "{sb Act: $0-}";
    more = "-- more --";
  };

  # there's two type of statusbars. root statusbars are either at the top
  # of the screen or at the bottom of the screen. window statusbars are at
  # the top/bottom of each split window in screen.
  default = {
    # the "default statusbar" to be displayed at the bottom of the window.
    # contains all the normal items.
    window = {
      disabled = "no";

      # window, root
      type = "window";
      # top, bottom
      placement = "bottom";
      # number
      position = "1";
      # active, inactive, always
      visible = "active";

      # list of items in statusbar in the display order
      items = {
        barstart = { priority = "100"; };
        time = { };
        user = { };
        window = { };
        window_empty = { };
        lag = { priority = "-1"; };
        act = { priority = "10"; };
        more = { priority = "-1"; alignment = "right"; };
        barend = { priority = "100"; alignment = "right"; };
      };
    };

    # statusbar to use in inactive split windows
    window_inact = {
      type = "window";
      placement = "bottom";
      position = "1";
      visible = "inactive";
      items = {
        barstart = { priority = "100"; };
        window = { };
        window_empty = { };
        more = { priority = "-1"; alignment = "right"; };
        barend = { priority = "100"; alignment = "right"; };
      };
    };

    # we treat input line as yet another statusbar :) It's possible to
    # add other items before or after the input line item.
    prompt = {
      type = "root";
      placement = "bottom";
      # we want to be at the bottom always
      position = "100";
      visible = "always";
      items = {
        prompt = { priority = "-1"; };
        prompt_empty = { priority = "-1"; };
        # treated specially, this is the real input line.
        input = { priority = "10"; };
      };
    };

    # topicbar
    topic = {
      type = "root";
      placement = "top";
      position = "1";
      visible = "always";
      items = {
        topicbarstart = { priority = "100"; };
        topic = { };
        topic_empty = { };
        topicbarend = { priority = "100"; alignment = "right"; };
      };
    };
  };
};
settings = {  
  core = {
    real_name = "You Dont Know Shat";
    user_name = "shat";
    nick = "shat";
    hostname = "akamai.us.com";
  };
  "fe-common/core" = {
      autolog = "yes";
    autolog_path = "~/irclogs/$tag/$0-%m%y.log";
    show_nickmod_empty = "yes";
    theme = "default";
  };
  "fe-text" = { actlist_sort = "refnum"; colors = "yes"; autostick_split_windows = "yes"; };
  "fe-common/xmpp" = {
    xmpp_status_window = "yes";
    xmpp_send_composing = "no";
  };
  "xmpp/core" = { xmpp_set_nick_as_username = "yes"; };
  "irc/core" = { cmd_queue_speed = "1msec"; };
};
logs = { };  
ignores = ( );  
keyboard = (  
  { key = "meta-1"; id = "change_window"; data = "1"; },
  { key = "meta-2"; id = "change_window"; data = "2"; },
  { key = "meta-3"; id = "change_window"; data = "3"; },
  { key = "meta-4"; id = "change_window"; data = "4"; },
  { key = "meta-5"; id = "change_window"; data = "5"; },
  { key = "meta-6"; id = "change_window"; data = "6"; },
  { key = "meta-7"; id = "change_window"; data = "7"; },
  { key = "meta-8"; id = "change_window"; data = "8"; },
  { key = "meta-9"; id = "change_window"; data = "9"; },
  { key = "meta-0"; id = "change_window"; data = "10"; }
);

windows = {  
  1 = {
    immortal = "yes";
    name = "(Status)";
    level = "ALL";
    sticky = "yes";
  };
  2 = { sticky = "yes"; name = "(Gtalk)"; parent = "1"; };
};

You will notice I have some additional settings that I did not explain to you. I might explain them later. For now, let us move on. Save your config and return to your ~/.irssi path.

Automatically load XMPP & OTR on launch of irssi.

Next, we want to inform irssi to launch xmpp and otr everytime we launch irssi. Do do this, we need to create and edit a file named startup within our ~/.irssi path.

The contents of startup should just be:

load xmpp  
load otr  

Now, launch irssi and you should see two new windows launched per our defining them above. Use your ALT modifier + the window number to switch windows or type /window next or /window previous to switch between them.

The only tasks left is to generate our key to be used with this instance of OTR. Within irssi type: /otr genkey [email protected] and it will begin the key generation process. It can take a few seconds to a minute, so be patient.

if you have any questions about how to use OTR or xmpp within irssi you can check out: