]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added the concept of Global UIDs that are preserved across copies.
authorTimo Sirainen <tss@iki.fi>
Thu, 7 Aug 2008 19:33:52 +0000 (15:33 -0400)
committerTimo Sirainen <tss@iki.fi>
Thu, 7 Aug 2008 19:33:52 +0000 (15:33 -0400)
They can be fetched, searched and specified for the save API. dbox format
supports them correctly, but with maildir the base filename is used so
maildir_copy_preserve_filename=yes is required to preserve GUIDs when copying.

--HG--
branch : HEAD

21 files changed:
src/imap/imap-fetch.c
src/lib-storage/index/cydir/cydir-save.c
src/lib-storage/index/dbox/dbox-file-maildir.c
src/lib-storage/index/dbox/dbox-file.h
src/lib-storage/index/dbox/dbox-mail.c
src/lib-storage/index/dbox/dbox-save.c
src/lib-storage/index/index-mail.c
src/lib-storage/index/index-mail.h
src/lib-storage/index/index-search.c
src/lib-storage/index/index-storage.c
src/lib-storage/index/index-storage.h
src/lib-storage/index/maildir/maildir-mail.c
src/lib-storage/index/maildir/maildir-save.c
src/lib-storage/index/mbox/mbox-save.c
src/lib-storage/mail-copy.c
src/lib-storage/mail-search-build.c
src/lib-storage/mail-search.h
src/lib-storage/mail-storage-private.h
src/lib-storage/mail-storage.c
src/lib-storage/mail-storage.h
src/lib-storage/mail.c

index c3975de39f8c2bf6e244deb5de325eaf991d2804..a1d204b35df5f3d78e6b491d4bc27ed8925ecac1 100644 (file)
@@ -22,7 +22,7 @@
 #define ENVELOPE_NIL_REPLY \
        "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)"
 
-#define IMAP_FETCH_HANDLER_COUNT 9
+#define IMAP_FETCH_HANDLER_COUNT 10
 extern const struct imap_fetch_handler
        imap_fetch_default_handlers[IMAP_FETCH_HANDLER_COUNT];
 static buffer_t *fetch_handlers = NULL;
@@ -779,6 +779,27 @@ fetch_uid_init(struct imap_fetch_context *ctx ATTR_UNUSED, const char *name,
        return TRUE;
 }
 
+static int fetch_guid(struct imap_fetch_context *ctx, struct mail *mail,
+                     void *context ATTR_UNUSED)
+{
+       const char *value;
+
+       if (mail_get_special(mail, MAIL_FETCH_GUID, &value) < 0)
+               return -1;
+
+       str_append(ctx->cur_str, "X-GUID ");
+       imap_quote_append_string(ctx->cur_str, value, FALSE);
+       return 1;
+}
+
+static bool
+fetch_guid_init(struct imap_fetch_context *ctx ATTR_UNUSED, const char *name,
+               const struct imap_arg **args ATTR_UNUSED)
+{
+       imap_fetch_add_handler(ctx, TRUE, FALSE, name, "", fetch_guid, NULL);
+       return TRUE;
+}
+
 static int fetch_x_mailbox(struct imap_fetch_context *ctx, struct mail *mail,
                           void *context ATTR_UNUSED)
 {
@@ -811,5 +832,6 @@ imap_fetch_default_handlers[IMAP_FETCH_HANDLER_COUNT] = {
        { "MODSEQ", fetch_modseq_init },
        { "RFC822", fetch_rfc822_init },
        { "UID", fetch_uid_init },
+       { "X-GUID", fetch_guid_init },
        { "X-MAILBOX", fetch_x_mailbox_init }
 };
index 7deec9f25dd69bc03bc0197b9f02b1d50cdfe10f..b74b9168b16ea5b36aef9ac2f8bd1d5ed680ee88 100644 (file)
@@ -216,6 +216,7 @@ int cydir_save_finish(struct mail_save_context *_ctx)
                                      _ctx->received_date, !ctx->failed);
        i_stream_unref(&ctx->input);
 
+       index_save_context_free(_ctx);
        return ctx->failed ? -1 : 0;
 }
 
index 5872e1bc499dec28cb156ba5de42b1481afb2d66..da64b507e206e69750a0bb8e2bdf4cc9a9f2c177 100644 (file)
@@ -40,13 +40,18 @@ const char *dbox_file_maildir_metadata_get(struct dbox_file *file,
 {
        struct stat st;
        uoff_t size;
-       const char *value = NULL;
+       const char *p, *value = NULL;
 
        switch (key) {
        case DBOX_METADATA_FLAGS:
        case DBOX_METADATA_KEYWORDS:
                value = dbox_file_maildir_get_flags(file, key);
                break;
+       case DBOX_METADATA_GUID:
+               p = strchr(file->fname, MAILDIR_INFO_SEP);
+               value = p == NULL ? file->fname :
+                       t_strdup_until(file->fname, p);
+               break;
        case DBOX_METADATA_RECEIVED_TIME:
        case DBOX_METADATA_SAVE_TIME:
                if (file->fd != -1) {
index 58ac4e7c0f6a2b5c7c5bce6f64d1dfa5d7e6165c..50afe1ed328ce5dc7748c099e235c36b566ac33a 100644 (file)
@@ -52,6 +52,9 @@ enum dbox_metadata_key {
        /* Message flags in dbox_metadata_flags order. '0' = not set, anything
           else = set. Unknown flags should be preserved. */
        DBOX_METADATA_FLAGS             = 'F',
+       /* Globally unique identifier for the message. Preserved when
+          copying. */
+       DBOX_METADATA_GUID              = 'G',
        /* Space separated list of keywords */
        DBOX_METADATA_KEYWORDS          = 'K',
        /* POP3 UIDL overriding the default format */
index 2fe27eb4953107493f8af6d6f3880d42462de1ba..7daa838316762a11ed2d9f1f8b8a40faeb2d5dac 100644 (file)
@@ -178,39 +178,52 @@ static int dbox_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
 }
 
 static int
-dbox_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
-                     const char **value_r)
+dbox_get_cached_metadata(struct dbox_mail *mail, enum dbox_metadata_key key,
+                        enum index_cache_field cache_field,
+                        const char **value_r)
 {
-       struct dbox_mail *mail = (struct dbox_mail *)_mail;
        struct index_mail *imail = &mail->imail;
-       const unsigned int pop3_uidl_cache_field =
-               imail->ibox->cache_fields[MAIL_CACHE_POP3_UIDL].idx;
+       const struct mail_cache_field *cache_fields = imail->ibox->cache_fields;
        struct dbox_file *file;
        const char *value;
        string_t *str;
 
-       switch (field) {
-       case MAIL_FETCH_UIDL_BACKEND:
-               /* keep the UIDL in cache file, otherwise POP3 would open all
-                  mail files and read the metadata */
-               str = str_new(imail->data_pool, 64);
-               if (mail_cache_lookup_field(imail->trans->cache_view, str,
-                                           _mail->seq,
-                                           pop3_uidl_cache_field) > 0) {
-                       *value_r = str_c(str);
-                       return 0;
-               }
+       str = str_new(imail->data_pool, 64);
+       if (mail_cache_lookup_field(imail->trans->cache_view, str,
+                                   imail->mail.mail.seq,
+                                   cache_fields[cache_field].idx) > 0) {
+               *value_r = str_c(str);
+               return 0;
+       }
 
-               if (dbox_mail_metadata_seek(mail, &file) < 0)
-                       return -1;
+       if (dbox_mail_metadata_seek(mail, &file) < 0)
+               return -1;
 
-               value = dbox_file_metadata_get(file, DBOX_METADATA_POP3_UIDL);
-               if (value == NULL)
-                       value = "";
-               index_mail_cache_add_idx(imail, pop3_uidl_cache_field,
-                                        value, strlen(value)+1);
-               *value_r = value;
-               return 0;
+       value = dbox_file_metadata_get(file, key);
+       if (value == NULL)
+               value = "";
+       index_mail_cache_add_idx(imail, cache_fields[cache_field].idx,
+                                value, strlen(value)+1);
+       *value_r = value;
+       return 0;
+}
+
+static int
+dbox_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
+                     const char **value_r)
+{
+       struct dbox_mail *mail = (struct dbox_mail *)_mail;
+
+       /* keep the UIDL in cache file, otherwise POP3 would open all
+          mail files and read the metadata. same for GUIDs if they're
+          used. */
+       switch (field) {
+       case MAIL_FETCH_UIDL_BACKEND:
+               return dbox_get_cached_metadata(mail, DBOX_METADATA_POP3_UIDL,
+                                               MAIL_CACHE_POP3_UIDL, value_r);
+       case MAIL_FETCH_GUID:
+               return dbox_get_cached_metadata(mail, DBOX_METADATA_GUID,
+                                               MAIL_CACHE_GUID, value_r);
        default:
                break;
        }
index b3e8c13b3ddbf9d8fe8ed09c2dcbb7d7a5ddd93e..d6d2ac77ea0808c5ba753425ec4d47cb9dbd5836 100644 (file)
@@ -178,6 +178,7 @@ static void dbox_save_write_metadata(struct dbox_save_context *ctx)
 {
        struct dbox_metadata_header metadata_hdr;
        char space[DBOX_EXTRA_SPACE];
+       const char *guid;
        string_t *str;
        uoff_t vsize;
 
@@ -197,6 +198,10 @@ static void dbox_save_write_metadata(struct dbox_save_context *ctx)
        str_printfa(str, "%c%llx\n", DBOX_METADATA_VIRTUAL_SIZE,
                    (unsigned long long)vsize);
 
+       guid = ctx->ctx.guid != NULL ? ctx->ctx.guid :
+               mail_generate_guid_string();
+       str_printfa(str, "%c%s\n", DBOX_METADATA_GUID, guid);
+
        /* flags */
        str_append_c(str, DBOX_METADATA_FLAGS);
        dbox_mail_metadata_flags_append(str, ctx->ctx.flags);
@@ -238,7 +243,7 @@ static int dbox_save_mail_write_header(struct dbox_save_mail *mail)
        return 0;
 }
 
-int dbox_save_finish(struct mail_save_context *_ctx)
+static int dbox_save_finish_write(struct mail_save_context *_ctx)
 {
        struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx;
        struct mail_storage *storage = &ctx->mbox->storage->storage;
@@ -290,6 +295,15 @@ int dbox_save_finish(struct mail_save_context *_ctx)
        }
 }
 
+int dbox_save_finish(struct mail_save_context *ctx)
+{
+       int ret;
+
+       ret = dbox_save_finish_write(ctx);
+       index_save_context_free(ctx);
+       return ret;
+}
+
 void dbox_save_cancel(struct mail_save_context *_ctx)
 {
        struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx;
index 25b572233bbf0b61dd2f5426971f922ce43c1ea3..022b3cdea25990d58b4fcf9a7919d28738159b6e 100644 (file)
@@ -33,6 +33,7 @@ struct mail_cache_field global_cache_fields[MAIL_INDEX_CACHE_FIELD_COUNT] = {
        { "imap.bodystructure", 0, MAIL_CACHE_FIELD_STRING, 0, 0 },
        { "imap.envelope", 0, MAIL_CACHE_FIELD_STRING, 0, 0 },
        { "pop3.uidl", 0, MAIL_CACHE_FIELD_STRING, 0, 0 },
+       { "guid", 0, MAIL_CACHE_FIELD_STRING, 0, 0 },
        { "mime.parts", 0, MAIL_CACHE_FIELD_VARIABLE_SIZE, 0, 0 }
 };
 
@@ -1013,6 +1014,7 @@ int index_mail_get_special(struct mail *_mail,
        case MAIL_FETCH_UIDL_FILE_NAME:
        case MAIL_FETCH_UIDL_BACKEND:
        case MAIL_FETCH_SEARCH_SCORE:
+       case MAIL_FETCH_GUID:
                *value_r = "";
                return 0;
        case MAIL_FETCH_HEADER_MD5:
index 014e3d10f9e7a571f0027072515b3ab832431f97..141782376bea31f00c9c2652dceae9d02533dc3a 100644 (file)
@@ -19,6 +19,7 @@ enum index_cache_field {
        MAIL_CACHE_IMAP_BODYSTRUCTURE,
        MAIL_CACHE_IMAP_ENVELOPE,
        MAIL_CACHE_POP3_UIDL,
+       MAIL_CACHE_GUID,
        MAIL_CACHE_MESSAGE_PARTS,
 
        MAIL_INDEX_CACHE_FIELD_COUNT
index 8953a8134f62d40c3e6d10f806cf76b6af95889a..41531b7a1bbeb77a9939f90e2b563866ca28a848 100644 (file)
@@ -267,6 +267,10 @@ static int search_arg_match_cached(struct index_search_context *ctx,
                else
                        return virtual_size > arg->value.size;
 
+       case SEARCH_GUID:
+               if (mail_get_special(ctx->mail, MAIL_FETCH_GUID, &str) < 0)
+                       return -1;
+               return strcmp(str, arg->value.str) == 0;
        case SEARCH_MAILBOX:
                if (mail_get_special(ctx->mail, MAIL_FETCH_MAILBOX_NAME,
                                     &str) < 0)
@@ -1131,6 +1135,7 @@ static bool search_arg_is_static(struct mail_search_arg *arg)
        case SEARCH_TEXT:
        case SEARCH_BODY_FAST:
        case SEARCH_TEXT_FAST:
+       case SEARCH_GUID:
        case SEARCH_MAILBOX:
                return TRUE;
        }
index 72f9aeeb6759829da5d16c3891032e7b19fcbd45..969d51bfca5f5dd48a80215ee22bef0bd86351c2 100644 (file)
@@ -621,3 +621,9 @@ void index_keywords_free(struct mail_keywords *keywords)
 {
        mail_index_keywords_free(&keywords);
 }
+
+void index_save_context_free(struct mail_save_context *ctx)
+{
+       i_free_and_null(ctx->from_envelope);
+       i_free_and_null(ctx->guid);
+}
index e7335efa8ce058c8521004b5377458b03839a809..3b7bc7938a584286e2ea209e7e2f8ffed62bf3c6 100644 (file)
@@ -189,6 +189,7 @@ int index_transaction_commit(struct mailbox_transaction_context *t,
                             uint32_t *first_saved_uid_r,
                             uint32_t *last_saved_uid_r);
 void index_transaction_rollback(struct mailbox_transaction_context *t);
+void index_save_context_free(struct mail_save_context *ctx);
 
 bool index_keyword_array_cmp(const ARRAY_TYPE(keyword_indexes) *k1,
                             const ARRAY_TYPE(keyword_indexes) *k2);
index 9eba59062d3eadd5e9908e915f76788c7c9c2b3c..996c084189231255800f4c5adc38fea3b849f3fe 100644 (file)
@@ -414,7 +414,9 @@ maildir_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
        struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
        const char *path, *fname, *end, *uidl;
 
-       if (field == MAIL_FETCH_UIDL_FILE_NAME) {
+       switch (field) {
+       case MAIL_FETCH_UIDL_FILE_NAME:
+       case MAIL_FETCH_GUID:
                if (_mail->uid != 0) {
                        if (!maildir_mail_get_fname(mbox, _mail, &fname))
                                return -1;
@@ -427,14 +429,14 @@ maildir_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
                end = strchr(fname, MAILDIR_INFO_SEP);
                *value_r = end == NULL ? fname : t_strdup_until(fname, end);
                return 0;
-       } else if (field == MAIL_FETCH_UIDL_BACKEND) {
+       case MAIL_FETCH_UIDL_BACKEND:
                uidl = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
                                        MAILDIR_UIDLIST_REC_EXT_POP3_UIDL);
                *value_r = uidl != NULL ? uidl : "";
                return 0;
+       default:
+               return index_mail_get_special(_mail, field, value_r);
        }
-
-       return index_mail_get_special(_mail, field, value_r);
 }
                                                        
 static int maildir_mail_get_stream(struct mail *_mail,
index 8f18a0971cd83af947360f7ca049e2a5dfb17b2d..00f829e73d24bd68ddbea8a7d7423f4f8f2bdd00 100644 (file)
@@ -543,6 +543,7 @@ int maildir_save_finish(struct mail_save_context *ctx)
        T_BEGIN {
                ret = maildir_save_finish_real(ctx);
        } T_END;
+       index_save_context_free(ctx);
        return ret;
 }
 
index 758883defa855fb8306b6ff557da2aece67d4563..3f55bd4a913ef80603f88025f0b1d9e6a12087f6 100644 (file)
@@ -662,7 +662,7 @@ int mbox_save_finish(struct mail_save_context *_ctx)
        if (ctx->output != NULL) {
                /* make sure everything is written */
                if (o_stream_flush(ctx->output) < 0)
-                       return write_error(ctx);
+                       write_error(ctx);
        }
 
        ctx->finished = TRUE;
@@ -690,6 +690,7 @@ int mbox_save_finish(struct mail_save_context *_ctx)
                ctx->mail_offset = (uoff_t)-1;
        }
 
+       index_save_context_free(_ctx);
        return ctx->failed ? -1 : 0;
 }
 
index ceb524ca7c3e6d508947b2032fbd09b15c3a2f42..5a3f55f0dd09bd3c03d36036375ada724007001a 100644 (file)
@@ -11,7 +11,7 @@ int mail_storage_copy(struct mailbox_transaction_context *t, struct mail *mail,
 {
        struct mail_save_context *ctx;
        struct istream *input;
-       const char *from_envelope;
+       const char *from_envelope, *guid;
        time_t received_date;
 
        if (mail_get_stream(mail, NULL, NULL, &input) < 0)
@@ -21,14 +21,16 @@ int mail_storage_copy(struct mailbox_transaction_context *t, struct mail *mail,
        if (mail_get_special(mail, MAIL_FETCH_FROM_ENVELOPE,
                             &from_envelope) < 0)
                return -1;
-
-       if (*from_envelope == '\0')
-               from_envelope = NULL;
+       if (mail_get_special(mail, MAIL_FETCH_GUID, &guid) < 0)
+               return -1;
 
        ctx = mailbox_save_alloc(t);
        mailbox_save_set_flags(ctx, flags, keywords);
        mailbox_save_set_received_date(ctx, received_date, 0);
-       mailbox_save_set_from_envelope(ctx, from_envelope);
+       if (*from_envelope != '\0')
+               mailbox_save_set_from_envelope(ctx, from_envelope);
+       if (*guid != '\0')
+               mailbox_save_set_guid(ctx, guid);
        mailbox_save_set_dest_mail(ctx, dest_mail);
 
        if (mailbox_save_begin(&ctx, input) < 0)
index 6c59b5320443e304e1a837169f2e583140c50c7d..204325b5984cda910b5c169a937d99c396609b6d 100644 (file)
@@ -599,6 +599,9 @@ static bool search_arg_build(struct search_build_data *data,
                                return ARG_NEW_SINGLE(SEARCH_ALL);
                        }
                        return ARG_NEW_STR(SEARCH_TEXT_FAST);
+               } else if (strcmp(str, "X-GUID") == 0) {
+                       /* <string> */
+                       return ARG_NEW_STR(SEARCH_GUID);
                } else if (strcmp(str, "X-MAILBOX") == 0) {
                        /* <string> */
                        return ARG_NEW_STR(SEARCH_MAILBOX);
index c0934b020d555778b7b88cfe859237586d8091d0..3c16ff6de14faf1f2dc2b57d18aa6f986eccadf3 100644 (file)
@@ -44,6 +44,7 @@ enum mail_search_arg_type {
        /* extensions */
        SEARCH_MODSEQ,
        SEARCH_INTHREAD,
+       SEARCH_GUID,
        SEARCH_MAILBOX
 };
 
index 22f8b858d901490bcdb2769d43b06c60ccb2c958..70f43ad26a4b09d696d19656611d3b5c5f9b7409 100644 (file)
@@ -323,7 +323,7 @@ struct mail_save_context {
        time_t received_date;
        int received_tz_offset;
 
-       char *from_envelope;
+       char *guid, *from_envelope;
 };
 
 struct mailbox_sync_context {
@@ -356,6 +356,7 @@ void mail_storage_set_critical(struct mail_storage *storage,
 void mail_storage_set_internal_error(struct mail_storage *storage);
 bool mail_storage_set_error_from_errno(struct mail_storage *storage);
 
+const char *mail_generate_guid_string(void);
 void mail_set_expunged(struct mail *mail);
 void mailbox_set_deleted(struct mailbox *box);
 
index 747d773756dd11a5748c756661920ed56944ea59..936ef6395dcb0f7de8df1d44c12dff729b7747d1 100644 (file)
@@ -816,6 +816,14 @@ void mailbox_save_set_from_envelope(struct mail_save_context *ctx,
        ctx->from_envelope = i_strdup(envelope);
 }
 
+void mailbox_save_set_guid(struct mail_save_context *ctx, const char *guid)
+{
+       i_assert(guid == NULL || *guid != '\0');
+
+       i_free(ctx->guid);
+       ctx->guid = i_strdup(guid);
+}
+
 void mailbox_save_set_dest_mail(struct mail_save_context *ctx,
                                struct mail *mail)
 {
@@ -852,7 +860,6 @@ int mailbox_save_finish(struct mail_save_context **_ctx)
        struct mail_save_context *ctx = *_ctx;
 
        *_ctx = NULL;
-       i_free(ctx->from_envelope);
        return ctx->transaction->box->v.save_finish(ctx);
 }
 
@@ -861,7 +868,6 @@ void mailbox_save_cancel(struct mail_save_context **_ctx)
        struct mail_save_context *ctx = *_ctx;
 
        *_ctx = NULL;
-       i_free(ctx->from_envelope);
        ctx->transaction->box->v.save_cancel(ctx);
 }
 
index 9e9933a419f9a98e77d7b9f54ee0fa19d1564e28..80dd30ef537638081cd68c63905fe63465276458 100644 (file)
@@ -128,7 +128,8 @@ enum mail_fetch_field {
        MAIL_FETCH_UIDL_FILE_NAME       = 0x00020000,
        MAIL_FETCH_UIDL_BACKEND         = 0x00040000,
        MAIL_FETCH_MAILBOX_NAME         = 0x00080000,
-       MAIL_FETCH_SEARCH_SCORE         = 0x00100000
+       MAIL_FETCH_SEARCH_SCORE         = 0x00100000,
+       MAIL_FETCH_GUID                 = 0x00200000
 };
 
 enum mailbox_transaction_flags {
@@ -466,6 +467,10 @@ void mailbox_save_set_received_date(struct mail_save_context *ctx,
    specify the address in From_-line. */
 void mailbox_save_set_from_envelope(struct mail_save_context *ctx,
                                    const char *envelope);
+/* Set globally unique ID for the saved mail. A new GUID is generated by
+   default. This function should usually be called only when copying an
+   existing mail (or restoring a mail from backup). */
+void mailbox_save_set_guid(struct mail_save_context *ctx, const char *guid);
 /* If dest_mail is set, the saved message can be accessed using it. Note that
    setting it may require mailbox syncing, so don't set it unless you need
    it. Also you shouldn't try to access it before mailbox_save_finish() is
index a88a626cc56e70d69f7fdb91853a892a464491a0..c6f9b80f244215476d0a6376ed0f4a985cda0c42 100644 (file)
@@ -2,8 +2,11 @@
 
 #include "lib.h"
 #include "ioloop.h"
+#include "hostpid.h"
 #include "mail-storage-private.h"
 
+#include <time.h>
+
 struct mail *mail_alloc(struct mailbox_transaction_context *t,
                        enum mail_fetch_field wanted_fields,
                        struct mailbox_header_lookup_ctx *wanted_headers)
@@ -200,3 +203,26 @@ void mail_set_cache_corrupted(struct mail *mail, enum mail_fetch_field field)
 
        p->v.set_cache_corrupted(mail, field);
 }
+
+const char *mail_generate_guid_string(void)
+{
+       static struct timespec ts = { 0, 0 };
+       static unsigned int pid = 0;
+
+       /* we'll use the current time in nanoseconds as the initial 64bit
+          counter. */
+       if (ts.tv_sec == 0) {
+               if (clock_gettime(CLOCK_REALTIME, &ts) < 0)
+                       i_fatal("clock_gettime() failed: %m");
+               pid = getpid();
+       } else if ((uint32_t)ts.tv_nsec < (uint32_t)-1) {
+               ts.tv_nsec++;
+       } else {
+               ts.tv_sec++;
+               ts.tv_nsec = 0;
+       }
+       return t_strdup_printf("%04x%04lx%04x%s",
+                              (unsigned int)ts.tv_nsec,
+                              (unsigned long)ts.tv_sec,
+                              pid, my_hostname);
+}