Beispiel #1
0
void mail::maildir::genericGetMessageFdStruct(string uid,
					      size_t messageNumber,
					      bool peek,
					      int &fdRet,
					      struct rfc2045 *&structret,
					      mail::callback &callback)
{
	if (uid == cacheUID && cachefd >= 0 && cacheRfcp != 0)
	{
		fdRet=cachefd;
		structret=cacheRfcp;
		callback.success("OK");
		return;
	}

	if (!fixMessageNumber(this, uid, messageNumber))
	{
		callback.fail("Message removed on the server");
		return;
	}

	if (cacheRfcp)
	{
		rfc2045_free(cacheRfcp);
		cacheRfcp=NULL;
	}

	if (cachefd >= 0)
	{
		close(cachefd);
		cachefd= -1;
	}

	if (!fixMessageNumber(this, uid, messageNumber))
	{
		callback.fail("Message removed on the server");
		return;
	}

	string messageFn=getfilename(messageNumber);

	if (messageFn.size() == 0)
	{
		callback.fail("Message removed on the server");
		return;
	}

	int fd=maildir_safeopen(messageFn.c_str(), O_RDONLY, 0);

	struct rfc2045 *rfcp;

	if (fd < 0 || fcntl(fd, F_SETFD, FD_CLOEXEC) < 0 ||
	    (rfcp=rfc2045_alloc()) == NULL)
	{
		if (fd >= 0)
			close(fd);
		callback.fail("Message removed on the server");
		return;
	}

	fcntl(fd, F_SETFD, FD_CLOEXEC);

	cachefd=fd;
	cacheRfcp=rfcp;
	cacheUID="";

	vector<char> buffer;

	buffer.insert(buffer.end(), BUFSIZ, 0);

	int n;

	while ((n=read(fd, &buffer[0], buffer.size())) > 0)
		rfc2045_parse(rfcp, &buffer[0], n);
	rfc2045_parse_partial(rfcp);

	if (n < 0)
	{
		callback.fail(strerror(errno));
		return;
	}

	fdRet=cachefd;
	structret=cacheRfcp;
	if (!peek && index[messageNumber].unread)
	{
		index[messageNumber].unread=false;
		saveFolderIndexInfo(messageNumber, index[messageNumber],
				    callback);
		return;
	}
	callback.success("OK");
}
Beispiel #2
0
void mail::maildir::open(string pathStr, mail::callback &callback,
			 mail::callback::folder &folderCallbackArg)
{
	index.clear();
	updateNotify(false);

	folderCallback=NULL;
	if (cacheRfcp)
	{
		rfc2045_free(cacheRfcp);
		cacheRfcp=NULL;
	}

	if (cachefd >= 0)
	{
		close(cachefd);
		cachefd=-1;
	}

	if (path == "")
	{
		callback.fail(strerror(errno));
		return;
	}

	set<string> recentMessages;

	string md;

	char *d=maildir_name2dir(path.c_str(), pathStr.c_str());

	if (!d)
	{
		callback.fail(strerror(errno));
		return;
	}

	try {
		md=d;
		free(d);
	} catch (...) {
		free(d);
		LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
	}

	{
		struct stat stat_buf;

		string d=md + "/" KEYWORDDIR;
		/* New Courier-IMAP maildirwatch code */

		mkdir(d.c_str(), 0700);

		if (stat(md.c_str(), &stat_buf) == 0)
			chmod(d.c_str(), stat_buf.st_mode & 0777);
	}

	maildir_purgetmp(md.c_str());
	maildir_getnew(md.c_str(), NULL,
		       &recent_callback_func, &recentMessages);

	scan(pathStr, index);

	folderCallback= &folderCallbackArg;
	folderPath=pathStr;

	vector<maildirMessageInfo>::iterator b=index.begin(), e=index.end();

	while (b != e)
	{
		b->recent=recentMessages.count(b->lastKnownFilename) > 0;
		b++;
	}

	if (lockFolder)
		maildirwatch_free(lockFolder);

	lockFolder=maildirwatch_alloc(md.c_str());

	readKeywordHelper rkh(this);

	bool rc;

	while (rkh.go(md, rc))
		;

	callback.success("Mail folder opened");
}
Beispiel #3
0
void mail::mbox::folder::renameFolder(const mail::folder *newParent,
				      std::string newName,
				      mail::callback::folderList &callback1,
				      mail::callback &callback) const
{
	if (isDestroyed(callback))
		return;

	if (path == "INBOX")
	{
		callback.fail("Not implemented.");
		return;
	}

	if (mboxAccount.currentFolder.size() > 0)
	{
		if (mboxAccount.currentFolder == path ||
		    (path + "/") ==
		    mboxAccount.currentFolder.substr(0, path.size()+1))
		{
			callback.fail("Cannot RENAME currently open folder.");
			return;
		}
	}

	// The name of the folder is translated from the local charset
	// to modified UTF-7 (Courier-IMAP compatibility), with the following
	// blacklisted characters:

	string nameutf7=mail::iconvert::convert(newName,
						unicode_default_chset(),
						unicode_x_imap_modutf7 " ./~:");

	string newpath=(newParent ? newParent->getPath() + "/":
			string("")) + nameutf7;

	if (newpath.size() == 0 || newpath[0] != '/')
		newpath=mboxAccount.rootPath + "/" + newpath;

	struct stat stat_buf;

	if (stat(path.c_str(), &stat_buf) == 0 &&
	    S_ISDIR(stat_buf.st_mode))
	{
		if (rename(path.c_str(), newpath.c_str()) < 0)
		{
			callback.fail(strerror(errno));
			return;
		}

		mail::mbox::folder newFolder(newpath, mboxAccount);

		vector<const mail::folder *> folders;

		folders.push_back(&newFolder);
		callback1.success( folders );
		callback.success("Mail folder renamed.");
		return;
	}

	mboxAccount.installTask(new mail::mbox::RenameTask(mboxAccount,
							   callback1,
							   callback,
							   path, newpath,
							   newName));
}
Beispiel #4
0
void mail::maildir::folder::renameFolder(const mail::folder *newParent,
					 std::string newName,
					 mail::callback::folderList &callback1,
					 mail::callback &callback2) const
{
	if (isDestroyed(callback2))
		return;

	if (maildirAccount->folderPath.size() > 0)
	{
		size_t l=path.size();

		if (strncmp(maildirAccount->folderPath.c_str(),
			    path.c_str(), l) == 0 &&
		    ((maildirAccount->folderPath.c_str())[l] == 0 ||
		     (maildirAccount->folderPath.c_str())[l] == '.'))
		{
			callback2.fail("Cannot RENAME currently open folder.");
			return;
		}
	}

	// The name of the folder is translated from the local charset
	// to modified UTF-7 (Courier-IMAP compatibility), with the following
	// blacklisted characters:

	char *s=libmail_u_convert_tobuf(newName.c_str(),
					unicode_default_chset(),
					unicode_x_imap_modutf7 " ./~:", NULL);

	if (!s)
	{
		callback2.fail(strerror(errno));
		return;
	}

	std::string nameutf7;

	errno=ENOMEM;
	try {
		nameutf7=s;
		free(s);
	} catch (...) {
		free(s);
		callback2.fail(strerror(errno));
		return;
	}

	mail::maildir::folder newFolder(maildirAccount,
					(newParent ?
					 newParent->getPath() + ".":
					 string("")) + nameutf7);

	newFolder.hasMessages( hasMessages() );
	newFolder.hasSubFolders( hasSubFolders() );

	vector<const mail::folder *> folders;

	// Paths are INBOX.foo

	string from, to;

	char *p=maildir_name2dir(".", path.c_str());

	if (p)
		try {
			from=p+2; // Skip ./
			free(p);
		} catch (...) {
			free(p);
			LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
		}

	p=maildir_name2dir(".", newFolder.path.c_str());
	if (p)
		try {
			to=p+2; // Skip ./
			free(p);
		} catch (...) {
			free(p);
			LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
		}


	if (from.size() > 0 &&
	    to.size() > 0 &&
	    maildir_rename(maildirAccount->path.c_str(),
			   from.c_str(), to.c_str(),
			   MAILDIR_RENAME_FOLDER |
			   MAILDIR_RENAME_SUBFOLDERS, NULL))
	{
		callback2.fail(strerror(errno));
	}
	else
	{
		folders.push_back(&newFolder);
		callback1.success( folders );
		callback2.success("Mail folder renamed");
	}
}
Beispiel #5
0
void mail::mbox::folder::destroy(mail::callback &callback, bool destroyDir)
	const
{
	if (destroyDir) {

		// Clean up garbage first.

		DIR *dirp=opendir(path.c_str());

		try {
			struct dirent *de;

			while (dirp && (de=readdir(dirp)) != NULL)
			{
				const char *p=strrchr(de->d_name, '~');

				if (p && p[1] == 0) // Temp file?
				{
					string s=path + "/" +
						string((const char *)
						       de->d_name, p);

					struct stat stat_buf;

					if (stat(s.c_str(), &stat_buf) < 0)
					{
						s += "~";
						unlink(s.c_str());
					}
					continue;
				}

				for (p=de->d_name; *p; p++)
				{
					if (strncmp(p, ".lock.", 6) == 0)
					{
						string s=path + "/" +
							de->d_name;

						struct stat stat_buf;

						if (stat(s.c_str(), &stat_buf)
						    == 0 &&
						    stat_buf.st_mtime + 120
						    < time(NULL))
							break;
					}

					if (strcmp(p, ".lock") == 0)
					{
						string s=path + "/"
							+ string((const char *)
								 de->d_name,
								 p);
						struct stat stat_buf;

						if (stat(s.c_str(), &stat_buf)
						    < 0)
							break;
					}
				}

				if (*p)
				{
					string s=path + "/" + de->d_name;

					unlink(s.c_str());
				}
			}

			if (dirp)
				closedir(dirp);
		} catch (...) {
			if (dirp)
				closedir(dirp);
			LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
		}

		if (rmdir(path.c_str()) < 0)
		{
			callback.fail(path + ": " + strerror(errno));
			return;
		}
	} else {
		if (unlink(path.c_str()) < 0)
		{
			callback.fail(path + ": " + strerror(errno));
			return;
		}
	}

	callback.success("OK");
}