Back to index

courier  0.68.2
maildirkeywords2.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2003-2007 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #if    HAVE_CONFIG_H
00007 #include      "config.h"
00008 #endif
00009 #include      <stdio.h>
00010 #include      <stdlib.h>
00011 #include      <string.h>
00012 #include      <errno.h>
00013 #include      <ctype.h>
00014 
00015 #include      "maildir/config.h"
00016 #include      "maildir/maildircreate.h"
00017 #include      "maildir/maildirmisc.h"
00018 #include      "maildir/maildirwatch.h"
00019 #include      "numlib/numlib.h"
00020 
00021 #if    HAVE_UNISTD_H
00022 #include      <unistd.h>
00023 #endif
00024 #include      "maildirkeywords.h"
00025 #if HAVE_DIRENT_H
00026 #include <dirent.h>
00027 #define NAMLEN(dirent) strlen((dirent)->d_name)
00028 #else
00029 #define dirent direct
00030 #define NAMLEN(dirent) (dirent)->d_namlen
00031 #if HAVE_SYS_NDIR_H
00032 #include <sys/ndir.h>
00033 #endif
00034 #if HAVE_SYS_DIR_H
00035 #include <sys/dir.h>
00036 #endif
00037 #if HAVE_NDIR_H
00038 #include <ndir.h>
00039 #endif
00040 #endif
00041 
00042 
00043 int libmail_kwEnabled=1;
00044 
00045 struct keywordUpdateInfo {
00046        size_t highestN;
00047        size_t highestT;
00048        size_t totalCnt;
00049        int foundNewest;
00050 };
00051 
00052 static void scan_updates(const char *dir,
00053                       time_t t,
00054                       time_t tn,
00055                       struct maildir_kwReadInfo *info,
00056                       struct keywordUpdateInfo **updateInfo);
00057 
00058 static void read_updates(const char *dir,
00059                       struct maildir_kwReadInfo *info,
00060                       struct keywordUpdateInfo *updateInfo);
00061 
00062 static void purge_old_updates(const char *dir,
00063                            time_t tn,
00064                            struct maildir_kwReadInfo *info,
00065                            struct keywordUpdateInfo *updateInfo);
00066 
00067 static int save_updated_keywords(const char *maildir, const char *kwname,
00068                              struct maildir_kwReadInfo *info,
00069                              struct keywordUpdateInfo *updateInfo);
00070 
00071 static void doReadKeywords2(const char *maildir, const char *dir,
00072                          struct maildir_kwReadInfo *rki);
00073 
00074 
00075 struct readLine {
00076        char *lineBuf;
00077        size_t lineBufSize;
00078        int errflag;
00079 };
00080 
00081 static void rl_init(struct readLine *p)
00082 {
00083        p->lineBuf=NULL;
00084        p->lineBufSize=0;
00085        p->errflag=0;
00086 }
00087 
00088 static void rl_free(struct readLine *p)
00089 {
00090        if (p->lineBuf)
00091               free(p->lineBuf);
00092 }
00093 
00094 static char *rl_read(struct readLine *p, FILE *f)
00095 {
00096        size_t n=0;
00097        int ch;
00098 
00099        for (;;)
00100        {
00101               if (n >= p->lineBufSize)
00102               {
00103                      size_t o= n + 1024;
00104                      char *b= p->lineBuf ? realloc(p->lineBuf, o):malloc(o);
00105 
00106                      if (!b)
00107                      {
00108                             p->errflag=1;
00109                             return NULL;
00110                      }
00111 
00112                      p->lineBuf=b;
00113                      p->lineBufSize=o;
00114               }
00115 
00116               if ((ch=getc(f)) == EOF || ch == '\n')
00117                      break;
00118               p->lineBuf[n++]=(char)ch;
00119        }
00120 
00121        p->lineBuf[n]=0;
00122 
00123        return n == 0 && ch == EOF ? NULL:p->lineBuf;
00124 }
00125 
00126 int maildir_kwRead(const char *maildir,
00127                        struct maildir_kwReadInfo *rki)
00128 {
00129        char *p=malloc(strlen(maildir)+sizeof("/" KEYWORDDIR));
00130 
00131        if (!p)
00132               return -1;
00133 
00134        strcat(strcpy(p, maildir), "/" KEYWORDDIR);
00135 
00136        rki->errorOccured=0;
00137        doReadKeywords2(maildir, p, rki);
00138        free(p);
00139 
00140        return rki->errorOccured;
00141 }
00142 
00143 static void doReadKeywords2(const char *maildir, const char *dir,
00144                         struct maildir_kwReadInfo *rki)
00145 {
00146        FILE *fp;
00147        char *kwname=malloc(strlen(dir)+sizeof("/:list"));
00148        struct keywordUpdateInfo *updateInfo;
00149 
00150        time_t t=time(NULL);
00151        time_t tn=t/300;
00152 
00153        rki->updateNeeded=0;
00154        rki->tryagain=0;
00155 
00156        if (!kwname)
00157        {
00158               rki->errorOccured= -1;
00159               return;
00160        }
00161 
00162        strcat(strcpy(kwname, dir), "/:list");
00163 
00164        fp=fopen(kwname, "r");
00165 
00166        if (!fp) /* Maybe the keyword directory needs creating? */
00167        {
00168               struct stat stat_buf;
00169 
00170               mkdir(dir, 0700);
00171 
00172               /* Give it same mode as the maildir */
00173 
00174               if (stat(maildir, &stat_buf) == 0)
00175                      chmod(dir, stat_buf.st_mode & 0777);
00176        }
00177 
00178        /*
00179        ** If keywords are disabled, we still need to create the keyword
00180        ** directory, otherwise FAM-based IDLE will not work.
00181        */
00182 
00183        if (!libmail_kwEnabled)
00184        {
00185               if (fp)
00186                      fclose(fp);
00187               free(kwname);
00188               return;
00189        }
00190 
00191        if (fp && maildir_kwImport(fp, rki))
00192               rki->updateNeeded=1;
00193        if (fp)
00194               fclose(fp);
00195 
00196        updateInfo=malloc(sizeof(struct keywordUpdateInfo)
00197                        *( 1+(*rki->getMessageCount)(rki->voidarg)));
00198 
00199        if (!updateInfo)
00200        {
00201               free(kwname);
00202               return;
00203        }
00204 
00205        scan_updates(dir, t, tn, rki, &updateInfo);
00206        read_updates(dir, rki, updateInfo);
00207 
00208        if (!rki->tryagain && !rki->errorOccured)
00209        {
00210               if (save_updated_keywords(maildir, kwname, rki, updateInfo)
00211                   == 0 && !rki->errorOccured)
00212                      purge_old_updates(dir, tn, rki, updateInfo);
00213        }
00214 
00215        free(updateInfo);
00216        free(kwname);
00217 }
00218 
00219 int maildir_kwImport(FILE *fp, struct maildir_kwReadInfo *rki)
00220 {
00221        struct keywordIndex {
00222               struct keywordIndex *next;
00223               struct libmail_keywordEntry *kw;
00224        } *firstKw=NULL, *lastKw=NULL, **index;
00225        size_t numKw=0;
00226        struct libmail_kwMessage *tmpMsg;
00227        char *p;
00228        int rc=0;
00229 
00230        struct readLine rl;
00231 
00232        if ((tmpMsg=libmail_kwmCreate()) == NULL)
00233        {
00234               rki->errorOccured=-1;
00235               return 0;
00236        }
00237 
00238        rl_init(&rl);
00239 
00240        while ((p=rl_read(&rl, fp)) != NULL && *p)
00241        {
00242               struct keywordIndex *ki=malloc(sizeof(*firstKw));
00243 
00244               if (!ki)
00245               {
00246                      rki->errorOccured=-1;
00247                      rl_free(&rl);
00248                      libmail_kwmDestroy(tmpMsg);
00249                      return 0;
00250               }
00251 
00252               if (lastKw)
00253                      lastKw->next=ki;
00254               else
00255                      firstKw=ki;
00256 
00257               lastKw=ki;
00258               ki->next=NULL;
00259               ++numKw;
00260 
00261               ki->kw=libmail_kweFind((*rki->getKeywordHashtable)
00262                                    (rki->voidarg), p, 1);
00263               if (libmail_kwmSet(tmpMsg, ki->kw) < 0)
00264               {
00265                      rki->errorOccured= -1;
00266                      break;
00267               }
00268        }
00269 
00270        if (rki->errorOccured ||
00271            (index=malloc(sizeof(*firstKw)*(numKw+1))) == NULL)
00272        {
00273               while ((lastKw=firstKw) != NULL)
00274               {
00275                      firstKw=firstKw->next;
00276                      free(lastKw);
00277               }
00278               libmail_kwmDestroy(tmpMsg);
00279               rki->errorOccured= -1;
00280               rl_free(&rl);
00281               return 0;
00282        }
00283 
00284        numKw=0;
00285 
00286        while (firstKw)
00287        {
00288               index[numKw]=firstKw;
00289               ++numKw;
00290               firstKw=firstKw->next;
00291        }
00292        index[numKw]=0;
00293 
00294        if (p)
00295               while ((p=rl_read(&rl, fp)) != NULL)
00296               {
00297                      char *q=strchr(p, ':');
00298                      struct libmail_kwMessage **i;
00299                      size_t l;
00300                      size_t n;
00301 
00302                      if (!q)
00303                      {
00304                             rc=1;
00305                             continue; /* Crap */
00306                      }
00307 
00308                      *q++=0;
00309 
00310                      i= (*rki->findMessageByFilename)(p, 0, &n,
00311                                                   rki->voidarg);
00312 
00313                      if (!i)
00314                      {
00315                             rc=1;
00316                             continue; /* Stale data */
00317                      }
00318 
00319                      if (*i) /* Already have it */
00320                             libmail_kwmDestroy(*i);
00321                      (*i)=NULL;
00322 
00323                      i=NULL;
00324 
00325                      while ((q=strtok(q, " ")) != NULL)
00326                      {
00327                             l=atoi(q);
00328                             q=NULL;
00329 
00330                             if (l < numKw)
00331                             {
00332                                    if (!i)
00333                                           i= (*rki->
00334                                               findMessageByFilename)
00335                                                  (p, 1, &n,
00336                                                   rki->voidarg);
00337                                    /* Autocreate it */
00338 
00339                                    if (*i == NULL) /* ENOMEM */
00340                                    {
00341                                           rc= -1;
00342                                           break;
00343                                    }
00344 
00345                                    if (libmail_kwmSet(*i, index[l]->kw)
00346                                        < 0)
00347                                           rki->errorOccured= -1;
00348                             }
00349                      }
00350               }
00351 
00352        rl_free(&rl);
00353        for (numKw=0; index[numKw]; numKw++)
00354               free(index[numKw]);
00355 
00356        free(index);
00357        libmail_kwmDestroy(tmpMsg);
00358        return rc;
00359 }
00360 
00361 /* See the README */
00362 
00363 static void scan_updates(const char *dir,
00364                       time_t t,
00365                       time_t tn,
00366                       struct maildir_kwReadInfo *info,
00367                       struct keywordUpdateInfo **updateInfo)
00368 {
00369        DIR *dirp;
00370        struct dirent *de;
00371        unsigned long i;
00372 
00373        size_t n= (*info->getMessageCount)(info->voidarg);
00374 
00375        for (i=0; i<n; i++)
00376        {
00377               (*updateInfo)[i].highestN=0;
00378               (*updateInfo)[i].highestT=0;
00379               (*updateInfo)[i].totalCnt=0;
00380               (*updateInfo)[i].foundNewest=0;
00381        }
00382 
00383        dirp=opendir(dir);
00384        while (dirp && (de=readdir(dirp)) != NULL)
00385        {
00386               struct libmail_kwMessage **i;
00387               unsigned long x=0;
00388               char *p, *q;
00389               size_t in;
00390 
00391               if (de->d_name[0] == ':')
00392                      continue;
00393 
00394               if (de->d_name[0] != '.')
00395                      i=(*info->findMessageByFilename)
00396                             (de->d_name, 0, &in, info->voidarg);
00397 
00398               else if ((x=libmail_atotime_t(de->d_name+1)) == 0)
00399               {
00400                      if (strncmp(de->d_name, ".tmp.", 5) == 0)
00401                      {
00402                             if ((x=libmail_atotime_t(de->d_name+5)) != 0
00403                                 && x >= t - 120)
00404                                    continue; /* New scratch file */
00405 
00406 
00407                             p=malloc(strlen(dir)+strlen(de->d_name)+2);
00408 
00409                             if (!p)
00410                             {
00411                                    closedir(dirp);
00412                                    info->errorOccured= -1;
00413                                    return;
00414                             }
00415 
00416                             strcat(strcat(strcpy(p, dir), "/"),
00417                                    de->d_name);
00418                             unlink(p);
00419                             free(p);
00420                      }
00421                      continue;
00422               }
00423               else
00424               {
00425                      const char *p=strchr(de->d_name+1, '.');
00426 
00427                      if (!p)
00428                             continue;
00429 
00430                      i=(*info->findMessageByFilename)
00431                             (p+1, 0, &in, info->voidarg);
00432               }
00433 
00434               p=malloc(strlen(dir)+strlen(de->d_name)+2);
00435 
00436               if (!p)
00437               {
00438                      closedir(dirp);
00439                      info->errorOccured= -1;
00440                      return;
00441               }
00442 
00443               strcat(strcat(strcpy(p, dir), "/"), de->d_name);
00444 
00445               if (!i)
00446               {
00447                      struct stat stat_buf;
00448 
00449                      if (stat(p, &stat_buf) == 0 &&
00450                          stat_buf.st_mtime < t - 15 * 60)
00451                             unlink(p);
00452                      free(p);
00453                      continue;
00454               }
00455               free(p);
00456 
00457 
00458               if (in >= n)
00459               {
00460                      /* libmail_kwgReadMaildir autocrerate */
00461                      
00462                      struct keywordUpdateInfo *u=
00463                             realloc(*updateInfo,
00464                                    sizeof(**updateInfo) * (in+1));
00465 
00466                      if (!u)
00467                      {
00468                             closedir(dirp);
00469                             info->errorOccured= -1;
00470                             return;
00471                      }
00472 
00473                      *updateInfo=u;
00474 
00475                      while (n <= in)
00476                      {
00477 
00478                             (*updateInfo)[n].highestN=0;
00479                             (*updateInfo)[n].highestT=0;
00480                             (*updateInfo)[n].totalCnt=0;
00481                             (*updateInfo)[n].foundNewest=0;
00482                             ++n;
00483                      }
00484               }
00485 
00486 
00487               if (de->d_name[0] != '.')
00488               {
00489                      x=tn+1;
00490 
00491                      (*updateInfo)[in].foundNewest=1;
00492               }
00493 
00494               ++(*updateInfo)[in].totalCnt;
00495 
00496               if (x >= tn)
00497               {
00498                      if (x > (*updateInfo)[in].highestT)
00499                             (*updateInfo)[in].highestT=x;
00500               }
00501               else if ((*updateInfo)[in].highestN < x)
00502               {
00503                      if ((*updateInfo)[in].highestN > 0)
00504                      {
00505                             char b[NUMBUFSIZE];
00506                             char *r;
00507 
00508                             libmail_str_size_t((*updateInfo)[in].highestN, b);
00509 
00510                             r=de->d_name;
00511                             if (*r == '.')
00512                                    r=strchr(r+1, '.')+1;
00513 
00514                             q=malloc(strlen(dir)+strlen(r)+
00515                                     strlen(b)+4);
00516 
00517                             if (!q)
00518                             {
00519                                    closedir(dirp);
00520                                    info->errorOccured= -1;
00521                                    return;
00522                             }
00523 
00524                             sprintf(q, "%s/.%s.%s", dir, b, r);
00525                             unlink(q);
00526                             free(q);
00527                      }
00528 
00529                      (*updateInfo)[in].highestN=x;
00530               }
00531        }
00532 
00533        if (dirp)
00534               closedir(dirp);
00535 }
00536 
00537 static void read_updates(const char *dir,
00538                       struct maildir_kwReadInfo *info,
00539                       struct keywordUpdateInfo *updateInfo)
00540 {
00541        unsigned long i;
00542        size_t msgCnt= (*info->getMessageCount)(info->voidarg);
00543        struct readLine rl;
00544 
00545        struct libmail_kwHashtable *h=
00546               (*info->getKeywordHashtable)(info->voidarg);
00547 
00548        rl_init(&rl);
00549        for (i=0; i<msgCnt; i++)
00550        {
00551               size_t n=updateInfo[i].highestN;
00552               char *p, *q;
00553               char b[NUMBUFSIZE];
00554               FILE *fp;
00555               struct libmail_kwMessage *km, **oldKm;
00556               const char *fn;
00557 
00558               if (n < updateInfo[i].highestT)
00559                      n=updateInfo[i].highestT;
00560 
00561               if (n == 0)
00562                      continue;
00563 
00564               libmail_str_size_t(n, b);
00565 
00566               fn= (*info->getMessageFilename)(i, info->voidarg);
00567 
00568               if (!fn)
00569                      continue; /* Shouldn't happen */
00570 
00571               p=malloc(strlen(dir)+strlen(b)+strlen(fn)+4);
00572 
00573               if (!p)
00574               {
00575                      info->errorOccured= -1;
00576                      rl_free(&rl);
00577                      return;
00578               }
00579 
00580               if (updateInfo[i].foundNewest)
00581                      sprintf(p, "%s/%s", dir, fn);
00582               else
00583                      sprintf(p, "%s/.%s.%s", dir, b, fn);
00584 
00585 
00586               q=strrchr(strrchr(p, '/'), MDIRSEP[0]);
00587               if (q)
00588                      *q=0;
00589 
00590               fp=fopen(p, "r");
00591               free(p);
00592 
00593               if (!fp)
00594               {
00595                      if (errno == ENOENT)
00596                      {
00597                             info->tryagain=1;
00598                             rl_free(&rl);
00599                             return;
00600                      }
00601 
00602                      continue;
00603               }
00604 
00605               if ((km=libmail_kwmCreate()) == NULL)
00606               {
00607                      fclose(fp);
00608                      info->errorOccured= -1;
00609                      rl_free(&rl);
00610                      return;
00611               }
00612 
00613               while ((p=rl_read(&rl, fp)) != NULL && *p)
00614                      if (libmail_kwmSetName(h, km, p) < 0)
00615                      {
00616                             fclose(fp);
00617                             info->errorOccured= -1;
00618                             rl_free(&rl);
00619                             return;
00620                      }
00621 
00622               if (km->firstEntry == NULL)
00623               {
00624                      oldKm= (*info->findMessageByIndex)(i,
00625                                                     0, info->voidarg);
00626                      if (oldKm && *oldKm)
00627                      {
00628                             info->updateNeeded=1;
00629                             libmail_kwmDestroy(*oldKm);
00630                             *oldKm=NULL;
00631                      }
00632                      libmail_kwmDestroy(km);
00633               }
00634               else
00635               {
00636                      oldKm= (*info->findMessageByIndex)(i, 1,
00637                                                     info->voidarg);
00638 
00639                      if (oldKm && *oldKm == NULL)
00640                      {
00641                             info->updateNeeded=1;
00642                             (*info->updateKeywords)(i, km, info->voidarg);
00643                      }
00644                      else if (!oldKm /* Shouldn't happen */
00645                          || libmail_kwmCmp(*oldKm, km) == 0)
00646                      {
00647                             libmail_kwmDestroy(km);
00648                      }
00649                      else
00650                      {
00651                             info->updateNeeded=1;
00652                             (*info->updateKeywords)(i, km, info->voidarg);
00653                      }
00654               }
00655 
00656               fclose(fp);
00657        }
00658        rl_free(&rl);
00659 }
00660 
00661 struct saveUpdateInfo {
00662        FILE *fp;
00663        unsigned long counter;
00664 };
00665 
00666 static int saveKeywordList(struct libmail_keywordEntry *ke,
00667                         void *vp)
00668 {
00669        struct saveUpdateInfo *sui=(struct saveUpdateInfo *)vp;
00670 
00671        fprintf(sui->fp, "%s\n", keywordName(ke));
00672 
00673        ke->u.userNum= sui->counter;
00674 
00675        ++sui->counter;
00676        return 0;
00677 }
00678 
00679 int maildir_kwExport(FILE *fp, struct maildir_kwReadInfo *info)
00680 {
00681        struct saveUpdateInfo sui;
00682        size_t i, n;
00683 
00684        sui.fp=fp;
00685        sui.counter=0;
00686        libmail_kwEnumerate((*info->getKeywordHashtable)(info->voidarg),
00687                       saveKeywordList, &sui);
00688 
00689        if (sui.counter == 0) /* No keywords set for any message */
00690               return 0;
00691 
00692        fprintf(fp, "\n");
00693 
00694        n= (*info->getMessageCount)(info->voidarg);
00695 
00696        for (i=0; i<n; i++)
00697        {
00698               const char *p;
00699 
00700               struct libmail_kwMessage **km=
00701                      (*info->findMessageByIndex)(i, 0, info->voidarg);
00702               struct libmail_kwMessageEntry *kme;
00703 
00704               if (!km || !*km || (*km)->firstEntry == NULL)
00705                      continue;
00706 
00707               for (p= (*info->getMessageFilename)(i, info->voidarg);
00708                    *p && *p != MDIRSEP[0]; p++)
00709                      putc(*p, fp);
00710 
00711               putc(':', fp);
00712               p="";
00713 
00714               for (kme=(*km)->firstEntry; kme; kme=kme->next)
00715               {
00716                      fprintf(fp, "%s%lu", p, kme->libmail_keywordEntryPtr
00717                             ->u.userNum);
00718                      p=" ";
00719               }
00720               fprintf(fp, "\n");
00721        }
00722 
00723        return 1;
00724 }
00725 
00726 static int save_updated_keywords(const char *maildir, const char *kwname,
00727                              struct maildir_kwReadInfo *info,
00728                              struct keywordUpdateInfo *updateInfo)
00729 {
00730        struct maildir_tmpcreate_info createInfo;
00731        FILE *fp;
00732 
00733        if (!info->updateNeeded)
00734               return 0;
00735 
00736        maildir_tmpcreate_init(&createInfo);
00737 
00738        createInfo.maildir=maildir;
00739        createInfo.hostname=getenv("HOSTNAME");
00740        createInfo.doordie=1;
00741 
00742        if ((fp=maildir_tmpcreate_fp(&createInfo)) == NULL)
00743        {
00744               perror("maildir_tmpcreate_fp");
00745               return -1;
00746        }
00747 
00748        if (maildir_kwExport(fp, info) == 0)
00749        {
00750               fclose(fp);
00751               unlink(createInfo.tmpname);
00752               maildir_tmpcreate_free(&createInfo);
00753               unlink(kwname);
00754               return 0;
00755        }
00756        if (fflush(fp) < 0 || ferror(fp))
00757        {
00758               fclose(fp);
00759               unlink(createInfo.tmpname);
00760               perror(createInfo.tmpname);
00761               maildir_tmpcreate_free(&createInfo);
00762               return -1;
00763        }
00764        fclose(fp);
00765 
00766        if (rename(createInfo.tmpname, kwname))
00767        {
00768               perror(createInfo.tmpname);
00769               unlink(createInfo.tmpname);
00770               perror(createInfo.tmpname);
00771               maildir_tmpcreate_free(&createInfo);
00772               return -1;
00773        }
00774        maildir_tmpcreate_free(&createInfo);
00775        return 0;
00776 }
00777 
00778 static void purge_old_updates(const char *dir,
00779                            time_t tn,
00780                            struct maildir_kwReadInfo *info,
00781                            struct keywordUpdateInfo *updateInfo)
00782 {
00783        size_t i;
00784 
00785        time_t x;
00786 
00787        size_t n= (*info->getMessageCount)(info->voidarg);
00788 
00789        for (i=0; i<n; i++)
00790        {
00791               char *p, *q, *c;
00792               char b[NUMBUFSIZE];
00793 
00794               const char *fn= (*info->getMessageFilename)(i, info->voidarg);
00795 
00796               if (!fn)
00797                      continue; /* Shouldn't happen */
00798 
00799               if (updateInfo[i].foundNewest)
00800               {
00801                      size_t l;
00802 
00803                      x=tn+1;
00804 
00805                      libmail_str_size_t(x, b);
00806 
00807                      l=strlen(dir)+strlen(b)+strlen(fn)+4;
00808 
00809                      p=malloc(l);
00810                      if (!p)
00811                      {
00812                             info->errorOccured= -1;
00813                             return;
00814                      }
00815 
00816                      q=malloc(l);
00817                      if (!q)
00818                      {
00819                             free(p);
00820                             info->errorOccured= -1;
00821                             return;
00822                      }
00823 
00824                      sprintf(p, "%s/%s", dir, fn);
00825 
00826                      sprintf(q, "%s/.%s.%s", dir, b, fn);
00827 
00828 
00829                      c=strrchr(strrchr(p, '/'), MDIRSEP[0]);
00830 
00831                      if (c) *c=0;
00832                      c=strrchr(strrchr(q, '/'), MDIRSEP[0]);
00833 
00834                      if (c) *c=0;
00835 
00836                      rename(p, q);
00837                      free(q);
00838                      free(p);
00839                      continue;
00840               }
00841 
00842               if (! (updateInfo[i].totalCnt == 1 &&
00843                      updateInfo[i].highestN))
00844                      continue;
00845 
00846               libmail_str_size_t(updateInfo[i].highestN, b);
00847 
00848               p=malloc(strlen(dir)+strlen(b)+strlen(fn)+4);
00849 
00850               if (!p)
00851               {
00852                      info->errorOccured= -1;
00853                      return;
00854               }
00855 
00856               sprintf(p, "%s/.%s.%s", dir, b, fn);
00857 
00858               q=strrchr(strrchr(p, '/'), MDIRSEP[0]);
00859               if (q) *q=0;
00860               unlink(p);
00861               free(p);
00862        }
00863 }
00864 
00865 
00866 /***************/
00867 
00868 static int maildir_kwSaveCommon(const char *maildir,
00869                             const char *filename,
00870                             struct libmail_kwMessage *newKeyword,
00871                             const char **newKeywordArray,
00872                             char **tmpname,
00873                             char **newname,
00874                             int tryAtomic);
00875 
00876 int maildir_kwSave(const char *maildir,
00877                  const char *filename,
00878                  struct libmail_kwMessage *newKeyword,
00879                  char **tmpname,
00880                  char **newname,
00881                  int tryAtomic)
00882 {
00883        return maildir_kwSaveCommon(maildir, filename, newKeyword, NULL,
00884                                 tmpname, newname, tryAtomic);
00885 }
00886 
00887 int maildir_kwSaveArray(const char *maildir,
00888                      const char *filename,
00889                      const char **flags,
00890                      char **tmpname,
00891                      char **newname,
00892                      int tryAtomic)
00893 {
00894        return maildir_kwSaveCommon(maildir, filename, NULL, flags,
00895                                 tmpname, newname, tryAtomic);
00896 }
00897 
00898 static int maildir_kwSaveCommon(const char *maildir,
00899                             const char *filename,
00900                             struct libmail_kwMessage *newKeyword,
00901                             const char **newKeywordArray,
00902                             char **tmpname,
00903                             char **newname,
00904                             int tryAtomic)
00905 {
00906        struct maildir_tmpcreate_info createInfo;
00907        FILE *fp;
00908        char *n=malloc(strlen(maildir)+strlen(filename)+10+
00909                      sizeof(KEYWORDDIR)), *p;
00910        struct libmail_kwMessageEntry *kme;
00911 
00912        if (!n)
00913               return -1;
00914 
00915        strcat(strcat(strcpy(n, maildir),
00916                     "/" KEYWORDDIR "/"), filename);
00917 
00918        p=strrchr(strrchr(n, '/'), MDIRSEP[0]);
00919        if (p)
00920               *p=0;
00921 
00922        
00923        maildir_tmpcreate_init(&createInfo);
00924 
00925        createInfo.maildir=maildir;
00926        createInfo.msgsize=0;
00927        createInfo.hostname=getenv("HOSTNAME");
00928        createInfo.doordie=1;
00929 
00930        if ((fp=maildir_tmpcreate_fp(&createInfo)) == NULL)
00931        {
00932               free(n);
00933               return -1;
00934        }
00935 
00936        if (newKeywordArray)
00937        {
00938               size_t i;
00939 
00940               for (i=0; newKeywordArray[i]; i++)
00941                      fprintf(fp, "%s\n", newKeywordArray[i]);
00942        }
00943        else for (kme=newKeyword ? newKeyword->firstEntry:NULL;
00944                 kme; kme=kme->next)
00945               fprintf(fp, "%s\n", keywordName(kme->libmail_keywordEntryPtr));
00946 
00947        errno=EIO;
00948 
00949        if (fflush(fp) < 0 || ferror(fp))
00950        {
00951               fclose(fp);
00952               free(n);
00953               return -1;
00954        }
00955 
00956        fclose(fp);
00957 
00958        *tmpname=createInfo.tmpname;
00959        createInfo.tmpname=NULL;
00960        *newname=n;
00961        maildir_tmpcreate_free(&createInfo);
00962 
00963        if (tryAtomic)
00964        {
00965               char timeBuf[NUMBUFSIZE];
00966 
00967               char *n=malloc(strlen(*tmpname)
00968                             + sizeof(KEYWORDDIR) + NUMBUFSIZE+10);
00969 
00970               if (!n)
00971               {
00972                      free(*tmpname);
00973                      free(*newname);
00974                      return -1;
00975               }
00976 
00977               strcat(strcat(strcat(strcpy(n, maildir),
00978                                  "/" KEYWORDDIR "/.tmp."),
00979                            libmail_str_time_t(time(NULL), timeBuf)),
00980                      strrchr( *tmpname, '/')+1);
00981 
00982 
00983               if (rename( *tmpname, n) < 0)
00984               {
00985                      free(n);
00986                      free(*tmpname);
00987                      free(*newname);
00988                      return -1;
00989               }
00990 
00991               free (*tmpname);
00992               *tmpname=n;
00993        }
00994        return 0;
00995 }