lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Tue, Sep 26, 2006 at 10:10:18AM -0700, Sam Roberts wrote:
> 1067   L Sep 22 To Lua list     (  71) Re: boolean operators
> 1068   L Sep 22 To Lua list     (  18) ??????>
> 1069 N L Sep 26 To Lua list     (  32) ???*>

> mutt has lots of hooks that should let you make the list look anyway you
> want.. with sufficient work! :-)

The problem with that particular approach (for me) is that I do like
seeing the author names.  If I could alter the formatting for just Lua
messages it might be okay, but I didn't see any hook to accomplish
that.  Another suggestion was to rewrite subject lines as messages are
received, but that has the problem that the edited subject lines would
be carried forward into replies.

So I started thinking, what if I simply embedded Lua into mutt and
added a callback that can adjust the subject line for the folder
display?  I keep forgetting how easy it can be to do that sort of
thing...


.muttrc:
  set luafile="~/.mutt.lua"


.mutt.lua:
  function is_lua_message(envelope)
          return envelope.to[1].mailbox == 'lua@bazar2.conectiva.com.br'
  end

  function get_printable_subject(envelope)
          local subject = envelope.subject
          if subject == nil then subject = '' end
          if is_lua_message(envelope) then
                  subject = '[Lua] ' .. subject
          end
          return subject
  end


2090 N   Sep 29 Hans-Dieter Kos (1.0K) [xine-devel] xine-ui: No Makefiles crea
2091 N   Sep 29 Darren Salt     (1.0K) +->
2092 N   Sep 30 Hans-Dieter Kos (0.9K)   +->
2093 N   Sep 28 chris@seberino. (0.5K) [Tinycc-devel] Basic questions about *i
2094 N   Sep 29 PerfectDark     (0.7K) +->
2095 N   Sep 29 chris@seberino. (0.6K)   +->
2096 N   Sep 28 Wesley Smith    (0.4K) [Lua] "clear" array
2097 N   Sep 28 Glenn Maynard   (0.8K) +->


Problem solved.  A (very rough) patch to mutt 1.5.2 is attached for
the adventurous.  Note that this modifies autotools input files so you
need to run "prepare" in the mutt tree after applying it.

                                                  -Dave Dodge
20060929 Dave Dodge

Embed Lua 5.1 into mutt 1.5.12.

A new "luafile" variable is added to .muttrc, which can be used to
give the path to a file containing Lua code for extending mutt.  If
not specified, no code is loaded.

If Lua defines a global function "get_printable_subject", mutt will
call the function when it needs to display a message subject.  The
function will be passed a table of envelope data for the message (see
the definition of ENVELOPE in mutt.h for an idea of what's in there),
and should return a string containing the message subject for display.

Example: this prepends '[Lua]' when displaying the subject line for
messages from the Lua mailing list:

  function is_lua_message(envelope)
          return envelope.to[1].mailbox == 'lua@bazar2.conectiva.com.br'
  end

  function get_printable_subject(envelope)
          local subject = envelope.subject
          if subject == nil then subject = '' end
          if is_lua_message(envelope) then
                  subject = '[Lua] ' .. subject
          end
          return subject
  end

Index: mutt-1.5.12/mutt-lua.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ mutt-1.5.12/mutt-lua.c	2006-09-29 18:41:45.000000000 -0400
@@ -0,0 +1,192 @@
+#include <stddef.h>
+#include <stdio.h>
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rfc822.h"
+#include "mutt.h"
+#include "mutt-lua.h"
+
+static lua_State * L;
+
+/*
+ * Initialize Lua.  If luafile is non-null this tries to load code
+ * from that file.
+ */
+void mutt_lua_init(const char * luafile)
+{
+	L = luaL_newstate();
+	luaL_openlibs(L);
+	if(luafile != NULL)
+		if(luaL_dofile(L,luafile) != 0)
+			fprintf(stderr,_("failed to load \"%s\" as Lua code.\n"),luafile);
+}
+
+void mutt_lua_set_field_boolean(const char * name,int val)
+{
+	lua_pushboolean(L,val);
+	lua_setfield(L,-2,name);
+}
+
+void mutt_lua_set_field_string_opt(const char * name,const char * value)
+{
+	if(value != NULL)
+	{
+		lua_pushstring(L,value);
+		lua_setfield(L,-2,name);
+	}
+}
+
+/*
+ * Push a table on the top of the stack containing the contents of a
+ * single address.
+ */
+void mutt_lua_push_single_address(ADDRESS * addr)
+{
+	lua_newtable(L);
+#ifdef EXACT_ADDRESS
+	mutt_lua_set_field_string_opt("val",addr->val);
+#endif
+	mutt_lua_set_field_string_opt("personal",addr->personal);
+	mutt_lua_set_field_string_opt("mailbox",addr->mailbox);
+	mutt_lua_set_field_boolean("group",addr->group);
+}
+
+/*
+ * Push a table on the top of the stack containing an array of
+ * addresses.
+ */
+void mutt_lua_push_address_list(ADDRESS * addr)
+{
+	int arrindex = 1;
+	ADDRESS * thisaddr = addr;
+
+	lua_newtable(L);
+
+	while(thisaddr != NULL)
+	{
+		lua_pushinteger(L,arrindex++);
+		mutt_lua_push_single_address(thisaddr);
+		lua_settable(L,-3);
+		thisaddr = thisaddr->next;
+	}
+}
+
+void mutt_lua_set_field_address_list_opt(const char * name,ADDRESS * value)
+{
+	if(value != NULL)
+	{
+		mutt_lua_push_address_list(value);
+		lua_setfield(L,-2,name);
+	}
+}
+
+/*
+ * Push a table on the top of the stack containing an array of
+ * strings.
+ */
+void mutt_lua_push_string_list(LIST * list)
+{
+	int arrindex = 1;
+	LIST * thisnode = list;
+
+	lua_newtable(L);
+
+	while((thisnode != NULL) && (thisnode->data != NULL))
+	{
+		lua_pushinteger(L,arrindex++);
+		lua_pushstring(L,thisnode->data);
+		lua_settable(L,-3);
+		thisnode = thisnode->next;
+	}
+}
+
+void mutt_lua_set_field_string_list_opt(const char * name,LIST * list)
+{
+	if((list != NULL) && (list->data != NULL))
+	{
+		mutt_lua_push_string_list(list);
+		lua_setfield(L,-2,name);
+	}
+}
+
+/*
+ * Push a table on the top of the stack containing the contents of an
+ * envelope.
+ */
+void mutt_lua_push_envelope(ENVELOPE * env)
+{
+	lua_newtable(L);
+	mutt_lua_set_field_address_list_opt("return-path",env->return_path);
+	mutt_lua_set_field_address_list_opt("from",env->from);
+	mutt_lua_set_field_address_list_opt("to",env->to);
+	mutt_lua_set_field_address_list_opt("cc",env->cc);
+	mutt_lua_set_field_address_list_opt("bcc",env->bcc);
+	mutt_lua_set_field_address_list_opt("sender",env->sender);
+	mutt_lua_set_field_address_list_opt("reply-to",env->reply_to);
+	mutt_lua_set_field_address_list_opt("mail-followup-to",env->mail_followup_to);
+	mutt_lua_set_field_string_opt("list-post",env->list_post);
+	mutt_lua_set_field_string_opt("subject",env->subject);
+	mutt_lua_set_field_string_opt("real-subj",env->real_subj);
+	mutt_lua_set_field_string_opt("message-id",env->message_id);
+	mutt_lua_set_field_string_opt("supersedes",env->supersedes);
+	mutt_lua_set_field_string_opt("date",env->date);
+	mutt_lua_set_field_string_opt("x-label",env->x_label);
+	mutt_lua_set_field_string_list_opt("references",env->references);
+	mutt_lua_set_field_string_list_opt("in-reply-to",env->in_reply_to);
+	mutt_lua_set_field_string_list_opt("userhdrs",env->userhdrs);
+	mutt_lua_set_field_boolean("irt_changed",env->irt_changed);
+	mutt_lua_set_field_boolean("refs_changed",env->refs_changed);
+}
+
+/*
+ * Get the printable subject for an envelope.  If a
+ * "get_printable_subject" function has been defined in the Lua state,
+ * that will be called with a table containing the envelope contents,
+ * and it should return the printable string for the subject.  If no
+ * such function is defined in Lua, this just returns the subject
+ * string from the envelope directly.
+ *
+ * The string returned by this function is only valid until the next
+ * call to any mutt_lua_* function.  If you need it for a longer
+ * period of time the caller must copy it.
+ */
+const char * mutt_lua_get_printable_subject(ENVELOPE * env)
+{
+	lua_getglobal(L,"get_printable_subject");
+	if(lua_isfunction(L,-1))
+	{
+		/* A Lua function was found. */
+		const char * substr;
+
+		mutt_lua_push_envelope(env);
+		lua_pcall(L,1,1,0);
+
+		/*
+		 * Copy the result string to the registry so that it
+		 * will not be subject to GC when we pop it off of the
+		 * stack.  The C pointer to the string data should
+		 * remain valid until something replaces it in the
+		 * registry.
+		 */
+		lua_pushvalue(L,-1);
+		lua_setfield(L,LUA_REGISTRYINDEX,
+			"mutt_lua_get_printable_subject_result");
+
+		substr = lua_tostring(L,-1);
+		lua_pop(L,1);
+		return (substr == NULL) ? "LUA ERROR" : substr;
+	}
+	else
+	{
+		/* No such Lua function. */
+		lua_pop(L,1);
+		return env->subject;
+	}
+}
Index: mutt-1.5.12/Makefile.am
===================================================================
--- mutt-1.5.12.orig/Makefile.am	2006-07-05 04:43:47.000000000 -0400
+++ mutt-1.5.12/Makefile.am	2006-09-29 16:33:20.000000000 -0400
@@ -29,10 +29,11 @@
 	score.c send.c sendlib.c signal.c sort.c \
 	status.c system.c thread.c charset.c history.c lib.c \
 	muttlib.c editmsg.c utf8.c mbyte.c wcwidth.c \
-	url.c ascii.c mutt_idna.c crypt-mod.c crypt-mod.h
+	url.c ascii.c mutt_idna.c crypt-mod.c crypt-mod.h \
+	mutt-lua.c
 
 mutt_LDADD = @MUTT_LIB_OBJECTS@ @LIBOBJS@ $(LIBIMAP) $(MUTTLIBS) \
-	$(INTLLIBS) $(LIBICONV)  $(LIBGPGME_LIBS)
+	$(INTLLIBS) $(LIBICONV)  $(LIBGPGME_LIBS) $(LUA_LIBS)
 
 mutt_DEPENDENCIES = @MUTT_LIB_OBJECTS@ @LIBOBJS@ $(LIBIMAPDEPS) \
 	$(INTLDEPS)
@@ -54,7 +55,7 @@
 	-DBINDIR=\"$(bindir)\" -DMUTTLOCALEDIR=\"$(datadir)/locale\" \
 	-DHAVE_CONFIG_H=1
 
-INCLUDES=-I. -I$(top_srcdir) $(IMAP_INCLUDES) $(LIBGPGME_CFLAGS) -Iintl
+INCLUDES=-I. -I$(top_srcdir) $(IMAP_INCLUDES) $(LIBGPGME_CFLAGS) $(LUA_INCLUDES) -Iintl
 
 CPPFLAGS=@CPPFLAGS@ -I$(includedir)
 
Index: mutt-1.5.12/configure.in
===================================================================
--- mutt-1.5.12.orig/configure.in	2006-07-14 14:15:32.000000000 -0400
+++ mutt-1.5.12/configure.in	2006-09-29 16:59:02.000000000 -0400
@@ -674,6 +674,72 @@
 
 dnl -- end socket --
 
+dnl -- Lua --
+dnl Based on various sources including a discussion on the Darcs list
+dnl and the Ethereal Lua test code.  We want Lua 5.1.
+
+AC_ARG_WITH([lua-prefix],
+	[AS_HELP_STRING([--with-lua-prefix=DIR],
+		[Lua files are in DIR])])
+
+if test "x$with_lua_prefix" = x; then
+    lua_search_path="$PATH"
+else
+    lua_search_path="$with_lua_prefix/bin"
+fi
+if test "x$LUA" = x; then
+    AC_PATH_PROG([LUA], [lua], [], [$lua_search_path])
+    test "x$LUA" = x && AC_MSG_ERROR([*** Can't build mutt without lua])
+fi
+
+AC_MSG_CHECKING([for lua version 5.1])
+lua_version=$($LUA -v 2>&1 | head -n 1 | cut -d' ' -f2)
+case $lua_version in
+5.1 | 5.1.*)
+    AC_MSG_RESULT([yes (found $lua_version)])
+    ;;
+*)
+    AC_MSG_RESULT([no (found $lua_version)])
+    AC_MSG_ERROR([*** can't build mutt with this version of lua])
+    ;;
+esac
+
+LUA_INCLUDES="-I$with_lua_prefix/include"
+LUA_LIBS="-L$with_lua_prefix/lib -llua -lm -ldl"
+
+save_CFLAGS="$CFLAGS"
+save_CPPFLAGS="$CPPFLAGS"
+save_LDFLAGS="$LDFLAGS"
+save_LIBS="$LIBS"
+
+CFLAGS="$CFLAGS $LUA_INCLUDES"
+CPPFLAGS="$CPPFLAGS $LUA_INCLUDES"
+LIBS="$LIBS $LUA_LIBS"
+LDFLAGS="$LDFLAGS $LUA_LIBS"
+
+AC_CHECK_HEADERS(
+	[lua.h lualib.h lauxlib.h],
+	[],
+	[AC_MSG_ERROR([*** missing headers lua.h or lualib.h.])],
+	[])
+
+AC_CHECK_LIB(
+	[lua],
+	[lua_call],
+	[],
+	[AC_MSG_ERROR([*** Can't find lua_call in liblua.])],
+	[])
+
+CFLAGS="$save_CFLAGS"
+CPPFLAGS="$save_CPPFLAGS"
+LIBS="$save_LIBS"
+LDFLAGS="$save_LDFLAGS"
+
+AC_SUBST(LUA_INCLUDES)
+AC_SUBST(LUA_LIBS)
+
+dnl -- end Lua --
+
 AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [Enable debugging support]),
         [ if test x$enableval = xyes ; then
                 AC_DEFINE(DEBUG,1,[ Define to enable debugging info. ])
Index: mutt-1.5.12/hdrline.c
===================================================================
--- mutt-1.5.12.orig/hdrline.c	2006-04-28 15:43:51.000000000 -0400
+++ mutt-1.5.12/hdrline.c	2006-09-29 16:50:02.000000000 -0400
@@ -26,6 +26,7 @@
 #include "charset.h"
 #include "mutt_crypt.h"
 #include "mutt_idna.h"
+#include "mutt-lua.h"
 
 #include <ctype.h>
 #include <stdlib.h>
@@ -548,7 +549,8 @@
       {
 	if (flags & M_FORMAT_FORCESUBJ)
 	{
-	  mutt_format_s (dest, destlen, "", NONULL (hdr->env->subject));
+	  mutt_format_s (dest, destlen, "",
+	    NONULL (mutt_lua_get_printable_subject (hdr->env)));
 	  snprintf (buf2, sizeof (buf2), "%s%s", hdr->tree, dest);
 	  mutt_format_s_tree (dest, destlen, prefix, buf2);
 	}
@@ -556,7 +558,8 @@
 	  mutt_format_s_tree (dest, destlen, prefix, hdr->tree);
       }
       else
-	mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->subject));
+	mutt_format_s (dest, destlen, prefix,
+          NONULL (mutt_lua_get_printable_subject (hdr->env)));
       break;
 
     case 'S':
Index: mutt-1.5.12/mutt-lua.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ mutt-1.5.12/mutt-lua.h	2006-09-29 17:19:04.000000000 -0400
@@ -0,0 +1,23 @@
+
+#ifndef MUTT_LUA_H_INCLUDED
+#define MUTT_LUA_H_INCLUDED
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rfc822.h"
+#include "mutt.h"
+
+extern void mutt_lua_init(const char *);
+extern void mutt_lua_set_field_boolean(const char *,int);
+extern void mutt_lua_set_field_string_opt(const char *,const char *);
+extern void mutt_lua_push_single_address(ADDRESS *);
+extern void mutt_lua_push_address_list(ADDRESS *);
+extern void mutt_lua_set_field_address_list_opt(const char *,ADDRESS *);
+extern void mutt_lua_push_string_list(LIST *);
+extern void mutt_lua_set_field_string_list_opt(const char *,LIST *);
+extern void mutt_lua_push_envelope(ENVELOPE *);
+extern const char * mutt_lua_get_printable_subject(ENVELOPE *);
+
+#endif /* MUTT_LUA_H_INCLUDED */
Index: mutt-1.5.12/globals.h
===================================================================
--- mutt-1.5.12.orig/globals.h	2006-07-05 04:40:05.000000000 -0400
+++ mutt-1.5.12/globals.h	2006-09-29 17:14:05.000000000 -0400
@@ -65,6 +65,7 @@
 WHERE char *Inbox;
 WHERE char *Ispell;
 WHERE char *Locale;
+WHERE char *Luafile;
 WHERE char *MailcapPath;
 WHERE char *Maildir;
 #if defined(USE_IMAP) || defined(USE_POP)
Index: mutt-1.5.12/init.h
===================================================================
--- mutt-1.5.12.orig/init.h	2006-07-05 04:40:05.000000000 -0400
+++ mutt-1.5.12/init.h	2006-09-29 17:17:06.000000000 -0400
@@ -1106,6 +1106,11 @@
   */
 #endif /* HAVE_QDBM */
 #endif /* USE_HCACHE */
+  { "luafile",		DT_PATH, R_NONE, UL &Luafile, 0 },
+  /*
+  ** .pp
+  ** The path of a file containing Lua code to be used to extend Mutt.
+  */
   { "maildir_trash", DT_BOOL, R_NONE, OPTMAILDIRTRASH, 0 },
   /*
   ** .pp
Index: mutt-1.5.12/main.c
===================================================================
--- mutt-1.5.12.orig/main.c	2006-07-11 19:38:47.000000000 -0400
+++ mutt-1.5.12/main.c	2006-09-29 17:19:58.000000000 -0400
@@ -31,6 +31,7 @@
 #include "url.h"
 #include "mutt_crypt.h"
 #include "mutt_idna.h"
+#include "mutt-lua.h"
 
 #ifdef USE_SASL
 #include "mutt_sasl.h"
@@ -706,6 +707,9 @@
   /* Initialize crypto backends.  */
   crypt_init ();
 
+  /* Initialize Lua support. */
+  mutt_lua_init (Luafile);
+
   if (queries)
     return mutt_query_variables (queries);
   if (dump_variables)