Unicode nickname support in UnrealIRCd

A recent release of UnrealIRCd has brought us support for some latin codepages and even mulitbyte encodings. Unicode, however, is not included, so that it looks a bit like a kludge.

But there’s a comprehensive discussion along with patches for better codepage support in the project’s bug tracker. Unfortunately, some of the patches are not done right, and the rest of them are a bit, uh, stale.

This procedure worked for me:

  1. Get UnrealIRCd 3.2.5 (3.2.x might work, too)
  2. Patch with unreal3.2.5.cvs.codepages-2.diff (allowed fuzz of five or so)
  3. Edit src/modules/Makefile.in manually (the patch was rejected here for me), adding m_names.so m_codepage.so to R_MODULES and COMMANDS.
  4. To allow full UTF8 nick names, change the conditional in src/modules/m_nick.c around line 150 to read:
            /* For a local clients, do proper nickname checking via do_nick_name()
             * and reject the nick if it returns false.
             * For remote clients, do a quick check by using do_remote_nick_name(),
             * if this returned false then reject and kill it. -- Syzop
             */
     
            if (!do_remote_nick_name(nick)) /* just do some basic checking */
            {

    That way you still won’t have

    \xA0!+%@&~#$:'\"?*,.

    but I guess this is a limitation of the IRC protocol.

    After that you should be ready to run ./Config && make, and set up your unrealircd.conf. It’s best to also enabled UTF-8 as the default in codepage.conf.

    Happy hacking!

Spaghetti Aglio e Olio

This is a simple Italian dish of pasta with garlic, spices and olive oil that tastes just great.

An excellent base recipe can be found at the bottom of Family Secrets #51.

For your convenience:

Spaghetti Aglio e Olio

Serves four

  • 1 lb. dried long pasta
  • 1/2 cup olive oil
  • 4 medium garlic cloves
  • Paprika
  • 1 tsp. salt
  • Freshly ground black pepper
  • Red pepper flakes (optional)
  • 1 or 2 Tblsp. minced fresh herbs such as parsley, fresh oregano or a mixture (optional)
  • Freshly grated Parmesan (pass separately)

Bring a large pot of salted water to the boil. Cook the pasta al dente and drain, saving about 1/2 cup of the pasta water. While the pasta is cooking, gently warm the olive oil in a large sauté pan, add the garlic either slivered or minced and heat just until the garlic turns golden. If you are using the red pepper flakes, add them here. Remove garlic or not according to your taste. Set oil aside until pasta is drained. Place oil back on medium low flame and toss pasta, in the sauté pan, with salt until well coated. If the pasta seems dry add dribbles of the pasta water. Add herbs and just heat through. Serve immediately with a good grind of black pepper, and pass the grated cheese at table. I also like to have a cruet of olive oil on the table so diners may add a drizzle if they wish.

Ironclad hashes in SBCL

Getting a SHA1 digest from Ironclad turned out to be a quite bumpy ride; its “convenience functions” are not convenient enough to take a string, they only operate on octets.

There’s a helper function that converts an ASCII string to octets, but I needed to be able to supply Unicode strings as well. I ended up finding STRING-TO-OCTETS:

(defun sha1 (str)
  (ironclad:byte-array-to-hex-string
    (ironclad::digest-sequence :sha1 (SB-EXT:STRING-TO-OCTETS str))))

If someone knows an easier or more portable way, I’m all for it. I’m also interested in other free implementations’ functions to convert their strings to octets.

Function encapsulation in SBCL

The advice functionality allows the programmer to replace or encapsulate an existing function binding (akin to :AROUND methods in the CLOS). See Gary King’s “What is advice” for some useful links and explanations on this.

CLISP and SBCL, my favourite Common Lisp implementations, do not seem to supply this functionality. I haven’t checked whether CLISP has advice under its hood, but SBCL does, and it’s termed “Function encapsulation” there. Once you know how to do it, it’s surprisingly simple to use.

This is the definition of SB-INT:ENCAPSULATE in SBCL’s src/code/fdefinition.lisp:

;;; Replace the definition of NAME with a function that binds NAME's
;;; arguments to a variable named ARG-LIST, binds name's definition
;;; to a variable named BASIC-DEFINITION, and evaluates BODY in that
;;; context. TYPE is whatever you would like to associate with this
;;; encapsulation for identification in case you need multiple
;;; encapsulations of the same name.
(defun encapsulate (name type body)
  (let ((fdefn (fdefinition-object name nil)))
    (unless (and fdefn (fdefn-fun fdefn))
      (error 'undefined-function :name name))
    ;; We must bind and close over INFO. Consider the case where we
    ;; encapsulate (the second) an encapsulated (the first)
    ;; definition, and later someone unencapsulates the encapsulated
    ;; (first) definition. We don't want our encapsulation (second) to
    ;; bind basic-definition to the encapsulated (first) definition
    ;; when it no longer exists. When unencapsulating, we make sure to
    ;; clobber the appropriate INFO structure to allow
    ;; basic-definition to be bound to the next definition instead of
    ;; an encapsulation that no longer exists.
    (let ((info (make-encapsulation-info type (fdefn-fun fdefn))))
      (setf (fdefn-fun fdefn)
            (named-lambda encapsulation (&rest arg-list)
              (declare (special arg-list))
              (let ((basic-definition (encapsulation-info-definition info)))
                (declare (special basic-definition))
                (eval body)))))))

From this we can figure out that basic advice can be gotten from SBCL like this:

CL-USER(19): (defun gorm (x) (1+ x))
GORM
 
CL-USER(20): (SB-INT:ENCAPSULATE 'gorm 'identity '(apply sb-int:basic-definition sb-int:arg-list))
 
#<closure (SB-C::&OPTIONAL-DISPATCH SB-IMPL::ENCAPSULATION) {ACE428D}>
CL-USER(21): (gorm 10)
11
 
CL-USER(22): (SB-INT:ENCAPSULATE 'gorm 'add-five '(+ 5 (apply sb-int:basic-definition sb-int:arg-list)))
#</closure><closure (SB-C::&OPTIONAL-DISPATCH SB-IMPL::ENCAPSULATION) {ACEE31D}>
 
CL-USER(23): (gorm 10)
16
 
CL-USER(24): (SB-INT:ENCAPSULATE 'gorm 'add-seven '(+ 7 (apply sb-int:basic-definition sb-int:arg-list)))
 
#</closure><closure (SB-C::&OPTIONAL-DISPATCH SB-IMPL::ENCAPSULATION) {ACF84ED}>
CL-USER(25): (gorm)
23
</closure>

We have built a pretty onion, each layer of which calls the next inner layer via BASIC-DEFINITION (the analog to CALL-NEXT-METHOD). Let’s peel specific layers from it:

CL-USER(26): (SB-INT:UNENCAPSULATE 'gorm 'add-five)
T
 
CL-USER(27): (gorm 10)
18
 
CL-USER(28): (SB-INT:UNENCAPSULATE 'gorm 'add-seven)
T
 
CL-USER(29): (gorm 10)
11

A kind of magic

One often has to checking file uploads for correctness, for example with respect to size, file type or file name.

Here’s a sketch for checking the type of image files:

(defun matches-magic (file magic &optional (offset 0))
    (with-open-file (s file :element-type '(unsigned-byte 8))
      (file-position s offset)
      (loop for c across magic
            unless (eql c (code-char (read-byte s)))
            do (return-from matches-magic))
      t))
 
(defun jpeg-p (file) ; won't catch Exif files with JPEG inside
  (matches-magic file "JFIF" 6))
 
(defun png-p (file)
  (matches-magic file "PNG" 1))
 
(defun gif-p (file)
  (matches-magic file "GIF89a"))
 
(defun canonical-image-extension (file)
  (cond
    ((png-p file) "png")
    ((gif-p file) "gif")
    ((jpeg-p file) "jpeg")))
 
(defmacro any-predicate (preds &rest args)
    `(or ,@(loop for p in preds
                 collect `(,p ,@args))))
 
(defun valid-image-p (file)
  (any-predicate (jpeg-p png-p gif-p) file))

ANY-PREDICATE could also be written as a function (with a slightly different form of arguments), here’s another quick draft:

(defun any-predicate (preds &rest args) ; largely untested
  (some #'identity (mapcar (lambda (x) (apply x args))  preds)))
 
(defun valid-image-p (file)
  (any-predicate (list #'jpeg-p #'png-p #'gif-p #'exif-p) file))

Of course, you could also chain SYMBOL-FUNCTION to get rid of the sharp-signs in the call. Whatever suits you.
I like the macro better, though, since it’s clearer and probably more efficient. Update: see below for a comment by Zach Beane on this.

Homework would be writing a simple DSL to jot down file type data:

(define-file-type "jpeg" JFIF 6)

Alternatives from the outer world would be calling file(1) or parsing magic(4).