xref: /plan9/sys/src/cmd/ip/imap4d/list.c (revision 59cc4ca53493a3c6d2349fe2b7f7c40f7dce7294)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include "imap4d.h"
57dd7cddfSDavid du Colombier 
67dd7cddfSDavid du Colombier #define SUBSCRIBED	"imap.subscribed"
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier static int	matches(char *ref, char *pat, char *name);
97dd7cddfSDavid du Colombier static int	mayMatch(char *pat, char *name, int star);
107dd7cddfSDavid du Colombier static int	checkMatch(char *cmd, char *ref, char *pat, char *mbox, long mtime, int isdir);
117dd7cddfSDavid du Colombier static int	listAll(char *cmd, char *ref, char *pat, char *mbox, long mtime);
127dd7cddfSDavid du Colombier static int	listMatch(char *cmd, char *ref, char *pat, char *mbox, char *mm);
137dd7cddfSDavid du Colombier static int	mkSubscribed(void);
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier static long
167dd7cddfSDavid du Colombier listMtime(char *file)
177dd7cddfSDavid du Colombier {
187dd7cddfSDavid du Colombier 	Dir d;
197dd7cddfSDavid du Colombier 
207dd7cddfSDavid du Colombier 	if(cdDirstat(mboxDir, file, &d) < 0)
217dd7cddfSDavid du Colombier 		return 0;
227dd7cddfSDavid du Colombier 	return d.mtime;
237dd7cddfSDavid du Colombier }
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier /*
267dd7cddfSDavid du Colombier  * check for subscribed mailboxes
277dd7cddfSDavid du Colombier  * each line is either a comment starting with #
287dd7cddfSDavid du Colombier  * or is a subscribed mailbox name
297dd7cddfSDavid du Colombier  */
307dd7cddfSDavid du Colombier int
317dd7cddfSDavid du Colombier lsubBoxes(char *cmd, char *ref, char *pat)
327dd7cddfSDavid du Colombier {
337dd7cddfSDavid du Colombier 	MbLock *mb;
347dd7cddfSDavid du Colombier 	Dir d;
357dd7cddfSDavid du Colombier 	Biobuf bin;
367dd7cddfSDavid du Colombier 	char *s;
377dd7cddfSDavid du Colombier 	int fd, ok, isdir;
387dd7cddfSDavid du Colombier 
397dd7cddfSDavid du Colombier 	mb = mbLock();
407dd7cddfSDavid du Colombier 	if(mb == nil)
417dd7cddfSDavid du Colombier 		return 0;
427dd7cddfSDavid du Colombier 	fd = cdOpen(mboxDir, SUBSCRIBED, OREAD);
437dd7cddfSDavid du Colombier 	if(fd < 0)
447dd7cddfSDavid du Colombier 		fd = mkSubscribed();
457dd7cddfSDavid du Colombier 	if(fd < 0){
467dd7cddfSDavid du Colombier 		mbUnlock(mb);
477dd7cddfSDavid du Colombier 		return 0;
487dd7cddfSDavid du Colombier 	}
497dd7cddfSDavid du Colombier 	ok = 0;
507dd7cddfSDavid du Colombier 	Binit(&bin, fd, OREAD);
517dd7cddfSDavid du Colombier 	while(s = Brdline(&bin, '\n')){
527dd7cddfSDavid du Colombier 		s[Blinelen(&bin) - 1] = '\0';
537dd7cddfSDavid du Colombier 		if(s[0] == '#')
547dd7cddfSDavid du Colombier 			continue;
557dd7cddfSDavid du Colombier 		isdir = 1;
567dd7cddfSDavid du Colombier 		if(cistrcmp(s, "INBOX") == 0){
577dd7cddfSDavid du Colombier 			d.mtime = listMtime("mbox");
587dd7cddfSDavid du Colombier 			isdir = 0;
597dd7cddfSDavid du Colombier 		}else if(cdDirstat(mboxDir, s, &d) >= 0 && !(d.mode & CHDIR))
607dd7cddfSDavid du Colombier 			isdir = 0;
617dd7cddfSDavid du Colombier 		ok |= checkMatch(cmd, ref, pat, s, d.mtime, isdir);
627dd7cddfSDavid du Colombier 	}
637dd7cddfSDavid du Colombier 	Bterm(&bin);
647dd7cddfSDavid du Colombier 	close(fd);
657dd7cddfSDavid du Colombier 	mbUnlock(mb);
667dd7cddfSDavid du Colombier 	return ok;
677dd7cddfSDavid du Colombier }
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier static int
707dd7cddfSDavid du Colombier mkSubscribed(void)
717dd7cddfSDavid du Colombier {
727dd7cddfSDavid du Colombier 	int fd;
737dd7cddfSDavid du Colombier 
747dd7cddfSDavid du Colombier 	fd = cdCreate(mboxDir, SUBSCRIBED, ORDWR, 0664);
757dd7cddfSDavid du Colombier 	if(fd < 0)
767dd7cddfSDavid du Colombier 		return -1;
777dd7cddfSDavid du Colombier 	fprint(fd, "#imap4 subscription list\nINBOX\n");
787dd7cddfSDavid du Colombier 	seek(fd, 0, 0);
797dd7cddfSDavid du Colombier 	return fd;
807dd7cddfSDavid du Colombier }
817dd7cddfSDavid du Colombier 
827dd7cddfSDavid du Colombier /*
837dd7cddfSDavid du Colombier  * either subscribe or unsubscribe to a mailbox
847dd7cddfSDavid du Colombier  */
857dd7cddfSDavid du Colombier int
867dd7cddfSDavid du Colombier subscribe(char *mbox, int how)
877dd7cddfSDavid du Colombier {
887dd7cddfSDavid du Colombier 	MbLock *mb;
897dd7cddfSDavid du Colombier 	char *s, *in, *ein;
907dd7cddfSDavid du Colombier 	int fd, tfd, ok, nmbox;
917dd7cddfSDavid du Colombier 
927dd7cddfSDavid du Colombier 	if(cistrcmp(mbox, "inbox") == 0)
937dd7cddfSDavid du Colombier 		mbox = "INBOX";
947dd7cddfSDavid du Colombier 	mb = mbLock();
957dd7cddfSDavid du Colombier 	if(mb == nil)
967dd7cddfSDavid du Colombier 		return 0;
977dd7cddfSDavid du Colombier 	fd = cdOpen(mboxDir, SUBSCRIBED, ORDWR);
987dd7cddfSDavid du Colombier 	if(fd < 0)
997dd7cddfSDavid du Colombier 		fd = mkSubscribed();
1007dd7cddfSDavid du Colombier 	if(fd < 0){
1017dd7cddfSDavid du Colombier 		mbUnlock(mb);
1027dd7cddfSDavid du Colombier 		return 0;
1037dd7cddfSDavid du Colombier 	}
1047dd7cddfSDavid du Colombier 	in = readFile(fd);
1057dd7cddfSDavid du Colombier 	if(in == nil){
1067dd7cddfSDavid du Colombier 		mbUnlock(mb);
1077dd7cddfSDavid du Colombier 		return 0;
1087dd7cddfSDavid du Colombier 	}
1097dd7cddfSDavid du Colombier 	nmbox = strlen(mbox);
1107dd7cddfSDavid du Colombier 	s = strstr(in, mbox);
1117dd7cddfSDavid du Colombier 	while(s != nil && (s != in && s[-1] != '\n' || s[nmbox] != '\n'))
1127dd7cddfSDavid du Colombier 		s = strstr(s+1, mbox);
1137dd7cddfSDavid du Colombier 	ok = 0;
1147dd7cddfSDavid du Colombier 	if(how == 's' && s == nil){
1157dd7cddfSDavid du Colombier 		if(fprint(fd, "%s\n", mbox) > 0)
1167dd7cddfSDavid du Colombier 			ok = 1;
1177dd7cddfSDavid du Colombier 	}else if(how == 'u' && s != nil){
1187dd7cddfSDavid du Colombier 		ein = strchr(s, '\0');
1197dd7cddfSDavid du Colombier 		memmove(s, &s[nmbox+1], ein - &s[nmbox+1]);
1207dd7cddfSDavid du Colombier 		ein -= nmbox+1;
1217dd7cddfSDavid du Colombier 		tfd = cdOpen(mboxDir, SUBSCRIBED, OWRITE|OTRUNC);
1227dd7cddfSDavid du Colombier 		if(tfd >= 0 && seek(fd, 0, 0) >= 0 && write(fd, in, ein-in) == ein-in)
1237dd7cddfSDavid du Colombier 			ok = 1;
1247dd7cddfSDavid du Colombier 		if(tfd > 0)
1257dd7cddfSDavid du Colombier 			close(tfd);
1267dd7cddfSDavid du Colombier 	}else
1277dd7cddfSDavid du Colombier 		ok = 1;
1287dd7cddfSDavid du Colombier 	close(fd);
1297dd7cddfSDavid du Colombier 	mbUnlock(mb);
1307dd7cddfSDavid du Colombier 	return ok;
1317dd7cddfSDavid du Colombier }
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier /*
1347dd7cddfSDavid du Colombier  * stupidly complicated so that % doesn't read entire directory structure
1357dd7cddfSDavid du Colombier  * yet * works
1367dd7cddfSDavid du Colombier  * note: in most places, inbox is case-insensitive,
1377dd7cddfSDavid du Colombier  * but here INBOX is checked for a case-sensitve match.
1387dd7cddfSDavid du Colombier  */
1397dd7cddfSDavid du Colombier int
1407dd7cddfSDavid du Colombier listBoxes(char *cmd, char *ref, char *pat)
1417dd7cddfSDavid du Colombier {
1427dd7cddfSDavid du Colombier 	int ok;
1437dd7cddfSDavid du Colombier 
1447dd7cddfSDavid du Colombier 	ok = checkMatch(cmd, ref, pat, "INBOX", listMtime("mbox"), 0);
1457dd7cddfSDavid du Colombier 	return ok | listMatch(cmd, ref, pat, ref, pat);
1467dd7cddfSDavid du Colombier }
1477dd7cddfSDavid du Colombier 
1487dd7cddfSDavid du Colombier /*
1497dd7cddfSDavid du Colombier  * look for all messages which may match the pattern
1507dd7cddfSDavid du Colombier  * punt when a * is reached
1517dd7cddfSDavid du Colombier  */
1527dd7cddfSDavid du Colombier static int
1537dd7cddfSDavid du Colombier listMatch(char *cmd, char *ref, char *pat, char *mbox, char *mm)
1547dd7cddfSDavid du Colombier {
1557dd7cddfSDavid du Colombier 	Dir dir, *dirs;
1567dd7cddfSDavid du Colombier 	char *mdir, *m, *mb, *wc;
1577dd7cddfSDavid du Colombier 	int c, i, nmb, nmdir, nd, ok, fd;
1587dd7cddfSDavid du Colombier 
1597dd7cddfSDavid du Colombier 	mdir = nil;
1607dd7cddfSDavid du Colombier 	for(m = mm; c = *m; m++){
1617dd7cddfSDavid du Colombier 		if(c == '%' || c == '*'){
1627dd7cddfSDavid du Colombier 			if(mdir == nil){
1637dd7cddfSDavid du Colombier 				fd = cdOpen(mboxDir, ".", OREAD);
164*59cc4ca5SDavid du Colombier 				if(fd < 0)
165*59cc4ca5SDavid du Colombier 					return 0;
1667dd7cddfSDavid du Colombier 				mbox = "";
1677dd7cddfSDavid du Colombier 				nmdir = 0;
1687dd7cddfSDavid du Colombier 			}else{
1697dd7cddfSDavid du Colombier 				*mdir = '\0';
1707dd7cddfSDavid du Colombier 				fd = cdOpen(mboxDir, mbox, OREAD);
1717dd7cddfSDavid du Colombier 				*mdir = '/';
1727dd7cddfSDavid du Colombier 				nmdir = mdir - mbox + 1;
173*59cc4ca5SDavid du Colombier 				if(fd < 0 || dirfstat(fd, &dir) < 0)
1747dd7cddfSDavid du Colombier 					return 0;
175*59cc4ca5SDavid du Colombier 				if(!(dir.mode & CHDIR))
176*59cc4ca5SDavid du Colombier 					break;
177*59cc4ca5SDavid du Colombier 			}
1787dd7cddfSDavid du Colombier 			wc = m;
1797dd7cddfSDavid du Colombier 			for(; c = *m; m++)
1807dd7cddfSDavid du Colombier 				if(c == '/')
1817dd7cddfSDavid du Colombier 					break;
1827dd7cddfSDavid du Colombier 			nmb = nmdir + strlen(m) + NAMELEN + 3;
1837dd7cddfSDavid du Colombier 			mb = emalloc(nmb);
1847dd7cddfSDavid du Colombier 			strncpy(mb, mbox, nmdir);
1857dd7cddfSDavid du Colombier 			dirs = emalloc(sizeof(Dir) * NDirs);
1867dd7cddfSDavid du Colombier 			ok = 0;
1877dd7cddfSDavid du Colombier 			while((nd = dirread(fd, dirs, sizeof(Dir) * NDirs)) >= sizeof(Dir)){
1887dd7cddfSDavid du Colombier 				nd /= sizeof(Dir);
1897dd7cddfSDavid du Colombier 				for(i = 0; i < nd; i++){
1907dd7cddfSDavid du Colombier 					if(*wc == '*' && (dirs[i].mode & CHDIR) && mayMatch(mm, dirs[i].name, 1)){
1917dd7cddfSDavid du Colombier 						snprint(mb+nmdir, nmb-nmdir, "%s", dirs[i].name);
1927dd7cddfSDavid du Colombier 						ok |= listAll(cmd, ref, pat, mb, dirs[i].mtime);
1937dd7cddfSDavid du Colombier 					}else if(mayMatch(mm, dirs[i].name, 0)){
1947dd7cddfSDavid du Colombier 						snprint(mb+nmdir, nmb-nmdir, "%s%s", dirs[i].name, m);
1957dd7cddfSDavid du Colombier 						if(*m == '\0')
1967dd7cddfSDavid du Colombier 							ok |= checkMatch(cmd, ref, pat, mb, dirs[i].mtime, (dirs[i].mode & CHDIR) == CHDIR);
1977dd7cddfSDavid du Colombier 						else if(dirs[i].mode & CHDIR)
1987dd7cddfSDavid du Colombier 							ok |= listMatch(cmd, ref, pat, mb, mb + nmdir + strlen(dirs[i].name));
1997dd7cddfSDavid du Colombier 					}
2007dd7cddfSDavid du Colombier 				}
2017dd7cddfSDavid du Colombier 			}
2027dd7cddfSDavid du Colombier 			close(fd);
2037dd7cddfSDavid du Colombier 			free(dirs);
2047dd7cddfSDavid du Colombier 			free(mb);
2057dd7cddfSDavid du Colombier 			return ok;
2067dd7cddfSDavid du Colombier 		}
2077dd7cddfSDavid du Colombier 		if(c == '/'){
2087dd7cddfSDavid du Colombier 			mdir = m;
2097dd7cddfSDavid du Colombier 			mm = m + 1;
2107dd7cddfSDavid du Colombier 		}
2117dd7cddfSDavid du Colombier 	}
2127dd7cddfSDavid du Colombier 	m = mbox;
2137dd7cddfSDavid du Colombier 	if(*mbox == '\0')
2147dd7cddfSDavid du Colombier 		m = ".";
2157dd7cddfSDavid du Colombier 	if(cdDirstat(mboxDir, m, &dir) < 0)
2167dd7cddfSDavid du Colombier 		return 0;
2177dd7cddfSDavid du Colombier 	return checkMatch(cmd, ref, pat, mbox, dir.mtime, (dir.mode & CHDIR) == CHDIR);
2187dd7cddfSDavid du Colombier }
2197dd7cddfSDavid du Colombier 
2207dd7cddfSDavid du Colombier /*
2217dd7cddfSDavid du Colombier  * too hard: recursively list all files rooted at mbox,
2227dd7cddfSDavid du Colombier  * and list checkMatch figure it out
2237dd7cddfSDavid du Colombier  */
2247dd7cddfSDavid du Colombier static int
2257dd7cddfSDavid du Colombier listAll(char *cmd, char *ref, char *pat, char *mbox, long mtime)
2267dd7cddfSDavid du Colombier {
2277dd7cddfSDavid du Colombier 	Dir *dirs;
2287dd7cddfSDavid du Colombier 	char *mb;
2297dd7cddfSDavid du Colombier 	int i, nmb, nd, ok, fd;
2307dd7cddfSDavid du Colombier 
2317dd7cddfSDavid du Colombier 	ok = checkMatch(cmd, ref, pat, mbox, mtime, 1);
2327dd7cddfSDavid du Colombier 	fd = cdOpen(mboxDir, mbox, OREAD);
2337dd7cddfSDavid du Colombier 	if(fd < 0)
2347dd7cddfSDavid du Colombier 		return ok;
2357dd7cddfSDavid du Colombier 
2367dd7cddfSDavid du Colombier 	nmb = strlen(mbox) + NAMELEN + 2;
2377dd7cddfSDavid du Colombier 	mb = emalloc(nmb);
2387dd7cddfSDavid du Colombier 	dirs = emalloc(sizeof(Dir) * NDirs);
2397dd7cddfSDavid du Colombier 	while((nd = dirread(fd, dirs, sizeof(Dir) * NDirs)) >= sizeof(Dir)){
2407dd7cddfSDavid du Colombier 		nd /= sizeof(Dir);
2417dd7cddfSDavid du Colombier 		for(i = 0; i < nd; i++){
2427dd7cddfSDavid du Colombier 			snprint(mb, nmb, "%s/%s", mbox, dirs[i].name);
2437dd7cddfSDavid du Colombier 			if(dirs[i].mode & CHDIR)
2447dd7cddfSDavid du Colombier 				ok |= listAll(cmd, ref, pat, mb, dirs[i].mtime);
2457dd7cddfSDavid du Colombier 			else
2467dd7cddfSDavid du Colombier 				ok |= checkMatch(cmd, ref, pat, mb, dirs[i].mtime, 0);
2477dd7cddfSDavid du Colombier 		}
2487dd7cddfSDavid du Colombier 	}
2497dd7cddfSDavid du Colombier 	close(fd);
2507dd7cddfSDavid du Colombier 	free(dirs);
2517dd7cddfSDavid du Colombier 	free(mb);
2527dd7cddfSDavid du Colombier 	return ok;
2537dd7cddfSDavid du Colombier }
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier static int
2567dd7cddfSDavid du Colombier mayMatch(char *pat, char *name, int star)
2577dd7cddfSDavid du Colombier {
2587dd7cddfSDavid du Colombier 	Rune r;
2597dd7cddfSDavid du Colombier 	int i, n;
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier 	for(; *pat && *pat != '/'; pat += n){
2627dd7cddfSDavid du Colombier 		r = *(uchar*)pat;
2637dd7cddfSDavid du Colombier 		if(r < Runeself)
2647dd7cddfSDavid du Colombier 			n = 1;
2657dd7cddfSDavid du Colombier 		else
2667dd7cddfSDavid du Colombier 			n = chartorune(&r, pat);
2677dd7cddfSDavid du Colombier 
2687dd7cddfSDavid du Colombier 		if(r == '*' || r == '%'){
2697dd7cddfSDavid du Colombier 			pat += n;
2707dd7cddfSDavid du Colombier 			if(r == '*' && star || *pat == '\0' || *pat == '/')
2717dd7cddfSDavid du Colombier 				return 1;
2727dd7cddfSDavid du Colombier 			while(*name){
2737dd7cddfSDavid du Colombier 				if(mayMatch(pat, name, star))
2747dd7cddfSDavid du Colombier 					return 1;
2757dd7cddfSDavid du Colombier 				name += chartorune(&r, name);
2767dd7cddfSDavid du Colombier 			}
2777dd7cddfSDavid du Colombier 			return 0;
2787dd7cddfSDavid du Colombier 		}
2797dd7cddfSDavid du Colombier 		for(i = 0; i < n; i++)
2807dd7cddfSDavid du Colombier 			if(name[i] != pat[i])
2817dd7cddfSDavid du Colombier 				return 0;
2827dd7cddfSDavid du Colombier 		name += n;
2837dd7cddfSDavid du Colombier 	}
2847dd7cddfSDavid du Colombier 	if(*name == '\0')
2857dd7cddfSDavid du Colombier 		return 1;
2867dd7cddfSDavid du Colombier 	return 0;
2877dd7cddfSDavid du Colombier }
2887dd7cddfSDavid du Colombier 
2897dd7cddfSDavid du Colombier /*
2907dd7cddfSDavid du Colombier  * mbox is a mailbox name which might match pat.
2917dd7cddfSDavid du Colombier  * verify the match
2927dd7cddfSDavid du Colombier  * generates response
2937dd7cddfSDavid du Colombier  */
2947dd7cddfSDavid du Colombier static int
2957dd7cddfSDavid du Colombier checkMatch(char *cmd, char *ref, char *pat, char *mbox, long mtime, int isdir)
2967dd7cddfSDavid du Colombier {
2977dd7cddfSDavid du Colombier 	char *s, *flags;
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier 	if(!matches(ref, pat, mbox) || !okMbox(mbox))
3007dd7cddfSDavid du Colombier 		return 0;
3017dd7cddfSDavid du Colombier 	if(strcmp(mbox, ".") == 0)
3027dd7cddfSDavid du Colombier 		mbox = "";
3037dd7cddfSDavid du Colombier 
3047dd7cddfSDavid du Colombier 	if(isdir)
3057dd7cddfSDavid du Colombier 		flags = "(\\Noselect)";
3067dd7cddfSDavid du Colombier 	else{
3077dd7cddfSDavid du Colombier 		s = impName(mbox);
3087dd7cddfSDavid du Colombier 		if(s != nil && listMtime(s) < mtime)
3097dd7cddfSDavid du Colombier 			flags = "(\\Noinferiors \\Marked)";
3107dd7cddfSDavid du Colombier 		else
3117dd7cddfSDavid du Colombier 			flags = "(\\Noinferiors)";
3127dd7cddfSDavid du Colombier 	}
3137dd7cddfSDavid du Colombier 
3147dd7cddfSDavid du Colombier 	s = strmutf7(mbox);
3157dd7cddfSDavid du Colombier 	if(s != nil)
3167dd7cddfSDavid du Colombier 		Bprint(&bout, "* %s %s \"/\" %s\r\n", cmd, flags, s);
3177dd7cddfSDavid du Colombier 	return 1;
3187dd7cddfSDavid du Colombier }
3197dd7cddfSDavid du Colombier 
3207dd7cddfSDavid du Colombier static int
3217dd7cddfSDavid du Colombier matches(char *ref, char *pat, char *name)
3227dd7cddfSDavid du Colombier {
3237dd7cddfSDavid du Colombier 	Rune r;
3247dd7cddfSDavid du Colombier 	int i, n;
3257dd7cddfSDavid du Colombier 
3267dd7cddfSDavid du Colombier 	while(ref != pat)
3277dd7cddfSDavid du Colombier 		if(*name++ != *ref++)
3287dd7cddfSDavid du Colombier 			return 0;
3297dd7cddfSDavid du Colombier 	for(; *pat; pat += n){
3307dd7cddfSDavid du Colombier 		r = *(uchar*)pat;
3317dd7cddfSDavid du Colombier 		if(r < Runeself)
3327dd7cddfSDavid du Colombier 			n = 1;
3337dd7cddfSDavid du Colombier 		else
3347dd7cddfSDavid du Colombier 			n = chartorune(&r, pat);
3357dd7cddfSDavid du Colombier 
3367dd7cddfSDavid du Colombier 		if(r == '*'){
3377dd7cddfSDavid du Colombier 			pat += n;
3387dd7cddfSDavid du Colombier 			if(*pat == '\0')
3397dd7cddfSDavid du Colombier 				return 1;
3407dd7cddfSDavid du Colombier 			while(*name){
3417dd7cddfSDavid du Colombier 				if(matches(pat, pat, name))
3427dd7cddfSDavid du Colombier 					return 1;
3437dd7cddfSDavid du Colombier 				name += chartorune(&r, name);
3447dd7cddfSDavid du Colombier 			}
3457dd7cddfSDavid du Colombier 			return 0;
3467dd7cddfSDavid du Colombier 		}
3477dd7cddfSDavid du Colombier 		if(r == '%'){
3487dd7cddfSDavid du Colombier 			pat += n;
3497dd7cddfSDavid du Colombier 			while(*name && *name != '/'){
3507dd7cddfSDavid du Colombier 				if(matches(pat, pat, name))
3517dd7cddfSDavid du Colombier 					return 1;
3527dd7cddfSDavid du Colombier 				name += chartorune(&r, name);
3537dd7cddfSDavid du Colombier 			}
3547dd7cddfSDavid du Colombier 			pat -= n;
3557dd7cddfSDavid du Colombier 			continue;
3567dd7cddfSDavid du Colombier 		}
3577dd7cddfSDavid du Colombier 		for(i = 0; i < n; i++)
3587dd7cddfSDavid du Colombier 			if(name[i] != pat[i])
3597dd7cddfSDavid du Colombier 				return 0;
3607dd7cddfSDavid du Colombier 		name += n;
3617dd7cddfSDavid du Colombier 	}
3627dd7cddfSDavid du Colombier 	if(*name == '\0')
3637dd7cddfSDavid du Colombier 		return 1;
3647dd7cddfSDavid du Colombier 	return 0;
3657dd7cddfSDavid du Colombier }
366