Hello community,

here is the log from the commit of package tboot for openSUSE:Factory checked 
in at 2013-08-12 10:17:08
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/tboot (Old)
 and      /work/SRC/openSUSE:Factory/.tboot.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "tboot"

Changes:
--------
--- /work/SRC/openSUSE:Factory/tboot/tboot.changes      2013-01-10 
15:20:19.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.tboot.new/tboot.changes 2013-08-12 
10:17:09.000000000 +0200
@@ -1,0 +2,8 @@
+Thu Aug  8 11:56:45 UTC 2013 - meiss...@suse.com
+
+- updated to 1.7.4/20130705
+  Fix possible empty submenu block in generated grub.cfg
+  Add a call_racm=check option for easy RACM launch result check
+  Fix type check for revocation ACM.
+
+-------------------------------------------------------------------

Old:
----
  tboot-1.7.3.tar.gz

New:
----
  tboot-1.7.4.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ tboot.spec ++++++
--- /var/tmp/diff_new_pack.tNhbkH/_old  2013-08-12 10:17:10.000000000 +0200
+++ /var/tmp/diff_new_pack.tNhbkH/_new  2013-08-12 10:17:10.000000000 +0200
@@ -17,8 +17,8 @@
 
 
 Name:           tboot
-%define ver 1.7.3
-Version:        20121228_1.7.3
+%define ver 1.7.4
+Version:        20130705_1.7.4
 Release:        0
 Summary:        Performs a verified launch using Intel(R) TXT
 License:        BSD-3-Clause

++++++ tboot-1.7.3.tar.gz -> tboot-1.7.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tboot-1.7.3/.hg_archival.txt 
new/tboot-1.7.4/.hg_archival.txt
--- old/tboot-1.7.3/.hg_archival.txt    2012-12-28 07:30:13.000000000 +0100
+++ new/tboot-1.7.4/.hg_archival.txt    2013-07-08 04:48:29.000000000 +0200
@@ -1,5 +1,5 @@
 repo: cedd93279188334eb41d248d5eb70a41a2bc70ca
-node: 5192fef95f6f443c1b017d6c9bcfb5823a0c447b
+node: 22b9704961c34f22f9ee12f4a822263d3159669d
 branch: default
-latesttag: v1.7.3
+latesttag: v1.7.4
 latesttagdistance: 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tboot-1.7.3/.hgtags new/tboot-1.7.4/.hgtags
--- old/tboot-1.7.3/.hgtags     2012-12-28 07:30:13.000000000 +0100
+++ new/tboot-1.7.4/.hgtags     2013-07-08 04:48:29.000000000 +0200
@@ -4,3 +4,4 @@
 bd086f9ac6abcc4403a4fd32ce2604882025bc2c v1.7.2
 221ec0974a31576ce197aa9ce793925b1cca0cfc v1.7.3-rc1
 feeb4cc736710d1b6abbb6561a31737f19d10021 v1.7.3
+794e9c2ef61a9a8911b9b58b2f3f3724bf3873be v1.7.4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tboot-1.7.3/CHANGELOG new/tboot-1.7.4/CHANGELOG
--- old/tboot-1.7.3/CHANGELOG   2012-12-28 07:30:13.000000000 +0100
+++ new/tboot-1.7.4/CHANGELOG   2013-07-08 04:48:29.000000000 +0200
@@ -1,4 +1,9 @@
-20121228  v1.7.3
+20130705: v1.7.4
+       Fix possible empty submenu block in generated grub.cfg
+       Add a call_racm=check option for easy RACM launch result check
+       Fix type check for revocation ACM.
+
+20121228: v1.7.3
        Update README with updated code repository url.
        Fix grub2 scripts to be compatible with more distros.
        Update README for RACM launch support
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tboot-1.7.3/README new/tboot-1.7.4/README
--- old/tboot-1.7.3/README      2012-12-28 07:30:13.000000000 +0100
+++ new/tboot-1.7.4/README      2013-07-08 04:48:29.000000000 +0200
@@ -205,7 +205,7 @@
 o  Tboot provides support to launch Revocation ACM (RACM) to revoke old buggy
    SINIT version if following command line option is used (default vaule is
    false):
-       call_racm=true|false
+       call_racm=true|false|check
 
    RACM is also loaded into memory via bootload like grub or syslinux, and is
    launched with getsec[ENTERACCS] instruction. Below is a example GRUB entry
@@ -217,9 +217,10 @@
            module /racm.bin
 
    Tboot will always warm reset platform after RACM was launched & executed.
-   Whether RACM launch has succeeded or not could be checked via doing a normal
-   tboot launch right after the warm reset and looking into the TXT.ERRORCODE
-   value output by the normal tboot launch.
+   Whether RACM launch has succeeded or not could be checked via doing a tboot
+   launch with "call_racm=check" right after the warm reset. This tboot launch
+   will end with halt right after the RACM launch result was output, and the
+   system need manually reset.
 
 
 PCR Usage:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tboot-1.7.3/tboot/20_linux_tboot 
new/tboot-1.7.4/tboot/20_linux_tboot
--- old/tboot-1.7.3/tboot/20_linux_tboot        2012-12-28 07:30:13.000000000 
+0100
+++ new/tboot-1.7.4/tboot/20_linux_tboot        2013-07-08 04:48:29.000000000 
+0200
@@ -127,7 +127,7 @@
       done`
 prepare_boot_cache=
 
-while [ "x${tboot_list}" != "x" ] ; do
+while [ "x${tboot_list}" != "x" ] && [ "x$linux_list" != "x" ] ; do
     list="${linux_list}"
     current_tboot=`version_find_latest $tboot_list`
     tboot_basename=`basename ${current_tboot}`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tboot-1.7.3/tboot/20_linux_xen_tboot 
new/tboot-1.7.4/tboot/20_linux_xen_tboot
--- old/tboot-1.7.3/tboot/20_linux_xen_tboot    2012-12-28 07:30:13.000000000 
+0100
+++ new/tboot-1.7.4/tboot/20_linux_xen_tboot    2013-07-08 04:48:29.000000000 
+0200
@@ -171,7 +171,7 @@
     rel_xen_dirname=`make_system_path_relative_to_its_root $xen_dirname`
     xen_version=`echo $xen_basename | sed -e "s,.gz$,,g;s,^xen-,,g"`
     tlist="${tboot_list}"
-    while [ "x${tlist}" != "x" ] ; do
+    while [ "x${tlist}" != "x" ] && [ "x$linux_list" != "x" ] ; do
         current_tboot=`version_find_latest $tlist`
         tboot_basename=`basename ${current_tboot}`
         tboot_dirname=`dirname ${current_tboot}`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tboot-1.7.3/tboot/Config.mk 
new/tboot-1.7.4/tboot/Config.mk
--- old/tboot-1.7.3/tboot/Config.mk     2012-12-28 07:30:13.000000000 +0100
+++ new/tboot-1.7.4/tboot/Config.mk     2013-07-08 04:48:29.000000000 +0200
@@ -32,7 +32,7 @@
 CFLAGS         += $(call cc-option,$(CC),-fno-stack-protector-all,)
 
 # changeset variable for banner
-CFLAGS         += -DTBOOT_CHANGESET=\""$(shell ((hg parents --template 
"{isodate|isodate} {rev}:{node|short}" >/dev/null && hg parents --template 
"{isodate|isodate} {rev}:{node|short}") || echo "2012-09-29 15:30 +0800 1.7.2") 
2>/dev/null)"\"
+CFLAGS         += -DTBOOT_CHANGESET=\""$(shell ((hg parents --template 
"{isodate|isodate} {rev}:{node|short}" >/dev/null && hg parents --template 
"{isodate|isodate} {rev}:{node|short}") || echo "2013-07-05 12:00 +0800 
1.7.4"") 2>/dev/null)"\"
 
 
 AFLAGS         += -D__ASSEMBLY__
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tboot-1.7.3/tboot/common/cmdline.c 
new/tboot-1.7.4/tboot/common/cmdline.c
--- old/tboot-1.7.3/tboot/common/cmdline.c      2012-12-28 07:30:13.000000000 
+0100
+++ new/tboot-1.7.4/tboot/common/cmdline.c      2013-07-08 04:48:29.000000000 
+0200
@@ -74,7 +74,7 @@
     { "ap_wake_mwait", "false" },    /* true|false */
     { "pcr_map", "legacy" },         /* legacy|da */
     { "min_ram", "0" },              /* size in bytes | 0 for no min */
-    { "call_racm", "false" },        /* true|false */
+    { "call_racm", "false" },        /* true|false|check */
     { NULL, NULL }
 };
 static char 
g_tboot_param_values[ARRAY_SIZE(g_tboot_cmdline_options)][MAX_VALUE_LEN];
@@ -469,7 +469,16 @@
 {
     const char *call_racm = get_option_val(g_tboot_cmdline_options,
                                        g_tboot_param_values, "call_racm");
-    if ( call_racm == NULL || strcmp(call_racm, "false") == 0 )
+    if ( call_racm == NULL || strcmp(call_racm, "true") != 0 )
+        return false;
+    return true;
+}
+
+bool get_tboot_call_racm_check(void)
+{
+    const char *call_racm = get_option_val(g_tboot_cmdline_options,
+                                       g_tboot_param_values, "call_racm");
+    if ( call_racm == NULL || strcmp(call_racm, "check") != 0 )
         return false;
     return true;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tboot-1.7.3/tboot/common/tboot.c 
new/tboot-1.7.4/tboot/common/tboot.c
--- old/tboot-1.7.3/tboot/common/tboot.c        2012-12-28 07:30:13.000000000 
+0100
+++ new/tboot-1.7.4/tboot/common/tboot.c        2013-07-08 04:48:29.000000000 
+0200
@@ -308,6 +308,13 @@
     apply_policy(err);
 }
 
+static void shutdown_system(uint32_t);
+void check_racm_result(void)
+{
+    txt_get_racm_error();
+    shutdown_system(TB_SHUTDOWN_HALT); 
+}
+
 void begin_launch(multiboot_info_t *mbi)
 {
     tb_error_t err;
@@ -337,6 +344,10 @@
     printk(TBOOT_INFO"*********************************************\n");
 
     printk(TBOOT_INFO"command line: %s\n", g_cmdline);
+    /* if telled to check revocation acm result, go with simplified path */
+    if ( get_tboot_call_racm_check() )
+        check_racm_result(); /* never return */
+
     if ( s3_flag )
         printk(TBOOT_INFO"resume from S3\n");
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tboot-1.7.3/tboot/include/cmdline.h 
new/tboot-1.7.4/tboot/include/cmdline.h
--- old/tboot-1.7.3/tboot/include/cmdline.h     2012-12-28 07:30:13.000000000 
+0100
+++ new/tboot-1.7.4/tboot/include/cmdline.h     2013-07-08 04:48:29.000000000 
+0200
@@ -51,6 +51,7 @@
 extern bool get_tboot_prefer_da(void);
 extern void get_tboot_min_ram(void);
 extern bool get_tboot_call_racm(void);
+extern bool get_tboot_call_racm_check(void);
 
 /* for parse cmdline of linux kernel, say vga and mem */
 extern void linux_parse_cmdline(const char *cmdline);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tboot-1.7.3/tboot/include/txt/acmod.h 
new/tboot-1.7.4/tboot/include/txt/acmod.h
--- old/tboot-1.7.3/tboot/include/txt/acmod.h   2012-12-28 07:30:13.000000000 
+0100
+++ new/tboot-1.7.4/tboot/include/txt/acmod.h   2013-07-08 04:48:29.000000000 
+0200
@@ -108,6 +108,8 @@
 /* chipset_acm_type field values */
 #define ACM_CHIPSET_TYPE_BIOS         0x00
 #define ACM_CHIPSET_TYPE_SINIT        0x01
+#define ACM_CHIPSET_TYPE_BIOS_REVOC   0x08
+#define ACM_CHIPSET_TYPE_SINIT_REVOC  0x09
 
 typedef struct __packed {
     uint32_t  flags;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tboot-1.7.3/tboot/include/txt/txt.h 
new/tboot-1.7.4/tboot/include/txt/txt.h
--- old/tboot-1.7.3/tboot/include/txt/txt.h     2012-12-28 07:30:13.000000000 
+0100
+++ new/tboot-1.7.4/tboot/include/txt/txt.h     2013-07-08 04:48:29.000000000 
+0200
@@ -40,6 +40,7 @@
 
 extern bool txt_is_launched(void);
 extern bool txt_get_error(void);
+extern void txt_get_racm_error(void);
 extern tb_error_t supports_txt(void);
 extern tb_error_t txt_verify_platform(void);
 extern bool txt_prepare_cpu(void);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tboot-1.7.3/tboot/txt/acmod.c 
new/tboot-1.7.4/tboot/txt/acmod.c
--- old/tboot-1.7.3/tboot/txt/acmod.c   2012-12-28 07:30:13.000000000 +0100
+++ new/tboot-1.7.4/tboot/txt/acmod.c   2013-07-08 04:48:29.000000000 +0200
@@ -432,8 +432,9 @@
     if ( !is_acmod(acmod_base, acmod_size, &type, quiet) )
         return false;
 
-    if ( type != ACM_CHIPSET_TYPE_BIOS ) {
-        printk(TBOOT_ERR"ACM is not an BIOS ACM (%x)\n", type);
+    if ( type != ACM_CHIPSET_TYPE_BIOS_REVOC &&
+         type != ACM_CHIPSET_TYPE_SINIT_REVOC ) {
+        printk(TBOOT_ERR"ACM is not an revocation ACM (%x)\n", type);
         return false;
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tboot-1.7.3/tboot/txt/errors.c 
new/tboot-1.7.4/tboot/txt/errors.c
--- old/tboot-1.7.3/tboot/txt/errors.c  2012-12-28 07:30:13.000000000 +0100
+++ new/tboot-1.7.4/tboot/txt/errors.c  2013-07-08 04:48:29.000000000 +0200
@@ -55,7 +55,7 @@
      * display TXT.ERRORODE error
      */
     err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE);
-    if (err._raw == 0 || err._raw == 0xc0000001)
+    if (err._raw == 0 || err._raw == 0xc0000001 || err._raw == 0xc0000009)
         printk(TBOOT_INFO"TXT.ERRORCODE: 0x%Lx\n", err._raw);
     else
         printk(TBOOT_ERR"TXT.ERRORCODE: 0x%Lx\n", err._raw);
@@ -70,7 +70,8 @@
                 printk(TBOOT_ERR"unknown SW error 0x%x:0x%x\n", sw_err.err1, 
sw_err.err2);
             else {                     /* ACM error */
                 acmod_err._raw = sw_err._raw;
-                if (acmod_err._raw == 0x0 || acmod_err._raw == 0x1)
+                if ( acmod_err._raw == 0x0 || acmod_err._raw == 0x1 ||
+                     acmod_err._raw == 0x9 )
                     printk(TBOOT_INFO"AC module error : acm_type=0x%x, 
progress=0x%02x, "
                            "error=0x%x\n", acmod_err.acm_type, 
acmod_err.progress,
                            acmod_err.error);
@@ -121,6 +122,154 @@
         return true;
 }
 
+#define CLASS_ACM_ENTRY 0x1
+enum ENUM_ACM_ENTRY {
+    ERR_LAUNCH = 1,
+    ERR_NEM_ENABLED,
+    ERR_CPU_LT_TYPE,
+    ERR_DEV_ID,
+    ERR_CPU_ID,
+    ERR_NO_UCODE_UPDATE ,
+    ERR_DEBUG_MCU,
+    ERR_DMI_LINK_DOWN,
+    ERR_ACM_REVOKED,   
+    ERR_TPM_DOUBLE_AUX
+};
+#define CLASS_TPM_ACCESS 0x4
+enum ENUM_TPM_ACCESS {
+    ERR_OK,                  /* Indicator of successful execution of the 
function.*/
+    ERR_TPM_ERROR,           /* TPM returned an error */
+    ERR_LOCALITY,
+    ERR_ACC_INVLD,
+    ERR_NV_UNLOCKED,          /* TPM NV RAM not locked */
+    ERR_TPM_DISABLED,         /* TPM is disabled */
+    ERR_TPM_DEACTIVATED,      /* TPM is deactivated */
+    ERR_TPM_NV_INDEX_INVALID, /* TPM NV indices incorrectly defined */
+    ERR_TPM_INCOMPET_BIOSAC,  /* Incompatible BIOS ACM */
+    ERR_TPM_INCOMPET_AUXREV,  /* Incompatible AUX revision */
+    ERR_TPM_INBUF_TOO_SHORT,  /* Input buffer is too short */
+    ERR_TPM_OUTBUF_TOO_SHORT, /* Output buffer is too short */
+    ERR_TPM_NV_PO_INDEX_INVALID = 0x10,
+
+    /*
+     *  Errors returned by TPM driver
+     */
+    ERR_OUTPUT_BUFFER_TOO_SHORT = 0x1B, /* Output buffer for the TPM response 
to short */
+    ERR_INVALID_INPUT_PARA = 0x1C,      /* Input parameter for the function 
invalid */
+    ERR_INVALID_RESPONSE_WR = 0x1D,     /* The response from the TPM was 
invalid */
+    ERR_INVALID_RESPONSE_RD = 0x1E,     /* The response from the TPM was 
invalid */
+    ERR_RESPONSE_TIMEOUT = 0x1F         /* Time out for TPM response */
+};     
+#define CLASS_MISC_CONFIG 0x8
+enum ENUM_MISC_CONFIG {
+    ERR_INTERRUPT = 1,
+    ERR_FORBIDDEN_BY_OWNER  = 0x10,
+    ERR_TOOL_LAUNCH,
+    ERR_CANNOT_REVERSE,
+    ERR_ALREADY_REVOKED,
+    ERR_INVALID_RETURN_ADDR,
+    ERR_NO_TPM,
+};
+
+void txt_get_racm_error(void)
+{
+    txt_errorcode_t err;
+    acmod_error_t acmod_err;
+
+    /*
+     * display TXT.ERRORODE error
+     */
+    err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE);
+
+    /* AC module error (don't know how to parse other errors) */
+    if ( err.valid == 0 ) {
+        printk(TBOOT_ERR
+               "Cannot retrieve status - ERRORSTS register is not valid.\n");
+        return;
+    } 
+
+    if ( err.external == 0 ) {      /* processor error */
+        printk(TBOOT_ERR"CPU generated error 0x%x\n", (uint32_t)err.type);
+        return;
+    }
+
+    acmod_err._raw = err.type;
+    if ( acmod_err.src == 1 ) {
+        printk(TBOOT_ERR"Unknown SW error.\n");
+        return;
+    }
+
+    if ( acmod_err.acm_type != 0x9 ) {
+        printk(TBOOT_ERR
+               "Cannot retrieve status - wrong ACM type in ERRORSTS 
register.\n");
+        return;
+    }
+
+    if ( acmod_err.progress == CLASS_ACM_ENTRY &&
+         acmod_err.error == ERR_TPM_DOUBLE_AUX ) {
+        printk(TBOOT_ERR
+               "Nothing to do: double AUX index is not valid TXT 
configuration.\n");
+        return;
+    }
+
+    if ( acmod_err.progress == CLASS_TPM_ACCESS &&
+         acmod_err.error == ERR_TPM_NV_INDEX_INVALID ) {
+        printk(TBOOT_ERR
+               "Nothing to do: invalid AUX index attributes.\n");
+        return;
+    }
+
+    if ( acmod_err.progress == CLASS_TPM_ACCESS &&
+         acmod_err.error == ERR_TPM_NV_PO_INDEX_INVALID ) {
+        printk(TBOOT_ERR
+               "Error: invalid PO index attributes.\n");
+        return;
+    }
+
+    if ( acmod_err.progress == CLASS_MISC_CONFIG &&
+         acmod_err.error == ERR_ALREADY_REVOKED ) {
+        printk(TBOOT_ERR
+               "Nothing to do: already revoked.\n");
+        return;
+    }
+
+    if ( acmod_err.progress == CLASS_MISC_CONFIG &&
+         acmod_err.error == ERR_FORBIDDEN_BY_OWNER ) {
+        printk(TBOOT_ERR
+               "Error: revocation forbidden by owner.\n");
+        return;
+    }
+
+    if ( acmod_err.progress == CLASS_MISC_CONFIG &&
+         acmod_err.error == ERR_CANNOT_REVERSE ) {
+        printk(TBOOT_ERR
+               "Error: cannot decrement revocation version.\n");
+        return;
+    }
+
+    if ( acmod_err.progress == CLASS_MISC_CONFIG &&
+         acmod_err.error == ERR_INVALID_RETURN_ADDR ) {
+        printk(TBOOT_ERR
+               "Error: invalid input address of return point.\n");
+        return;
+    }
+
+    if ( acmod_err.progress == CLASS_MISC_CONFIG &&
+         acmod_err.error == ERR_NO_TPM ) {
+        printk(TBOOT_ERR
+               "Nothing to do: No TPM present.\n");
+        return;
+    }
+
+    if ( acmod_err.progress == 0 && acmod_err.error == 0 ) {
+        printk(TBOOT_INFO
+               "Success: Revocation completed.\n");
+        return;
+    }
+
+    printk(TBOOT_ERR"RACM generated error 0x%Lx.\n", err._raw);
+}
+
 /*
  * Local variables:
  * mode: C
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tboot-1.7.3/tboot/txt/txt.c 
new/tboot-1.7.4/tboot/txt/txt.c
--- old/tboot-1.7.3/tboot/txt/txt.c     2012-12-28 07:30:13.000000000 +0100
+++ new/tboot-1.7.4/tboot/txt/txt.c     2013-07-08 04:48:29.000000000 +0200
@@ -696,6 +696,10 @@
     if ( !set_mtrrs_for_acmod(racm) )
         return TB_ERR_FATAL;
 
+    /* clear MSEG_BASE/SIZE registers */
+    write_pub_config_reg(TXTCR_MSEG_BASE, 0);
+    write_pub_config_reg(TXTCR_MSEG_SIZE, 0);
+
     printk(TBOOT_INFO"executing GETSEC[ENTERACCS]...\n");
     /* (optionally) pause before executing GETSEC[ENTERACCS] */
     if ( g_vga_delay > 0 )

-- 
To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org
For additional commands, e-mail: opensuse-commit+h...@opensuse.org

Reply via email to