Friday, March 18, 2011

Javascript delaying

In need of executing Javascript after the page has loaded, or something else has been initialized I came up with a simple but useful tiny "Delayer":



/**
* @param handler a callback accepting Delayer.dispatch as argument
*/
function Delayer(handler) {
var self = this;

this.dispatch = function() {
for (var i = 0; i < self.length; ++i) {
console.log("running delayed init "+i+": "+self[i]);
self[i]();
}
};

if (typeof handler == "function" || handler instanceof Function) {
handler(this.dispatch);
}
}

Delayer.prototype = Array.prototype;

It can be initialized the following way:



/* e.g. with jQuery */
window.delayedInits = new Delayer($(document).ready);
/* e.g. with Facebook */
window.fbDelayedInits = new Delayer(function(dp){window.fbAsyncInit = dp;});

Then you push your work the usual way:



delayedInits.push(function() {alert("Hello, delayed!");});

Monday, March 14, 2011

courier imap, authdaemond and vpopmails vchkpw

A few years ago, it was possible to have courier-imap update the open-smtp relay file with it's authvchkpw module. This feature and thus imap-before-smtp disappeared with the introduction of courier-authdaemond because the vchkpw code of authdaemond does not have a chance to see the TCPREMOTEIP environment variable.


I more or less lived with that, until a friend of mine got a new iphone... well yeah, one of those i-geeks, and that gadget apparently only supports imap, no pop.


To re-enable imap-before-smtp I wrote a little setuid wrapper, calling vpopmails open_smtp_relay(). This wrapper has to replace the imapd command in your courier-imap startup script and will exec imapd, after opening the smtp relay, wile imap-login is still in place to authenticate via authdaemond's vchkpw module.



#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <vpopmail_config.h>
#include <vauth.h>
#include <vpopmail.h>

#ifndef IMAPD
# define IMAPD "/usr/bin/imapd"
#endif

extern char **environ;

int main(int argc, const char *argv[]) {
if (argc != 2) {
printf("1 NO argc != 2n");
return -1;
}

open_smtp_relay();
/* no need to chown vpopmail.vchkpw the open-smtp file
* because vchkpw used by qmail-pop3d is setuid root */

sleep(1);

if (setgid(VPOPMAILGID) || setuid(VPOPMAILUID)) {
printf("1 NO setuid/gid, getuid=%dn", getuid());
return -2;
}

execl(IMAPD, IMAPD, argv[1], NULL);

printf("1 NO exec %s failedn", IMAPD);
return -3;
}

So while this worked to my satisfaction, I noticed that the tcp.smtp.cdb not always contained the IPs of the open-smtp file:



$ for ip in $(sed -re 's/:.*//' < open-smtp); do
cdbget $ip < tcp.smtp.cdb > /dev/null
|| echo "$ip is missing";
done

I also found out that, while the vpopmail FAQ is claiming that clearopensmtp is requesting locks on the open-smtp(.lock) file, the source does not read like it would.
I opened a bug report for that issue, but as you might have already guessed, I'm running all of this on an archaic debian box, where no upgrades are planned. So I came up with another home-brewed solution:



#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <vpopmail_config.h>
#include <vauth.h>
#include <vpopmail.h>
#include <fcntl.h>

extern int get_write_lock(FILE*);
extern int lock_reg(int,int,int,off_t,int,off_t);
#define unlock(F) lock_reg(fileno(F), F_SETLK, F_UNLCK, 0, SEEK_SET, 0)

int main(int argc, const char *argv[]) {
FILE *fs_temp, *fs_smtp, *fs_lock = fopen(OPEN_SMTP_LOK_FILE, "w+");
time_t clear = RELAY_CLEAR_MINUTES * 60, now = time(NULL);
int cc = 0, rc = 0;

if (!fs_lock) {
return -1;
}
if (get_write_lock(fs_lock)) {
unlock(fs_lock);
fclose(fs_lock);
return -2;
}

if (!(fs_temp = fopen(OPEN_SMTP_TMP_FILE ".clear", "w"))) {
rc = -3;
} else if (!(fs_smtp = fopen(OPEN_SMTP_CUR_FILE, "r+"))) {
fclose(fs_temp);
rc = -4;
} else {
while (!rc && !feof(fs_smtp)) {
unsigned stime;
char sdata[256];

switch (fscanf(fs_smtp, "%255st%un", sdata, &stime)) {
case 2:
if ((clear + stime) >= now) {
fprintf(fs_temp, "%st%un", sdata, stime);
} else {
++cc;
}
break;

default:
rc = -5;
case EOF:
break;
}
}
fclose(fs_smtp);
fclose(fs_temp);
}

if (!rc) {
if (cc) {
if (rename(OPEN_SMTP_TMP_FILE ".clear", OPEN_SMTP_CUR_FILE)) {
rc = -6;
} else if(update_rules()) {
rc = -7;
}
} else {
unlink(OPEN_SMTP_TMP_FILE ".clear");
}
}

unlock(fs_lock);
fclose(fs_lock);
return rc;
}

It's not the prettiest piece of code, but it helps.
Well, maybe someone else running last-millenium software finds this useful