QVariant SubkeyListModel::data( const QModelIndex & idx, int role ) const { if ( role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::ToolTipRole ) return QVariant(); const Subkey subkey = this->subkey( idx ); if ( subkey.isNull() ) return QVariant(); switch ( idx.column() ) { case ID: return QString::fromLatin1( subkey.keyID() ); case Type: return Formatting::type( subkey ); case ValidFrom: if ( role == Qt::EditRole ) return Formatting::creationDate( subkey ); else return Formatting::creationDateString( subkey ); case ValidUntil: if ( role == Qt::EditRole ) return Formatting::expirationDate( subkey ); else return Formatting::expirationDateString( subkey ); case Status: return Formatting::validityShort( subkey ); case Bits: return subkey.length(); } return QVariant(); }
QString Formatting::toolTip( const Key & key, int flags ) { if ( flags == 0 || ( key.protocol() != CMS && key.protocol() != OpenPGP ) ) return QString(); const Subkey subkey = key.subkey( 0 ); QString result; if ( flags & Validity ) { if ( key.protocol() == OpenPGP || ( key.keyListMode() & Validate ) ) if ( key.isRevoked() ) result += make_red( i18n( "This certificate has been revoked." ) ); else if ( key.isExpired() ) result += make_red( i18n( "This certificate has expired." ) ); else if ( key.isDisabled() ) result += i18n( "This certificate has been disabled locally." ); else result += i18n( "This certificate is currently valid." ); else result += i18n( "The validity of this certificate cannot be checked at the moment." ); } if ( flags == Validity ) return result; result += QLatin1String( "<table border=\"0\">" ); if ( key.protocol() == CMS ) { if ( flags & SerialNumber ) result += format_row( i18n("Serial number"), key.issuerSerial() ); if ( flags & Issuer ) result += format_row( i18n("Issuer"), key.issuerName() ); } if ( flags & UserIDs ) { const std::vector<UserID> uids = key.userIDs(); if ( !uids.empty() ) result += format_row( key.protocol() == CMS ? i18n("Subject") : i18n("User-ID"), prettyUserID( uids.front() ) ); if ( uids.size() > 1 ) for ( std::vector<UserID>::const_iterator it = uids.begin() + 1, end = uids.end() ; it != end ; ++it ) if ( !it->isRevoked() && !it->isInvalid() ) result += format_row( i18n("a.k.a."), prettyUserID( *it ) ); } if ( flags & ExpiryDates ) result += format_row( i18n("Validity"), subkey.neverExpires() ? i18n( "from %1 until forever", time_t2string( subkey.creationTime() ) ) : i18n( "from %1 through %2", time_t2string( subkey.creationTime() ), time_t2string( subkey.expirationTime() ) ) ); if ( flags & CertificateType ) result += format_row( i18n("Certificate type"), format_keytype( key ) ); if ( flags & CertificateUsage ) result += format_row( i18n("Certificate usage"), format_keyusage( key ) ); if ( flags & Fingerprint ) result += format_row( i18n("Fingerprint"), key.primaryFingerprint() ); result += QLatin1String( "</table><br>" ); return result; }
void Key::setFingerprint(const KeyID& keyID, const QCString &fpr) { Subkey *key; if ((key = getSubkey(keyID)) != 0) { key->setFingerprint(fpr); } else kdDebug(5006) << "Error: Can't set fingerprint. A subkey with key ID 0x" << keyID << " doesn't exist." << endl; }
QString Formatting::validityShort( const Subkey & subkey ) { if ( subkey.isRevoked() ) return i18n("revoked"); if ( subkey.isExpired() ) return i18n("expired"); if ( subkey.isDisabled() ) return i18n("disabled"); if ( subkey.isInvalid() ) return i18n("invalid"); return i18nc("as in good/valid signature", "good"); }
QModelIndex SubkeyListModel::index( const Subkey & subkey, int col ) const { // O(N), but not sorted, so no better way... for ( unsigned int row = 0, end = d->key.numSubkeys() ; row != end ; ++row ) if ( qstricmp( subkey.keyID(), d->key.subkey( row ).keyID() ) == 0 ) return index( row, col ); return QModelIndex(); }
void ChangeExpiryCommand::doStart() { const std::vector<Key> keys = d->keys(); if ( keys.size() != 1 || keys.front().protocol() != GpgME::OpenPGP || !keys.front().hasSecret() || keys.front().subkey(0).isNull() ) { d->finished(); return; } d->key = keys.front(); d->ensureDialogCreated(); assert( d->dialog ); const Subkey subkey = d->key.subkey(0); d->dialog->setDateOfExpiry( subkey.neverExpires() ? QDate() : QDateTime::fromTime_t( d->key.subkey(0).expirationTime() ).date() ); d->dialog->show(); }
QString Formatting::type( const Subkey & subkey ) { return QString::fromUtf8( subkey.publicKeyAlgorithmAsString() ); }
Key * BaseG::parseKeyData(const QCString &output, int &offset, Key *key /* = 0 */) // This function parses the data for a single key which is output by GnuPG // with the following command line arguments: // --batch --list-public-keys --with-fingerprint --with-colons // --fixed-list-mode [--no-expensive-trust-checks] // It expects the key data to start at offset and returns the start of // the next key's data in offset. // Subkeys are currently ignored. { int index = offset; if((strncmp(output.data() + offset, "pub:", 4) != 0) && (strncmp(output.data() + offset, "sec:", 4) != 0)) { return 0; } if(key == 0) key = new Key(); else key->clear(); QCString keyID; bool firstKey = true; while(true) { int eol; // search the end of the current line if((eol = output.find('\n', index)) == -1) break; bool bIsPublicKey = false; if((bIsPublicKey = !strncmp(output.data() + index, "pub:", 4)) || !strncmp(output.data() + index, "sec:", 4)) { // line contains primary key data // Example: pub:f:1024:17:63CB691DFAEBD5FC:860451781::379:-:::scESC: // abort parsing if we found the start of the next key if(!firstKey) break; firstKey = false; key->setSecret(!bIsPublicKey); Subkey *subkey = new Subkey(QCString(), !bIsPublicKey); int pos = index + 4; // begin of 2nd field int pos2 = output.find(':', pos); for(int field = 2; field <= 12; field++) { switch(field) { case 2: // the calculated trust if(pos2 > pos) { switch(output[pos]) { case 'o': // unknown (this key is new to the system) break; case 'i': // the key is invalid, e.g. missing self-signature subkey->setInvalid(true); key->setInvalid(true); break; case 'd': // the key has been disabled subkey->setDisabled(true); key->setDisabled(true); break; case 'r': // the key has been revoked subkey->setRevoked(true); key->setRevoked(true); break; case 'e': // the key has expired subkey->setExpired(true); key->setExpired(true); break; case '-': // undefined (no path leads to the key) case 'q': // undefined (no trusted path leads to the key) case 'n': // don't trust this key at all case 'm': // the key is marginally trusted case 'f': // the key is fully trusted case 'u': // the key is ultimately trusted (secret key available) // These values are ignored since we determine the key trust // from the trust values of the user ids. break; default: kdDebug(5100) << "Unknown trust value\n"; } } break; case 3: // length of key in bits if(pos2 > pos) subkey->setKeyLength(output.mid(pos, pos2 - pos).toUInt()); break; case 4: // the key algorithm if(pos2 > pos) subkey->setKeyAlgorithm(output.mid(pos, pos2 - pos).toUInt()); break; case 5: // the long key id keyID = output.mid(pos, pos2 - pos); subkey->setKeyID(keyID); break; case 6: // the creation date (in seconds since 1970-01-01 00:00:00) if(pos2 > pos) subkey->setCreationDate(output.mid(pos, pos2 - pos).toLong()); break; case 7: // the expiration date (in seconds since 1970-01-01 00:00:00) if(pos2 > pos) subkey->setExpirationDate(output.mid(pos, pos2 - pos).toLong()); else subkey->setExpirationDate(-1); // key expires never break; case 8: // local ID (ignored) case 9: // Ownertrust (ignored for now) case 10: // User-ID (always empty in --fixed-list-mode) case 11: // signature class (always empty except for key signatures) break; case 12: // key capabilities for(int i = pos; i < pos2; i++) switch(output[i]) { case 'e': subkey->setCanEncrypt(true); break; case 's': subkey->setCanSign(true); break; case 'c': subkey->setCanCertify(true); break; case 'E': key->setCanEncrypt(true); break; case 'S': key->setCanSign(true); break; case 'C': key->setCanCertify(true); break; default: kdDebug(5100) << "Unknown key capability\n"; } break; } pos = pos2 + 1; pos2 = output.find(':', pos); } key->addSubkey(subkey); } else if(!strncmp(output.data() + index, "uid:", 4)) { // line contains a user id // Example: uid:f::::::::Philip R. Zimmermann <*****@*****.**>: UserID *userID = new UserID(""); int pos = index + 4; // begin of 2nd field int pos2 = output.find(':', pos); for(int field = 2; field <= 10; field++) { switch(field) { case 2: // the calculated trust if(pos2 > pos) { switch(output[pos]) { case 'i': // the user id is invalid, e.g. missing self-signature userID->setInvalid(true); break; case 'r': // the user id has been revoked userID->setRevoked(true); break; case '-': // undefined (no path leads to the key) case 'q': // undefined (no trusted path leads to the key) userID->setValidity(KPGP_VALIDITY_UNDEFINED); break; case 'n': // don't trust this key at all userID->setValidity(KPGP_VALIDITY_NEVER); break; case 'm': // the key is marginally trusted userID->setValidity(KPGP_VALIDITY_MARGINAL); break; case 'f': // the key is fully trusted userID->setValidity(KPGP_VALIDITY_FULL); break; case 'u': // the key is ultimately trusted (secret key available) userID->setValidity(KPGP_VALIDITY_ULTIMATE); break; default: kdDebug(5100) << "Unknown trust value\n"; } } break; case 3: // these fields are empty case 4: case 5: case 6: case 7: case 8: case 9: break; case 10: // User-ID QCString uid = output.mid(pos, pos2 - pos); // replace "\xXX" with the corresponding character; // other escaped characters, i.e. \n, \r etc., are ignored // because they shouldn't appear in user IDs for(int idx = 0 ; (idx = uid.find("\\x", idx)) >= 0 ; ++idx) { char str[2] = "x"; str[0] = (char) QString(uid.mid(idx + 2, 2)).toShort(0, 16); uid.replace(idx, 4, str); } QString uidString = QString::fromUtf8(uid.data()); // check whether uid was utf-8 encoded bool isUtf8 = true; for(unsigned int i = 0; i + 1 < uidString.length(); ++i) { if(uidString[i].unicode() == 0xdbff && uidString[i + 1].row() == 0xde) { // we found a non-Unicode character (see QString::fromUtf8()) isUtf8 = false; break; } } if(!isUtf8) { // The user id isn't utf-8 encoded. It was most likely // created with PGP which either used latin1 or koi8-r. kdDebug(5100) << "User Id '" << uid << "' doesn't seem to be utf-8 encoded." << endl; // We determine the ratio between non-ASCII and ASCII chars. // A koi8-r user id should have lots of non-ASCII chars. int nonAsciiCount = 0, asciiCount = 0; // We only look at the first part of the user id (i. e. everything // before the email address resp. before a comment) for(signed char *ch = (signed char *)uid.data(); *ch && (*ch != '(') && (*ch != '<'); ++ch) { if(((*ch >= 'A') && (*ch <= 'Z')) || ((*ch >= 'a') && (*ch <= 'z'))) ++asciiCount; else if(*ch < 0) ++nonAsciiCount; } kdDebug(5100) << "ascii-nonAscii ratio : " << asciiCount << ":" << nonAsciiCount << endl; if(nonAsciiCount > asciiCount) { // assume koi8-r encoding kdDebug(5100) << "Assume koi8-r encoding." << endl; QTextCodec *codec = QTextCodec::codecForName("KOI8-R"); uidString = codec->toUnicode(uid.data()); // check the case of the first two characters to find out // whether the user id is probably CP1251 encoded (for some // reason in CP1251 the lower case characters have smaller // codes than the upper case characters, so if the first char // of the koi8-r decoded user id is lower case and the second // char is upper case then it's likely that the user id is // CP1251 encoded) if((uidString.length() >= 2) && (uidString[0].lower() == uidString[0]) && (uidString[1].upper() == uidString[1])) { // koi8-r decoded user id has inverted case, so assume // CP1251 encoding kdDebug(5100) << "No, it doesn't seem to be koi8-r. " "Use CP 1251 instead." << endl; QTextCodec *codec = QTextCodec::codecForName("CP1251"); uidString = codec->toUnicode(uid.data()); } } else { // assume latin1 encoding kdDebug(5100) << "Assume latin1 encoding." << endl; uidString = QString::fromLatin1(uid.data()); } } userID->setText(uidString); break; } pos = pos2 + 1; pos2 = output.find(':', pos); } // user IDs are printed in UTF-8 by gpg (if one uses --with-colons) key->addUserID(userID); } else if(!strncmp(output.data() + index, "fpr:", 4)) { // line contains a fingerprint // Example: fpr:::::::::17AFBAAF21064E513F037E6E63CB691DFAEBD5FC: if(key == 0) // invalid key data break; // search the fingerprint (it's in the 10th field) int pos = index + 4; for(int i = 0; i < 8; i++) pos = output.find(':', pos) + 1; int pos2 = output.find(':', pos); key->setFingerprint(keyID, output.mid(pos, pos2 - pos)); } index = eol + 1; } //kdDebug(5100) << "finished parsing key data\n"; offset = index; return key; }