17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
49a747e4fSDavid du Colombier #include <auth.h>
57dd7cddfSDavid du Colombier #include "imap4d.h"
67dd7cddfSDavid du Colombier
77dd7cddfSDavid du Colombier #define SUBSCRIBED "imap.subscribed"
87dd7cddfSDavid du Colombier
97dd7cddfSDavid du Colombier static int matches(char *ref, char *pat, char *name);
107dd7cddfSDavid du Colombier static int mayMatch(char *pat, char *name, int star);
117dd7cddfSDavid du Colombier static int checkMatch(char *cmd, char *ref, char *pat, char *mbox, long mtime, int isdir);
127dd7cddfSDavid du Colombier static int listAll(char *cmd, char *ref, char *pat, char *mbox, long mtime);
137dd7cddfSDavid du Colombier static int listMatch(char *cmd, char *ref, char *pat, char *mbox, char *mm);
147dd7cddfSDavid du Colombier static int mkSubscribed(void);
157dd7cddfSDavid du Colombier
167dd7cddfSDavid du Colombier static long
listMtime(char * file)177dd7cddfSDavid du Colombier listMtime(char *file)
187dd7cddfSDavid du Colombier {
199a747e4fSDavid du Colombier Dir *d;
209a747e4fSDavid du Colombier long mtime;
217dd7cddfSDavid du Colombier
229a747e4fSDavid du Colombier d = cdDirstat(mboxDir, file);
239a747e4fSDavid du Colombier if(d == nil)
247dd7cddfSDavid du Colombier return 0;
259a747e4fSDavid du Colombier mtime = d->mtime;
269a747e4fSDavid du Colombier free(d);
279a747e4fSDavid du Colombier return mtime;
287dd7cddfSDavid du Colombier }
297dd7cddfSDavid du Colombier
307dd7cddfSDavid du Colombier /*
317dd7cddfSDavid du Colombier * check for subscribed mailboxes
327dd7cddfSDavid du Colombier * each line is either a comment starting with #
337dd7cddfSDavid du Colombier * or is a subscribed mailbox name
347dd7cddfSDavid du Colombier */
357dd7cddfSDavid du Colombier int
lsubBoxes(char * cmd,char * ref,char * pat)367dd7cddfSDavid du Colombier lsubBoxes(char *cmd, char *ref, char *pat)
377dd7cddfSDavid du Colombier {
387dd7cddfSDavid du Colombier MbLock *mb;
399a747e4fSDavid du Colombier Dir *d;
407dd7cddfSDavid du Colombier Biobuf bin;
417dd7cddfSDavid du Colombier char *s;
429a747e4fSDavid du Colombier long mtime;
437dd7cddfSDavid du Colombier int fd, ok, isdir;
447dd7cddfSDavid du Colombier
457dd7cddfSDavid du Colombier mb = mbLock();
467dd7cddfSDavid du Colombier if(mb == nil)
477dd7cddfSDavid du Colombier return 0;
487dd7cddfSDavid du Colombier fd = cdOpen(mboxDir, SUBSCRIBED, OREAD);
497dd7cddfSDavid du Colombier if(fd < 0)
507dd7cddfSDavid du Colombier fd = mkSubscribed();
517dd7cddfSDavid du Colombier if(fd < 0){
527dd7cddfSDavid du Colombier mbUnlock(mb);
537dd7cddfSDavid du Colombier return 0;
547dd7cddfSDavid du Colombier }
557dd7cddfSDavid du Colombier ok = 0;
567dd7cddfSDavid du Colombier Binit(&bin, fd, OREAD);
577dd7cddfSDavid du Colombier while(s = Brdline(&bin, '\n')){
587dd7cddfSDavid du Colombier s[Blinelen(&bin) - 1] = '\0';
597dd7cddfSDavid du Colombier if(s[0] == '#')
607dd7cddfSDavid du Colombier continue;
617dd7cddfSDavid du Colombier isdir = 1;
627dd7cddfSDavid du Colombier if(cistrcmp(s, "INBOX") == 0){
6343aadf5eSDavid du Colombier if(access("msgs", AEXIST) == 0)
6443aadf5eSDavid du Colombier mtime = listMtime("msgs");
6543aadf5eSDavid du Colombier else
669a747e4fSDavid du Colombier mtime = listMtime("mbox");
677dd7cddfSDavid du Colombier isdir = 0;
689a747e4fSDavid du Colombier }else{
699a747e4fSDavid du Colombier d = cdDirstat(mboxDir, s);
709a747e4fSDavid du Colombier if(d != nil){
719a747e4fSDavid du Colombier mtime = d->mtime;
729a747e4fSDavid du Colombier if(!(d->mode & DMDIR))
737dd7cddfSDavid du Colombier isdir = 0;
749a747e4fSDavid du Colombier free(d);
759a747e4fSDavid du Colombier }else
769a747e4fSDavid du Colombier mtime = 0;
779a747e4fSDavid du Colombier }
789a747e4fSDavid du Colombier ok |= checkMatch(cmd, ref, pat, s, mtime, isdir);
797dd7cddfSDavid du Colombier }
807dd7cddfSDavid du Colombier Bterm(&bin);
817dd7cddfSDavid du Colombier close(fd);
827dd7cddfSDavid du Colombier mbUnlock(mb);
837dd7cddfSDavid du Colombier return ok;
847dd7cddfSDavid du Colombier }
857dd7cddfSDavid du Colombier
867dd7cddfSDavid du Colombier static int
mkSubscribed(void)877dd7cddfSDavid du Colombier mkSubscribed(void)
887dd7cddfSDavid du Colombier {
897dd7cddfSDavid du Colombier int fd;
907dd7cddfSDavid du Colombier
917dd7cddfSDavid du Colombier fd = cdCreate(mboxDir, SUBSCRIBED, ORDWR, 0664);
927dd7cddfSDavid du Colombier if(fd < 0)
937dd7cddfSDavid du Colombier return -1;
947dd7cddfSDavid du Colombier fprint(fd, "#imap4 subscription list\nINBOX\n");
957dd7cddfSDavid du Colombier seek(fd, 0, 0);
967dd7cddfSDavid du Colombier return fd;
977dd7cddfSDavid du Colombier }
987dd7cddfSDavid du Colombier
997dd7cddfSDavid du Colombier /*
1007dd7cddfSDavid du Colombier * either subscribe or unsubscribe to a mailbox
1017dd7cddfSDavid du Colombier */
1027dd7cddfSDavid du Colombier int
subscribe(char * mbox,int how)1037dd7cddfSDavid du Colombier subscribe(char *mbox, int how)
1047dd7cddfSDavid du Colombier {
1057dd7cddfSDavid du Colombier MbLock *mb;
1067dd7cddfSDavid du Colombier char *s, *in, *ein;
1077dd7cddfSDavid du Colombier int fd, tfd, ok, nmbox;
1087dd7cddfSDavid du Colombier
1097dd7cddfSDavid du Colombier if(cistrcmp(mbox, "inbox") == 0)
1107dd7cddfSDavid du Colombier mbox = "INBOX";
1117dd7cddfSDavid du Colombier mb = mbLock();
1127dd7cddfSDavid du Colombier if(mb == nil)
1137dd7cddfSDavid du Colombier return 0;
1147dd7cddfSDavid du Colombier fd = cdOpen(mboxDir, SUBSCRIBED, ORDWR);
1157dd7cddfSDavid du Colombier if(fd < 0)
1167dd7cddfSDavid du Colombier fd = mkSubscribed();
1177dd7cddfSDavid du Colombier if(fd < 0){
1187dd7cddfSDavid du Colombier mbUnlock(mb);
1197dd7cddfSDavid du Colombier return 0;
1207dd7cddfSDavid du Colombier }
1217dd7cddfSDavid du Colombier in = readFile(fd);
1227dd7cddfSDavid du Colombier if(in == nil){
1237dd7cddfSDavid du Colombier mbUnlock(mb);
1247dd7cddfSDavid du Colombier return 0;
1257dd7cddfSDavid du Colombier }
1267dd7cddfSDavid du Colombier nmbox = strlen(mbox);
1277dd7cddfSDavid du Colombier s = strstr(in, mbox);
1287dd7cddfSDavid du Colombier while(s != nil && (s != in && s[-1] != '\n' || s[nmbox] != '\n'))
1297dd7cddfSDavid du Colombier s = strstr(s+1, mbox);
1307dd7cddfSDavid du Colombier ok = 0;
1317dd7cddfSDavid du Colombier if(how == 's' && s == nil){
1327dd7cddfSDavid du Colombier if(fprint(fd, "%s\n", mbox) > 0)
1337dd7cddfSDavid du Colombier ok = 1;
1347dd7cddfSDavid du Colombier }else if(how == 'u' && s != nil){
1357dd7cddfSDavid du Colombier ein = strchr(s, '\0');
1367dd7cddfSDavid du Colombier memmove(s, &s[nmbox+1], ein - &s[nmbox+1]);
1377dd7cddfSDavid du Colombier ein -= nmbox+1;
1387dd7cddfSDavid du Colombier tfd = cdOpen(mboxDir, SUBSCRIBED, OWRITE|OTRUNC);
1397dd7cddfSDavid du Colombier if(tfd >= 0 && seek(fd, 0, 0) >= 0 && write(fd, in, ein-in) == ein-in)
1407dd7cddfSDavid du Colombier ok = 1;
1417dd7cddfSDavid du Colombier if(tfd > 0)
1427dd7cddfSDavid du Colombier close(tfd);
1437dd7cddfSDavid du Colombier }else
1447dd7cddfSDavid du Colombier ok = 1;
1457dd7cddfSDavid du Colombier close(fd);
1467dd7cddfSDavid du Colombier mbUnlock(mb);
1477dd7cddfSDavid du Colombier return ok;
1487dd7cddfSDavid du Colombier }
1497dd7cddfSDavid du Colombier
1507dd7cddfSDavid du Colombier /*
1517dd7cddfSDavid du Colombier * stupidly complicated so that % doesn't read entire directory structure
1527dd7cddfSDavid du Colombier * yet * works
1537dd7cddfSDavid du Colombier * note: in most places, inbox is case-insensitive,
1547dd7cddfSDavid du Colombier * but here INBOX is checked for a case-sensitve match.
1557dd7cddfSDavid du Colombier */
1567dd7cddfSDavid du Colombier int
listBoxes(char * cmd,char * ref,char * pat)1577dd7cddfSDavid du Colombier listBoxes(char *cmd, char *ref, char *pat)
1587dd7cddfSDavid du Colombier {
1597dd7cddfSDavid du Colombier int ok;
1607dd7cddfSDavid du Colombier
1617dd7cddfSDavid du Colombier ok = checkMatch(cmd, ref, pat, "INBOX", listMtime("mbox"), 0);
1627dd7cddfSDavid du Colombier return ok | listMatch(cmd, ref, pat, ref, pat);
1637dd7cddfSDavid du Colombier }
1647dd7cddfSDavid du Colombier
1657dd7cddfSDavid du Colombier /*
1667dd7cddfSDavid du Colombier * look for all messages which may match the pattern
1677dd7cddfSDavid du Colombier * punt when a * is reached
1687dd7cddfSDavid du Colombier */
1697dd7cddfSDavid du Colombier static int
listMatch(char * cmd,char * ref,char * pat,char * mbox,char * mm)1707dd7cddfSDavid du Colombier listMatch(char *cmd, char *ref, char *pat, char *mbox, char *mm)
1717dd7cddfSDavid du Colombier {
1729a747e4fSDavid du Colombier Dir *dir, *dirs;
1737dd7cddfSDavid du Colombier char *mdir, *m, *mb, *wc;
1749a747e4fSDavid du Colombier long mode;
1757dd7cddfSDavid du Colombier int c, i, nmb, nmdir, nd, ok, fd;
1767dd7cddfSDavid du Colombier
1777dd7cddfSDavid du Colombier mdir = nil;
1787dd7cddfSDavid du Colombier for(m = mm; c = *m; m++){
1797dd7cddfSDavid du Colombier if(c == '%' || c == '*'){
1807dd7cddfSDavid du Colombier if(mdir == nil){
1817dd7cddfSDavid du Colombier fd = cdOpen(mboxDir, ".", OREAD);
18259cc4ca5SDavid du Colombier if(fd < 0)
18359cc4ca5SDavid du Colombier return 0;
1847dd7cddfSDavid du Colombier mbox = "";
1857dd7cddfSDavid du Colombier nmdir = 0;
1867dd7cddfSDavid du Colombier }else{
1877dd7cddfSDavid du Colombier *mdir = '\0';
1887dd7cddfSDavid du Colombier fd = cdOpen(mboxDir, mbox, OREAD);
1897dd7cddfSDavid du Colombier *mdir = '/';
1907dd7cddfSDavid du Colombier nmdir = mdir - mbox + 1;
1919a747e4fSDavid du Colombier if(fd < 0)
1927dd7cddfSDavid du Colombier return 0;
1939a747e4fSDavid du Colombier dir = dirfstat(fd);
1949a747e4fSDavid du Colombier if(dir == nil){
1959a747e4fSDavid du Colombier close(fd);
1969a747e4fSDavid du Colombier return 0;
1979a747e4fSDavid du Colombier }
1989a747e4fSDavid du Colombier mode = dir->mode;
1999a747e4fSDavid du Colombier free(dir);
2009a747e4fSDavid du Colombier if(!(mode & DMDIR))
20159cc4ca5SDavid du Colombier break;
20259cc4ca5SDavid du Colombier }
2037dd7cddfSDavid du Colombier wc = m;
2047dd7cddfSDavid du Colombier for(; c = *m; m++)
2057dd7cddfSDavid du Colombier if(c == '/')
2067dd7cddfSDavid du Colombier break;
2079a747e4fSDavid du Colombier nmb = nmdir + strlen(m) + MboxNameLen + 3;
2087dd7cddfSDavid du Colombier mb = emalloc(nmb);
2097dd7cddfSDavid du Colombier strncpy(mb, mbox, nmdir);
2107dd7cddfSDavid du Colombier ok = 0;
2119a747e4fSDavid du Colombier while((nd = dirread(fd, &dirs)) > 0){
2127dd7cddfSDavid du Colombier for(i = 0; i < nd; i++){
21343aadf5eSDavid du Colombier if(strcmp(mbox, "") == 0 &&
21443aadf5eSDavid du Colombier !okMbox(dirs[i].name))
21543aadf5eSDavid du Colombier continue;
21643aadf5eSDavid du Colombier /* Safety: ignore message dirs */
21743aadf5eSDavid du Colombier if(strstr(dirs[i].name, "mails") != 0 ||
21843aadf5eSDavid du Colombier strcmp(dirs[i].name, "out") == 0 ||
21943aadf5eSDavid du Colombier strcmp(dirs[i].name, "obox") == 0 ||
22043aadf5eSDavid du Colombier strcmp(dirs[i].name, "ombox") == 0)
22143aadf5eSDavid du Colombier continue;
22243aadf5eSDavid du Colombier if(strcmp(dirs[i].name, "msgs") == 0)
22343aadf5eSDavid du Colombier dirs[i].mode &= ~DMDIR;
22443aadf5eSDavid du Colombier if(*wc == '*' && dirs[i].mode & DMDIR &&
22543aadf5eSDavid du Colombier mayMatch(mm, dirs[i].name, 1)){
22643aadf5eSDavid du Colombier snprint(mb+nmdir, nmb-nmdir,
22743aadf5eSDavid du Colombier "%s", dirs[i].name);
22843aadf5eSDavid du Colombier ok |= listAll(cmd, ref, pat, mb,
22943aadf5eSDavid du Colombier dirs[i].mtime);
2307dd7cddfSDavid du Colombier }else if(mayMatch(mm, dirs[i].name, 0)){
23143aadf5eSDavid du Colombier snprint(mb+nmdir, nmb-nmdir,
23243aadf5eSDavid du Colombier "%s%s", dirs[i].name, m);
2337dd7cddfSDavid du Colombier if(*m == '\0')
23443aadf5eSDavid du Colombier ok |= checkMatch(cmd,
23543aadf5eSDavid du Colombier ref, pat, mb,
23643aadf5eSDavid du Colombier dirs[i].mtime,
23743aadf5eSDavid du Colombier dirs[i].mode &
23843aadf5eSDavid du Colombier DMDIR);
2399a747e4fSDavid du Colombier else if(dirs[i].mode & DMDIR)
24043aadf5eSDavid du Colombier ok |= listMatch(cmd,
24143aadf5eSDavid du Colombier ref, pat, mb, mb
24243aadf5eSDavid du Colombier + nmdir + strlen(
24343aadf5eSDavid du Colombier dirs[i].name));
2447dd7cddfSDavid du Colombier }
2457dd7cddfSDavid du Colombier }
2469a747e4fSDavid du Colombier free(dirs);
2477dd7cddfSDavid du Colombier }
2487dd7cddfSDavid du Colombier close(fd);
2497dd7cddfSDavid du Colombier free(mb);
2507dd7cddfSDavid du Colombier return ok;
2517dd7cddfSDavid du Colombier }
2527dd7cddfSDavid du Colombier if(c == '/'){
2537dd7cddfSDavid du Colombier mdir = m;
2547dd7cddfSDavid du Colombier mm = m + 1;
2557dd7cddfSDavid du Colombier }
2567dd7cddfSDavid du Colombier }
2577dd7cddfSDavid du Colombier m = mbox;
2587dd7cddfSDavid du Colombier if(*mbox == '\0')
2597dd7cddfSDavid du Colombier m = ".";
2609a747e4fSDavid du Colombier dir = cdDirstat(mboxDir, m);
2619a747e4fSDavid du Colombier if(dir == nil)
2627dd7cddfSDavid du Colombier return 0;
2639a747e4fSDavid du Colombier ok = checkMatch(cmd, ref, pat, mbox, dir->mtime, (dir->mode & DMDIR) == DMDIR);
2649a747e4fSDavid du Colombier free(dir);
2659a747e4fSDavid du Colombier return ok;
2667dd7cddfSDavid du Colombier }
2677dd7cddfSDavid du Colombier
2687dd7cddfSDavid du Colombier /*
2697dd7cddfSDavid du Colombier * too hard: recursively list all files rooted at mbox,
2707dd7cddfSDavid du Colombier * and list checkMatch figure it out
2717dd7cddfSDavid du Colombier */
2727dd7cddfSDavid du Colombier static int
listAll(char * cmd,char * ref,char * pat,char * mbox,long mtime)2737dd7cddfSDavid du Colombier listAll(char *cmd, char *ref, char *pat, char *mbox, long mtime)
2747dd7cddfSDavid du Colombier {
2757dd7cddfSDavid du Colombier Dir *dirs;
2767dd7cddfSDavid du Colombier char *mb;
2777dd7cddfSDavid du Colombier int i, nmb, nd, ok, fd;
2787dd7cddfSDavid du Colombier
2797dd7cddfSDavid du Colombier ok = checkMatch(cmd, ref, pat, mbox, mtime, 1);
2807dd7cddfSDavid du Colombier fd = cdOpen(mboxDir, mbox, OREAD);
2817dd7cddfSDavid du Colombier if(fd < 0)
2827dd7cddfSDavid du Colombier return ok;
2837dd7cddfSDavid du Colombier
2849a747e4fSDavid du Colombier nmb = strlen(mbox) + MboxNameLen + 2;
2857dd7cddfSDavid du Colombier mb = emalloc(nmb);
2869a747e4fSDavid du Colombier while((nd = dirread(fd, &dirs)) > 0){
2877dd7cddfSDavid du Colombier for(i = 0; i < nd; i++){
2887dd7cddfSDavid du Colombier snprint(mb, nmb, "%s/%s", mbox, dirs[i].name);
28943aadf5eSDavid du Colombier /* safety: do not recurr */
29043aadf5eSDavid du Colombier if(0 && dirs[i].mode & DMDIR)
2917dd7cddfSDavid du Colombier ok |= listAll(cmd, ref, pat, mb, dirs[i].mtime);
2927dd7cddfSDavid du Colombier else
2937dd7cddfSDavid du Colombier ok |= checkMatch(cmd, ref, pat, mb, dirs[i].mtime, 0);
2947dd7cddfSDavid du Colombier }
2959a747e4fSDavid du Colombier free(dirs);
2967dd7cddfSDavid du Colombier }
2977dd7cddfSDavid du Colombier close(fd);
2987dd7cddfSDavid du Colombier free(mb);
2997dd7cddfSDavid du Colombier return ok;
3007dd7cddfSDavid du Colombier }
3017dd7cddfSDavid du Colombier
3027dd7cddfSDavid du Colombier static int
mayMatch(char * pat,char * name,int star)3037dd7cddfSDavid du Colombier mayMatch(char *pat, char *name, int star)
3047dd7cddfSDavid du Colombier {
3057dd7cddfSDavid du Colombier Rune r;
3067dd7cddfSDavid du Colombier int i, n;
3077dd7cddfSDavid du Colombier
3087dd7cddfSDavid du Colombier for(; *pat && *pat != '/'; pat += n){
3097dd7cddfSDavid du Colombier r = *(uchar*)pat;
3107dd7cddfSDavid du Colombier if(r < Runeself)
3117dd7cddfSDavid du Colombier n = 1;
3127dd7cddfSDavid du Colombier else
3137dd7cddfSDavid du Colombier n = chartorune(&r, pat);
3147dd7cddfSDavid du Colombier
3157dd7cddfSDavid du Colombier if(r == '*' || r == '%'){
3167dd7cddfSDavid du Colombier pat += n;
3177dd7cddfSDavid du Colombier if(r == '*' && star || *pat == '\0' || *pat == '/')
3187dd7cddfSDavid du Colombier return 1;
3197dd7cddfSDavid du Colombier while(*name){
3207dd7cddfSDavid du Colombier if(mayMatch(pat, name, star))
3217dd7cddfSDavid du Colombier return 1;
3227dd7cddfSDavid du Colombier name += chartorune(&r, name);
3237dd7cddfSDavid du Colombier }
3247dd7cddfSDavid du Colombier return 0;
3257dd7cddfSDavid du Colombier }
3267dd7cddfSDavid du Colombier for(i = 0; i < n; i++)
3277dd7cddfSDavid du Colombier if(name[i] != pat[i])
3287dd7cddfSDavid du Colombier return 0;
3297dd7cddfSDavid du Colombier name += n;
3307dd7cddfSDavid du Colombier }
3317dd7cddfSDavid du Colombier if(*name == '\0')
3327dd7cddfSDavid du Colombier return 1;
3337dd7cddfSDavid du Colombier return 0;
3347dd7cddfSDavid du Colombier }
3357dd7cddfSDavid du Colombier
3367dd7cddfSDavid du Colombier /*
3377dd7cddfSDavid du Colombier * mbox is a mailbox name which might match pat.
3387dd7cddfSDavid du Colombier * verify the match
3397dd7cddfSDavid du Colombier * generates response
3407dd7cddfSDavid du Colombier */
3417dd7cddfSDavid du Colombier static int
checkMatch(char * cmd,char * ref,char * pat,char * mbox,long mtime,int isdir)3427dd7cddfSDavid du Colombier checkMatch(char *cmd, char *ref, char *pat, char *mbox, long mtime, int isdir)
3437dd7cddfSDavid du Colombier {
3447dd7cddfSDavid du Colombier char *s, *flags;
3457dd7cddfSDavid du Colombier
3467dd7cddfSDavid du Colombier if(!matches(ref, pat, mbox) || !okMbox(mbox))
3477dd7cddfSDavid du Colombier return 0;
3487dd7cddfSDavid du Colombier if(strcmp(mbox, ".") == 0)
3497dd7cddfSDavid du Colombier mbox = "";
3507dd7cddfSDavid du Colombier
3517dd7cddfSDavid du Colombier if(isdir)
3527dd7cddfSDavid du Colombier flags = "(\\Noselect)";
3537dd7cddfSDavid du Colombier else{
3547dd7cddfSDavid du Colombier s = impName(mbox);
3557dd7cddfSDavid du Colombier if(s != nil && listMtime(s) < mtime)
3567dd7cddfSDavid du Colombier flags = "(\\Noinferiors \\Marked)";
3577dd7cddfSDavid du Colombier else
3587dd7cddfSDavid du Colombier flags = "(\\Noinferiors)";
3597dd7cddfSDavid du Colombier }
3607dd7cddfSDavid du Colombier
3617dd7cddfSDavid du Colombier s = strmutf7(mbox);
3627dd7cddfSDavid du Colombier if(s != nil)
363*8cf6001eSDavid du Colombier Bprint(&bout, "* %s %s \"/\" \"%s\"\r\n", cmd, flags, s);
3647dd7cddfSDavid du Colombier return 1;
3657dd7cddfSDavid du Colombier }
3667dd7cddfSDavid du Colombier
3677dd7cddfSDavid du Colombier static int
matches(char * ref,char * pat,char * name)3687dd7cddfSDavid du Colombier matches(char *ref, char *pat, char *name)
3697dd7cddfSDavid du Colombier {
3707dd7cddfSDavid du Colombier Rune r;
3717dd7cddfSDavid du Colombier int i, n;
3727dd7cddfSDavid du Colombier
3737dd7cddfSDavid du Colombier while(ref != pat)
3747dd7cddfSDavid du Colombier if(*name++ != *ref++)
3757dd7cddfSDavid du Colombier return 0;
3767dd7cddfSDavid du Colombier for(; *pat; pat += n){
3777dd7cddfSDavid du Colombier r = *(uchar*)pat;
3787dd7cddfSDavid du Colombier if(r < Runeself)
3797dd7cddfSDavid du Colombier n = 1;
3807dd7cddfSDavid du Colombier else
3817dd7cddfSDavid du Colombier n = chartorune(&r, pat);
3827dd7cddfSDavid du Colombier
3837dd7cddfSDavid du Colombier if(r == '*'){
3847dd7cddfSDavid du Colombier pat += n;
3857dd7cddfSDavid du Colombier if(*pat == '\0')
3867dd7cddfSDavid du Colombier return 1;
3877dd7cddfSDavid du Colombier while(*name){
3887dd7cddfSDavid du Colombier if(matches(pat, pat, name))
3897dd7cddfSDavid du Colombier return 1;
3907dd7cddfSDavid du Colombier name += chartorune(&r, name);
3917dd7cddfSDavid du Colombier }
3927dd7cddfSDavid du Colombier return 0;
3937dd7cddfSDavid du Colombier }
3947dd7cddfSDavid du Colombier if(r == '%'){
3957dd7cddfSDavid du Colombier pat += n;
3967dd7cddfSDavid du Colombier while(*name && *name != '/'){
3977dd7cddfSDavid du Colombier if(matches(pat, pat, name))
3987dd7cddfSDavid du Colombier return 1;
3997dd7cddfSDavid du Colombier name += chartorune(&r, name);
4007dd7cddfSDavid du Colombier }
4017dd7cddfSDavid du Colombier pat -= n;
4027dd7cddfSDavid du Colombier continue;
4037dd7cddfSDavid du Colombier }
4047dd7cddfSDavid du Colombier for(i = 0; i < n; i++)
4057dd7cddfSDavid du Colombier if(name[i] != pat[i])
4067dd7cddfSDavid du Colombier return 0;
4077dd7cddfSDavid du Colombier name += n;
4087dd7cddfSDavid du Colombier }
4097dd7cddfSDavid du Colombier if(*name == '\0')
4107dd7cddfSDavid du Colombier return 1;
4117dd7cddfSDavid du Colombier return 0;
4127dd7cddfSDavid du Colombier }
413