diff --git a/README b/README new file mode 100644 index 0000000..2fa3013 --- /dev/null +++ b/README @@ -0,0 +1,29 @@ +Woozle IRC +========= + +This is a sort of bouncer for clients with transient network connections, +like cell phones and laptops. +It's a lot like [tapchat](https://github.com/tapchat/tapchat) but is a whole lot simpler +while being (at time of writing) much more feature-complete. + +It supports (currently) an JavaScript browser-based client, +and can also be worked from the command-line using Unix tools like "tail" and "echo". + +Ironically, it doesn't currently work with any existing IRC clients, +although we are kicking around ideas for such a thing. +Honestly, though, if you want a bouncer for a traditional IRC client, +you are better off using something like znc. + +We have an [architectural diagram](https://docs.google.com/drawings/d/1am_RTUh89kul-318GoYK73AbjOE_jMYi4vI4NyEgKrY/edit?usp=sharing) if you care about such things. + + +Features +-------- + +* Gracefully handles clients with transient networking, such as cell phones and laptops. + + +Todo +----- + +I need to make this document suck less. diff --git a/index.html b/index.html index 323399b..7d42f5a 100644 --- a/index.html +++ b/index.html @@ -3,58 +3,16 @@ #tron - - + + -
+
+
- +
diff --git a/irc.css b/irc.css new file mode 100644 index 0000000..4e2e243 --- /dev/null +++ b/irc.css @@ -0,0 +1,58 @@ + +#foraText, #kiboze { + max-height: 20em; + overflow: scroll; +} +#foraText p, #kiboze p { + margin: 0em 0em 0em 4em; + text-indent: -4em; +} +#kiboze { + max-height: 7em; + background-color: #eee; +} +.timestamp { + color: silver; +} +.forum { + color: darkblue; + display: none; +} +.sender { + color: green; +} +.sender:before { + content: "<"; +} +.sender:after { + content: ">"; +} +.sender.notice { + color: olive; +} +.sender.notice:before { + content: "-"; +} +.sender.notice:after { + content: "-"; +} +.raw { + color: purple; +} + +.active { + background-color: yellow; +} +.current { + background-color: aquamarine; +} + +input[name~=target] { + width: 7em; +} +input[name~=text] { + width: 75%; +} +body { + height: 100%; +} \ No newline at end of file diff --git a/irc.go b/irc.go index 7d7ef5e..ceba86b 100644 --- a/irc.go +++ b/irc.go @@ -123,9 +123,12 @@ func parse(v string) (Message, error) { m.Command = strings.ToUpper(parts[0]) switch m.Command { case "PRIVMSG", "NOTICE": - if isChannel(parts[1]) { + switch { + case isChannel(parts[1]): m.Forum = parts[1] - } else { + case m.FullSender == ".": + m.Forum = parts[1] + default: m.Forum = m.Sender } case "PART", "MODE", "TOPIC", "KICK": diff --git a/irc.js b/irc.js index 133ab01..6ef0ab7 100644 --- a/irc.js +++ b/irc.js @@ -1,10 +1,59 @@ var msgRe = /([^ ]+) (<[^>]+>) (.*)/; -var kibozeRe = "[Nn]eal"; +var kibozeRe = /[Nn]eal/; +var urlRe = /[a-z]+:\/\/[^ ]*/; + +var nick = "Mme. M"; function isinView(oObject) { return (oObject.offsetParent.clientHeight <= oObject.offsetTop); } +function selectForum(fe) { + var kids = document.getElementById("foraText").childNodes; + + for (i = 0; i < kids.length; i += 1) { + e = kids[i]; + console.log(i, e); + if (e == fe) { + e.style.display = "block"; + } else { + e.style.display = "none"; + if (e.button.className == "current") { + e.button.className = ""; + } + } + } + + fe.button.className = "current"; + if (fe.lastChild) { + fe.lastChild.scrollIntoView(false); + } + document.getElementById("target").value = fe.forum; +} + +function getForumElement(forum) { + var id = "a:" + forum; + var fe = document.getElementById(id); + + if (! fe) { + var button = document.createElement("button"); + button.appendChild(document.createTextNode(forum)); + button.onclick = function() { selectForum(fe); } + document.getElementById("foraButtons").appendChild(button); + + fe = document.createElement("div"); + fe.id = id + fe.forum = forum + fe.button = button + document.getElementById("foraText").appendChild(fe); + } + + if (fe.button.className != "current") { + fe.button.className = "active"; + } + return fe; +} + function addMessagePart(p, className, text) { var e = document.createElement("span"); e.className = className; @@ -12,11 +61,48 @@ function addMessagePart(p, className, text) { p.appendChild(e); p.appendChild(document.createTextNode(" ")); } + +function addText(p, text, kiboze) { + // Look for a URL + var txtElement = document.createElement("span"); + txtElement.className = "text"; + var rhs = text; + var match; + + while ((match = urlRe.exec(rhs)) != null) { + var before = rhs.substr(0, match.index); + var a = document.createElement("a"); + var href = match[0]; + + if (href.indexOf("hxx") == 0) { + href = "htt" + href.substr(3); + } + a.href = href + a.target = "_blank"; + a.appendChild(document.createTextNode(match[0])); + txtElement.appendChild(document.createTextNode(before)); + txtElement.appendChild(a); + rhs = rhs.substr(match.index + match[0].length); + } + txtElement.appendChild(document.createTextNode(rhs)); + p.appendChild(txtElement); + + if ((kiboze) || (-1 != text.search(kibozeRe))) { + var k = document.getElementById("kiboze"); + var p2 = p.cloneNode(true); + k.insertBefore(p2, k.firstChild); + p2.onclick = function() { focus(p); } + + // Setting title makes the tab flash sorta + document.title = document.title; + } +} function focus(e) { var pct = 1; var timeout; + selectForum(e.parentNode); e.scrollIntoView(false); e.style.backgroundColor = "yellow"; @@ -41,7 +127,7 @@ function addMessage(txt) { var args = parts.slice(5); var msg = txt.substr(lhs.length + 2) - var a = document.getElementById("a"); + var forumElement = getForumElement(forum); var p = document.createElement("p"); addMessagePart(p, "timestamp", ts.toLocaleTimeString()); @@ -54,17 +140,12 @@ function addMessage(txt) { case "PRIVMSG": addMessagePart(p, "forum", forum); addMessagePart(p, "sender", sender); - addMessagePart(p, "text", msg); - if ((sender == forum) || (-1 != msg.search(kibozeRe))) { - var k = document.getElementById("kiboze"); - var p2 = p.cloneNode(true); - k.insertBefore(p2, k.firstChild); - p2.onclick = function() { focus(p); } - // Supposedly changing title makes the tab flash sorta - t = document.title - document.title = "!" - document.title = t - } + addText(p, msg, (sender == forum)); + break; + case "NOTICE": + addMessagePart(p, "forum", forum); + addMessagePart(p, "sender notice", sender); + addText(p, msg, (sender == forum)); break; default: addMessagePart(p, "forum", forum); @@ -72,7 +153,7 @@ function addMessage(txt) { addMessagePart(p, "raw", command + " " + args + " " + msg); break; } - a.appendChild(p); + forumElement.appendChild(p); p.scrollIntoView(false); }