Hi List! I read a post about moving a .mailbixlist to a .subscriptionfile when a user did not have one, but did have a .mailboxlist file. Timo emailed a module for that purpose, so it could be done for this user. My question is: - Where and how does dovecot call this function? - Would it be easy to use a module to a) create a mailpath (can be done as the mailuser's id, I use one uid, and my path is all owned by that uid), and b) simply remove a quota file? Thank you for your time, Maikel Verheijen. Ps: the email I am referring to has: Subject: Re: [Dovecot] 0.99.10-rc3 Message-Id: <1056538261.8144.38.camel at hurina> Date: 25 Jun 2003 13:51:01 +0300 -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://dovecot.org/pipermail/dovecot/attachments/20030718/d7583a20/attachment-0001.html>
On Saturday, Jul 19, 2003, at 00:40 Europe/Helsinki, Maikel Verheijen wrote:> I read a post about moving a .mailbixlist to a .subscriptionfile when > a user did not have one, but did have a .mailboxlist file. Timo > emailed a module for that purpose, so it could be done for this user. > > My question is: > > - Where and how does dovecot call this function?<module name>_init(); is called after initializing Dovecot's core code, but before opening any message store or creating client structure. I think I'd have to add some hooks for store creation and client creation so you wouldn't need kludges if you want to modify them in some way. You'll have to enable modules of course in configuration file and place the module to right directory.> - Would it be easy to use a module to a) create a mailpath (can be > done as the mailuser's id, I use one uid, and my path is all owned by > that uid), and b) simply remove a quota file?Yes, the modules can do whatever they want. Just use mkdir() and unlink().
Hi Timo, When you have time to create the hooks to the various locations within dovecot, I am willing to try to make a module to support Maildir quota's. Would that be possible with the hooks, and can that be done using a plugin as well? Kind regards, Maikel Verheijen.> -----Original Message----- > From: Timo Sirainen [mailto:tss at iki.fi] > Sent: Saturday, July 19, 2003 12:14 AM > To: Maikel Verheijen > Cc: 'dovecot at procontrol.fi' > Subject: Re: [Dovecot] Loadable module > > > On Saturday, Jul 19, 2003, at 00:40 Europe/Helsinki, Maikel Verheijen > wrote: > > > I read a post about moving a .mailbixlist to a > .subscriptionfile when > > a user did not have one, but did have a .mailboxlist file. Timo > > emailed a module for that purpose, so it could be done for > this user. > > > > My question is: > > > > - Where and how does dovecot call this function? > > <module name>_init(); is called after initializing Dovecot's > core code, > but before opening any message store or creating client structure. I > think I'd have to add some hooks for store creation and > client creation > so you wouldn't need kludges if you want to modify them in some way. > > You'll have to enable modules of course in configuration file > and place > the module to right directory. > > > - Would it be easy to use a module to a) create a mailpath (can be > > done as the mailuser's id, I use one uid, and my path is > all owned by > > that uid), and b) simply remove a quota file? > > Yes, the modules can do whatever they want. Just use mkdir() and > unlink(). >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://dovecot.org/pipermail/dovecot/attachments/20030722/03f9070b/attachment-0001.html>
On Tue, 2003-07-22 at 14:04, Maikel Verheijen wrote:> When you have time to create the hooks to the various locations within > dovecot, I am willing to try to make a module to support Maildir > quota's. Would that be possible with the hooks, and can that be done > using a plugin as well?Hmm. You probably want to override mailbox class's (yea, C class :) expunge, copy and save_*() methods and make them check/update the quota files. You can do the above by overriding mail_storage's open_mailbox() method. Only hook that I'd need to add is the "mail_storage created" where you can override the open_mailbox(). You probably want to add some own variables to mailbox class (eg. pointers to original expunge/copy/save* methods). I'm not really sure how this should be done. A few possibilities: 1) C++ -like class extension. You create: struct maildir_quota_mailbox { struct index_mailbox parent; // mbox/maildir uses index_mailbox // your stuff here }; And then casting mailbox -> maildir_quota_mailbox. But this has the problem that you can't create more than one module which extents a class. 2) A common module_data mapping for all modules. You'd call struct maildir_quota_data *data = map_lookup(mailbox, "maildir quota"); 3) Something more object oriented, piping the requests through possibly multiple classes: // more easily described in C++: mailbox = new acl_mailbox(new quota_mailbox(new maildir_mailbox())); struct quota_mailbox { struct mailbox mailbox; struct mailbox *next_mailbox; // your own stuff }; quota_mailbox_init(struct mailbox *next) { struct quota_mailbox *box = i_new(struct quota_mailbox, 1); box->next_mailbox = next; // fill in the functions we want to grab box->mailbox = quota_mailbox_defaults; // whatever functions we left NULL, copy them from "next". mailbox_fill_defaults(&box->mailbox, next); } int quota_mailbox_expunge(struct mailbox *box) { struct quota_mailbox *qbox = (struct quota_mailbox *) mailbox; if (!qbox->next->expunge(qbox->next)) return FALSE; return quota_update(qbox); } OK. 3) is the best idea :) But it requires a few changes to make it work. Actually, I think this is exactly how I want quota and ACLs to be implemented. No extra interface changes for either one of them. For quota, you'd want to do something like: expunge(): nothing special, just update the quota file after expunges save_next(): Check data istream's size and if it's over quota, fail. copy(): this is somewhat problematic, if there wasn't the maildir hardlinks you wouldn't have to touch it at all..
Hi Timo, [snipped possible scenario's]> OK. 3) is the best idea :) But it requires a few changes to > make it work.I wouldn't expect it to work out of the box :) But if I read your suggestions right, you propose a "fixed" change in the maildir functions that call the quota update functions if necessary. So perhaps we should make a quota_enabled = yes|no flag int the config file, and use that? I would still be trying to make the quota update functions for you, and try to put them in.> Actually, I think this is exactly how I want quota and ACLs > to be implemented. No extra interface changes for either one of them. > > For quota, you'd want to do something like: > > expunge(): nothing special, just update the quota file after expungesExpunge should recalculate the whole mailfolder?> save_next(): Check data istream's size and if it's over quota, fail.Ok. So this one can be "easy". Just check if mailsize + current usage < max_quota. :)> copy(): this is somewhat problematic, if there wasn't the > maildir hardlinks you wouldn't have to touch it at all..A copy can duplicate a message in the same store, but do hardlinks work on nfs? If not, we should add the message to the quota list. And maybe we should just add size of the email anyway, it won't be that much of a loss to the user, and it would save us a lot of checking. :) And how about a user that has no quota file (yet), can we "recreate" them? Maybe do a quota lookup for the user (database or file)? This can be done using a module I guess, so it could be "user configurable". Regards, Maikel Verheijen. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://dovecot.org/pipermail/dovecot/attachments/20030722/c3485689/attachment-0001.html>
On Tuesday, Jul 22, 2003, at 18:11 Europe/Helsinki, Maikel Verheijen wrote:> But if I read your suggestions right, you propose a "fixed" change in > the maildir functions that call the quota update functions if > necessary. So perhaps we should make a quota_enabled = yes|no flag int > the config file, and use that? I would still be trying to make the > quota update functions for you, and try to put them in.No, the core code wouldn't know anything about quota. The module would simply grab the calls to mailbox interface itself. Actually I'd really like if the same quota code was mail storage independent. So if you accessed the messages only through Dovecot's APIs the same code would work with maildir, mbox and whatever future formats I come up with. But I'm not sure how good idea this is with current APIs .. you probably could do it but it could be done faster.> > expunge(): nothing special, just update the quota file after expunges > Expunge should recalculate the whole mailfolder?Well .. it would be faster if it didn't have to. Problem is that you might not know the message's size always. Also there's some locking problems / race conditions if you try to calculate the new quota before actually expunging.> > copy(): this is somewhat problematic, if there wasn't the > > maildir hardlinks you wouldn't have to touch it at all.. > > A copy can duplicate a message in the same store, but do hardlinks > work on nfs? If not, we should add the message to the quota list. And > maybe we should just add size of the email anyway, it won't be that > much of a loss to the user, and it would save us a lot of checking. :)Hard links work with NFS. But the problem is adding the message to quota list. Normally copy() reads the messages and saves them using the normal save*() functions, so the quota checking would be done automatically. With hard links it doesn't go through save*(), so you'd have to do some special kludging if you wanted to account that copied message from quota too. One possibility is to just go through the messageset, get the message sizes, call copy(), see if quota was accounted by save*() functions, if not do it yourself. Another possibility is to fix the API by splitting all functions which handle multiple messages at once and replace them with iterator functions. ie. fetch*(), search*() and save*() are ok now, but expunge() and copy() are not. Something like: // initialize. very much like fetching messages. struct mail_copy_context *(*copy_init)(struct mailbox *box, enum mail_fetch_field wanted_fields, const char *messageset, int uidset); // copy next message. returns pointer to original message where you can find it's info // including message's size struct mail *(*copy_next)(struct mail_copy_context *ctx); You'd call copy_init() with wanted_fields being MESSAGE_FETCH_SIZE (or actually I should probably add _REAL_SIZE which would tell how much actual disk space it takes rather than the size with virtual CRs). Then you'd call copy_next(), use some kludge to see if it called your save_next(), if not you get the message size with mail->get_size(mail) and add it to quota. Expunging would work pretty much the same way: struct mail_expunge_context *(*expunge_init)(struct mailbox *box, enum mail_fetch_field wanted_fields); struct mail (*expunge_next)(struct mail_expunge_context *ctx); Only difference would be that mail->get_size() might return you -1, ie. unknown. In that case you'd have to recalculate the quota for the mailbox. Hmm. There's still a few small problems. And the _next() calls should probably be split to two, so you can first fetch the record, then decide if you really want to copy/expunge that message by calling _doit() or something. Umm. Actually then I might just as well use the normal fetch*() interface and just add a few new methods to struct mail: int (*expunge)(struct mail *mail); int (*copy)(struct mail *mail, struct mailbox *dest); I think that'd work. :) I'll try to make these changes to CVS soon.> And how about a user that has no quota file (yet), can we "recreate" > them? Maybe do a quota lookup for the user (database or file)? This > can be done using a module I guess, so it could be "user > configurable".Depends on how you want the quota stuff to work. I'm not sure about that yet. Maildir++ quota seemed a bit slow. It would require rescanning _all_ the mailboxes once in a while. That's kind of pointless if only a few mailboxes have changed. Of course we could internally calculate the quotas per mailbox and combine them all to one Maildir++ compatible quota file.