shithub: mongrel

ref: cdb993dffbd3050112b2fc3a93d7f51eead2ec74
dir: /pager.c/

View raw version
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <thread.h>
#include <plumb.h>
#include "theme.h"
#include "a.h"
#include "w.h"

enum
{
	Padding = 4,
};

static Mousectl *mc;
static Text text;
static Rectangle viewr;
static Rectangle headr;
static Rectangle partsr;
static Rectangle textr;
static Image *cols[NCOLS];
static Image *headercol;
static Message *mesg;
static Tzone *tz;
static int showcc;
static Message *parts[16];
static int nparts;

char*
findtextpart(Message *m)
{
	Message *p;
	int i;

	if(strncmp(m->type, "multipart/", 10) == 0){
		for(i = 0; i < m->parts->nelts; i++){
			p = m->parts->elts[i];
			if(strcmp(p->type, "text/plain") == 0)
				return p->body;
			else if(strncmp(p->type, "multipart/", 10) == 0)
				return findtextpart(p);
		}
	}
	return m->body;
}

void
collectparts(Message *m)
{
	Message *p;
	int i;

	if(m->parts == nil)
		return;
	for(i = 0; i < m->parts->nelts; i++){
		p = m->parts->elts[i];
		if(strncmp(p->type, "multipart/", 10) == 0)
			collectparts(p);
		else{
			if(strcmp(p->type, "text/plain") == 0)
				continue;
			parts[nparts++] = p;
		}
	}
}

void
pagershow(Message *m)
{
	char *body;
	int needresize;
	int oldnparts;

	oldnparts = nparts;
	needresize = 0;
	mesg = m;
	if(showcc){
		if(mesg->cc == nil || mesg->cc[0] == 0){
			showcc = 0;
			needresize = 1;
		}
	}else{
		if(mesg->cc != nil && mesg->cc[0] != 0){
			showcc = 1;
			needresize = 1;
		}
	}
	mesgloadbody(mesg);
	nparts = 0;
	collectparts(mesg);
	if(nparts != oldnparts)
		needresize = 1;
	if(needresize)
		pagerresize(viewr);
	body = findtextpart(mesg);
	textset(&text, body, strlen(body));
	pagerdraw();
}

static
Point
drawheader(Point p, char *h, char *s)
{
	Rune r;
	
	p = string(screen, p, cols[BORD], ZP, font, h);
	while(s && *s){
		s += chartorune(&r, s);
		p = runestringn(screen, p, cols[TEXT], ZP, font, &r, 1);
	}
	return p;
}

Point
drawparts(Point p)
{
	Point q;
	int i;

	for(i = 0; i < nparts; i++){
//		q = string(screen, p, cols[TEXT], ZP, font, "=> ");
		q = p;
		if(parts[i]->filename != nil && parts[i]->filename[0] != 0)
			q = string(screen, q, cols[TEXT], ZP, font, parts[i]->filename);
		else
			q = string(screen, q, cols[TEXT], ZP, font, "unnamed");
		q = string(screen, q, cols[BORD], ZP, font, " [");
		q = string(screen, q, cols[BORD], ZP, font, parts[i]->type);
		string(screen, q, cols[BORD], ZP, font, "]");
		p.y += font->height + Padding;
	}
	return p;
}

void
pagerdraw(void)
{
	Point p, q;
	char buf[32], *s;
	Rune r;
	Tm t;
	int w;

	draw(screen, viewr, cols[BACK], nil, ZP);
	if(mesg != nil){
		p = addpt(headr.min, Pt(Padding, Padding));
		tmtime(&t, mesg->time, tz);
		snprint(buf, sizeof buf, "%τ", tmfmt(&t, "DD/MM/YYYY hh:mm"));
		w = stringwidth(font, buf);
		string(screen, addpt(p, Pt(Dx(headr) - w - 2*Padding, 0)), cols[TEXT], ZP, font, buf);
		q = drawheader(p, "   From ", mesg->sender);
		if(strcmp(mesg->sender, mesg->from) != 0){
			q = string(screen, q, cols[TEXT], ZP, font, " <");
			s = mesg->from;
			while(s && *s){
				s += chartorune(&r, s);
				q = runestringn(screen, q, cols[TEXT], ZP, font, &r, 1);
			}
			string(screen, q, cols[TEXT], ZP, font, ">");
		}
		p.y += font->height + Padding;
		drawheader(p, "     To ", mesg->to);
		if(showcc){
			p.y += font->height + Padding;
			drawheader(p, "     Cc ", mesg->cc);
		}
		p.y += font->height + Padding;
		drawheader(p, "Subject ", mesg->subject);
	}
	line(screen, addpt(headr.min, Pt(0, Dy(headr))), headr.max, 0, 0, 0, headercol, ZP);
	if(nparts > 0){
		p = addpt(partsr.min, Pt(Padding, Padding));
		drawparts(p);
		line(screen, addpt(partsr.min, Pt(0, Dy(partsr))), partsr.max, 0, 0, 0, headercol, ZP);
	}
	textdraw(&text);
}

void
pagerresize(Rectangle r)
{
	int n;

	n = showcc ? 4 : 3;
	viewr = r;
	headr = viewr;
	headr.max.y = headr.min.y + Padding + n*(font->height + Padding);
	if(nparts > 0){
		partsr = viewr;
		partsr.min.y = headr.max.y + 1;
		partsr.max.y = partsr.min.y + nparts*(font->height + Padding) + Padding;
	}
	textr = viewr;
	if(nparts > 0)
		textr.min.y = partsr.max.y + 1;
	else
		textr.min.y = headr.max.y + 1;
	textresize(&text, textr);
}

void
partclick(Point p)
{
	Message *m;
	char *dst, buf[1024] = {0};
	int fd, n;

	fd = plumbopen("send", OWRITE);
	if(fd < 0)
		return;
	n = (p.y - partsr.min.y) / (font->height+Padding);
	if(n < 0 || n >= nparts){
		close(fd);
		return;
	}
	m = parts[n];
	dst = nil;
	if(strcmp(m->type, "text/html") == 0){
		snprint(buf, sizeof buf, "file://%s/body.html", m->path);
		dst = "web";
	}else if(strncmp(m->type, "image/", 6) == 0){
		snprint(buf, sizeof buf, "%s/body.%s", m->path, m->type+6);
		dst = "image";
	}else{
		snprint(buf, sizeof buf, "%s/body", m->path);
	}
	plumbsendtext(fd, "mongrel", dst, nil, buf);
	close(fd);
}

void
pagermouse(Mouse m)
{
	if(!ptinrect(m.xy, viewr))
		return;
	if(nparts > 0 && ptinrect(m.xy, partsr) && m.buttons == 4)
		partclick(m.xy);
	else if(ptinrect(m.xy, textr))
		textmouse(&text, mc);
}

void
pagerkey(Rune k)
{
	textkeyboard(&text, k);
}

void
pagerinit(Mousectl *mctl, Theme *theme)
{
	Rectangle r;

	mc = mctl;
	tz = tzload("local");
	showcc = 0;
	nparts = 0;
	if(theme != nil){
		cols[BACK] = theme->back;
		cols[BORD] = theme->border;
		cols[TEXT] = theme->text;
		cols[HTEXT] = theme->htext;
		cols[HIGH] = theme->high;
		headercol = theme->title;
	}else{
		r = Rect(0, 0, 1, 1);
		cols[BACK] = display->white;
		cols[BORD] = allocimage(display, r, screen->chan, 1, 0x999999FF);
		cols[TEXT] = allocimage(display, r, screen->chan, 1, 0x000000FF);
		cols[HTEXT] = allocimage(display, r, screen->chan, 1, 0x000000FF);
		cols[HIGH] = allocimage(display, r, screen->chan, 1, 0xCCCCCCFF);
		headercol = allocimage(display, r, screen->chan, 1, DGreygreen);
	}
	textinit(&text, screen, screen->r, font, cols);
}