Bug #3461403 Error when create certificate with CRL distribution point

become more userfriendly:
 - by indicating the validity with an appropriate
   icon in front of AIA, SAN IAN and CDP.

 - by checking the validity before creating the real certificate.

 - by improving the edit button, to automatically add an "URI"
   as type, if the type is missing, or is for example "http"
This commit is contained in:
Christian Hohnstaedt 2012-04-01 12:15:14 +02:00
parent 5f4d3e1084
commit a9b5caa0bc
10 changed files with 329 additions and 177 deletions

View File

@ -22,5 +22,6 @@
<file>validcertkey.png</file>
<file>validcert.png</file>
<file>done.png</file>
<file>warn.png</file>
</qresource>
</RCC>

BIN
img/warn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -562,12 +562,6 @@ If this list is disabled, you only can create a self-signed certificate.</string
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>200</number>
</attribute>
</widget>
</item>
<item>
@ -925,24 +919,53 @@ It also copies the issuer and serial number from the issuer certificate. Normall
</spacer>
</item>
<item>
<layout class="QGridLayout" name="_8">
<item row="3" column="0">
<widget class="QLabel" name="TextLabel1_2_3_2_2_3">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="TextLabel1_2_2_3">
<property name="toolTip">
<string>Authority Info Access</string>
<string>subject alternative name</string>
</property>
<property name="text">
<string notr="true">Authority Info Access</string>
<string notr="true">subject alternative name</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="TextLabel1_2_3_2_3">
<property name="toolTip">
<string>CRL distribution point</string>
<item row="0" column="1">
<widget class="QLabel" name="subAltIco">
<property name="minimumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="text">
<string notr="true">CRL distribution point</string>
<string/>
</property>
</widget>
</item>
<item row="0" column="2" colspan="2">
<widget class="QLineEdit" name="subAltName">
<property name="toolTip">
<string>DNS: IP: URI: email: RID:</string>
</property>
<property name="whatsThis">
<string>The subject alternative name extension allows various literal values to be used. These include &quot;email&quot; (an email address) , &quot;URI&quot; a uniform resource indicator, &quot;DNS&quot; (a DNS domain name) , RID (a registered ID: OBJECT IDENTIFIER) and IP (an IP address).
Examples:
email:my@other.address, IP: 1.1.1.1 , URI:http://my.url.here/
email:my@other.address, RID:1.2.3.4, DNS: ns.server.tld</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="editSubAlt">
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
@ -956,7 +979,56 @@ It also copies the issuer and serial number from the issuer certificate. Normall
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<item row="1" column="2" colspan="2">
<widget class="QLineEdit" name="issAltName">
<property name="toolTip">
<string>DNS: IP: URI: email: RID:</string>
</property>
<property name="whatsThis">
<string>The issuer alternative name extension allows various literal values to be used. These include &quot;email&quot; (an email address) , &quot;URI&quot; a uniform resource indicator, &quot;DNS&quot; (a DNS domain name), RID (a registered ID: OBJECT IDENTIFIER) and IP (an IP address).
Examples:
email:my@other.address, IP: 1.1.1.1 , URI:http://my.url.here/
email:my@other.address, RID:1.2.3.4, DNS: ns.server.tld</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="editIssAlt">
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="TextLabel1_2_3_2_3">
<property name="toolTip">
<string>CRL distribution point</string>
</property>
<property name="text">
<string notr="true">CRL distribution point</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="crlDistIco">
<property name="minimumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="2" colspan="2">
<widget class="QLineEdit" name="crlDist">
<property name="toolTip">
<string>URI:</string>
@ -972,28 +1044,50 @@ URI:http://www.my.com/my.crl, URI:http://www.oth.com/my.crl</string>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QPushButton" name="editCrlDist">
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="TextLabel1_2_3_2_2_3">
<property name="toolTip">
<string>Authority Info Access</string>
</property>
<property name="text">
<string notr="true">Authority Info Access</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="authInfAccIco">
<property name="minimumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QComboBox" name="aiaOid">
<property name="toolTip">
<string>can be altered by the file &quot;aia.txt&quot;</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="editSubAlt">
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="editIssAlt">
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item row="3" column="2">
<item row="3" column="3">
<widget class="QLineEdit" name="authInfAcc">
<property name="toolTip">
<string>DNS: IP: URI: email: RID:</string>
@ -1008,53 +1102,29 @@ caIssuers;URI:http://my.ca/ca.html</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="subAltName">
<property name="toolTip">
<string>DNS: IP: URI: email: RID:</string>
</property>
<property name="whatsThis">
<string>The subject alternative name extension allows various literal values to be used. These include &quot;email&quot; (an email address) , &quot;URI&quot; a uniform resource indicator, &quot;DNS&quot; (a DNS domain name) , RID (a registered ID: OBJECT IDENTIFIER) and IP (an IP address).
Examples:
email:my@other.address, IP: 1.1.1.1 , URI:http://my.url.here/
email:my@other.address, RID:1.2.3.4, DNS: ns.server.tld</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="editCrlDist">
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="TextLabel1_2_2_3">
<property name="toolTip">
<string>subject alternative name</string>
</property>
<property name="text">
<string notr="true">subject alternative name</string>
</property>
</widget>
</item>
<item row="3" column="3">
<item row="3" column="4">
<widget class="QPushButton" name="editAuthInfAcc">
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QLineEdit" name="issAltName">
<property name="toolTip">
<string>DNS: IP: URI: email: RID:</string>
<item row="1" column="1">
<widget class="QLabel" name="issAltIco">
<property name="minimumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="whatsThis">
<string>The issuer alternative name extension allows various literal values to be used. These include &quot;email&quot; (an email address) , &quot;URI&quot; a uniform resource indicator, &quot;DNS&quot; (a DNS domain name), RID (a registered ID: OBJECT IDENTIFIER) and IP (an IP address).
Examples:
email:my@other.address, IP: 1.1.1.1 , URI:http://my.url.here/
email:my@other.address, RID:1.2.3.4, DNS: ns.server.tld</string>
<property name="maximumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>

View File

@ -41,7 +41,7 @@ QPixmap *MainWindow::keyImg = NULL, *MainWindow::csrImg = NULL,
*MainWindow::certImg = NULL, *MainWindow::tempImg = NULL,
*MainWindow::nsImg = NULL, *MainWindow::revImg = NULL,
*MainWindow::appIco = NULL, *MainWindow::scardImg = NULL,
*MainWindow::doneIco = NULL;
*MainWindow::doneIco = NULL, *MainWindow::warnIco = NULL;
db_key *MainWindow::keys = NULL;
db_x509req *MainWindow::reqs = NULL;
@ -270,6 +270,7 @@ void MainWindow::init_images()
scardImg = loadImg("bigscard.png");
appIco = loadImg("key.xpm");
doneIco = loadImg("done.png");
warnIco = loadImg("warn.png");
bigKey->setPixmap(*keyImg);
bigCsr->setPixmap(*csrImg);
bigCert->setPixmap(*certImg);

View File

@ -57,7 +57,7 @@ class MainWindow: public QMainWindow, public Ui::MainWindow
static db_crl *crls;
static QPixmap *keyImg, *csrImg, *certImg, *tempImg,
*nsImg, *revImg, *appIco, *scardImg,
*doneIco;
*doneIco, *warnIco;
static NIDlist *eku_nid, *dn_nid, *aia_nid;
static QString mandatory_dn;
int exitApp;

View File

@ -60,6 +60,15 @@ NewX509::NewX509(QWidget *parent)
connect(extDNlist->itemDelegateForColumn(1),
SIGNAL(setupLineEdit(const QString &, QLineEdit *)),
this, SLOT(setupExtDNwidget(const QString &, QLineEdit *)));
connect(subAltName, SIGNAL(textChanged(const QString &)),
this, SLOT(checkSubAltName(const QString &)));
connect(issAltName, SIGNAL(textChanged(const QString &)),
this, SLOT(checkIssAltName(const QString &)));
connect(crlDist, SIGNAL(textChanged(const QString &)),
this, SLOT(checkCrlDist(const QString &)));
connect(authInfAcc, SIGNAL(textChanged(const QString &)),
this, SLOT(checkAuthInfAcc(const QString &)));
setWindowTitle(XCA_TITLE);
for (i=0; i<tabWidget->count(); i++) {
@ -724,80 +733,163 @@ void NewX509::editV3ext(QLineEdit *le, QString types, int n)
void NewX509::on_adv_validate_clicked()
{
if (!nconf_data->isReadOnly()) {
QString errtxt;
extList el;
ign_openssl_error();
QString result;
setupTmpCtx();
v3ext_backup = nconf_data->toPlainText();
if (fromReqCB->isChecked() && copyReqExtCB->isChecked()) {
el = getSelectedReq()->getV3ext();
}
if (el.size() > 0) {
result = "<h2><center>";
result += tr("From PKCS#10 request") +
"</center></h2><p>\n";
result += el.getHtml("<br>");
}
try {
el = getGuiExt();
el += getNetscapeExt();
el.delInvalid();
} catch (errorEx &err) {
errtxt = err.getString();
el.clear();
}
if (el.size() > 0) {
if (!result.isEmpty())
result += "\n<hr>\n";
result += "<h2><center>";
result += tr("Other Tabs") + "</center></h2><p>\n";
result += el.getHtml("<br>");
}
try {
el = getAdvanced();
} catch (errorEx &err) {
errtxt += err.getString();
el.clear();
}
if (el.size() > 0) {
if (!result.isEmpty())
result += "\n<hr>\n";
result += "<h2><center>";
result += tr("Advanced Tab") + "</center></h2><p>\n";
result += el.getHtml("<br>");
}
if (!errtxt.isEmpty()) {
if (!result.isEmpty())
result += "\n<hr>\n";
result += "<h2><center>";
result += tr("Errors") + "</center></h2><p>\n";
result += errtxt;
}
nconf_data->document()->setHtml(result);
nconf_data->setReadOnly(true);
adv_validate->setText(tr("Edit"));
valid_htmltext = result;
checkExtDuplicates();
/* switch from edit to display mode */
do_validateExtensions();
} else {
nconf_data->document()->setPlainText(v3ext_backup);
nconf_data->setReadOnly(false);
adv_validate->setText(tr("Validate"));
valid_htmltext = "";
/* switch back to edit mode */
undo_validateExtensions();
}
}
void NewX509::checkIcon(const QString &text, int nid, QLabel *img)
{
if (text.isEmpty()) {
img->clear();
return;
}
ign_openssl_error();
switch (nid) {
case NID_subject_alt_name:
getSubAltName();
break;
case NID_issuer_alt_name:
getIssAltName();
break;
case NID_crl_distribution_points:
getCrlDist();
break;
case NID_info_access:
getAuthInfAcc();
break;
}
if (ign_openssl_error()) {
img->setPixmap(*MainWindow::warnIco);
return;
}
img->setPixmap(*MainWindow::doneIco);
}
void NewX509::checkSubAltName(const QString & text)
{
checkIcon(text, NID_subject_alt_name, subAltIco);
}
void NewX509::checkIssAltName(const QString & text)
{
checkIcon(text, NID_issuer_alt_name, issAltIco);
}
void NewX509::checkCrlDist(const QString & text)
{
checkIcon(text, NID_crl_distribution_points, crlDistIco);
}
void NewX509::checkAuthInfAcc(const QString & text)
{
checkIcon(text, NID_info_access, authInfAccIco);
}
int NewX509::do_validateExtensions()
{
QString result;
int ret = 0;
if (!nconf_data->isReadOnly()) {
v3ext_backup = nconf_data->toPlainText();
}
ret = validateExtensions(v3ext_backup, result);
nconf_data->document()->setHtml(result);
nconf_data->setReadOnly(true);
adv_validate->setText(tr("Edit"));
return ret;
}
void NewX509::undo_validateExtensions()
{
if (nconf_data->isReadOnly()) {
nconf_data->document()->setPlainText(v3ext_backup);
}
nconf_data->setReadOnly(false);
adv_validate->setText(tr("Validate"));
}
int NewX509::validateExtensions(QString nconf, QString &result)
{
int ret = 0;
QStringList errors;
extList el;
ign_openssl_error();
setupTmpCtx();
if (fromReqCB->isChecked() && copyReqExtCB->isChecked()) {
el = getSelectedReq()->getV3ext();
}
if (el.size() > 0) {
result = "<h2><center>";
result += tr("From PKCS#10 request") +"</center></h2><p>\n";
result += el.getHtml("<br>");
}
try {
el = getGuiExt();
el += getNetscapeExt();
el.delInvalid();
} catch (errorEx &err) {
errors += err.getString();
el.clear();
}
if (el.size() > 0) {
if (!result.isEmpty())
result += "\n<hr>\n";
result += "<h2><center>";
result += tr("Other Tabs") + "</center></h2><p>\n";
result += el.getHtml("<br>");
}
try {
el = getAdvanced();
} catch (errorEx &err) {
errors += err.getString();
el.clear();
}
if (el.size() > 0) {
if (!result.isEmpty())
result += "\n<hr>\n";
result += "<h2><center>";
result += tr("Advanced Tab") + "</center></h2><p>\n";
result += el.getHtml("<br>");
}
if (errors.size()) {
if (!result.isEmpty())
result += "\n<hr>\n";
result += "<h2><center>";
result += tr("Errors") + "</center></h2><p><ul><li>\n";
result += errors.join("</li><li>\n");
result += "</li></ul>";
ret = 1;
}
el = getExtDuplicates();
if (el.size() > 0) {
QString errtxt;
ret = 1;
errtxt = "<h2><center><font color=\"red\">Error:</font>"
"duplicate extensions:</center></h2><p><ul>\n";
for(int i = 0; i< el.size(); i++) {
errtxt += "<li>" +el[i].getObject() +"</li>\n";
}
errtxt += "</ul>\n<hr>\n";
result = errtxt + result;
}
ign_openssl_error();
return ret;
}
void NewX509::on_editSubAlt_clicked()
{
QString s = "email,RID,URI,DNS,IP,otherName";
QString s = "URI,email,RID,DNS,IP,otherName";
editV3ext(subAltName, s, NID_subject_alt_name);
}
void NewX509::on_editIssAlt_clicked()
{
QString s = "email,RID,URI,DNS,IP,otherName,issuer";
QString s = "URI,email,RID,DNS,IP,otherName,issuer";
editV3ext(issAltName, s, NID_issuer_alt_name);
}
@ -808,14 +900,13 @@ void NewX509::on_editCrlDist_clicked()
void NewX509::on_editAuthInfAcc_clicked()
{
editV3ext(authInfAcc, "email,RID,URI,DNS,IP", NID_info_access);
editV3ext(authInfAcc, "URI,email,RID,DNS,IP", NID_info_access);
}
void NewX509::on_tabWidget_currentChanged(int)
void NewX509::on_tabWidget_currentChanged(int tab)
{
/* reset advanced tab to editable text */
if (nconf_data->isReadOnly())
on_adv_validate_clicked();
if (tabWidget->tabText(tab) == tabnames[5])
do_validateExtensions();
}
QString NewX509::mandatoryDnRemain()
@ -1038,10 +1129,9 @@ void NewX509::accept()
break;
}
}
on_adv_validate_clicked();
if (checkExtDuplicates()) {
if (do_validateExtensions()) {
gotoTab(5);
QString text = tr("The certificate contains duplicated extensions. Check the validation on the advanced tab.");
QString text = tr("The certificate contains invalid or duplicate extensions. Check the validation on the advanced tab.");
QMessageBox msg(QMessageBox::Warning, XCA_TITLE,
text, QMessageBox::NoButton, this);
msg.addButton(QMessageBox::Ok)->setText(tr("Edit extensions"));

View File

@ -47,8 +47,9 @@ class NewX509: public QDialog, public Ui::NewX509
QStringList private_keys, private_keys0, tabnames;
pki_x509 *ctx_cert;
QString v3ext_backup;
QString valid_htmltext;
kvmodel *extDNmodel;
extList getExtDuplicates();
void checkIcon(const QString &text, int nid, QLabel*img);
public:
static int name_nid[EXPLICIT_NAME_CNT];
@ -97,6 +98,9 @@ class NewX509: public QDialog, public Ui::NewX509
pki_temp *currentTemplate();
void gotoTab(int tab);
void setupLineEditByNid(int nid, QLineEdit *l);
int validateExtensions(QString nconf, QString &result);
int do_validateExtensions();
void undo_validateExtensions();
public slots:
void on_fromReqCB_clicked();
@ -121,6 +125,10 @@ class NewX509: public QDialog, public Ui::NewX509
void on_reqSubChange_clicked();
void accept();
void setupExtDNwidget(const QString &s, QLineEdit *w);
void checkSubAltName(const QString & text);
void checkIssAltName(const QString & text);
void checkCrlDist(const QString & text);
void checkAuthInfAcc(const QString & text);
signals:
void genKey(QString);

View File

@ -36,7 +36,6 @@ x509v3ext NewX509::getBasicConstraints()
}
ext.create(NID_basic_constraints, cont.join(", "), &ext_ctx);
}
openssl_error();
return ext;
}
@ -45,7 +44,6 @@ x509v3ext NewX509::getSubKeyIdent()
x509v3ext ext;
if (subKey->isChecked())
ext.create(NID_subject_key_identifier, "hash", &ext_ctx);
openssl_error();
return ext;
}
@ -63,7 +61,6 @@ x509v3ext NewX509::getAuthKeyIdent()
x = "keyid:always,issuer:always";
}
ext.create(NID_authority_key_identifier, x, &ext_ctx);
openssl_error();
return ext;
}
@ -87,7 +84,6 @@ x509v3ext NewX509::getKeyUsage()
if (kuCritical->isChecked() && cont.count() > 0)
cont.prepend("critical");
ext.create(NID_key_usage, cont.join(", "), &ext_ctx);
openssl_error();
return ext;
}
@ -107,7 +103,6 @@ x509v3ext NewX509::getEkeyUsage()
if (ekuCritical->isChecked() && cont.count() > 0)
cont.prepend("critical");
ext.create(NID_ext_key_usage, cont.join(", "), &ext_ctx);
openssl_error();
return ext;
}
@ -124,7 +119,6 @@ x509v3ext NewX509::getSubAltName()
s = sn.join(",");
}
ext.create(NID_subject_alt_name, s, &ext_ctx);
openssl_error();
return ext;
}
@ -141,7 +135,6 @@ x509v3ext NewX509::getIssAltName()
s = sn.join(",");
}
ext.create(NID_issuer_alt_name, s, &ext_ctx);
openssl_error();
return ext;
}
@ -151,7 +144,6 @@ x509v3ext NewX509::getCrlDist()
if (!crlDist->text().isEmpty()) {
ext.create(NID_crl_distribution_points, crlDist->text(), &ext_ctx);
}
openssl_error();
return ext;
}
@ -195,7 +187,6 @@ x509v3ext NewX509::getAuthInfAcc()
if (!aia_txt.isEmpty()) {
ext.create(NID_info_access, aia_txt, &ext_ctx);
}
openssl_error();
return ext;
}
@ -211,9 +202,10 @@ extList NewX509::getAdvanced()
int ret, start;
if (nconf_data->isReadOnly()) {
on_adv_validate_clicked();
conf_str = v3ext_backup;
} else {
conf_str = nconf_data->toPlainText();
}
conf_str = nconf_data->toPlainText();
if (conf_str.isEmpty())
return elist;
@ -266,6 +258,7 @@ extList NewX509::getGuiExt()
ne << getIssAltName();
ne << getCrlDist();
ne << getAuthInfAcc();
openssl_error();
return ne;
}
@ -319,7 +312,7 @@ void NewX509::initCtx(pki_x509 *subj, pki_x509 *iss, pki_x509req *req)
X509V3_set_ctx(&ext_ctx, s, s1, r, NULL, 0);
}
int NewX509::checkExtDuplicates()
extList NewX509::getExtDuplicates()
{
int i, start, cnt, n1, n;
x509v3ext e;
@ -330,7 +323,7 @@ int NewX509::checkExtDuplicates()
if (ext_ctx.subject_cert) {
sk = ext_ctx.subject_cert->cert_info->extensions;
} else
return 0;
return el_dup;
el.setStack(sk, 0);
if (fromReqCB->isChecked() && copyReqExtCB->isChecked()) {
@ -351,23 +344,7 @@ int NewX509::checkExtDuplicates()
}
}
}
if (el_dup.size() <= 0)
return 0;
tabWidget->setCurrentIndex(tabWidget->count() -1);
if (!nconf_data->isReadOnly()) {
on_adv_validate_clicked();
}
olist = "<h2><center><font color=\"red\">Error:</font> "
"duplicate extensions:</center></h2><p><ul>\n";
for(int i = 0; i< el_dup.size(); i++) {
olist += "<li>" + el_dup[i].getObject() + "</li>\n";
}
olist += "</ul>\n<hr>\n";
olist += valid_htmltext;
nconf_data->document()->setHtml(olist);
return el_dup.size();
return el_dup;
}
void NewX509::setExt(const x509v3ext &ext)

View File

@ -61,6 +61,7 @@ void v3ext::addInfo(QLineEdit *myle, const QStringList &sl, int n,
le = myle;
ext_ctx = ctx;
tab->setKeys(sl);
keys = sl;
tab->setInfoLabel(infoLabel);
connect(tab->itemDelegateForColumn(1),
SIGNAL(setupLineEdit(const QString &, QLineEdit *)),
@ -127,12 +128,15 @@ void v3ext::addEntry(QString line)
int idx = line.indexOf(':');
QString type, value;
if (idx == -1) {
type = line;
value = "";
value = line;
} else {
type = line.left(idx);
value = line.mid(idx+1);
}
if (!keys.contains(type)) {
type = keys[0];
value = line;
}
tab->addRow(QStringList(type) << value);
}

View File

@ -26,6 +26,7 @@ class v3ext: public QDialog, public Ui::v3ext
int nid;
X509V3_CTX *ext_ctx;
bool __validate(bool showSuccess);
QStringList keys;
public:
v3ext( QWidget *parent);
void addItem(QString list);