/[winpt]/trunk/Src/wptKeyPropsDlg.cpp
ViewVC logotype

Diff of /trunk/Src/wptKeyPropsDlg.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 22 by twoaday, Wed Aug 10 11:33:35 2005 UTC revision 129 by twoaday, Fri Dec 30 13:56:10 2005 UTC
# Line 1  Line 1 
1  /* wptKeyPropsDlg.cpp - WinPT key properties dialog  /* wptKeyPropsDlg.cpp - WinPT key properties dialog
2   *      Copyright (C) 2000, 2001, 2002, 2003, 2005 Timo Schulz   *      Copyright (C) 2000, 2001, 2002, 2003, 2005 Timo Schulz
3   *   *
4   * This file is part of WinPT.   * This file is part of WinPT.
5   *   *
6   * WinPT is free software; you can redistribute it and/or modify   * WinPT is free software; you can redistribute it and/or modify
7   * it under the terms of the GNU General Public License as published by   * it under the terms of the GNU General Public License as published by
8   * the Free Software Foundation; either version 2 of the License, or   * the Free Software Foundation; either version 2 of the License, or
9   * (at your option) any later version.   * (at your option) any later version.
10   *   *
11   * WinPT is distributed in the hope that it will be useful,   * WinPT is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.   * GNU General Public License for more details.
15   *   *
16   * You should have received a copy of the GNU General Public License   * You should have received a copy of the GNU General Public License
17   * along with WinPT; if not, write to the Free Software Foundation,   * along with WinPT; if not, write to the Free Software Foundation,
18   * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA   * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19   */   */
20    #ifdef HAVE_CONFIG_H
21  #include <windows.h>  #include <config.h>
22    #endif
23  #include "../resource.h"  
24  #include "wptErrors.h"  #include <windows.h>
25  #include "wptGPG.h"  
26  #include "wptCommonCtl.h"  #include "resource.h"
27  #include "wptContext.h" /* for passphrase_s */  #include "wptErrors.h"
28  #include "wptNLS.h"  #include "wptGPG.h"
29  #include "wptDlgs.h"  #include "wptCommonCtl.h"
30  #include "wptTypes.h"  #include "wptContext.h" /* for passphrase_s */
31  #include "wptKeylist.h"  #include "wptNLS.h"
32  #include "wptW32API.h"  #include "wptDlgs.h"
33  #include "wptVersion.h"  #include "wptTypes.h"
34  #include "wptKeyEdit.h"  #include "wptKeylist.h"
35    #include "wptW32API.h"
36  int keyedit_ownertrust_get_val (void);  #include "wptVersion.h"
37    #include "wptKeyEdit.h"
38    
39  static void  
40  do_change_ownertrust (winpt_key_t k, const char *s)  /* Check that the key is not expired or revoked. */
41  {  static int
42      char ot[64];  do_check_key (gpgme_key_t key)
43        {
44      if( strstr( s, "ultimate" ) ) {      int okay = 0;
45          listview_get_item_text (k->callback.ctl, k->callback.idx, 5, ot, DIM (ot)-1);      okay = key->expired;
46          strcpy (ot, "Ultimate");      if (!okay)
47          listview_add_sub_item (k->callback.ctl, k->callback.idx, 5, ot);          okay = key->revoked;
48          /* fixme: If we switch back from Ultimate to a lower level */      return okay;
49      }  }
50  } /* do_change_ownertrust */  
51    
52    /* Convert a trust integer into a string representation. */
53  static int  static const char*
54  do_check_key (gpgme_key_t key)  ownertrust_to_string (int val)
55  {  {
56      int okay = 0;      const char *inf;
57      okay = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_EXPIRED, NULL, 0);      int id = val;
58      if (!okay)  
59          okay = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_REVOKED, NULL, 0);      switch (id) {
60      return okay;      case 1: inf = _("Don't know");         break;
61  } /* do_check_key */      case 2: inf = _("I do NOT trust");     break;
62        case 3: inf = _("I trust marginally"); break;
63        case 4: inf = _("I trust fully");      break;
64  static const char*      case 5:
65  ownertrust_to_string (gpgme_editkey_t ctx, int val)      case 6: inf = _("I trust ultimately"); break;
66  {      default:inf = _("Unknown");            break;
67      const char * inf;      }
68      int id;      
69            return inf;
70      if (ctx)  }
71          id = keyedit_ownertrust_get_val ();  
72      else if (!ctx && val)  
73          id = val;  /* Generate a unique temp name for the photo which
74      switch (id) {     depends on the dialog handle and return it. */
75      case 1: inf = _("Don't know");         break;  static const char*
76      case 2: inf = _("I do NOT trust");     break;  get_photo_tmpname (HWND dlg)
77      case 3: inf = _("I trust marginally"); break;  {
78      case 4: inf = _("I trust fully");      break;      static char buf[64];
79      case 5:  
80      case 6: inf = _("I trust ultimately"); break;      _snprintf (buf, sizeof (buf)-1, "winpt_photo_%08lX.tmp", (DWORD)dlg);
81      default:inf = _("Unknown");            break;      return buf;
82      }  }
83        
84      return inf;  
85  } /* ownertrust_to_string */  static void
86    draw_nophoto_img (HWND dlg)
87    {
88  #define PHOTO_TMPNAME "winpt_temp_photo.jpg"      /*..
89        n = DrawText (hdc, "No Photo-ID", -1, &r, DT_LEFT);
90  static int      ..*/
91  keyprops_show_photo (HWND dlg, gpgme_key_t key)  }
92  {  
93      RECT r;      
94      POINT p;  /* Load the photo from the key @key */
95      HWND h;  static int
96      const BYTE *img;  keyprops_load_photo (HWND dlg, gpgme_key_t key, gpgme_validity_t *r_valid)
97      DWORD imglen = 0;  {
98      int pos=0;      winpt_key_s k;
99        FILE *f;
100      img = (const byte *)gpgme_key_get_string_attr (key, GPGME_ATTR_PHOTO,      const BYTE *img;
101                                                     (void **)&imglen, 0);      DWORD imglen = 0;
102      if (!img || !imglen)      int pos=0;
103          return -1;  
104      FILE *f = fopen (PHOTO_TMPNAME, "wb");      winpt_get_pubkey (key->subkeys->keyid, &k);
105      if (f) {      img = k.ext->attrib.d;
106          for (pos = 0; img[pos] != 0x10; pos++)      imglen = k.ext->attrib.len;
107                  ;      if (!k.ext->attrib.validity)
108          pos += 16;          get_uat_validity (key->subkeys->keyid, &k.ext->attrib.validity);
109          fwrite (img + pos, 1, imglen - pos, f);      *r_valid = k.ext->attrib.validity;
110          fwrite (img, 1, imglen, f);  
111          fclose (f);      if (!img || !imglen) {
112      }          draw_nophoto_img (dlg);
113            return -1;
114      h = GetDlgItem (dlg, IDC_KEYPROPS_IMG);      }
115      GetWindowRect (h, &r);      f = fopen (get_photo_tmpname (dlg), "wb");
116      p.x = r.left + 5;      if (f) {
117      p.y = r.top - 2;          for (pos = 0; img[pos] != 0x10; pos++)
118      memset (&p, 0, sizeof (p));                  ;
119      PTD_jpg_show (h, &p, PHOTO_TMPNAME);          pos += 16;
120      unlink (PHOTO_TMPNAME);          fwrite (img + pos, 1, imglen - pos, f);
121            fwrite (img, 1, imglen, f);
122      return 0;          fclose (f);
123  }      }
124        return 0;
125    }
126  static const char*  
127  get_validity (gpgme_key_t key)  
128  {  /* Display the photo in the image control in the dialog @dlg. */
129      int val;  static int
130      val = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_EXPIRED, NULL, 0);  keyprops_show_photo (HWND dlg)
131      if (val)  {
132          return "Expired";            RECT r;    
133      val = gpgme_key_get_ulong_attr( key, GPGME_ATTR_KEY_REVOKED, NULL, 0 );      POINT p;
134      if (val)      HWND h;
135          return "Revoked";  
136      val = gpgme_key_get_ulong_attr (key, GPGME_ATTR_VALIDITY, NULL, 0);      h = GetDlgItem (dlg, IDC_KEYPROPS_IMG);
137      return gpgme_key_expand_attr (GPGME_ATTR_VALIDITY, val);      GetWindowRect (h, &r);
138  }      p.x = r.left + 5;
139        p.y = r.top - 2;
140        memset (&p, 0, sizeof (p));
141  BOOL CALLBACK      PTD_jpg_show (h, &p, get_photo_tmpname (dlg));
142  keyprops_dlg_proc( HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam )      
143  {      return 0;
144      static winpt_key_t k;  }
145      static gpgme_key_t key, sk;  
146      static int photo_done = 0;  
147      gpgme_editkey_t ek;  /* Return string representation of the key validity. @key. */
148      gpgme_ctx_t ctx;  static const char*
149      gpgme_error_t ec;      get_validity (gpgme_key_t key)
150      refresh_cache_s rcs = {0};  {
151      const char *inf;      int val;
152      const char * sym_prefs;      val = key->expired;
153      char info[2048], dummy_symprefs[] = {0x01, 0x00};      if (val)
154      u32 created, expires;          return _("Expired");    
155      int ot, cancel = 0;      val = key->revoked;
156      int rc;      if (val)
157                return _("Revoked");
158      switch (msg) {      val = key->disabled;
159      case WM_INITDIALOG:      if (val)
160          if (!lparam)          return _("Disabled");
161              dlg_fatal_error( dlg, "Could not get dialog param!" );      return get_key_trust2 (NULL, key->uids->validity, 0, 0);
162          k = (winpt_key_t)lparam;  }
163          #ifndef LANG_DE  
164          SetWindowText( dlg, _("Key Properties") );  
165          SetDlgItemText (dlg, IDC_KEYPROPS_OT_CHANGE, _("&Change"));  /* Return the preferred sym. algorithm from @key as a string. */
166          SetDlgItemText (dlg, IDC_KEYPROPS_REVOKERS, _("&Revokers"));  static const char*
167          SetDlgItemText (dlg, IDC_KEYPROPS_CHANGE_PWD, _("Change &Passwd"));  get_pref_cipher (winpt_key_t k)
168          #endif    {
169        if (k->is_v3)
170          photo_done = 0;          return "IDEA";
171          get_seckey (k->keyid, &sk);      if (!k->ext->sym_prefs)
172          if (sk)          return "3DES";
173              k->is_protected = gpgme_key_get_ulong_attr( sk, GPGME_ATTR_IS_PROTECTED, NULL, 0 );      switch (*k->ext->sym_prefs) {
174          if (get_pubkey (k->keyid, &key))      case 1: return "IDEA";
175              BUG (0);      case 2: return "3DES";
176          created = gpgme_key_get_ulong_attr( key, GPGME_ATTR_CREATED, NULL, 0 );      case 3: return "CAST5";
177          expires = gpgme_key_get_ulong_attr( key, GPGME_ATTR_EXPIRES, NULL, 0 );      case 4: return "Blowfish";
178          sym_prefs = gpgme_key_get_string_attr( key, GPGME_ATTR_KEY_SYMPREFS, NULL, 0 );      case 7:
179          if (!sym_prefs)      case 8:
180              sym_prefs = dummy_symprefs;            case 9: return "AES";
181          _snprintf (info, sizeof info -1,      case 10:return "Twofish";
182                    "Type: %s\r\n"      }
183                    "Key ID: %s\r\n"      return "Unknown";
184                    "Algorithm: %s\r\n"  }
185                    "Size: %s\r\n"  
186                    "Created: %s\r\n"  
187                    "Expires: %s\r\n"  /* Return true if the key has designated revokers. */
188                    "Validity: %s\r\n"  static bool
189                    "Cipher: %s\r\n",  check_for_desig_rev (gpgme_key_t key)
190                    get_key_type( key ),  {
191                    k->keyid,      winpt_key_s k;
192                    get_key_algo( key, 0 ),      memset (&k, 0, sizeof (k));
193                    get_key_size( key, 0 ),      if (!winpt_get_pubkey (key->subkeys->keyid, &k))
194                    get_key_created( created ),          return k.ext->gloflags.has_desig_rev? true : false;
195                    get_key_expire_date( expires ),      return false;
196                    get_validity (key),  }
197                    gpgme_key_expand_attr( GPGME_ATTR_KEY_SYMPREFS, *sym_prefs ) );  
198          SetDlgItemText( dlg, IDC_KEYPROPS_INFO, info );  
199          SetDlgItemText( dlg, IDC_KEYPROPS_FPR, get_key_fpr( key ) );  /* Print information (name) of the smart card. */
200          ot = gpgme_key_get_ulong_attr( key, GPGME_ATTR_OTRUST, NULL, 0 );                static const char*
201          inf = ownertrust_to_string( NULL, ot );  get_card_type (winpt_key_t k)
202          SetDlgItemText( dlg, IDC_KEYPROPS_OT, inf );  {    
203          if( k->key_pair )      static char buf[64];
204              EnableWindow( GetDlgItem( dlg, IDC_KEYPROPS_CHANGE_PWD ), TRUE );  
205          if( gpgme_key_count_items( key, GPGME_ATTR_REVKEY_FPR ) )      if (!k->ext->card_type)
206              EnableWindow( GetDlgItem( dlg, IDC_KEYPROPS_REVOKERS ), TRUE );          return "";
207          center_window (dlg);      _snprintf (buf, sizeof (buf)-1, _("Card-Type: %s\r\n"), k->ext->card_type);
208          SetForegroundWindow (dlg);            return buf;
209          return TRUE;  }
210          
211      case WM_PAINT:        
212          if (photo_done == 0) {  /* Display the key information for key @k.
213              photo_done = 1;     Return value: gpgme key on success. */
214              keyprops_show_photo (dlg, key);  static void
215          }  display_key_info (HWND dlg, winpt_key_t k, gpgme_key_t *r_key)
216          break;  {
217        struct winpt_key_s k2;
218      case WM_SYSCOMMAND:      gpgme_key_t sk, key;
219          if( LOWORD( wparam ) == SC_CLOSE )      char info[512];
220              EndDialog( dlg, TRUE );      const char *inf;
221          return FALSE;      u32 created, expires;
222            
223      case WM_COMMAND:      memset (&k2, 0, sizeof (k2));      
224          switch( LOWORD( wparam ) ) {      if (k->key_pair)
225          case IDOK:          winpt_get_seckey (k->keyid, &k2);
226              EndDialog( dlg, TRUE );      else    
227              return TRUE;          winpt_get_pubkey (k->keyid, &k2);
228                    sk = k2.ctx;
229          case IDC_KEYPROPS_OT_CHANGE:      if (sk)
230              if( do_check_key( key ) ) {          k->is_protected = k2.is_protected;
231                  msg_box( dlg, _("The status of this key is 'revoked' or 'expired'.\n"      if (get_pubkey (k->keyid, &key))
232                                  "You cannot change the ownertrust of such keys."),          BUG (0);    
233                                  _("WinPT Warning"), MB_ERR );      created = key->subkeys->timestamp;  
234                  return FALSE;      expires = key->subkeys->expires;    
235              }      _snprintf (info, DIM (info)-1,
236              if( !k->key_pair && gpgme_key_get_ulong_attr( key, GPGME_ATTR_VALIDITY, NULL, 0 ) < 3 ) {                 _("Type: %s\r\n"
237                  rc = msg_box( dlg, _("This is a non-valid key.\n"                 "Key ID: %s\r\n"
238                                       "Modifying the ownertrust has no effect on such keys.\n"                 "Algorithm: %s\r\n"
239                                       "Do you really want to continue?"),                 "Size: %s bits\r\n"
240                                       _("WinPT Warning"), MB_ICONWARNING|MB_YESNO );                 "Created: %s\r\n"
241                  if (rc == IDNO)                 "Expires: %s\r\n"
242                      return FALSE;                 "Validity: %s\r\n"
243              }                 "Cipher: %s\r\n"
244              GetDlgItemText( dlg, IDC_KEYPROPS_OT, info, sizeof info -1 );                 "%s\r\n"),
245              gpgme_editkey_new( &ek );                 get_key_type (key),
246              gpgme_editkey_is_secret( ek, k->key_pair );                 k->keyid,
247              dialog_box_param( glob_hinst, (LPCSTR)IDD_WINPT_KEYEDIT_OWNERTRUST,                 get_key_algo (key, 0),
248                               dlg, (DLGPROC)keyedit_ownertrust_dlg_proc,                 get_key_size (key, 0),
249                               (LPARAM)ek, _("Change Ownertrust"),                 get_key_created (created),
250                               IDS_WINPT_KEYEDIT_OWNERTRUST );                 get_key_expire_date (expires),
251              if (!gpgme_editkey_is_valid (ek))                 get_validity (key),
252                  return FALSE;                 get_pref_cipher (&k2),
253              ec = gpgme_new (&ctx);                 get_card_type (&k2));
254              if (ec)  
255                  BUG (0);      SetDlgItemText (dlg, IDC_KEYPROPS_INFO, info);
256              gpgme_set_edit_ctx( ctx, ek, GPGME_EDITKEY_TRUST );      SetDlgItemText (dlg, IDC_KEYPROPS_FPR, get_key_fpr (key));  
257              ec = gpgme_op_editkey( ctx, k->keyid );      inf = ownertrust_to_string (key->owner_trust);
258              gpgme_editkey_release( ek );      SetDlgItemText (dlg, IDC_KEYPROPS_OT, inf);
259                  gpgme_release( ctx );  
260              if( ec ) {      *r_key = key;
261                  msg_box( dlg, gpgme_strerror( ec ), _("Ownertrust"), MB_ERR );  }
262                  return FALSE;  
263              }  
264              inf = ownertrust_to_string (ek, 0);  /* Dialog box procedure to show the key properties. */
265              k->callback.new_val = keyedit_ownertrust_get_val ();  BOOL CALLBACK
266              do_change_ownertrust (k, inf);  keyprops_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
267              SetDlgItemText (dlg, IDC_KEYPROPS_OT, inf);  {
268              msg_box (dlg, _("Ownertrust successfully changed."), _("GnuPG Status"), MB_OK);      static winpt_key_t k;
269                    static gpgme_key_t key;
270              /* reload only the keylist */      gpgme_validity_t valid;
271              rcs.kr_reload = 1; rcs.kr_update = 1;      refresh_cache_s rcs = {0};
272              rcs.tr_update = 0;      const char *inf;
273              DialogBoxParam( glob_hinst, (LPCSTR)IDD_WINPT_KEYCACHE, dlg,      int rc;
274                              keycache_dlg_proc, (LPARAM)&rcs );      
275              get_seckey (k->keyid, &sk);      /* XXX: static variable (k) prevent that the dialog can
276              if (get_pubkey (k->keyid, &key))              be opened twice. */
277                  BUG (0);      switch (msg) {
278              return TRUE;      case WM_INITDIALOG:
279                        if (!lparam)
280          case IDC_KEYPROPS_CHANGE_PWD:              dlg_fatal_error (dlg, "Could not get dialog param!");
281              keyedit_change_passwd (k, dlg);                  k = (winpt_key_t)lparam;
282              return TRUE;          SetWindowText (dlg, _("Key Properties"));
283            SetDlgItemText (dlg, IDC_KEYPROPS_OT_CHANGE, _("&Change"));
284          case IDC_KEYPROPS_REVOKERS:                  SetDlgItemText (dlg, IDC_KEYPROPS_REVOKERS, _("&Revokers"));
285              dialog_box_param( glob_hinst, (LPCTSTR)IDD_WINPT_KEYREVOKERS, dlg,          SetDlgItemText (dlg, IDC_KEYPROPS_CHANGE_PWD, _("Change &Passwd"));
286                                key_revokers_dlg_proc, (LPARAM)key, _("Key Revokers"),          SetDlgItemText (dlg, IDC_KEYPROPS_OTINF, _("Ownertrust"));
287                                IDS_WINPT_KEY_REVOKERS );  
288              break;          display_key_info (dlg, k, &key);
289          }          if (!keyprops_load_photo (dlg, key, &valid)) {
290      }              k->has_photo = 1;  
291                    if (valid < GPGME_VALIDITY_MARGINAL)
292      return FALSE;                  SetDlgItemText (dlg, IDC_KEYPROPS_IMGINF, _("Photo-ID not validated."));
293  } /* keyprops_dlg_proc */          }
294            if (k->key_pair)
295                EnableWindow (GetDlgItem (dlg, IDC_KEYPROPS_CHANGE_PWD), TRUE);
296            if (check_for_desig_rev (key))
297                EnableWindow (GetDlgItem (dlg, IDC_KEYPROPS_REVOKERS), TRUE);
298            center_window (dlg, NULL);
299            SetForegroundWindow (dlg);      
300            return TRUE;
301    
302        case WM_DESTROY:
303            remove (get_photo_tmpname (dlg));
304            break;
305          
306        case WM_PAINT:
307            if (k->has_photo)
308                keyprops_show_photo (dlg);
309            break;
310    
311        case WM_SYSCOMMAND:
312            if (LOWORD (wparam) == SC_CLOSE)
313                EndDialog (dlg, TRUE);
314            return FALSE;
315            
316        case WM_COMMAND:
317            switch (LOWORD (wparam)) {
318            case IDOK:
319                EndDialog (dlg, TRUE);
320                return TRUE;
321                
322            case IDC_KEYPROPS_OT_CHANGE:
323                if (do_check_key (key)) {
324                    msg_box (dlg, _("The status of this key is 'revoked' or 'expired'.\n"
325                                    "You cannot change the ownertrust of such keys."),
326                                    _("WinPT Warning"), MB_ERR);
327                    return TRUE;
328                }
329                if( !k->key_pair && key->uids->validity < 3 ) {
330                    rc = msg_box( dlg, _("This is a non-valid key.\n"
331                                         "Modifying the ownertrust has no effect on such keys.\n\n"
332                                         "Do you really want to continue?"),
333                                         _("WinPT Warning"), MB_ICONWARNING|MB_YESNO );
334                    if (rc == IDNO)
335                        return TRUE;
336                }
337                dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_KEYEDIT_OWNERTRUST,
338                                  dlg, (DLGPROC)keyedit_ownertrust_dlg_proc,
339                                  (LPARAM)k, _("Change Ownertrust"),
340                                  IDS_WINPT_KEYEDIT_OWNERTRUST);
341                if (k->callback.new_val == -1) { /* Cancel */
342                    EndDialog (dlg, FALSE);
343                    break;
344                }
345    
346                inf = ownertrust_to_string (k->callback.new_val);
347                SetDlgItemText (dlg, IDC_KEYPROPS_OT, inf);
348                msg_box (dlg, _("Ownertrust successfully changed."),
349                         _("GnuPG Status"), MB_OK);
350                
351                /* XXX: modified ownertrust values can effect the entire
352                        WoT so we reload the cache. But this is very slow. */
353                memset (&rcs, 0, sizeof (rcs));
354                rcs.kr_reload = 1; rcs.kr_update = 1; /* reload only keylist */
355                DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_KEYCACHE, dlg,
356                                keycache_dlg_proc, (LPARAM)&rcs);
357                return TRUE;
358                
359            case IDC_KEYPROPS_CHANGE_PWD:
360                keyedit_change_passwd (k, dlg);        
361                return TRUE;
362    
363            case IDC_KEYPROPS_REVOKERS:
364                dialog_box_param (glob_hinst, (LPCTSTR)IDD_WINPT_KEYREVOKERS, dlg,
365                                  key_revokers_dlg_proc, (LPARAM)key,
366                                  _("Key Revokers"), IDS_WINPT_KEY_REVOKERS);
367                break;
368            }
369        }
370        
371        return FALSE;
372    }

Legend:
Removed from v.22  
changed lines
  Added in v.129

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26