Friday, December 25, 2009

Sending HTML email from Cocoa

In a previous post I described sending email using c-client. This post takes things a little bit further and describes sending an email containing HTML content using the same c-client API.

First things first - people usually call HTML email an HTML fragment that refers inline images. These images are part of the email too and they are referred in the HTML source by their content id (using a special construct on the source reference, i.e. img src="cid:image_content_id").

Mail clients (at least Snow Leopard's Mail.app) expect the HTML fragment and the images they refer to be part of the same container. This container is a MIME multipart/related container.

The simplest HTML message that we can send is based on the following MIME multipart structure:




#include <c-client.h>

#include "c-client-interface.c"
int main()
{
#include "linkage.c"

char * hostlist[] = { "smtp.gmail.com/ssl/user=user@gmail.com/smtp", NULL };

SENDSTREAM * sndstream = smtp_open(hostlist, 0);
if(sndstream == NULL)
{
fprintf(stderr, "Can't open SMTP connection\n");
return 1;
}

BODY * body = mail_newbody();

ENVELOPE * env = mail_newenvelope();
ADDRESS * to = mail_newaddr();

env->from = mail_newaddr();
env->from->personal = strdup("User Name");
env->from->mailbox = strdup("username");
env->from->host = strdup("gmail.com");
env->subject = strdup("subject");

rfc822_parse_adrlist(&env->to, strdup("username"), strdup("destination.dom"));

char *text = (char *) fs_get (8*MAILTMPLEN);
strcpy(text, "test message \015\012\0");

#define HTMLfragment "<HTML><p>A little bit in <b>bold</b> and some <i>italic</i><br/><br/> </p><p><img src=\"cid:55665566\"></p><p>The end</p></HTML>"

/* We need three parts, a part for HTML, a part for the image and
a part that groups them (called related). */



PART * htmlpart, *imagepart, *related;
related = mail_newbody_part();
related->body.type = TYPEMULTIPART;
related->body.subtype = cpystr("related");

htmlpart = mail_newbody_part();
htmlpart->body.encoding = ENCBASE64;
htmlpart->body.contents.text.data = (char *) rfc822_binary (HTMLfragment, strlen(HTMLfragment), &htmlpart->body.contents.text.size);

htmlpart->body.parameter = mail_newbody_parameter ();
htmlpart->body.parameter->attribute = cpystr ("CHARSET");
htmlpart->body.parameter->value = cpystr ("US-ASCII");
htmlpart->body.type = TYPETEXT;
htmlpart->body.subtype = cpystr ("HTML");
htmlpart->body.description = cpystr ("html version");

//for brevity, we define a GIF file inline. in real code, you would probably load this from a file
unsigned char buf[] = {0x47, 0x49, 0x46,0x38,0x37,0x61,0x0c,0x00,0x0c,0x00,0xc2,0x04,0x00,0x00,0x24,0xff,0xff,0x00,0x00,0x00,0xa0,0x0b,0xf6,0x7a
,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x0c,0x00,0x0c,0x00,0x00,0x03,0x23,0x18,0xba,0xd3,0xbe,0xcc,0
x35,0xa8,0xe4,0xa4,0x76,0x50,0x42,0x2c,0xe4,0x9c,0x24,0x8c,0x02,0x48,0x00,0x28,0x40,0x8e,0x5c,0x8a,0xae,0xa3,0xfb,0xc2,0xb2,0x4a,0xcb,0xb0,0x50,0x27,0x0
0,0x3b};

/* allocate a MIME part for the image content at the end of the HTML part */
imagepart = (htmlpart->next = mail_newbody_part());
/* the image is binary so we encode in base64 */
imagepart->body.encoding = ENCBASE64;
imagepart->body.contents.text.data = (char *) rfc822_binary(buf, 86, &imagepart->body.contents.text.size);
imagepart->body.type = TYPEIMAGE;
imagepart->body.subtype = cpystr ("GIF");
imagepart->body.id = cpystr("<55665566>");

/* Our body's content is of type multipart and it contains a nested part
that is in fact the related part that we have created above */

body->type = TYPEMULTIPART;
body->subtype = cpystr("alternative");
body->nested.part = mail_newbody_part ();
body->nested.part->body.contents.text.data = text;
body->nested.part->body.contents.text.size = strlen (text);


related->body.nested.part = htmlpart;
body->nested.part->next = related;

long result = smtp_mail(sndstream, "MAIL", env, body);

if(sndstream)
smtp_close(sndstream);

mail_free_envelope(&env);
mail_free_body(&body);
}



Our message in Mail.app:

Friday, December 11, 2009

Creating QR codes on Mac OS X Snow Leopard

This post describes a step by step procedure to compile and run qrencode, a command line tool for encoding text into png files of QRcodes written by FUKUCHI Kentaro as part of libqrencode (licensed under LGPL).


1/ Create a directory for our project
cristi:~ diciu$ mkdir qr
cristi:~ diciu$ cd qr/


2/ Download the libqrencode source, and untar it.
cristi:qr diciu$ tar zxvf qrencode-3.1.0.tar.gz
cristi:qr diciu$ cd qrencode-3.1.0


3/ We need to set a couple of environment variables to tell configure where the libpng libraries and headers are:
cristi:qrencode-3.1.0 diciu$export png_CFLAGS="-I /usr/X11/include/"
cristi:qrencode-3.1.0 diciu$export png_LIBS="-lpng -L/usr/X11/lib/"


4/ Even though we don't need pkg-config (that's why we exported vars in step 3), configure requires a pkg-config script, so we'll create an empty one and add it to the path.

cristi:qrencode-3.1.0 diciu$ touch pkg-config
cristi:qrencode-3.1.0 diciu$ chmod +x pkg-config
cristi:qrencode-3.1.0 diciu$ export PATH=$PATH:.


5/ Now we have everything we need, so we can run ./configure

./configure --disable-video --without-imagemagick --without-gtk --without-qt --without-python


6/ Once configure runs, we can run make to build it
make


7/ And finally we get to encode a qr code:
./qrencode -o ~/Desktop/modulo.png "http://www.modulo.ro"


The end result:

Friday, December 04, 2009

Query strings received from Google

Some of the unexpected queries that get here and some hopefully useful answers:

1/ Some netstat based commands, e.g.:

netstat -anp | grep "tcp\|udp" | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n

As far as I can tell, it prints a summary of network connections. This includes established connections and connections that are about to close, and also connections that are locally awaiting for a client.

In the Mac OS X version of netstat, the "-p" option is not supported; sort is also capable of uniquing its results so you can rewrite the line as:

netstat -an | grep "tcp\|udp" | awk '{print $5}' | cut -d: -f1 | sort -nu




2/ check a word how many times in nsstring

I'd do something like:

int count = 0;
NSString * s = [NSString stringWithString:@"foobar contains foobar and some more foobar"];
while([s rangeOfString:@"foobar"].location != NSNotFound)
{
count++;
s = [s substringFromIndex:([s rangeOfString:@"foobar"].location + [s rangeOfString:@"foobar"].length)];
}



3/ /tmp/msgsends

It's the prefix of files created by setting the variable NSObjCMessageLoggingEnabled to YES in the environment of a Cocoa application. The ObjC runtime will write an entry for each ObjC message received in the application.

4/ average life expectancy of macbook

I don't really know - we've had two in the office, one ran for about 18 months before dying (mine), the other is still running (after more then 2 years).

5/ core image histogram
Look for vImageHistogramCalculation_ARGB8888, part of Accelarate.framework.

6/ raising x to power of y "objective c"

NSLog(@"2 to the power of 3: %f", pow(2.0, 3.0));