#lang racket/base (provide (struct-out irc-message) (struct-out irc-user) (struct-out irc-privmsg) parse-irc-message render-irc-message) (require racket/string) (require racket/match) (require racket/format) ;; ::= [':' ] ;; ::= | [ '!' ] [ '@' ] ;; ::= { } | ;; ::= ' ' { ' ' } ;; ::= [ ':' | ] ;; ;; ::= ;; ::= ;; ;; ::= CR LF ;; ::= [ "," ] ;; ::= | '@' | | ;; ::= ('#' | '&') ;; ::= ;; ::= see RFC 952 [DNS:4] for details on allowed hostnames ;; ::= { | | } ;; ::= ('#' | '$') ;; ::= ;; ::= { } ;; ::= 'a' ... 'z' | 'A' ... 'Z' ;; ::= '0' ... '9' ;; ::= '-' | '[' | ']' | '\' | '`' | '^' | '{' | '}' ;; ::= (struct irc-message (prefix command params trailing) #:prefab) (struct irc-user (username hostname servername realname) #:prefab) (struct irc-privmsg (source target text) #:prefab) (define (parse-irc-message line0) (match (string-trim #:left? #f line0 #px"[\r\n]") [(pregexp #px"^:([^ ]+) +(.*)$" (list _ prefix rest)) (parse-command prefix rest)] [line (parse-command #f line)])) (define (parse-command prefix line) (match-define (pregexp #px"^([^ ]+)( +([^:]+)?(:(.*))?)?$" (list _ command _ params _ rest)) line) (irc-message prefix command (string-split (or params "")) rest)) (define (render-irc-message m) (match-define (irc-message prefix command params trailing) m) (string-append (if prefix (string-append ":" prefix " ") "") (~a command) (if (pair? params) (string-append " " (string-join (map ~a params))) "") (if trailing (string-append " :" trailing) "")))