123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <auth.h>
- #include "imap4d.h"
- static int copyData(int ffd, int tfd, MbLock *ml);
- static MbLock mLock =
- {
- .fd = -1
- };
- static char curDir[MboxNameLen];
- void
- resetCurDir(void)
- {
- curDir[0] = '\0';
- }
- int
- myChdir(char *dir)
- {
- if(strcmp(dir, curDir) == 0)
- return 0;
- if(dir[0] != '/' || strlen(dir) > MboxNameLen)
- return -1;
- strcpy(curDir, dir);
- if(chdir(dir) < 0){
- werrstr("mychdir failed: %r");
- return -1;
- }
- return 0;
- }
- int
- cdCreate(char *dir, char *file, int mode, ulong perm)
- {
- if(myChdir(dir) < 0)
- return -1;
- return create(file, mode, perm);
- }
- Dir*
- cdDirstat(char *dir, char *file)
- {
- if(myChdir(dir) < 0)
- return nil;
- return dirstat(file);
- }
- int
- cdExists(char *dir, char *file)
- {
- Dir *d;
- d = cdDirstat(dir, file);
- if(d == nil)
- return 0;
- free(d);
- return 1;
- }
- int
- cdDirwstat(char *dir, char *file, Dir *d)
- {
- if(myChdir(dir) < 0)
- return -1;
- return dirwstat(file, d);
- }
- int
- cdOpen(char *dir, char *file, int mode)
- {
- if(myChdir(dir) < 0)
- return -1;
- return open(file, mode);
- }
- int
- cdRemove(char *dir, char *file)
- {
- if(myChdir(dir) < 0)
- return -1;
- return remove(file);
- }
- /*
- * open the one true mail lock file
- */
- MbLock*
- mbLock(void)
- {
- if(mLock.fd >= 0)
- bye("mail lock deadlock");
- mLock.fd = openLocked(mboxDir, "L.mbox", OREAD);
- if(mLock.fd >= 0)
- return &mLock;
- return nil;
- }
- void
- mbUnlock(MbLock *ml)
- {
- if(ml != &mLock)
- bye("bad mail unlock");
- if(ml->fd < 0)
- bye("mail unlock when not locked");
- close(ml->fd);
- ml->fd = -1;
- }
- void
- mbLockRefresh(MbLock *ml)
- {
- char buf[1];
- seek(ml->fd, 0, 0);
- read(ml->fd, buf, 1);
- }
- int
- mbLocked(void)
- {
- return mLock.fd >= 0;
- }
- char*
- impName(char *name)
- {
- char *s;
- int n;
- if(cistrcmp(name, "inbox") == 0)
- name = "mbox";
- n = strlen(name) + STRLEN(".imp") + 1;
- s = binalloc(&parseBin, n, 0);
- if(s == nil)
- return nil;
- snprint(s, n, "%s.imp", name);
- return s;
- }
- /*
- * massage the mailbox name into something valid
- * eliminates all .', and ..',s, redundatant and trailing /'s.
- */
- char *
- mboxName(char *s)
- {
- char *ss;
- ss = mutf7str(s);
- if(ss == nil)
- return nil;
- cleanname(ss);
- return ss;
- }
- char *
- strmutf7(char *s)
- {
- char *m;
- int n;
- n = strlen(s) * MUtf7Max + 1;
- m = binalloc(&parseBin, n, 0);
- if(m == nil)
- return nil;
- if(encmutf7(m, n, s) < 0)
- return nil;
- return m;
- }
- char *
- mutf7str(char *s)
- {
- char *m;
- int n;
- /*
- * n = strlen(s) * UTFmax / (2.67) + 1
- * UTFMax / 2.67 == 3 / (8/3) == 9 / 8
- */
- n = strlen(s);
- n = (n * 9 + 7) / 8 + 1;
- m = binalloc(&parseBin, n, 0);
- if(m == nil)
- return nil;
- if(decmutf7(m, n, s) < 0)
- return nil;
- return m;
- }
- void
- splitr(char *s, int c, char **left, char **right)
- {
- char *d;
- int n;
- n = strlen(s);
- d = binalloc(&parseBin, n + 1, 0);
- if(d == nil)
- parseErr("out of memory");
- strcpy(d, s);
- s = strrchr(d, c);
- if(s != nil){
- *left = d;
- *s++ = '\0';
- *right = s;
- }else{
- *right = d;
- *left = d + n;
- }
- }
- /*
- * create the mailbox and all intermediate components
- * a trailing / implies the new mailbox is a directory;
- * otherwise, it's a file.
- *
- * return with the file open for write, or directory open for read.
- */
- int
- createBox(char *mbox, int dir)
- {
- char *m;
- int fd;
- fd = -1;
- for(m = mbox; *m; m++){
- if(*m == '/'){
- *m = '\0';
- if(access(mbox, AEXIST) < 0){
- if(fd >= 0)
- close(fd);
- fd = cdCreate(mboxDir, mbox, OREAD, DMDIR|0775);
- if(fd < 0)
- return -1;
- }
- *m = '/';
- }
- }
- if(dir)
- fd = cdCreate(mboxDir, mbox, OREAD, DMDIR|0775);
- else
- fd = cdCreate(mboxDir, mbox, OWRITE, 0664);
- return fd;
- }
- /*
- * move one mail folder to another
- * destination mailbox doesn't exist.
- * the source folder may be a directory or a mailbox,
- * and may be in the same directory as the destination,
- * or a completely different directory.
- */
- int
- moveBox(char *from, char *to)
- {
- Dir *d;
- char *fd, *fe, *td, *te, *fimp;
- splitr(from, '/', &fd, &fe);
- splitr(to, '/', &td, &te);
- /*
- * in the same directory: try rename
- */
- d = cdDirstat(mboxDir, from);
- if(d == nil)
- return 0;
- if(strcmp(fd, td) == 0){
- nulldir(d);
- d->name = te;
- if(cdDirwstat(mboxDir, from, d) >= 0){
- fimp = impName(from);
- d->name = impName(te);
- cdDirwstat(mboxDir, fimp, d);
- free(d);
- return 1;
- }
- }
- /*
- * directory copy is too hard for now
- */
- if(d->mode & DMDIR)
- return 0;
- free(d);
- return copyBox(from, to, 1);
- }
- /*
- * copy the contents of one mailbox to another
- * either truncates or removes the source box if it succeeds.
- */
- int
- copyBox(char *from, char *to, int doremove)
- {
- MbLock *ml;
- char *fimp, *timp;
- int ffd, tfd, ok;
- if(cistrcmp(from, "inbox") == 0)
- from = "mbox";
- ml = mbLock();
- if(ml == nil)
- return 0;
- ffd = openLocked(mboxDir, from, OREAD);
- if(ffd < 0){
- mbUnlock(ml);
- return 0;
- }
- tfd = createBox(to, 0);
- if(tfd < 0){
- mbUnlock(ml);
- close(ffd);
- return 0;
- }
- ok = copyData(ffd, tfd, ml);
- close(ffd);
- close(tfd);
- if(!ok){
- mbUnlock(ml);
- return 0;
- }
- fimp = impName(from);
- timp = impName(to);
- if(fimp != nil && timp != nil){
- ffd = cdOpen(mboxDir, fimp, OREAD);
- if(ffd >= 0){
- tfd = cdCreate(mboxDir, timp, OWRITE, 0664);
- if(tfd >= 0){
- copyData(ffd, tfd, ml);
- close(tfd);
- }
- close(ffd);
- }
- }
- cdRemove(mboxDir, fimp);
- if(doremove)
- cdRemove(mboxDir, from);
- else
- close(cdOpen(mboxDir, from, OWRITE|OTRUNC));
- mbUnlock(ml);
- return 1;
- }
- /*
- * copies while holding the mail lock,
- * then tries to copy permissions and group ownership
- */
- static int
- copyData(int ffd, int tfd, MbLock *ml)
- {
- Dir *fd, td;
- char buf[BufSize];
- int n;
- for(;;){
- n = read(ffd, buf, BufSize);
- if(n <= 0){
- if(n < 0)
- return 0;
- break;
- }
- if(write(tfd, buf, n) != n)
- return 0;
- mbLockRefresh(ml);
- }
- fd = dirfstat(ffd);
- if(fd != nil){
- nulldir(&td);
- td.mode = fd->mode;
- if(dirfwstat(tfd, &td) >= 0){
- nulldir(&td);
- td.gid = fd->gid;
- dirfwstat(tfd, &td);
- }
- }
- return 1;
- }
|