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 static int copyData(int ffd, int tfd, MbLock *ml);
87dd7cddfSDavid du Colombier static MbLock mLock =
97dd7cddfSDavid du Colombier {
107dd7cddfSDavid du Colombier .fd = -1
117dd7cddfSDavid du Colombier };
127dd7cddfSDavid du Colombier
139a747e4fSDavid du Colombier static char curDir[MboxNameLen];
147dd7cddfSDavid du Colombier
157dd7cddfSDavid du Colombier void
resetCurDir(void)167dd7cddfSDavid du Colombier resetCurDir(void)
177dd7cddfSDavid du Colombier {
187dd7cddfSDavid du Colombier curDir[0] = '\0';
197dd7cddfSDavid du Colombier }
207dd7cddfSDavid du Colombier
217dd7cddfSDavid du Colombier int
myChdir(char * dir)227dd7cddfSDavid du Colombier myChdir(char *dir)
237dd7cddfSDavid du Colombier {
247dd7cddfSDavid du Colombier if(strcmp(dir, curDir) == 0)
257dd7cddfSDavid du Colombier return 0;
269a747e4fSDavid du Colombier if(dir[0] != '/' || strlen(dir) > MboxNameLen)
277dd7cddfSDavid du Colombier return -1;
287dd7cddfSDavid du Colombier strcpy(curDir, dir);
297dd7cddfSDavid du Colombier if(chdir(dir) < 0){
309a747e4fSDavid du Colombier werrstr("mychdir failed: %r");
317dd7cddfSDavid du Colombier return -1;
327dd7cddfSDavid du Colombier }
337dd7cddfSDavid du Colombier return 0;
347dd7cddfSDavid du Colombier }
357dd7cddfSDavid du Colombier
367dd7cddfSDavid du Colombier int
cdCreate(char * dir,char * file,int mode,ulong perm)377dd7cddfSDavid du Colombier cdCreate(char *dir, char *file, int mode, ulong perm)
387dd7cddfSDavid du Colombier {
397dd7cddfSDavid du Colombier if(myChdir(dir) < 0)
407dd7cddfSDavid du Colombier return -1;
417dd7cddfSDavid du Colombier return create(file, mode, perm);
427dd7cddfSDavid du Colombier }
437dd7cddfSDavid du Colombier
449a747e4fSDavid du Colombier Dir*
cdDirstat(char * dir,char * file)459a747e4fSDavid du Colombier cdDirstat(char *dir, char *file)
467dd7cddfSDavid du Colombier {
477dd7cddfSDavid du Colombier if(myChdir(dir) < 0)
489a747e4fSDavid du Colombier return nil;
499a747e4fSDavid du Colombier return dirstat(file);
509a747e4fSDavid du Colombier }
519a747e4fSDavid du Colombier
529a747e4fSDavid du Colombier int
cdExists(char * dir,char * file)539a747e4fSDavid du Colombier cdExists(char *dir, char *file)
549a747e4fSDavid du Colombier {
559a747e4fSDavid du Colombier Dir *d;
569a747e4fSDavid du Colombier
579a747e4fSDavid du Colombier d = cdDirstat(dir, file);
589a747e4fSDavid du Colombier if(d == nil)
599a747e4fSDavid du Colombier return 0;
609a747e4fSDavid du Colombier free(d);
619a747e4fSDavid du Colombier return 1;
627dd7cddfSDavid du Colombier }
637dd7cddfSDavid du Colombier
647dd7cddfSDavid du Colombier int
cdDirwstat(char * dir,char * file,Dir * d)657dd7cddfSDavid du Colombier cdDirwstat(char *dir, char *file, Dir *d)
667dd7cddfSDavid du Colombier {
677dd7cddfSDavid du Colombier if(myChdir(dir) < 0)
687dd7cddfSDavid du Colombier return -1;
697dd7cddfSDavid du Colombier return dirwstat(file, d);
707dd7cddfSDavid du Colombier }
717dd7cddfSDavid du Colombier
727dd7cddfSDavid du Colombier int
cdOpen(char * dir,char * file,int mode)737dd7cddfSDavid du Colombier cdOpen(char *dir, char *file, int mode)
747dd7cddfSDavid du Colombier {
757dd7cddfSDavid du Colombier if(myChdir(dir) < 0)
767dd7cddfSDavid du Colombier return -1;
777dd7cddfSDavid du Colombier return open(file, mode);
787dd7cddfSDavid du Colombier }
797dd7cddfSDavid du Colombier
807dd7cddfSDavid du Colombier int
cdRemove(char * dir,char * file)817dd7cddfSDavid du Colombier cdRemove(char *dir, char *file)
827dd7cddfSDavid du Colombier {
837dd7cddfSDavid du Colombier if(myChdir(dir) < 0)
847dd7cddfSDavid du Colombier return -1;
857dd7cddfSDavid du Colombier return remove(file);
867dd7cddfSDavid du Colombier }
877dd7cddfSDavid du Colombier
887dd7cddfSDavid du Colombier /*
897dd7cddfSDavid du Colombier * open the one true mail lock file
907dd7cddfSDavid du Colombier */
917dd7cddfSDavid du Colombier MbLock*
mbLock(void)927dd7cddfSDavid du Colombier mbLock(void)
937dd7cddfSDavid du Colombier {
94*43aadf5eSDavid du Colombier int i;
95*43aadf5eSDavid du Colombier
967dd7cddfSDavid du Colombier if(mLock.fd >= 0)
977dd7cddfSDavid du Colombier bye("mail lock deadlock");
98*43aadf5eSDavid du Colombier for(i = 0; i < 5; i++){
997dd7cddfSDavid du Colombier mLock.fd = openLocked(mboxDir, "L.mbox", OREAD);
1007dd7cddfSDavid du Colombier if(mLock.fd >= 0)
1017dd7cddfSDavid du Colombier return &mLock;
102*43aadf5eSDavid du Colombier sleep(1000);
103*43aadf5eSDavid du Colombier }
1047dd7cddfSDavid du Colombier return nil;
1057dd7cddfSDavid du Colombier }
1067dd7cddfSDavid du Colombier
1077dd7cddfSDavid du Colombier void
mbUnlock(MbLock * ml)1087dd7cddfSDavid du Colombier mbUnlock(MbLock *ml)
1097dd7cddfSDavid du Colombier {
1107dd7cddfSDavid du Colombier if(ml != &mLock)
1117dd7cddfSDavid du Colombier bye("bad mail unlock");
1127dd7cddfSDavid du Colombier if(ml->fd < 0)
1137dd7cddfSDavid du Colombier bye("mail unlock when not locked");
1147dd7cddfSDavid du Colombier close(ml->fd);
1157dd7cddfSDavid du Colombier ml->fd = -1;
1167dd7cddfSDavid du Colombier }
1177dd7cddfSDavid du Colombier
1187dd7cddfSDavid du Colombier void
mbLockRefresh(MbLock * ml)1197dd7cddfSDavid du Colombier mbLockRefresh(MbLock *ml)
1207dd7cddfSDavid du Colombier {
1217dd7cddfSDavid du Colombier char buf[1];
1227dd7cddfSDavid du Colombier
1237dd7cddfSDavid du Colombier seek(ml->fd, 0, 0);
1247dd7cddfSDavid du Colombier read(ml->fd, buf, 1);
1257dd7cddfSDavid du Colombier }
1267dd7cddfSDavid du Colombier
1277dd7cddfSDavid du Colombier int
mbLocked(void)1287dd7cddfSDavid du Colombier mbLocked(void)
1297dd7cddfSDavid du Colombier {
1307dd7cddfSDavid du Colombier return mLock.fd >= 0;
1317dd7cddfSDavid du Colombier }
1327dd7cddfSDavid du Colombier
1337dd7cddfSDavid du Colombier char*
impName(char * name)1347dd7cddfSDavid du Colombier impName(char *name)
1357dd7cddfSDavid du Colombier {
1367dd7cddfSDavid du Colombier char *s;
1377dd7cddfSDavid du Colombier int n;
1387dd7cddfSDavid du Colombier
1397dd7cddfSDavid du Colombier if(cistrcmp(name, "inbox") == 0)
140*43aadf5eSDavid du Colombier if(access("msgs", AEXIST) == 0)
141*43aadf5eSDavid du Colombier name = "msgs";
142*43aadf5eSDavid du Colombier else
1437dd7cddfSDavid du Colombier name = "mbox";
1447dd7cddfSDavid du Colombier n = strlen(name) + STRLEN(".imp") + 1;
14580ee5cbfSDavid du Colombier s = binalloc(&parseBin, n, 0);
1467dd7cddfSDavid du Colombier if(s == nil)
1477dd7cddfSDavid du Colombier return nil;
1487dd7cddfSDavid du Colombier snprint(s, n, "%s.imp", name);
1497dd7cddfSDavid du Colombier return s;
1507dd7cddfSDavid du Colombier }
1517dd7cddfSDavid du Colombier
1527dd7cddfSDavid du Colombier /*
1537dd7cddfSDavid du Colombier * massage the mailbox name into something valid
1547dd7cddfSDavid du Colombier * eliminates all .', and ..',s, redundatant and trailing /'s.
1557dd7cddfSDavid du Colombier */
1567dd7cddfSDavid du Colombier char *
mboxName(char * s)1577dd7cddfSDavid du Colombier mboxName(char *s)
1587dd7cddfSDavid du Colombier {
1597dd7cddfSDavid du Colombier char *ss;
1607dd7cddfSDavid du Colombier
1617dd7cddfSDavid du Colombier ss = mutf7str(s);
1627dd7cddfSDavid du Colombier if(ss == nil)
1637dd7cddfSDavid du Colombier return nil;
1647dd7cddfSDavid du Colombier cleanname(ss);
1657dd7cddfSDavid du Colombier return ss;
1667dd7cddfSDavid du Colombier }
1677dd7cddfSDavid du Colombier
1687dd7cddfSDavid du Colombier char *
strmutf7(char * s)1697dd7cddfSDavid du Colombier strmutf7(char *s)
1707dd7cddfSDavid du Colombier {
1717dd7cddfSDavid du Colombier char *m;
1727dd7cddfSDavid du Colombier int n;
1737dd7cddfSDavid du Colombier
1747dd7cddfSDavid du Colombier n = strlen(s) * MUtf7Max + 1;
17580ee5cbfSDavid du Colombier m = binalloc(&parseBin, n, 0);
1767dd7cddfSDavid du Colombier if(m == nil)
1777dd7cddfSDavid du Colombier return nil;
1787dd7cddfSDavid du Colombier if(encmutf7(m, n, s) < 0)
1797dd7cddfSDavid du Colombier return nil;
1807dd7cddfSDavid du Colombier return m;
1817dd7cddfSDavid du Colombier }
1827dd7cddfSDavid du Colombier
1837dd7cddfSDavid du Colombier char *
mutf7str(char * s)1847dd7cddfSDavid du Colombier mutf7str(char *s)
1857dd7cddfSDavid du Colombier {
1867dd7cddfSDavid du Colombier char *m;
1877dd7cddfSDavid du Colombier int n;
1887dd7cddfSDavid du Colombier
1897dd7cddfSDavid du Colombier /*
1907dd7cddfSDavid du Colombier * n = strlen(s) * UTFmax / (2.67) + 1
1917dd7cddfSDavid du Colombier * UTFMax / 2.67 == 3 / (8/3) == 9 / 8
1927dd7cddfSDavid du Colombier */
1937dd7cddfSDavid du Colombier n = strlen(s);
1947dd7cddfSDavid du Colombier n = (n * 9 + 7) / 8 + 1;
19580ee5cbfSDavid du Colombier m = binalloc(&parseBin, n, 0);
1967dd7cddfSDavid du Colombier if(m == nil)
1977dd7cddfSDavid du Colombier return nil;
1987dd7cddfSDavid du Colombier if(decmutf7(m, n, s) < 0)
1997dd7cddfSDavid du Colombier return nil;
2007dd7cddfSDavid du Colombier return m;
2017dd7cddfSDavid du Colombier }
2027dd7cddfSDavid du Colombier
2037dd7cddfSDavid du Colombier void
splitr(char * s,int c,char ** left,char ** right)2047dd7cddfSDavid du Colombier splitr(char *s, int c, char **left, char **right)
2057dd7cddfSDavid du Colombier {
2067dd7cddfSDavid du Colombier char *d;
2077dd7cddfSDavid du Colombier int n;
2087dd7cddfSDavid du Colombier
2097dd7cddfSDavid du Colombier n = strlen(s);
21080ee5cbfSDavid du Colombier d = binalloc(&parseBin, n + 1, 0);
2117dd7cddfSDavid du Colombier if(d == nil)
2127dd7cddfSDavid du Colombier parseErr("out of memory");
2137dd7cddfSDavid du Colombier strcpy(d, s);
2147dd7cddfSDavid du Colombier s = strrchr(d, c);
2157dd7cddfSDavid du Colombier if(s != nil){
2167dd7cddfSDavid du Colombier *left = d;
2177dd7cddfSDavid du Colombier *s++ = '\0';
2187dd7cddfSDavid du Colombier *right = s;
2197dd7cddfSDavid du Colombier }else{
2207dd7cddfSDavid du Colombier *right = d;
2217dd7cddfSDavid du Colombier *left = d + n;
2227dd7cddfSDavid du Colombier }
2237dd7cddfSDavid du Colombier }
2247dd7cddfSDavid du Colombier
2257dd7cddfSDavid du Colombier /*
2267dd7cddfSDavid du Colombier * create the mailbox and all intermediate components
2277dd7cddfSDavid du Colombier * a trailing / implies the new mailbox is a directory;
2287dd7cddfSDavid du Colombier * otherwise, it's a file.
2297dd7cddfSDavid du Colombier *
2307dd7cddfSDavid du Colombier * return with the file open for write, or directory open for read.
2317dd7cddfSDavid du Colombier */
2327dd7cddfSDavid du Colombier int
createBox(char * mbox,int dir)2337dd7cddfSDavid du Colombier createBox(char *mbox, int dir)
2347dd7cddfSDavid du Colombier {
2357dd7cddfSDavid du Colombier char *m;
2367dd7cddfSDavid du Colombier int fd;
2377dd7cddfSDavid du Colombier
2387dd7cddfSDavid du Colombier fd = -1;
2397dd7cddfSDavid du Colombier for(m = mbox; *m; m++){
2407dd7cddfSDavid du Colombier if(*m == '/'){
2417dd7cddfSDavid du Colombier *m = '\0';
2427dd7cddfSDavid du Colombier if(access(mbox, AEXIST) < 0){
2437dd7cddfSDavid du Colombier if(fd >= 0)
2447dd7cddfSDavid du Colombier close(fd);
2459a747e4fSDavid du Colombier fd = cdCreate(mboxDir, mbox, OREAD, DMDIR|0775);
2467dd7cddfSDavid du Colombier if(fd < 0)
2477dd7cddfSDavid du Colombier return -1;
2487dd7cddfSDavid du Colombier }
2497dd7cddfSDavid du Colombier *m = '/';
2507dd7cddfSDavid du Colombier }
2517dd7cddfSDavid du Colombier }
2527dd7cddfSDavid du Colombier if(dir)
2539a747e4fSDavid du Colombier fd = cdCreate(mboxDir, mbox, OREAD, DMDIR|0775);
2547dd7cddfSDavid du Colombier else
2557dd7cddfSDavid du Colombier fd = cdCreate(mboxDir, mbox, OWRITE, 0664);
2567dd7cddfSDavid du Colombier return fd;
2577dd7cddfSDavid du Colombier }
2587dd7cddfSDavid du Colombier
2597dd7cddfSDavid du Colombier /*
2607dd7cddfSDavid du Colombier * move one mail folder to another
2617dd7cddfSDavid du Colombier * destination mailbox doesn't exist.
2627dd7cddfSDavid du Colombier * the source folder may be a directory or a mailbox,
2637dd7cddfSDavid du Colombier * and may be in the same directory as the destination,
2647dd7cddfSDavid du Colombier * or a completely different directory.
2657dd7cddfSDavid du Colombier */
2667dd7cddfSDavid du Colombier int
moveBox(char * from,char * to)2677dd7cddfSDavid du Colombier moveBox(char *from, char *to)
2687dd7cddfSDavid du Colombier {
2699a747e4fSDavid du Colombier Dir *d;
2707dd7cddfSDavid du Colombier char *fd, *fe, *td, *te, *fimp;
2717dd7cddfSDavid du Colombier
2727dd7cddfSDavid du Colombier splitr(from, '/', &fd, &fe);
2737dd7cddfSDavid du Colombier splitr(to, '/', &td, &te);
2747dd7cddfSDavid du Colombier
2757dd7cddfSDavid du Colombier /*
2767dd7cddfSDavid du Colombier * in the same directory: try rename
2777dd7cddfSDavid du Colombier */
2789a747e4fSDavid du Colombier d = cdDirstat(mboxDir, from);
2799a747e4fSDavid du Colombier if(d == nil)
2807dd7cddfSDavid du Colombier return 0;
2817dd7cddfSDavid du Colombier if(strcmp(fd, td) == 0){
2829a747e4fSDavid du Colombier nulldir(d);
2839a747e4fSDavid du Colombier d->name = te;
2849a747e4fSDavid du Colombier if(cdDirwstat(mboxDir, from, d) >= 0){
2857dd7cddfSDavid du Colombier fimp = impName(from);
2869a747e4fSDavid du Colombier d->name = impName(te);
2879a747e4fSDavid du Colombier cdDirwstat(mboxDir, fimp, d);
2889a747e4fSDavid du Colombier free(d);
2897dd7cddfSDavid du Colombier return 1;
2907dd7cddfSDavid du Colombier }
2917dd7cddfSDavid du Colombier }
2927dd7cddfSDavid du Colombier
2937dd7cddfSDavid du Colombier /*
2947dd7cddfSDavid du Colombier * directory copy is too hard for now
2957dd7cddfSDavid du Colombier */
2969a747e4fSDavid du Colombier if(d->mode & DMDIR)
2977dd7cddfSDavid du Colombier return 0;
2989a747e4fSDavid du Colombier free(d);
2997dd7cddfSDavid du Colombier
3007dd7cddfSDavid du Colombier return copyBox(from, to, 1);
3017dd7cddfSDavid du Colombier }
3027dd7cddfSDavid du Colombier
3037dd7cddfSDavid du Colombier /*
3047dd7cddfSDavid du Colombier * copy the contents of one mailbox to another
3057dd7cddfSDavid du Colombier * either truncates or removes the source box if it succeeds.
3067dd7cddfSDavid du Colombier */
3077dd7cddfSDavid du Colombier int
copyBox(char * from,char * to,int doremove)3087dd7cddfSDavid du Colombier copyBox(char *from, char *to, int doremove)
3097dd7cddfSDavid du Colombier {
3107dd7cddfSDavid du Colombier MbLock *ml;
3117dd7cddfSDavid du Colombier char *fimp, *timp;
3127dd7cddfSDavid du Colombier int ffd, tfd, ok;
3137dd7cddfSDavid du Colombier
3147dd7cddfSDavid du Colombier if(cistrcmp(from, "inbox") == 0)
315*43aadf5eSDavid du Colombier if(access("msgs", AEXIST) == 0)
316*43aadf5eSDavid du Colombier from = "msgs";
317*43aadf5eSDavid du Colombier else
3187dd7cddfSDavid du Colombier from = "mbox";
3197dd7cddfSDavid du Colombier
3207dd7cddfSDavid du Colombier ml = mbLock();
3217dd7cddfSDavid du Colombier if(ml == nil)
3227dd7cddfSDavid du Colombier return 0;
3237dd7cddfSDavid du Colombier ffd = openLocked(mboxDir, from, OREAD);
3247dd7cddfSDavid du Colombier if(ffd < 0){
3257dd7cddfSDavid du Colombier mbUnlock(ml);
3267dd7cddfSDavid du Colombier return 0;
3277dd7cddfSDavid du Colombier }
3287dd7cddfSDavid du Colombier tfd = createBox(to, 0);
3297dd7cddfSDavid du Colombier if(tfd < 0){
3307dd7cddfSDavid du Colombier mbUnlock(ml);
3317dd7cddfSDavid du Colombier close(ffd);
3327dd7cddfSDavid du Colombier return 0;
3337dd7cddfSDavid du Colombier }
3347dd7cddfSDavid du Colombier
3357dd7cddfSDavid du Colombier ok = copyData(ffd, tfd, ml);
3367dd7cddfSDavid du Colombier close(ffd);
3377dd7cddfSDavid du Colombier close(tfd);
3387dd7cddfSDavid du Colombier if(!ok){
3397dd7cddfSDavid du Colombier mbUnlock(ml);
3407dd7cddfSDavid du Colombier return 0;
3417dd7cddfSDavid du Colombier }
3427dd7cddfSDavid du Colombier
3437dd7cddfSDavid du Colombier fimp = impName(from);
3447dd7cddfSDavid du Colombier timp = impName(to);
3457dd7cddfSDavid du Colombier if(fimp != nil && timp != nil){
3467dd7cddfSDavid du Colombier ffd = cdOpen(mboxDir, fimp, OREAD);
3477dd7cddfSDavid du Colombier if(ffd >= 0){
3487dd7cddfSDavid du Colombier tfd = cdCreate(mboxDir, timp, OWRITE, 0664);
3497dd7cddfSDavid du Colombier if(tfd >= 0){
3507dd7cddfSDavid du Colombier copyData(ffd, tfd, ml);
3517dd7cddfSDavid du Colombier close(tfd);
3527dd7cddfSDavid du Colombier }
3537dd7cddfSDavid du Colombier close(ffd);
3547dd7cddfSDavid du Colombier }
3557dd7cddfSDavid du Colombier }
3567dd7cddfSDavid du Colombier cdRemove(mboxDir, fimp);
3577dd7cddfSDavid du Colombier if(doremove)
3587dd7cddfSDavid du Colombier cdRemove(mboxDir, from);
3597dd7cddfSDavid du Colombier else
3607dd7cddfSDavid du Colombier close(cdOpen(mboxDir, from, OWRITE|OTRUNC));
3617dd7cddfSDavid du Colombier mbUnlock(ml);
3627dd7cddfSDavid du Colombier return 1;
3637dd7cddfSDavid du Colombier }
3647dd7cddfSDavid du Colombier
3657dd7cddfSDavid du Colombier /*
3667dd7cddfSDavid du Colombier * copies while holding the mail lock,
3677dd7cddfSDavid du Colombier * then tries to copy permissions and group ownership
3687dd7cddfSDavid du Colombier */
3697dd7cddfSDavid du Colombier static int
copyData(int ffd,int tfd,MbLock * ml)3707dd7cddfSDavid du Colombier copyData(int ffd, int tfd, MbLock *ml)
3717dd7cddfSDavid du Colombier {
3729a747e4fSDavid du Colombier Dir *fd, td;
3737dd7cddfSDavid du Colombier char buf[BufSize];
3747dd7cddfSDavid du Colombier int n;
3757dd7cddfSDavid du Colombier
3767dd7cddfSDavid du Colombier for(;;){
3777dd7cddfSDavid du Colombier n = read(ffd, buf, BufSize);
3787dd7cddfSDavid du Colombier if(n <= 0){
3797dd7cddfSDavid du Colombier if(n < 0)
3807dd7cddfSDavid du Colombier return 0;
3817dd7cddfSDavid du Colombier break;
3827dd7cddfSDavid du Colombier }
3837dd7cddfSDavid du Colombier if(write(tfd, buf, n) != n)
3847dd7cddfSDavid du Colombier return 0;
3857dd7cddfSDavid du Colombier mbLockRefresh(ml);
3867dd7cddfSDavid du Colombier }
3879a747e4fSDavid du Colombier fd = dirfstat(ffd);
3889a747e4fSDavid du Colombier if(fd != nil){
3899a747e4fSDavid du Colombier nulldir(&td);
3909a747e4fSDavid du Colombier td.mode = fd->mode;
3917dd7cddfSDavid du Colombier if(dirfwstat(tfd, &td) >= 0){
3929a747e4fSDavid du Colombier nulldir(&td);
3939a747e4fSDavid du Colombier td.gid = fd->gid;
3947dd7cddfSDavid du Colombier dirfwstat(tfd, &td);
3957dd7cddfSDavid du Colombier }
3967dd7cddfSDavid du Colombier }
3977dd7cddfSDavid du Colombier return 1;
3987dd7cddfSDavid du Colombier }
399