The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

MODULE = MIME::Fast		PACKAGE = MIME::Fast::Hash::Header		PREFIX=hash_

MIME::Fast::Hash::Header
hash_TIEHASH(Class, objptr)
        char *			Class
        MIME::Fast::Message		objptr
    PREINIT:
        hash_header *		hash;
    CODE:
        hash = g_malloc(sizeof(hash_header));
        hash->keyindex = 0;
        hash->objptr = objptr;
	hash->fetchvalue = NULL;
        if (gmime_debug)
        warn("function hash_TIEHASH(%s, 0x%x) returns 0x%x\n", Class, objptr, hash);
        RETVAL = hash;
    OUTPUT:
        RETVAL

void
hash_DESTROY(obj)
        MIME::Fast::Hash::Header	obj
    CODE:
        if (gmime_debug)
        warn("function hash_DESTROY(0x%x)\n", obj);
        obj->objptr = NULL;
        g_free(obj);

void
hash_FETCH(obj, key)
        MIME::Fast::Hash::Header	obj
        const char *		key
    PREINIT:
        MIME__Fast__Message		msg;
        GList			*gret = NULL, *item;
        AV *			retav;
        I32			gimme = GIMME_V;
    PPCODE:
        msg = obj->objptr;

        /* THE HACK - FETCH method would get value indirectly from NEXTKEY */
        if (obj->keyindex != -1 && obj->fetchvalue != NULL) {
          XPUSHs(sv_2mortal(newSVpv(obj->fetchvalue,0)));
          obj->fetchvalue == NULL;
          XSRETURN(1);
        }

        obj->fetchvalue = NULL;
        
        gret = message_get_header(msg, key);
        if (gmime_debug)
          warn("hash_FETCH(0x%x, '%s', items=%d)", obj, key ? key : "NULL", items);

        if (!gret || gret->data == NULL) {
          if (gmime_debug)
            warn("fetch returns undef\n");
          
          if (gret)
            g_list_free(gret);
          
          XSRETURN(0);
        } else {
          if (gret->next == NULL) { // one value
            XPUSHs(sv_2mortal(newSVpv((char *)(gret->data),0)));
          } else {
            if (gimme == G_ARRAY) {
              item = gret;
              while (item && item->data) {
                XPUSHs(sv_2mortal(newSVpv((char *)(item->data),0)));
                item = item->next;
              }
            } else if (gimme == G_SCALAR) {
              retav = newAV();
              item = gret;
              while (item && item->data) {
                av_push(retav, newSVpv((char *)g_strdup((item->data)), 0));
                item = item->next;
              }
              XPUSHs(newRV_noinc((SV *)retav));
            }
          }
        }
        if (gret) {
          item = gret;
          while (item) {
            if (item->data)
              g_free((char *)(item->data));
            item = item->next;
          }
          g_list_free(gret);
        }

void
hash_STORE(obj, key, svmixed)
        MIME::Fast::Hash::Header	obj
        const char *		key
        SV *			svmixed
    PREINIT:
        MIME__Fast__Message		msg;
        char *			value;
        SV *			svvalue;
        svtype			svvaltype;
        STRLEN			vallen;
    CODE:
        /* only one value can be stored - no arrays allowed by perl */
        msg = obj->objptr;

        svvalue = svmixed;
        if (SvROK(svmixed)) {
          svvalue = SvRV(svmixed);
        }
        svvaltype = SvTYPE(svvalue);

        if (SvGMAGICAL(svvalue)) {
          if (gmime_debug)
            warn("hash_STORE: mg_get sv magical");
          mg_get(svvalue);
        }
        
        // TEST: display sv value
        if (gmime_debug)
          warn_type(svvalue, "hash_STORE");

        /* delete header for the first array item */
	g_mime_object_remove_header (GMIME_OBJECT(msg), key);

        if (svvaltype == SVt_PVAV) {
          AV *	avvalue;
          I32		i, avlen;
          SV *	svtmp;

          /* set header */
          avvalue = (AV *)svvalue;
          avlen = av_len(avvalue);
          for (i=avlen; i>=0; --i) {
            svtmp = (SV *)(*(av_fetch(avvalue, i, 0)));

            if (SvGMAGICAL(svtmp)) {
              if (gmime_debug)
                warn("hash_STORE(AV): mg_get sv magical");
              mg_get(svtmp);
            }
            
            if (svtmp && SvPOKp(svtmp)) {
              value = (char *)SvPV(svtmp, vallen);
              message_set_header(msg, key, value);
            }
          }
        } else if (SvPOK(svvalue) || SvIOK(svvalue) || SvNOK(svvalue)) {
          value = (char *)SvPV(svvalue, vallen);
          message_set_header(msg, key, value);
        } else { /* assume scalar value */
          /* undefined value -> remove header */
          if (!(SvOK(svvalue)))
	    g_mime_object_remove_header (GMIME_OBJECT(msg), key);
          else if (!(SvPOKp(svvalue)))
            croak("hash_STORE: Unknown sv type: %d for field %s 0x%x/0x%x/0x%x",
              SvTYPE(svvalue), key, &svvalue, &PL_sv_undef, svvalue);
        }
        if (gmime_debug)
          warn("hash_STORE: %s(0x%x) = %s\n", key, svvalue, SvPV(svvalue, vallen));

gboolean
hash_EXISTS(obj, key)
        MIME::Fast::Hash::Header	obj
        const char *		key
    PREINIT:
        MIME__Fast__Message		msg;
        GList			*gret, *item;
    CODE:
        msg = obj->objptr;
        if (gmime_debug)
         warn("hash_EXISTS(%s)\n", key);
        gret = message_get_header(msg, key);
        RETVAL = (gret != NULL && gret->data != NULL);
        if (gret) {
          item = gret;
          while (item) {
            if (item->data)
              g_free((char *)(item->data));
            item = item->next;
          }
          g_list_free(gret);
        }
    OUTPUT:
        RETVAL

void
hash_DELETE(obj, key)
        MIME::Fast::Hash::Header	obj
        const char *		key
    CODE:
        if (gmime_debug)
          warn("hash_DELETE %s\n", key);
	g_mime_object_remove_header (GMIME_OBJECT(obj->objptr), key);

void
hash_NEXTKEY(obj, lastkey = NULL)
        MIME::Fast::Hash::Header	obj
        const char *		lastkey
    ALIAS:
        MIME::Fast::Hash::Header::FIRSTKEY = 1
    PREINIT:
        char *			key = NULL;
        char *			value = NULL;
        MIME__Fast__Message		msg;
        I32			gimme = GIMME_V;
        gint			i, j, found;
        local_GMimeHeader *		header;
        struct raw_header	*h;
    INIT:
        if (ix == 1) {
          obj->keyindex = -1;
        }
    PPCODE:
        msg = obj->objptr;
        ++obj->keyindex;
        if (gmime_debug)
          warn("hash_NEXTKEY");
        i = obj->keyindex;
        header = GMIME_OBJECT(msg)->headers;

        h = header->headers;
        j = 0;
        found = 0;
        while (h) {
          if (j >= i) {
            key = h->name;
            value = h->value;
            found = 1;
            break;
          }
          j++;
          h = h->next;
        }
        
        if (!found && key == NULL) {
          obj->keyindex = -1;
        }

        if (gimme != G_SCALAR && !value) {
          // TODO: does each, keys, retrieves the value?
          // retrieve the value
          warn("Error in hash_NEXTKEY: NEED TO RETRIEVE THE VALUE, contact the author\n");
        }
        
        /* THE HACK - FETCH method would get value indirectly */
        obj->fetchvalue = NULL;

        if (key) {
          XPUSHs(sv_2mortal(newSVpv(key,0)));
          if (gimme != G_SCALAR && value)
            XPUSHs(sv_2mortal(newSVpv(value,0)));
          /* THE HACK - FETCH method would get value indirectly */
          obj->fetchvalue = value;
        }
        if (gmime_debug)
          warn("hash_%s(0x%x, %s) = (\"%s\",\"%s\") key no. %d%s",
        	(ix == 1) ? "FIRSTKEY" : "NEXTKEY",
        	obj, lastkey ? lastkey : "NULL",
        	key ? key : "NULL",
        	value ? value : "NULL",
        	i, obj->keyindex == -1 ? " (last)" : "");



void
hash_CLEAR(obj)
        MIME::Fast::Hash::Header	obj
    PREINIT:
        MIME__Fast__Message		message;
        local_GMimeHeader		*header;
    CODE:
        message = obj->objptr;
        if (gmime_debug)
        warn("function hash_CLEAR(0x%x)\n", obj);
        
        g_free (message->from);
        message->from = NULL;

        g_free (message->reply_to);
        message->reply_to = NULL;
        
        /* destroy all recipients */
        g_hash_table_foreach_remove (message->recipients, recipients_destroy, NULL);
        //g_hash_table_destroy (message->header->recipients);
        //message->header->recipients = g_hash_table_new (g_str_hash, g_str_equal);	
        
        g_free (message->subject);
        message->subject = NULL;
        
        g_free (message->message_id);
        message->message_id = NULL;

        /* free all the headers */
        header = GMIME_OBJECT(message)->headers;
        g_mime_header_destroy(header);
        GMIME_OBJECT(message)->headers = g_mime_header_new ();