Wednesday, May 25, 2011

Email Me At...

I have long looked for a feature for Gmail that will delay sending a message until a certain time. Recently I wanted to send a good friend a Happy Birthday message, right when it was her birthday (one second after midnight). If only there was some way to do that...

Luckily, I didn't have to stay up until midnight to do it, but rather cobbled together a nifty Python script that will wait until a given time, then send a message (including HTML if you have it).

#!/usr/bin/env python

import datetime
import re
import smtplib
import time

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

gmail_user = "yourname@gmail.com"
gmail_pwd = "MyP@$$W0Rd"

def mail(to, subject, body):
msg = MIMEMultipart('alternative')

msg['From'] = gmail_user
msg['To'] = to
msg['Subject'] = subject

if '<html>' in body:
msg.attach(MIMEText(re.sub(r'<.*?>', '', body), 'plain'))
msg.attach(MIMEText(body, 'html'))
else:
msg.attach(MIMEText(body, 'plain'))

m = smtplib.SMTP("smtp.gmail.com", 587)
m.ehlo()
m.starttls()
m.ehlo()
m.login(gmail_user, gmail_pwd)
m.sendmail(gmail_user, to, msg.as_string())
m.quit()

if __name__ == "__main__":
while datetime.datetime.today() < datetime.datetime(2011, 5, 24):
time.sleep(1)

mail("someone_else@gmail.com", "subject",
"<html><b>bold body</b> non-bold body</html>")

Things to Note:
  • Line 11-12, you will need to enter your Gmail address, along with your password in plaintext, so be careful.
  • Line 21, If the body of the message you want to send has the tag <html> it will be sent as an HTML message, all tags will also be stripped and a plaintext version will be put in the document as well.
  • Line 36, The date you use needs to be in ISO format, YYYY-MM-DD, if you want you can even add HH, MM, and SS like this:
    datetime.datetime(2011, 5, 24, 13, 5, 19)
  • Line 39: The first param is the address you are sending to, the second is the subject, and the third is the body (with or without html).
Making one of these read from a .csv file could be insanely useful.

    Wednesday, May 18, 2011

    Three Comics

    It is unlikely that I'll become Randall Munroe any time soon, but hey, I figure I'll just share these while my code is compiling for the "One Hour Linux Distribution With an X-Server" (if it works, I'll post it later).






    All made in Gimp.

    Saturday, May 14, 2011

    SVN Branch Copy

    I was recently in the position of needing a particular SVN branch copied including history. However I didn't have administrator access on the SVN machine, and using the SVNSYNC command was going to copy all eighteen thousand revisions, mine were about fifty scattered within the last thousand. That was less than ideal.

    I devised a way to do it though, and in a few hours came up with a handy script (yeah yeah, a few hours isn't exactly a one hour hack, but downloading the SVN branch you want should be).


    Essentially the script does this:
    1. INIT a new repo at the desired location.
    2. Check out the most current branch of the old repo.
    3. Check the history of the old repo to check which revisions to sync (the changed ones).
    4. For each changed one, check it out, rsync it to the checked out new repo, and commit it to the new repo with the old log message.
    5. Finish some time later after you have made yourself a cup of tea and watched the most recent Doctor Who.

    #!/bin/bash

    # Check for proper args
    if [ -z "$1" ];
    then
    echo -e "Usage:\n$0 URL_TO_COPY_FROM URL_TO_COPY_TO" && exit 1
    fi;

    SVNFROM=$1
    SVNTO=$2

    echo "Fetching branch from: $SVNFROM"
    echo "Copying branch to: $SVNTO"

    # Set up environment.
    if [ -e tempsvn ];
    then
    rm -rf tempsvn
    fi;

    mkdir tempsvn tempsvn/download tempsvn/upload tempsvn/current
    cd tempsvn

    echo "Checking out current..."
    svn co $SVNFROM current
    HISTORY=`svn log current | grep \| | cut -d\ -f1 | sed 's/r\([0-9]*\).*/\1/' | sort -k1,1n`

    # Init the new repo at the given location.
    svn import upload $SVNTO -m ""
    svn co $SVNTO upload

    num=`echo $HISTORY | wc -w`
    echo "There are $num revisions in this branch."


    for REVNO in $HISTORY; do
    rm -rf download
    echo "-----------------------------------------------------------------------"
    echo "Revision: $REVNO"
    echo "Fetching..."
    ENTRIES=`svn co $SVNFROM@$REVNO download`
    CHANGES=`echo $ENTRIES | wc -l`
    echo "Found $CHANGES change(s)."

    echo "Change Log:"
    cd download
    LOG=`svn log -r $REVNO | grep \- -v`
    echo $LOG
    echo ""
    cd ..

    echo "Exporting..."
    rsync -a --exclude='.svn' download/ upload/

    cd upload

    IFS_BAK=$IFS
    IFS=$'\n'
    for E in $ENTRIES; do
    BEGIN=`echo $E | cut -d\ -f1`
    END=`echo $E | cut -d\ -f5- | cut -d/ -f2-`

    case "$BEGIN" in
    'A') svn add -q $END ;;
    'D') svn del $END ;;
    esac
    done
    IFS=$IFS_BAK

    if [ -e log.log ]; then rm log.log; fi;

    echo $LOG > log.log
    echo "Commiting new..."
    svn commit -F log.log
    cd ..
    done
    # Tear down environment.
    cd ..
    rm -rf tempsvn

    One slight problem though, it removes and re-checks out the branch it is copying from every time because I was getting strange errors about branches being out of date, if anyone could fix that, it would increase the speed greatly.

    Tuesday, May 3, 2011

    Protocols #6, Character Generator Protocol

    In May of 1983, the Character Generator Protocol was introduced in RFC 864. It existed already on computers mainly as a test for terminals (TTYs in that image you can actually see a character test program) to make sure that they could properly display all of the characters in the vastly huge ASCII character set. Now ASCII is a bad joke. The protocol was introduced to do the same thing over networks (an early ping like utility).


    In the modern day Internet, the original protocol needs to be amended slightly: the RFC states that the protocol will continue sending information until the client closes the connection; however I made it auto-close after 1000 outputs because eventually node.js runs out of memory and dies. It would also be nice not to have all of your Internet connection lines taken up by three people that never closed their chargen. Without further ado:
    #!/usr/bin/nodejs

    var net = require('net');
    var dgram = require('dgram');

    var linewidth = 72; //Width of a line of text on the console.
    var str = "";

    //Generate from: ! to ~
    for(var i = 33; i < 127; i++) {
    str += String.fromCharCode(i);
    }

    //Make sure length is at least 512 bytes (max for udp)
    for(var i = str.length; i < 512; i += str.length)
    {
    str += str;
    }


    function getline(lineno) {
    return str.substr(lineno % (127 - 33), linewidth ) + "\n";
    }

    //TCP
    var tcpserver = net.createServer(function (socket) {
    var j = 0;
    while(j < 1000)
    {
    socket.write(getline(j));
    j++;
    }
    socket.end();
    })

    //UDP
    var udpserver = dgram.createSocket("udp4", function (msg, rinfo) {
    var ret = new Buffer(str.substr(0, Math.floor(Math.random()*(513))));
    udpserver.send(ret, 0, ret.length, rinfo.port, rinfo.address);
    });

    //Bind and serve (Port 19 is actual)
    tcpserver.listen(8019, "127.0.0.1");
    udpserver.bind(8019, "127.0.0.1");

    As usual the port numbers have been boosted by 8000, so before actually using, change those and the host computer IP addresses.