/* -*-C-*-
*******************************************************************************
*
* File:         MailReader.m
* RCS:          /usr/local/sources/CVS/EnhanceMail/MailReader.m,v 1.21 1998/06/30 20:18:49 tom Exp
* Description:  
* Author:       Carl Edman
* Created:      Fri Oct 13 11:48:05 1995
* Modified:     Sat Apr 13 19:09:44 1996 (Carl Edman) cedman@capitalist.princeton.edu
* Language:     C
* Package:      N/A
* Status:       Experimental (Do Not Distribute)
*
* (C) Copyright 1995, but otherwise this file is perfect freeware.
*
*******************************************************************************
*/

#import "EnhanceMail.h"
#import "MailReader.h"
#import "MailBox.h"
#import "XFace.h"
#import "XImageURL.h"
#import "XImageAliases.h"
#import "Preferences.h"
#import "TransferPanel.h"

#define MENU_MESSAGE_FLAG NXLocalizedStringFromTableInBundle("Localizable", EnhanceBundle, "Message/Flag", NULL, Slashed menu path to flag command)
#define MENU_MESSAGE_STRIP NXLocalizedStringFromTableInBundle("Localizable", EnhanceBundle, "Message/Strip", NULL, Slashed menu path to strip command)
#define MENU_MAILBOX_INDEX NXLocalizedStringFromTableInBundle("Localizable", EnhanceBundle, "Mailbox/Index", NULL, Slashed menu path to create index command)
#define MENU_MAILBOX_UNINDEX NXLocalizedStringFromTableInBundle("Localizable", EnhanceBundle, "Mailbox/Delete index", NULL, Slashed menu path to remove index command)
#define STATUS_INDEXED NXLocalizedStringFromTableInBundle("Localizable", EnhanceBundle, "indexed", NULL, in MailReader status field)

/* This is to avoid genstrings from breaking. */
#define LOCALIZE(TABLE,BUNDLE,KEY,VALUE) NXLoadLocalized\
StringFromTableInBundle(TABLE,BUNDLE,KEY,VALUE)

static id index_menucell=nil;
static id indextag_image=nil;

@implementation EnhanceMailReader

+ finishLoading:(struct mach_header *)header
{
   char path[MAXPATHLEN+1];
   
   EnhanceBundleInit();
   [self poseAs:[self superclass]];
   [[NXApp mainMenu] addSlashItem:MENU_MESSAGE_FLAG action:@selector(toggleFlagged:) keyEquivalent:0];
#if 0
   [[NXApp mainMenu] addSlashItem:MENU_MESSAGE_STRIP action:@selector(strip:) keyEquivalent:0];
#endif
   index_menucell=[[NXApp mainMenu] addSlashItem:MENU_MAILBOX_INDEX action:@selector(toggleIndexing:) keyEquivalent:0];

   if ([EnhanceBundle getPath:path forResource:"indexTag" ofType:"tiff"])
      indextag_image=[[NXImage alloc] initFromFile:path];
   
   return self;
}

- loadMessage:(int)fp16 newMsg:(BOOL)fp20 withAllHeaders:(BOOL)fp24
{
   const char *header;
   id ret;
   Window *w = [self window];

   [w disableFlushWindow];

   ret = [super loadMessage:fp16 newMsg:fp20 withAllHeaders:fp24];

   if (EnhanceShowXImageURL)
   {
      const char *url = [mailMessage headerValueForKey:"X-Image-URL"];
      char *address = NULL;
      int len;

      if ((header = [mailMessage headerValueForKey:"From"]) ||
	  (header = [mailMessage headerValueForKey:"Reply-To"]))
      {
	 if (EnhanceGetAddress(header, &header, &len))
	 {
	    address = alloca(len+1);
	    strncpy(address, header, len);
	    address[len] = '\0';
	 }
      }
      [command setXImageURL:url address:address];
   }
   if (EnhanceShowXFace
       && (header=[mailMessage headerValueForKey:"X-Face"]))
   {
      [command setXFace:header];
   }
   [w reenableFlushWindow];
   [w flushWindowIfNeeded];

   return ret;
}

- (void)loadMessage:(MailMessage *)message into:fp20
{
   /* This fixes the annoying habit of Mail.app to display ASCII messages sent
      by NeXT Mail.app in a proportional font, even if "Use Fixed Pitch Font
      For Plain Text" is selected (subject to an EM preference, of course;
      some people may actually like the old behaviour). */
   if (EnhanceUseFixedPitchFontForPlainMessages)
   {
      if ([[Defaults new] autoSelectFont] && ![message isRichBody])
      {
	 [self loadMessage:message into:fp20 headerFont:msgFont
	       bodyFont:fixedFont allHeaders:[self displayAllHeaders]];
	 return;
      }
   }
   [super loadMessage:message into:fp20];
}


- (void)updateTransferPanel:(int)oldMessageCount
{
   //printf("oldMessageCount:%d\n", oldMessageCount);
   //printf("newMessageCount:%d\n", newMessageCount);
   if (newMessageCount != oldMessageCount)
   {
      //printf("updating Transferpanel for %s\n",[mailbox dirname]);
      [[TransferPanel new] updateMessageCount:newMessageCount old:oldMessageCount
       forMailBoxNamed:[mailbox dirname] isNew:NO];
   }
}

- free
{
   /* XXX For now, don't autocompact indexed mailboxes. */
   if (EnhanceAutoCompact && mailbox && ![mailbox hasStore])
   {
      struct u_mailboxstatus stat;
      [mailbox getMailboxStatus:&stat];
      if (stat.delmsgno>0) [self compact:self];
   }
   return [super free];
}

- compact:sender
{
   if (mailbox && [mailbox hasStore])
   {
      id ret;
      [self toggleIndexing:sender];
      ret=[super compact:sender];
      [self toggleIndexing:sender];
      return ret;
   }
   return [super compact:sender];
}

- strip:sender
{
#if 0
   id list=[matrix getSelectedCells:nil];
   id cell;
   int i;

   for(i=0;i<[list count];i++)
   {
      cell=[list objectAt:i];
      if (cell==nil) continue;
      /* XXX Strip every message of all NeXT/MIME/uuencoded attachments XXX */
   }
   
   list=[list free];
#endif
   return self;
}

- (void)_newMailMsg
{
   if (!EnhanceSilentNewMail &&
       strcmp([mailbox dirname], [[Defaults new] activeMailbox]) != 0)
   {
      [NXApp newMailMsg];
   }
}

- incorporateMail:sender
{
   int oldMessageCount = newMessageCount;
   id ret = [super incorporateMail:sender];

   if (newMessageCount > oldMessageCount)
   {
      [[TransferPanel new] setNewMailFlagForMailBoxNamed:[mailbox dirname]];
      [self _newMailMsg];
   }
   return ret;
}

- newMail:sender
{
   if ([[TransferPanel new] checkNewMailForReader:self])
   {
      /* Don't invoke super if successful, because it tends to beep. */
      return self;
   }
   return [super newMail:sender];
}

- (void)setFlagged:(BOOL)flag
{
   id cell=[matrix selectedCell];
   if (cell==nil) return;
#if 0
   [cell setFlagged:YES];
   if (mailbox==nil) return;
   [mailbox setState:'+' forMsg:[cell msgId] flush:NO];
   [self display];
#endif
   if ([cell isFlagged] == !flag)
   {
      [self toggleFlagged:self];
   }
   return;
}

- toggleFlagged:sender
{
   id ret = [super toggleFlagged:sender];
   id cell = [matrix selectedCell];

   if (cell)
   {
      [[TransferPanel new] updateFlaggedCountBy:([cell isFlagged] ? +1 : -1)
       forMailBoxNamed:[mailbox dirname]];
   }
   return ret;
}

- toggleIndexing:sender
{
   if (mailbox==nil) return nil;
   if ([mailbox hasStore])
      [mailbox deleteStore];
   else
      [mailbox createStore];

   [self display];
   [self windowDidBecomeMain:self];
   [self updateStatus];
   return self;
}

- windowDidBecomeMain:sender
{
   const char *c;

   if ((mailbox==nil)||(index_menucell==nil)) return self;
   
   c=[mailbox hasStore] ? MENU_MAILBOX_UNINDEX : MENU_MAILBOX_INDEX;
   if (c=rindex(c,'/')) [index_menucell setTitle:(c+1)];
   return self;
}

static const char *formatSize(char *buf, unsigned long size)
{
   /* Take size format from Mail.app's UI.strings. */
   const unsigned long MB_CUTOFF = (750*1024);
   const unsigned long KB_CUTOFF = (750);
   const char *format = LOCALIZE("UI", nil, ((size > MB_CUTOFF) ? "%.1fMB" :
					     (size > KB_CUTOFF) ? "%dKB" : "%d bytes"), NULL);

   if (size > MB_CUTOFF)
   {
      sprintf(buf, format, (float)size / (1024*1024));
   }
   else
   {
      sprintf(buf, format, (size > KB_CUTOFF) ? (size + 1024/2-1)/1024 : size); 
   }
   return buf;
}

- (void)updateStatus
{
   int indexSize = 0;
   int oldMessageCount = newMessageCount;
   Window *w = [statusField window];

   [w disableFlushWindow];

   [super updateStatus];
   [self updateTransferPanel:oldMessageCount];

   if (statusField && mailbox &&
       ((indexSize = [mailbox storeSize]) >= 0 || newMessageCount > 0))
   {
      char buf[MAXPATHLEN+1], sizeBuf[20];
      BOOL showSizes = [[self matrix] showSizes];

      strcpy(buf, [statusField stringValue]);

      if (newMessageCount > 0)
      {
	 /* Take `unread' from Mail.app's UI.strings. */
	 const char *unread = LOCALIZE("UI", nil, (newMessageCount==1) ?
				       "new_message" : "new_messages", "unread");

	 sprintf(buf+strlen(buf), " \320 %d %s", newMessageCount, unread);
	 if (showSizes)
	 {
	    struct u_mailboxstatus st;

	    [mailbox getMailboxStatus:&st];
	    sprintf(buf+strlen(buf), " (%s)", formatSize(sizeBuf, st.unreadmsgsize));
	 }
      }
      if (indexSize >= 0 && showSizes)
      {
	 /* Not much sense to add "indexed" without size, since we already
	    display an index icon if mailbox is indexed. */
	 sprintf(buf+strlen(buf), " \320 %s (%s)", STATUS_INDEXED, formatSize(sizeBuf, indexSize));
      }
      [statusField setStringValue:buf];
   }

   [w reenableFlushWindow];
   [w flushWindowIfNeeded];
}

- drawSelf:(const NXRect *)rects :(int)rectCount
{
   id ret=[super drawSelf:rects:rectCount];

   if ((mailbox==nil)||(indextag_image==nil)) return nil;

   if ([mailbox hasStore])
   {
      NXPoint p;
      NXSize s;

      [indextag_image getSize:&s];
      p.x=0; p.y=s.height;
      [indextag_image composite:NX_SOVER toPoint:&p];
   }
   return ret;
}

#if 0 // Experimental cruft.
// flagged messages loose their flag when transferred
- showTransferMsg:(int)fp16 to:(const char *)fp20;
{
   //printf("showTransferMsg:%d,%s\n",fp16,fp20);
   return [super showTransferMsg:fp16 to:fp20];
}
- transfer:fp16;
{
   //printf("transfer:%p class=%s\n",fp16,[[fp16 class] name]);
   return [super transfer:fp16];
}
- showTransfer:fp16;
{
   //printf("showTransfer:%p\n",fp16);
   return [super showTransfer:fp16];
}
#endif

@end // EnhanceMailReader


@implementation CommandView(EnhanceMailReaderFace)

- setXFace:(const char *)xface
{
   NXSize size;
   
   if (face) return self;
   size.width=size.height=64;
   face=[[NXImage alloc] initXFace:xface size:&size];
   [self display];
   return self;
}

- setXImageURL:(const char *)ximageurl address:(const char *)address
{
   if (!face)
   {
      EnhanceXImageAliases *aliases = [EnhanceXImageAliases aliases];
      const char *imageFile;

      if (ximageurl)
      {
	 if ((imageFile = [aliases fileForURL:ximageurl]))
	 {
	    face = [[NXImage alloc] initFromFile:imageFile];
	 }
	 else
	 {
	    face = [[NXImage alloc] initURL:ximageurl];

	    if (!face) face = [NXImage findImageNamed:"user"];

	    [aliases recordURL:ximageurl forAddress:address];
	 }
      }
      else if (address)
      {
	 if ((imageFile = [aliases fileForAddress:address]))
	 {
	    face = [[NXImage alloc] initFromFile:imageFile];
	 }
      }
      if (face) [self display];
   }
   return self;
}

@end // CommandView (EnhanceMailReader)
