diff --git a/doc/INSTALL.md b/INSTALL.md similarity index 100% rename from doc/INSTALL.md rename to INSTALL.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a4af36e --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2015 Neale Pickett + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +The software is provided "as is", without warranty of any kind, express or +implied, including but not limited to the warranties of merchantability, +fitness for a particular purpose and noninfringement. In no event shall +the authors or copyright holders be liable for any claim, damages or +other liability, whether in an action of contract, tort or otherwise, +arising from, out of or in connection with the Software or the use or +other dealings in the Software. + diff --git a/Makefile b/Makefile deleted file mode 100644 index 6f90e66..0000000 --- a/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -ICONS += app/icon-16.png -ICONS += app/icon-32.png -ICONS += app/icon-48.png -ICONS += app/icon-128.png -ICONS += app/icon-256.png - -all: icons serverside - -serverside: spongy spongy.cgi - -spongy: src/spongy/spongy.go - GOPATH=$(CURDIR) go build -v $@ - -spongy.cgi: src/spongy.cgi/spongy.cgi.go - GOPATH=$(CURDIR) go build -v $@ - chmod +s $@ - -icons: $(ICONS) - -app/icon-%.png: chat.svg - inkscape --export-png=$@ --export-width=$* $< - -package: icons - cd app && zip -ru ../package.zip . diff --git a/doc/PROTOCOL.md b/PROTOCOL.md similarity index 100% rename from doc/PROTOCOL.md rename to PROTOCOL.md diff --git a/doc/TODO.md b/TODO.md similarity index 100% rename from doc/TODO.md rename to TODO.md diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json deleted file mode 100644 index 89e140c..0000000 --- a/app/_locales/en/messages.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "appName": { - "description": "Application name", - "message": "Spongy Chat Client" - }, - "appShortName": { - "description": "Short application name", - "message": "Spongy Chat" - }, - "appDesc": { - "description": "Application description for app store listing", - "message": "Chat client for the Spongy bouncer thingamajiggy" - }, - - - "unknownCommand": { - "description": "Text for unrecognized command", - "message": "??? $COMMAND$ $ARGS$ $TEXT$", - "placeholders": { - "fullSender": { - "content": "$1", - "example": "fritz!~bob@example.net" - }, - "command": { - "content": "$2", - "example": "PRIVMSG" - }, - "sender": { - "content": "$3", - "example": "fritz" - }, - "forum": { - "content": "$4", - "example": "#hottub" - }, - "args": { - "content": "$5", - "example": "+o,fred" - }, - "text": { - "content": "$6", - "example": "Hello everybody" - } - } - }, - - "privmsgCommand": { - "description": "Text for a privmsg (a regular chat message)", - "message": "$6" - }, - - "noticeCommand": { - "description": "Text for a notice", - "message": "$6" - }, - - "nickCommand": { - "description": "Text for nickname change", - "message": "$1 is now known as $3" - }, - - "modeCommand": { - "message": "sets channel mode $5" - }, - - "joinCommand": { - "description": "Channel join", - "message": "joins the channel." - }, - - "faultCommand": { - "description": "Spongy fault", - "message": "Spongy error: $6" - } -} diff --git a/app/background.js b/app/background.js deleted file mode 100644 index 78df071..0000000 --- a/app/background.js +++ /dev/null @@ -1,10 +0,0 @@ -chrome.app.runtime.onLaunched.addListener(function() { - chrome.app.window.create('wirc.html', { - state: 'normal', - width: 775, - height: 400, - minWidth: 320, - minHeight: 160, - id: 'spongy' - }) -}) diff --git a/app/channel.js b/app/channel.js deleted file mode 100644 index cde7a42..0000000 --- a/app/channel.js +++ /dev/null @@ -1 +0,0 @@ -merf. \ No newline at end of file diff --git a/app/example.html b/app/example.html deleted file mode 100644 index 0c07b8a..0000000 --- a/app/example.html +++ /dev/null @@ -1,361 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CIRC undefined - - - -
- -
-
-
-
-
-
- -
- -
  • -
    -
    -
    -
  • - - - -
  • -
    -
  • - - - -
  • -
    -
    -
    -
    -
    -
  • - -
    - - -
    -
    -
    -
    -

    rooms

    -
    -
    -
    us.slashnet.org
    -
    -
    -
    -
    • -
      #tron
      -
      -
      -
    -
    - -
      -
      -
      -
      -

      members

      -
      • -
        also
        -
      • -
        atob
        -
      • -
        Bermuda
        -
      • -
        bit
        -
      • -
        bk
        -
      • -
        bz2
        -
      • -
        caycos
        -
      • -
        ckape
        -
      • -
        clavicle
        -
      • -
        CrackMonkey
        -
      • -
        Dumont
        -
      • -
        dzho
        -
      • -
        emad
        -
      • -
        eythian
        -
      • -
        felixc
        -
      • -
        fo0bar
        -
      • -
        fuzzie
        -
      • -
        GodEater
        -
      • -
        hollow
        -
      • -
        hoylemd
        -
      • -
        jhewl
        -
      • -
        jv
        -
      • -
        kees
        -
      • -
        khmer
        -
      • -
        lamont
        -
      • -
        lexicondal
        -
      • -
        neale
        -
      • -
        nemo
        -
      • -
        nerdtron3000
        -
      • -
        nornagon
        -
      • -
        Octal
        -
      • -
        pdx6
        -
      • -
        pedro
        -
      • -
        Randall
        -
      • -
        sarah
        -
      • -
        Sciri
        -
      • -
        scorche
        -
      • -
        scorche|sh
        -
      • -
        Screwtape
        -
      • -
        sneakums
        -
      • -
        squinky
        -
      • -
        stat
        -
      • -
        teferi
        -
      • -
        tiaz
        -
      • -
        watson
        -
      • -
        wcarss
        -
      • -
        wombat
        -
      • -
        X11R5
        -
      • -
        Zen
        -
      -
      - -
      - -
      -
      - -
      Spel werkt, vertel het door! | hype mismatch error | ERG DRUK | <ginnie> everything is awesome! | Save The Date: 20150212 is Dumont's 15th Birthday | sparrows form Voltron | Deksels! | sysadmin establishment "hanged" by lunatic devop | Levis dehydrates unisexual cleavage. | A fanfare for locked traffic --
      -
      -
      -
      - - - -
      -
      • -
        3:46:12 PM
        -
        -
        -
        Awesome, you've connected to #tron.
        -
        -
      • -
        3:46:12 PM
        -
        -
        -
        If you're ever stuck, type /help to see a list of all commands.
        -
        -
      • -
        3:46:12 PM
        -
        -
        -
        You can switch windows with alt+[0-9] or click in the channel list on the left.
        -
        -
      • -
        3:46:12 PM
        -
        -
        -
        (You joined the channel)
        -
        -
      • -
        3:46:12 PM
        -
        -
        -
        The topic is: Spel werkt, vertel het door! | hype mismatch error | ERG DRUK | <ginnie> everything is awesome! | Save The Date: 20150212 is Dumont's 15th Birthday | sparrows form Voltron | Deksels! | sysadmin establishment "hanged" by lunatic devop | Levis dehydrates unisexual cleavage. | A fanfare for locked traffic --
        -
        -
      • -
        3:46:12 PM
        -
        -
        -
        Topic set by sneakums on Fri Oct 17 2014 16:05:00 GMT-0600 (MDT).
        -
        -
      • -
        3:46:12 PM
        -
        -
        -
        Received a CTCP VERSION from squinky.
        -
        -
      • -
        3:47:13 PM
        -
        -
        nerdtron3000
        -
        merf
        -
        -
      • -
        3:47:53 PM
        -
        -
        nerdtron3000
        -
        X11R5: say something to me
        -
        -
      • -
        3:47:55 PM
        -
        -
        X11R5
        -
        nerdtron3000: Get me some of those things where 99 times out on to something.
        -
        -
      • -
        3:48:01 PM
        -
        -
        nerdtron3000
        -
        ...
        -
        -
      • -
        3:48:02 PM
        -
        -
        Dumont
        -
        [You have a sad feeling for a moment, then it passes.]
        -
        -
      -
      -
      nerdtron3000
      -
      -
      -
      - - - - \ No newline at end of file diff --git a/app/manifest.json b/app/manifest.json deleted file mode 100644 index aa8e692..0000000 --- a/app/manifest.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "manifest_version": 2, - "version": "1.0", - - "name": "__MSG_appName__", - "short_name": "__MSG_appShortName__", - "description": "__MSG_appDesc__", - "author": "Neale Pickett ", - "icons": { - "16": "icon-16.png", - "32": "icon-32.png", - "48": "icon-48.png", - "128": "icon-128.png", - "256": "icon-256.png" - }, - "app": { - "background": { - "scripts": ["background.js"] - } - }, - "permissions": [ - "storage", - "fileSystem", - "https://woozle.org/" - ], - "default_locale": "en" -} diff --git a/app/message_style.css b/app/message_style.css deleted file mode 100644 index 163113e..0000000 --- a/app/message_style.css +++ /dev/null @@ -1,165 +0,0 @@ -.message.mode, .message.nick, .message.join { - color: #606043; -} - -.message.notice { - color: #97008B; - font-style: oblique; -} - -.message.error { - color: #B33B2D; -} - -.message.self { - color: #005816; -} - -.message.privmsg { - color: #505053; -} - -.message.privmsg.self { - color: gray; -} - -.message.privmsg.mention { - color: darkred; -} - -.message.privmsg.mention .source { - font-weight: bold; -} - -.message.privmsg.direct .source { - color: #488AA8; -} - -/* Nickname Colors. Taken from Textual */ - -.message.privmsg.self .source-content-container .source { - color: #ea0d68; -} - -.message:not(.self) .source-content-container .source[colornumber='0'] { - color: #0080ff; -} - -.message:not(.self) .source-content-container .source[colornumber='1'] { - color: #059005; -} - -.message:not(.self) .source-content-container .source[colornumber='2'] { - color: #a80054; -} - -.message:not(.self) .source-content-container .source[colornumber='3'] { - color: #9b0db1; -} - -.message:not(.self) .source-content-container .source[colornumber='4'] { - color: #108860; -} - -.message:not(.self) .source-content-container .source[colornumber='5'] { - color: #7F4FFF; -} - -.message:not(.self) .source-content-container .source[colornumber='6'] { - color: #58701a; -} - -.message:not(.self) .source-content-container .source[colornumber='7'] { - color: #620a8e; -} - -.message:not(.self) .source-content-container .source[colornumber='8'] { - color: #BB0008; -} - -.message:not(.self) .source-content-container .source[colornumber='9'] { - color: #44345f; -} - -.message:not(.self) .source-content-container .source[colornumber='10'] { - color: #2f5353; -} - -.message:not(.self) .source-content-container .source[colornumber='11'] { - color: #904000; -} - -.message:not(.self) .source-content-container .source[colornumber='12'] { - color: #808000; -} - -.message:not(.self) .source-content-container .source[colornumber='13'] { - color: #57797e; -} - -.message:not(.self) .source-content-container .source[colornumber='14'] { - color: #3333dd; -} - -.message:not(.self) .source-content-container .source[colornumber='15'] { - color: #5f4d22; -} - -.message:not(.self) .source-content-container .source[colornumber='16'] { - color: #706616; -} - -.message:not(.self) .source-content-container .source[colornumber='17'] { - color: #46799c; -} - -.message:not(.self) .source-content-container .source[colornumber='18'] { - color: #80372e; -} - -.message:not(.self) .source-content-container .source[colornumber='19'] { - color: #8F478E; -} - -.message:not(.self) .source-content-container .source[colornumber='20'] { - color: #5b9e4c; -} - -.message:not(.self) .source-content-container .source[colornumber='21'] { - color: #13826c; -} - -.message:not(.self) .source-content-container .source[colornumber='22'] { - color: #b13637; -} - -.message:not(.self) .source-content-container .source[colornumber='23'] { - color: #e45d59; -} - -.message:not(.self) .source-content-container .source[colornumber='24'] { - color: #1b51ae; -} - -.message:not(.self) .source-content-container .source[colornumber='25'] { - color: #4855ac; -} - -.message:not(.self) .source-content-container .source[colornumber='26'] { - color: #7f1d86; -} -.message:not(.self) .source-content-container .source[colornumber='27'] { - color: #73643f; -} - -.message:not(.self) .source-content-container .source[colornumber='28'] { - color: #0b9578; -} - -.message:not(.self) .source-content-container .source[colornumber='29'] { - color: #569c96; -} - -.message:not(.self) .source-content-container .source[colornumber='30'] { - color: #08465f; -} diff --git a/app/network.js b/app/network.js deleted file mode 100644 index 7c93913..0000000 --- a/app/network.js +++ /dev/null @@ -1,102 +0,0 @@ -// Functionality dealing with server-level things - -var maxScrollback = 500; -var networks = {}; - -function networkConnect(network, baseURL, authtok) { - var eventSource; - var element = getTemplate("server-channels"); - var channels = element.getElementsByClassName("channels")[0]; - var roomElement = element.getElementsByClassName("server")[0]; - var rooms = {".": roomElement}; - newRoom(roomElement, element, network, maxScrollback); - - function makeRoom(name) { - var rElement = getTemplate("channel"); - newRoom(rElement, element, name, maxScrollback); - channels.appendChild(rElement); - rooms[name] = rElement; - return rElement; - } - - function handleEventSourceLine(line) { - var lhs = line.split(" :", 1)[0]; - var parts = lhs.split(' '); - - var timestamp = new Date(parts[0] * 1000); - var fullSender = parts[1]; - var command = parts[2].toLowerCase(); - var sender = parts[3]; - var forum = parts[4]; - var args = parts.slice(5); - var txt = line.substr(lhs.length + 2); - - switch (command) { - case "prevlog": - // Just ignore this - return; - } - - var room = rooms[forum]; - if (! room) { - room = makeRoom(forum); - } - - // XXX: Handle differently based on command - room.addMessage(timestamp, fullSender, command, sender, args, txt); - } - - function handleEventSourceMessage(oEvent) { - msgs = oEvent.data.split("\n"); - - var first = Math.max(0, msgs.length - maxScrollback); - for (var i = first; i < msgs.length; i += 1) { - handleEventSourceLine(msgs[i]); - } - } - - function handleEventSourceError(oEvent) { - timestamp = new Date(); - roomElement.addMessage(timestamp, ".", "fault", ".", [], "Unable to open events feed (permissions problem on server?)"); - console.log(oEvent); - } - - element.send = function(target, text) { - function handleError(oEvent) { - console.log("XXX: That didn't work out.", target, text) - } - - var form = new FormData(); - form.append("type", "command"); - form.append("auth", authtok); - form.append("network", network); - form.append("target", target); - form.append("text", text); - - var oReq = new XMLHttpRequest(); - oReq.addEventListener("error", handleError); - oReq.open("POST", baseURL, true); - oReq.send(form); - } - - element.close = function() { - console.log("Closing"); - eventSource.close(); - element.parentNode.removeChild(element); - roomElement.close(); - // XXX: Close all associated rooms, too! - } - - - if (networks[network]) { - networks[network].close(); - } - networks[network] = element; - - var pullURL = baseURL + "?network=" + encodeURIComponent(network) + "&auth=" + encodeURIComponent(authtok); - eventSource = new EventSource(pullURL); - eventSource.addEventListener("message", handleEventSourceMessage); - eventSource.addEventListener("error", handleEventSourceError); - - document.getElementsByClassName("rooms")[0].appendChild(element); -} diff --git a/app/room.js b/app/room.js deleted file mode 100644 index 24413ed..0000000 --- a/app/room.js +++ /dev/null @@ -1,162 +0,0 @@ -function djbhash(a) { - var r = 5381; - - for (var i = 0; i < a.length; i += 1) { - r = (((r << 5) + r) + a.charCodeAt(i)) & 0xffff; - } - return r; -} - -function purtify(text) { - // 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)); - - return txtElement; -} - -function kiboze(this_is_currently_busted) { - - if ((kiboze) || (-1 != text.search(kibozeRe))) { - var k = document.getElementById("kiboze"); - var p2 = p.cloneNode(true); - - if (k) { - k.insertBefore(p2, k.firstChild); - p2.onclick = function() { focus(p); } - - // Setting title makes the tab flash sorta - document.title = document.title; - } - } -} - - -var visibleRoom; - -function newRoom(element, network, name, maxSize) { - var messages = getTemplate("messages"); - var lastmsg; - if (! maxSize) { - maxSize = 500; - } - - function purtify(fullSender, command, sender, args, txt) { - var txtElement = document.createElement("span"); - var msg = chrome.i18n.getMessage(command + "Command", [fullSender, command, sender, name, args, txt]); - if (! msg) { - msg = chrome.i18n.getMessage("unknownCommand", [fullSender, command, sender, name, String(args), txt]); - } - - var rhs = msg; - 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)); - - return txtElement; - } - - - element.addMessage = function(timestamp, fullSender, command, sender, args, txt) { - var message = getTemplate("message"); - - var eTimestamp = message.getElementsByClassName("timestamp")[0]; - var eSource = message.getElementsByClassName("source")[0]; - var eContent = message.getElementsByClassName("content")[0]; - - message.classList.add(command); - if (sender == ".") { - message.classList.add("self"); - } - - eTimestamp.textContent = timestamp.toLocaleTimeString(); - eSource.textContent = sender; - eSource.setAttribute("colornumber", djbhash(sender) % 31); - eContent.appendChild(purtify(fullSender, command, sender, args, txt)); - - messages.appendChild(message); - - while (messages.childNodes.length > maxSize) { - messages.removeChild(messages.firstChild); - } - - lastmsg = message; - - if (visibleRoom == element) { - lastmsg.scrollIntoView(false); - } - } - - element.hide = function() { - element.classList.remove("selected"); - messages.style.display = "none"; - } - - element.show = function() { - if (visibleRoom) { - visibleRoom.hide() - } - element.classList.add("selected"); - messages.style.display = null; - lastmsg.scrollIntoView(false); - visibleRoom = element; - } - - element.send = function(text) { - network.send(name, text); - } - - element.close = function() { - console.log(messages); - console.log(messages.parent); - messages.parent.removeChild(messages); - element.parent.removeChild(element); - } - - function clicked() { - element.show(); - } - - // start hidden - element.hide(); - element.addEventListener("click", clicked); - element.getElementsByClassName("content-item")[0].textContent = name; - - document.getElementById("messages-container").appendChild(messages); - - return element; -} \ No newline at end of file diff --git a/app/style.css b/app/style.css deleted file mode 100644 index 1fc5645..0000000 --- a/app/style.css +++ /dev/null @@ -1,484 +0,0 @@ -html, body { - margin: 0; - padding: 0 -} - -*, *:before, *:after { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; -} - -body { - color: #505053; - /* font-family: sans-serif; */ - font-size: 100%; -} - -.hidden { - display: none; -} - -#templates { - display: none; -} - -ul { - list-style: none; - margin: 0; - padding: 0; -} - -.footer { - display: none; - font-style: italic; - color: #9493A2; -} - -.help-command { - display: inline-block; - width: 7em; -} - -.content-item { - white-space: nowrap; - overflow-x: hidden; - text-overflow: ellipsis; -} - -#main { - display: -webkit-box; - -webkit-box-orient: horizontal; - width: 100%; - height: 100%; - position: absolute; - border-top: 1px solid rgba(0,0,0,0.15); -} - -#main-top-border { - position: absolute; - top: 0; - z-index: 100; - width: 100%; - height: 1px; - background-color: rgba(0,0,0,0.05); - pointer-events: none; -} - -#rooms-and-nicks { - background-color: #F7F5E4; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-box-flex: 0; - width: 150px; - height: inherit; - padding: 4px 0px; - border-right: 1px solid rgba(0, 0, 0, .15); - overflow-y: auto; - -webkit-overflow-scrolling: touch; -} - -#rooms-and-nicks h1 { - color: #406698; - text-transform: uppercase; - font-size: smaller; - padding: 8px 0px 2px 8px; - margin: 0px; -} - -#rooms-and-nicks .nick, -#rooms-and-nicks .room { - padding: 0 8px; - line-height: 26px; -} - -#rooms-and-nicks .room { - cursor: pointer; -} - -#rooms-and-nicks .server.footer { - display: block; -} - -.dragbar:hover { - width: 6px; - transition: width .1s; -} - -.dragbar { - height: 100%; - width: 1px; - cursor: col-resize; -} - -#ghostbar{ - width:3px; - background-color:#000; - opacity:0.8; - position:absolute; - cursor: col-resize; - z-index:999 -} - -#rooms-container { - -webkit-box-flex: 0; - border-bottom: 1px solid #CCC; - padding-bottom: 10px; -} - -.no-nicks #rooms-container { - border-bottom-style: none; - padding-bottom: 0px; -} - -#rooms-and-nicks.hidden { - display: none; -} - -#rooms-and-nicks .room.server { - background-color: #F2EFD3; - position: relative; -} - -#rooms-and-nicks:hover .room.server .content-item { - width: 130px; -} - -#rooms-and-nicks .add-channel { - position: absolute; - right: 2px; - top: -1px; - cursor: pointer; - font-size: larger; - display: none; -} - -#rooms-and-nicks:hover .add-channel { - display: block; -} - -#rooms-and-nicks .add-channel:hover { - color: #888; -} - -#rooms-and-nicks .room.channel:first-child { - padding-top: 3px; -} - -#rooms-and-nicks .room.channel:first-child .content-item { - padding-bottom: 3px; - line-height: 20px; -} - -#rooms-and-nicks not(.current-server) + .channels .room.channel:nth-last-child(2) { - padding-bottom: 3px; -} -#rooms-and-nicks .room.channel:last-child { - padding-bottom: 3px; -} - -#rooms-and-nicks not(.current-server) + .channels .room.channel:nth-last-child(2) .content-item { - padding-top: 3px; - line-height: 20px; -} -#rooms-and-nicks .room.channel:last-child .content-item { - padding-top: 3px; - line-height: 20px; -} - -#rooms-and-nicks not(.current-server) + .channels .room.channel:nth-last-child(2):first-child .content-item { - line-height: 14px; -} -#rooms-and-nicks .room.channel:last-child:first-child .content-item { - line-height: 14px; -} - -#rooms-and-nicks .current-server:not(.always-empty) + .channels .footer { - display: block; -} - -#rooms-and-nicks .room.channel .content-item { - border-left: 1px solid rgba(0, 0, 0, .5); - padding-left: 7px; -} - -#rooms-and-nicks .room.activity { - font-weight: bold; -} - -#rooms-and-nicks .room.mention { - color: darkred; -} - -#rooms-and-nicks .room.disconnected .content-item { - color: #9493A2; - font-style: italic; -} - -#rooms-and-nicks .room.channel.disconnected .content-item { - border-left: 1px solid #9493A2; -} - -#rooms-and-nicks .room.selected { - background-color: #F0E798; -} - -#rooms-and-nicks .room { - position: relative; -} - -#rooms-and-nicks .room .remove-button { - position: absolute; - right: 6px; - top: -1px; - cursor: pointer; - font-size: x-large; - color: rgba(0, 0, 0, .25); - display: none; -} - -#rooms-and-nicks .room .remove-button:hover { - color: rgba(0, 0, 0, .5); -} - -#rooms-and-nicks .room.selected:not(.footer):not(.always-empty) .content-item { - width: 123px; -} -#rooms-and-nicks .room:hover:not(.footer):not(.always-empty) .content-item { - width: 123px; -} - -#rooms-and-nicks .room.selected:not(.footer):not(.always-empty) .remove-button { - display: inline-block; -} -#rooms-and-nicks .room:hover:not(.footer):not(.always-empty) .remove-button { - display: inline-block; -} - -#nicks-container { - border-top: 1px solid #FFF; - -webkit-box-flex: 1; -} - -.no-nicks #nicks-container { - display: none; -} - -.rooms, -.nicks { - padding-top: 5px; -} - -.nicks li:nth-child(odd) { - background-color: #F2EFD3; -} - -#notice { - background-color: #406698; - box-shadow: 0px 1px 4px #888; - color: #FFF; - position: absolute; - width: 100%; - -webkit-transition: 150ms; - top: 0; - padding: 2px 0; -} - -#notice.hide { - top: -38px; -} - -#notice .content { - display: inline; - padding-left: 14px; - text-overflow: ellipsis; - white-space: nowrap; - overflow-x: hidden; - position: absolute; - top: 50%; - margin-top: -.5em; -} - -#notice button { - float: right; - height: 22px; - font-size: 14px; - padding: 0px 4px; - margin: 4px; - border: none; - background-color: #ECECEC; - color: #505053; - cursor: pointer; - outline: none; -} - -#notice button.close { - margin-right: 8px; - font-size: 12px; - border-radius: 42px; - width: 21px; - height: 21px; -} - -#messages-and-input { - -webkit-box-flex: 1; - display: -webkit-box; - -webkit-box-orient: vertical; - box-shadow: 0px 0px 8px #CCC; - position: relative; -} - -#messages-container { - overflow-y: auto; - -webkit-overflow-scrolling: touch; - -webkit-box-flex: 1; - border-bottom: 1px solid #CCC; -} - -.messages { - display: table; -} - -.message { - display: table-row; - -webkit-user-select: initial; -} - -.message.activity-marker .source-content-container { - border-top: 1px solid rgb(224, 179, 179); -} - -.message .timestamp { - color: #6060C0; - font-style: italic; - /* font-size: smaller; */ - white-space: nowrap; - display: table-cell; - text-align: right; - padding: 0px 10px 0px 10px; - border-right: 1px solid rgba(0,0,0,0.15); - cursor: text; -} - -.source-content-container { - display: table-cell; - padding: 1px 10px 1px 15px; - width: 100%; -} - -.message .source { - font-weight: bold; - padding-right: 5px; - margin-left: -5px; - white-space: nowrap; - display: inline; - text-align: right; - cursor: text; -} - -.message .source.empty { - padding-right: 0; -} - -.message .content { - display: inline; - white-space: pre-wrap; - cursor: text; - word-break: break-word; -} - -#messages-container .messages .message:first-child .source-content-container { - padding-top: 10px; -} - -#messages-container .messages .message:last-child .source-content-container { - padding-bottom: 8px; -} - -.message.list { - /* empty style for now */ -} - -.longword { word-break: break-all; } - -#nick-and-input { - border-top: 1px solid #F9F9F9; - -webkit-box-flex: 0; - display: -webkit-box; - background-color: #ECECEC; - padding: 5px 10px 5px 10px; -} - -#nick { - padding-top: 5px; -} - -#nick > span { - padding-right: 10px; -} - -#nick > .name:before { - font-weight: bold; - content: "[ " -} -#nick > .name:after { - font-weight: bold; - content: " ]" -} - -#nick .away:before { - content: "(" -} -#nick .away:after { - content: ")" -} - -#input-bar { - -webkit-box-flex: 1; - display: -webkit-box; -} - -#input { - background-color: #F9F9F9; - display: block; - -webkit-box-flex: 1; - width: 100%; - height: 30px; - border: 1px; - border-radius: 5px; - -webkit-box-shadow: 0px 0px 3px #888; - color: #505053; - font-size: 100%; - padding: 0px 8px; - outline: 0; -} - -#input.blink { - -webkit-box-shadow: 0px 0px 6px #406698; -} - -::-webkit-scrollbar { - width: 9px; - height: 9px; -} -::-webkit-scrollbar-button:start:decrement, -::-webkit-scrollbar-button:end:increment { - display: block; - height: 0; -} -::-webkit-scrollbar-track-piece { - background-color: rgba(0,0,0,0.1); -} -::-webkit-scrollbar-thumb:vertical { - height: 50px; - background-color: #999; - border-radius: 8px; -} -::-webkit-scrollbar-thumb:vertical:hover { - background-color: #888; -} -::-webkit-scrollbar-thumb:horizontal { - width: 50px; - background-color: #999; - border-radius: 8px; -} diff --git a/app/topbar.css b/app/topbar.css deleted file mode 100644 index 8db1003..0000000 --- a/app/topbar.css +++ /dev/null @@ -1,43 +0,0 @@ -#hide-channels { - display: inline-block; - font-size: 12px; -} - -#topic-container { - border-bottom: 1px solid #CCC; - -webkit-box-flex: 0; - display: -webkit-box; - background-color: #ECECEC; - padding: 4px 6px; -} - -#status { - -webkit-box-flex: 1; - padding: 4px 5px; -} - -#status .topic { - font-style: italic; -} - -.topbar-button { - background: rgba(0, 0, 0, .08); - border: 0 transparent; - text-decoration: none; - cursor: pointer; - border-radius: 2px; - -webkit-transition: .1s linear -webkit-box-shadow; - margin-right: 4px; -} - -.topbar-button:active { - box-shadow: 0 0 0 1px rgba(0 ,0 ,0 ,.15) inset, 0 0 6px rgba(0, 0, 0, .2) inset; -} - -.topbar-button:hover { - background: rgba(0, 0, 0, .13); -} - -.topbar-button:focus { - outline: none; -} diff --git a/app/wirc.html b/app/wirc.html deleted file mode 100644 index c383fb5..0000000 --- a/app/wirc.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - -
      - -
      -
      -
      -
      -
      -
      -
        -
        - -
      • -
        -
        -
        -
      • - - - -
      • -
        -
      • - - - -
      • -
        -
        -
        -
        -
        -
      • - -
        - - -
        -
        -
        -
        -

        rooms

        -
        -
        -
        -

        members

        -
        -
        - -
        - -
        -
        - -
        -
        -
        -
        - - - -
        -
        -
        -
        -
        -
        -
        - - diff --git a/app/wirc.js b/app/wirc.js deleted file mode 100644 index 919f72a..0000000 --- a/app/wirc.js +++ /dev/null @@ -1,106 +0,0 @@ -var msgRe = /([^ ]+) (<[^>]+>) (.*)/; -var kibozeRe = /[Nn]eal/; -var urlRe = /[a-z]+:\/\/[^ ]*/; - -var nick = "Mme. M"; - -if (String.prototype.startsWith == null) { - String.prototype.startsWith = function(needle) { - return this.lastIndexOf(needle, 0) == 0; - } -} - -function getTemplate(className) { - return templates.getElementsByClassName(className)[0].cloneNode(true); -} - -function isinView(oObject) { - return (oObject.offsetParent.clientHeight <= oObject.offsetTop); -} - -function addMessagePart(p, className, text) { - var e = document.createElement("span"); - e.className = className; - e.appendChild(document.createTextNode(text)); - p.appendChild(e); - p.appendChild(document.createTextNode(" ")); -} - -function focus(e) { - var pct = 1; - var timeout; - - selectForum(e.parentNode); - e.scrollIntoView(false); - e.style.backgroundColor = "yellow"; - - timeout = setInterval(function() { - pct = pct - 0.1; - e.style.backgroundColor = "rgba(255, 255, 0, " + pct + ")"; - if (pct <= 0) { - e.style.backgroundColor = "inherit"; - clearInterval(timeout); - } - }, 50) -} - -function handleInput(oEvent) { - console.log(oEvent); - var txt = oEvent.target.value; - if (txt.startsWith("/connect ")) { - // XXX: should allow tokens with spaces - var parts = txt.split(" "); - var network = parts[1]; - var url = parts[2]; - var authtok = parts[3]; - - networkConnect(network, url, authtok); - storedConnections[network] = [url, authtok]; - chrome.storage.sync.set({"connections": storedConnections}); - } else { - visibleRoom.send(txt); - } - - oEvent.target.value = ""; - - return false; -} - -function hideChannels(oEvent) { - var lhs = document.getElementById("rooms-and-nicks"); - - if (lhs.classList.contains("hidden")) { - lhs.classList.remove("hidden"); - } else { - lhs.classList.add("hidden"); - } -} - -function keyPress(oEvent) { - document.getElementById("input").focus(); - if (oEvent.keyIdentifier == "Enter") { - handleInput(oEvent); - } -} - -function restore(items) { - storedConnections = items["connections"]; - - for (var network in storedConnections) { - var conn = storedConnections[network]; - - networkConnect(network, conn[0], conn[1]); - } -} - -function init() { - chrome.storage.sync.get(["connections"], restore); - //document.getElementById("input").addEventListener("change", handleInput); - document.getElementById("hide-channels").addEventListener("click", hideChannels); - window.addEventListener("keypress", keyPress); - - templates = document.getElementById("templates"); - rooms = document.getElementById("rooms-container").getElementsByClassName("rooms")[0]; -} - -window.addEventListener("load", init); diff --git a/doc/LICENSE.md b/doc/LICENSE.md deleted file mode 100644 index 853d0ff..0000000 --- a/doc/LICENSE.md +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Neale Pickett - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/res/chat.svg b/res/chat.svg deleted file mode 100644 index 05732e8..0000000 --- a/res/chat.svg +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - Openclipart - - - - 2008-02-19T10:10:56 - - https://openclipart.org/detail/14475/callout-chat-by-ericlemerdy - - - ericlemerdy - - - - - balloon - bubble - callout - speech - - - - - - - - - - - diff --git a/spongy.cgi/spongy.cgi b/spongy.cgi/spongy.cgi new file mode 100755 index 0000000..c198064 Binary files /dev/null and b/spongy.cgi/spongy.cgi differ diff --git a/spongy/irc.go b/spongy/irc.go new file mode 100644 index 0000000..0762dbe --- /dev/null +++ b/spongy/irc.go @@ -0,0 +1,98 @@ +package main + +import ( + "strconv" + "strings" +) + +type Message struct { + Command string + FullSender string + Sender string + Forum string + Args []string + Text string +} + +func Parse(v string) (Message, error) { + var m Message + var parts []string + var lhs string + + parts = strings.SplitN(v, " :", 2) + if len(parts) == 2 { + lhs = parts[0] + m.Text = parts[1] + } else { + lhs = v + m.Text = "" + } + + m.FullSender = "." + m.Forum = "." + m.Sender = "." + + parts = strings.Split(lhs, " ") + if parts[0][0] == ':' { + m.FullSender = parts[0][1:] + parts = parts[1:] + + n, u, _ := nuhost(m.FullSender) + if u != "" { + m.Sender = n + } + } + + m.Command = strings.ToUpper(parts[0]) + switch m.Command { + case "PRIVMSG", "NOTICE": + switch { + case isChannel(parts[1]): + m.Forum = parts[1] + case m.FullSender == ".": + m.Forum = parts[1] + default: + m.Forum = m.Sender + } + case "PART", "MODE", "TOPIC", "KICK": + m.Forum = parts[1] + m.Args = parts[2:] + case "JOIN": + if len(parts) == 1 { + m.Forum = m.Text + m.Text = "" + } else { + m.Forum = parts[1] + } + case "INVITE": + if m.Text != "" { + m.Forum = m.Text + m.Text = "" + } else { + m.Forum = parts[2] + } + case "NICK": + if len(parts) > 1 { + m.Sender = parts[1] + m.Args = parts[2:] + } else { + m.Sender = m.Text + m.Text = "" + m.Args = parts[1:] + } + m.Forum = m.Sender + case "353": + m.Forum = parts[3] + default: + numeric, _ := strconv.Atoi(m.Command) + if numeric >= 300 { + if len(parts) > 2 { + m.Forum = parts[2] + } + } + m.Args = parts[1:] + } + + return m, nil +} + diff --git a/spongy/network.go b/spongy/network.go new file mode 100644 index 0000000..2cde5dd --- /dev/null +++ b/spongy/network.go @@ -0,0 +1,167 @@ +package main + +import ( + "bufio" + "fmt" + "io" + "log" + "net" + "os" + "path" + "strings" + "time" +) + +// This gets called a lot. +// So it's easy to fix stuff while running. + +func ReadLines(fn string) ([]string, error) { + lines := make([]string, 0) + + f, err := os.Open(fn) + if err != nil { + return lines, err + } + defer f.Close() + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + switch { + case line == "": + case line[0] == '#': + default: + lines = append(lines, line) + } + } + + return lines, nil +} + +type Network struct { + basePath string + + conn io.ReadWriteCloser + logq chan Message + inq chan string + outq chan string +} + +func NewNetwork(basePath string) (*Network, error) { + nicks, err := ReadLines(path.Join(basePath, "nicks")) + if err != nil { + return nil, err + } + + gecoses, err := ReadLines(path.Join(basePath, "gecos")) + if err != nil { + return nil, err + } + + return &Network{ + basePath: basePath, + + servers: servers, + nicks: nicks, + gecos: gecoses[0], + + logq: make(chan Message), + inq: make(chan string), + outq: make(chan string), + }, err +} + +func (n *Network) Close() { + close(n.logq) + close(n.inq) + close(n.outq) +} + +func (n *Network) WatchOutqDirectory() { + outqDirname := path.Join(n.basePath, "outq") + + dir, err := os.Open(outqDirname) + if err != nil { + log.Fatal(err) + } + defer dir.Close() + + // XXX: Do this with fsnotify + for running { + entities, _ := dir.Readdirnames(0) + for _, fn := range entities { + pathname := path.Join(outqDirname, fn) + n.HandleInfile(pathname) + } + _, _ = dir.Seek(0, 0) + time.Sleep(500 * time.Millisecond) + } +} + +func (n *Network) HandleInfile(fn string) { + f, err := os.Open(fn) + if err != nil { + return + } + defer f.Close() + + // Do this after Open attempt. + // If Open fails, the file will stick around. + // Hopefully this is helpful for debugging. + os.Remove(fn) + + inf := bufio.NewScanner(f) + for inf.Scan() { + txt := inf.Text() + n.outq <- txt + } +} + +func (n *Network) WriteLoop() { + for v := range n.outq { + m, _ := Parse(v) + n.logq <- m + fmt.Fprintln(n.conn, v) + } +} + +func (n *Network) ReadLoop() { + scanner := bufio.NewScanner(conn) + for scanner.Scan() { + n.inq <- scanner.Text() + } + close(n.inq) +} + +func + +func (n *Network) Connect(){ + serverIndex := 0 + for running { + servers, err := ReadLines(path.Join(basePath, "servers")) + if err != nil { + log.Print(err) + serverIndex := 0 + time.sleep(2 * time.Second) + continue + } + + if serverIndex > len(servers) { + serverIndex = 0 + } + server := servers[serverIndex] + + switch (server[0]) { + case '|': + + + if dotls { + config := &tls.Config{ + InsecureSkipVerify: true, + } + return tls.Dial("tcp", host, config) + } else { + return net.Dial("tcp", host) + } +} + diff --git a/spongy/spongy.go b/spongy/spongy.go index 72b28d0..3725774 100644 --- a/spongy/spongy.go +++ b/spongy/spongy.go @@ -5,24 +5,14 @@ import ( "crypto/tls" "flag" "fmt" + "github.com/nealey/spongy/logfile" "log" - "logfile" "net" "os" - "strconv" "strings" "time" ) -type Message struct { - Command string - FullSender string - Sender string - Forum string - Args []string - Text string -} - var running bool = true var nick string var gecos string @@ -30,7 +20,7 @@ var maxlogsize uint var logq chan Message func isChannel(s string) bool { - if (s == "") { + if s == "" { return false } @@ -50,7 +40,7 @@ func (m Message) String() string { func logLoop() { logf := logfile.NewLogfile(int(maxlogsize)) defer logf.Close() - + for m := range logq { logf.Log(m.String()) } @@ -71,114 +61,6 @@ func nuhost(s string) (string, string, string) { return n, parts[0], parts[1] } -func connect(host string, dotls bool) (net.Conn, error) { - if dotls { - config := &tls.Config{ - InsecureSkipVerify: true, - } - return tls.Dial("tcp", host, config) - } else { - return net.Dial("tcp", host) - } -} - -func readLoop(conn net.Conn, inq chan<- string) { - scanner := bufio.NewScanner(conn) - for scanner.Scan() { - inq <- scanner.Text() - } - close(inq) -} - -func writeLoop(conn net.Conn, outq <-chan string) { - for v := range outq { - m, _ := parse(v) - logq <- m - fmt.Fprintln(conn, v) - } -} - -func parse(v string) (Message, error) { - var m Message - var parts []string - var lhs string - - parts = strings.SplitN(v, " :", 2) - if len(parts) == 2 { - lhs = parts[0] - m.Text = parts[1] - } else { - lhs = v - m.Text = "" - } - - m.FullSender = "." - m.Forum = "." - m.Sender = "." - - parts = strings.Split(lhs, " ") - if parts[0][0] == ':' { - m.FullSender = parts[0][1:] - parts = parts[1:] - - n, u, _ := nuhost(m.FullSender) - if u != "" { - m.Sender = n - } - } - - m.Command = strings.ToUpper(parts[0]) - switch m.Command { - case "PRIVMSG", "NOTICE": - switch { - case isChannel(parts[1]): - m.Forum = parts[1] - case m.FullSender == ".": - m.Forum = parts[1] - default: - m.Forum = m.Sender - } - case "PART", "MODE", "TOPIC", "KICK": - m.Forum = parts[1] - m.Args = parts[2:] - case "JOIN": - if len(parts) == 1 { - m.Forum = m.Text - m.Text = "" - } else { - m.Forum = parts[1] - } - case "INVITE": - if m.Text != "" { - m.Forum = m.Text - m.Text = "" - } else { - m.Forum = parts[2] - } - case "NICK": - if len(parts) > 1 { - m.Sender = parts[1] - m.Args = parts[2:] - } else { - m.Sender = m.Text - m.Text = "" - m.Args = parts[1:] - } - m.Forum = m.Sender - case "353": - m.Forum = parts[3] - default: - numeric, _ := strconv.Atoi(m.Command) - if numeric >= 300 { - if len(parts) > 2 { - m.Forum = parts[2] - } - } - m.Args = parts[1:] - } - - return m, nil -} func dispatch(outq chan<- string, m Message) { logq <- m @@ -248,7 +130,7 @@ func main() { log.Fatal(err) } defer dir.Close() - + nick := flag.Arg(0) host := flag.Arg(1) @@ -268,7 +150,7 @@ func main() { outq <- fmt.Sprintf("NICK %s", nick) outq <- fmt.Sprintf("USER %s %s %s: %s", nick, nick, nick, gecos) for v := range inq { - p, err := parse(v) + p, err := Parse(v) if err != nil { continue }