Kennwortmanager KeePassX Weiterentwicklung der Version 1
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 
 
 
 
keepassx1/src/lib/AutoType_X11.cpp

665 lines
18 KiB

/***************************************************************************
* Copyright (C) 2005-2006 by Tarek Saidi, Felix Geyer *
* tarek.saidi@arcor.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; version 2 of the License. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <QX11Info>
#include <X11/Xutil.h>
#include "mainwindow.h"
#include "HelperX11.h"
#include "AutoType.h"
#ifdef GLOBAL_AUTOTYPE
#include "dialogs/AutoTypeDlg.h"
#endif
enum AutoTypeActionType{
TypeKey, Delay
};
struct AutoTypeAction{
AutoTypeAction(AutoTypeActionType t, quint16 d);
AutoTypeActionType type;
quint16 data;
};
class AutoTypePrivate{
public:
static void sleep(int msec);
inline static void sleepKeyStrokeDelay(){ sleep(config->autoTypeKeyStrokeDelay()); };
static void templateToKeysyms(const QString& Template, QList<AutoTypeAction>& KeySymList,IEntryHandle* entry);
static void stringToKeysyms(const QString& string,QList<AutoTypeAction>& KeySymList);
static QString getRootGroupName(IEntryHandle* entry);
};
// AutoType
KeepassMainWindow* AutoType::MainWin=NULL;
#ifdef GLOBAL_AUTOTYPE
Shortcut AutoType::shortcut;
#endif
void AutoType::perform(IEntryHandle* entry, QString& err,bool hideWindow,int nr,bool wasLocked){
QString indexStr;
if (nr==0)
indexStr = "Auto-Type:";
else
indexStr = QString("Auto-Type-%1:").arg(nr);
QString str;
QString comment=entry->comment();
int c=comment.count(indexStr, Qt::CaseInsensitive);
if(c>1){
err=QCoreApplication::translate("AutoType","More than one 'Auto-Type:' key sequence found.\nAllowed is only one per entry.");
return;
}
else if(c==1){
int start = comment.indexOf(indexStr,0,Qt::CaseInsensitive) + indexStr.length();
int end = comment.indexOf("\n", start);
if (end == -1)
end = comment.length();
str=comment.mid(start,end-start).trimmed();
if (str.isEmpty())
return;
}
else
str="{USERNAME}{TAB}{PASSWORD}{ENTER}";
QList<AutoTypeAction> Keys;
for(int i=0;i<str.size();i++){
if(str[i]=='{'){
QString tmpl;
i++;
while(str[i]!='}' && i<str.size()){
tmpl += str[i];
i++;
}
if(i>=str.size()){
err=QCoreApplication::translate("AutoType","Syntax Error in Auto-Type sequence near character %1\n\
Found '{' without closing '}'").arg(i+10);
return;
}
AutoTypePrivate::templateToKeysyms(tmpl.toLower(),Keys,entry);
continue;
}
else{
Keys << AutoTypeAction(TypeKey, HelperX11::getKeysym(str[i]));
}
}
if (hideWindow)
MainWin->hide();
AutoTypePrivate::sleep(config->autoTypePreGap());
Display* pDisplay = QX11Info::display();
bool capsEnabled = HelperX11::keyboardModifiers(pDisplay)&LockMask;
if (capsEnabled){
XTestFakeKeyEvent(pDisplay,XKeysymToKeycode(pDisplay,XK_Caps_Lock),true,0);
XTestFakeKeyEvent(pDisplay,XKeysymToKeycode(pDisplay,XK_Caps_Lock),false,0);
AutoTypePrivate::sleepKeyStrokeDelay();
}
char keys_return[32];
XQueryKeymap(pDisplay, keys_return);
for (int i=0; i<32; i++)
for (int j=0; j<8; j++)
if ( keys_return[i] & (1<<j) ){
XTestFakeKeyEvent(pDisplay,i*8+j,false,2);
AutoTypePrivate::sleepKeyStrokeDelay();
}
for(int i=0;i<Keys.size();i++){
if (Keys[i].type==TypeKey){
int keycode=XKeysymToKeycode(pDisplay,Keys[i].data);
if (keycode==0){
err = QCoreApplication::translate("AutoType","Auto-Type string contains invalid characters");
break;
}
int mods=HelperX11::getModifiers(pDisplay,Keys[i].data,keycode);
HelperX11::pressModifiers(pDisplay,mods);
AutoTypePrivate::sleepKeyStrokeDelay();
XTestFakeKeyEvent(pDisplay,keycode,True,0);
AutoTypePrivate::sleepKeyStrokeDelay();
XTestFakeKeyEvent(pDisplay,keycode,False,1);
AutoTypePrivate::sleepKeyStrokeDelay();
HelperX11::releaseModifiers(pDisplay,mods);
AutoTypePrivate::sleepKeyStrokeDelay();
}
else if (Keys[i].type==Delay){
QApplication::processEvents();
AutoTypePrivate::sleep(Keys[i].data);
}
}
if (capsEnabled){
XTestFakeKeyEvent(pDisplay,XKeysymToKeycode(pDisplay,XK_Caps_Lock),true,0);
XTestFakeKeyEvent(pDisplay,XKeysymToKeycode(pDisplay,XK_Caps_Lock),false,0);
}
if (config->lockOnMinimize()){
if (hideWindow || wasLocked){
if ( !(config->showSysTrayIcon() && config->minimizeTray()) )
MainWin->showMinimized();
else
MainWin->OnUnLockWorkspace();
}
}
else{
if (hideWindow && !(config->showSysTrayIcon() && config->minimizeTray()) )
MainWin->showMinimized();
if (wasLocked)
MainWin->OnUnLockWorkspace();
}
}
#ifdef GLOBAL_AUTOTYPE
Window windowRoot;
//QSet<QString> windowBlacklist;
QSet<QString> classBlacklist;
Atom wm_state;
void windowTitles(Window window, QStringList& titleList){
Display* d = QX11Info::display();
Atom type = None;
int format;
unsigned long nitems, after;
unsigned char* data;
XGetWindowProperty(d, window, wm_state, 0, 0, false, AnyPropertyType, &type, &format, &nitems, &after, &data);
if (type){
XTextProperty textProp;
if (XGetWMName(d, window, &textProp) != 0) {
char** list = NULL;
int count;
if (Xutf8TextPropertyToTextList(d, &textProp, &list, &count)>=0 && list){
QString title = QString::fromUtf8(list[0]);
QString className;
XClassHint* wmClass = XAllocClassHint();
if (XGetClassHint(d, window, wmClass)!=0 && wmClass->res_name!=NULL)
className = QString::fromLocal8Bit(wmClass->res_name);
XFree(wmClass);
if (window!=windowRoot && window!=AutoType::MainWin->winId() &&
(QApplication::activeWindow()==NULL || window!=QApplication::activeWindow()->winId()) &&
// !windowBlacklist.contains(title) &&
(className.isNull() || !classBlacklist.contains(className))
){
titleList.append(title);
}
XFreeStringList(list);
}
}
}
Window root;
Window parent;
Window* children = NULL;
unsigned int num_children;
int tree = XQueryTree(d, window, &root, &parent, &children, &num_children);
if (tree && children){
for (int i=0; i<num_children; i++)
windowTitles(children[i], titleList);
}
else
XFree(children);
}
void AutoType::init(){
Display* d = QX11Info::display();
wm_state = XInternAtom(d, "WM_STATE", true);
windowRoot = XRootWindow(d, MainWin->x11Info().screen());
//windowBlacklist << "kicker" << "KDE Desktop";
classBlacklist << "desktop_window" << "gnome-panel"; // Gnome
classBlacklist << "kdesktop" << "kicker"; // KDE 3
classBlacklist << "xfdesktop" << "xfce4-panel"; // Xfce 4
}
QStringList AutoType::getAllWindowTitles(){
QStringList titleList;
if (wm_state) // don't do anything if WM_STATE doesn't exist
windowTitles(windowRoot, titleList);
return titleList;
}
void AutoType::performGlobal(){
bool wasLocked = MainWin->isLocked();
if (wasLocked)
MainWin->OnUnLockWorkspace();
if (!MainWin->isOpened())
return;
Display* d = QX11Info::display();
Window w;
int revert_to_return;
XGetInputFocus(d, &w, &revert_to_return);
char** list = NULL;
int tree;
do {
XTextProperty textProp;
if (XGetWMName(d, w, &textProp) != 0) {
int count;
if (Xutf8TextPropertyToTextList(d, &textProp, &list, &count)<0) return;
if (list) break;
}
Window root = 0;
Window parent = 0;
Window* children = NULL;
unsigned int num_children;
tree = XQueryTree(d, w, &root, &parent, &children, &num_children);
w = parent;
if (children) XFree(children);
} while (tree && w);
if (!list) return;
QString title = QString::fromUtf8(list[0]).toLower();
XFreeStringList(list);
QList<IEntryHandle*> validEntries;
QList<int> entryNumbers;
QList<IEntryHandle*> entries = MainWin->db->entries();
QRegExp lineMatch("Auto-Type-Window(?:-(\\d+)|):([^\\n]+)", Qt::CaseInsensitive, QRegExp::RegExp2);
QDateTime now = QDateTime::currentDateTime();
for (int i=0; i<entries.size(); i++){
if ( (entries[i]->expire()!=Date_Never && entries[i]->expire()<now) ||
(AutoTypePrivate::getRootGroupName(entries[i]).compare("backup",Qt::CaseInsensitive)==0)
){
continue;
}
bool hasWindowEntry=false;
QString comment = entries[i]->comment();
int offset = 0;
while ( (offset=lineMatch.indexIn(comment, offset))!=-1 ){
QStringList captured = lineMatch.capturedTexts();
offset += captured[0].length();
int nr;
QString entryWindow;
bool valid;
if (captured.size()==2){
nr = 0;
entryWindow = captured[1].trimmed().toLower();
}
else{
nr = captured[1].toInt();
entryWindow = captured[2].trimmed().toLower();
}
if (entryWindow.length()==0) continue;
hasWindowEntry = true;
bool wildStart = (entryWindow[0]=='*');
bool wildEnd = (entryWindow[entryWindow.size()-1]=='*');
if (wildStart&&wildEnd){
entryWindow.remove(0,1);
if (entryWindow.length()!=0){
entryWindow.remove(entryWindow.size()-1,1);
valid = title.contains(entryWindow);
}
else
valid = true;
}
else if (wildStart){
entryWindow.remove(0,1);
valid = title.endsWith(entryWindow);
}
else if (wildEnd){
entryWindow.remove(entryWindow.size()-1,1);
valid = title.startsWith(entryWindow);
}
else {
valid = (title==entryWindow);
}
if (valid){
validEntries << entries[i];
entryNumbers << nr;
break;
}
}
if (!hasWindowEntry && config->entryTitlesMatch()){
QString entryTitle = entries[i]->title().toLower();
if (!entryTitle.isEmpty() && title.contains(entryTitle)){
validEntries << entries[i];
entryNumbers << 0;
}
}
}
if (validEntries.size()==1){
QString err;
perform(validEntries[0],err,wasLocked,entryNumbers[0],wasLocked);
}
else if (validEntries.size()>1){
AutoTypeDlg* dlg = new AutoTypeDlg(validEntries, entryNumbers, wasLocked);
dlg->show();
}
}
bool AutoType::registerGlobalShortcut(const Shortcut& s){
if (s.key==shortcut.key && s.ctrl==shortcut.ctrl && s.shift==shortcut.shift && s.alt==shortcut.alt && s.altgr==shortcut.altgr && s.win==shortcut.win)
return true;
Display* display = QX11Info::display();
Window root = XRootWindow(display, MainWin->x11Info().screen());
int code=XKeysymToKeycode(display, HelperX11::getKeysym(s.key));
int mod=HelperX11::getShortcutModifierMask(s);
HelperX11::startCatchErrors();
XGrabKey(display, code, mod, root, True, GrabModeAsync, GrabModeAsync);
XGrabKey(display, code, mod | Mod2Mask, root, True, GrabModeAsync, GrabModeAsync);
XGrabKey(display, code, mod | LockMask, root, True, GrabModeAsync, GrabModeAsync);
XGrabKey(display, code, mod | Mod2Mask | LockMask, root, True, GrabModeAsync, GrabModeAsync);
HelperX11::stopCatchErrors();
if (HelperX11::errorOccurred()){
XUngrabKey(display, code, mod, root);
XUngrabKey(display, code, mod | Mod2Mask, root);
XUngrabKey(display, code, mod | LockMask, root);
XUngrabKey(display, code, mod | Mod2Mask | LockMask, root);
return false;
}
else {
unregisterGlobalShortcut();
shortcut = s;
return true;
}
}
void AutoType::unregisterGlobalShortcut(){
if (shortcut.key==0) return;
Display* display = QX11Info::display();
Window root = XDefaultRootWindow(display);
int code=XKeysymToKeycode(display, HelperX11::getKeysym(shortcut.key));
int mod=HelperX11::getShortcutModifierMask(shortcut);
XUngrabKey(display, code, mod, root);
XUngrabKey(display, code, mod | Mod2Mask, root);
XUngrabKey(display, code, mod | LockMask, root);
XUngrabKey(display, code, mod | Mod2Mask | LockMask, root);
shortcut.key = 0;
}
#endif // GLOBAL_AUTOTYPE
AutoTypeAction::AutoTypeAction(AutoTypeActionType t, quint16 d) : type(t), data(d){
}
// AutoTypePrivate
void AutoTypePrivate::sleep(int msec){
if (msec==0) return;
timespec timeOut, remains;
timeOut.tv_sec = msec/1000;
timeOut.tv_nsec = (msec%1000)*1000000;
nanosleep(&timeOut, &remains);
}
void AutoTypePrivate::templateToKeysyms(const QString& tmpl, QList<AutoTypeAction>& keys,IEntryHandle* entry){
//tmpl must be lower case!!!
if(!tmpl.compare("title")){
stringToKeysyms(entry->title(),keys);
return;}
if(!tmpl.compare("username")){
stringToKeysyms(entry->username(),keys);
return;}
if(!tmpl.compare("url")){
stringToKeysyms(entry->url(),keys);
return;}
if(!tmpl.compare("password")){
SecString password=entry->password();
password.unlock();
stringToKeysyms(password,keys);
return;
}
if(!tmpl.compare("space")){
keys << AutoTypeAction(TypeKey, HelperX11::getKeysym(' '));
return;}
if(!tmpl.compare("backspace") || !tmpl.compare("bs") || !tmpl.compare("bksp")){
keys << AutoTypeAction(TypeKey, XK_BackSpace);
return;}
if(!tmpl.compare("break")){
keys << AutoTypeAction(TypeKey, XK_Break);
return;}
if(!tmpl.compare("capslock")){
keys << AutoTypeAction(TypeKey, XK_Caps_Lock);
return;}
if(!tmpl.compare("del") || !tmpl.compare("delete")){
keys << AutoTypeAction(TypeKey, XK_Delete);
return;}
if(!tmpl.compare("end")){
keys << AutoTypeAction(TypeKey, XK_End);
return;}
if(!tmpl.compare("enter")){
keys << AutoTypeAction(TypeKey, XK_Return);
return;}
if(!tmpl.compare("esc")){
keys << AutoTypeAction(TypeKey, XK_Escape);
return;}
if(!tmpl.compare("help")){
keys << AutoTypeAction(TypeKey, XK_Help);
return;}
if(!tmpl.compare("home")){
keys << AutoTypeAction(TypeKey, XK_Home);
return;}
if(!tmpl.compare("insert") || !tmpl.compare("ins")){
keys << AutoTypeAction(TypeKey, XK_Insert);
return;}
if(!tmpl.compare("numlock")){
keys << AutoTypeAction(TypeKey, XK_Num_Lock);
return;}
if(!tmpl.compare("scroll")){
keys << AutoTypeAction(TypeKey, XK_Scroll_Lock);
return;}
if(!tmpl.compare("pgdn")){
keys << AutoTypeAction(TypeKey, XK_Page_Down);
return;}
if(!tmpl.compare("pgup")){
keys << AutoTypeAction(TypeKey, XK_Page_Up);
return;}
if(!tmpl.compare("prtsc")){
keys << AutoTypeAction(TypeKey, XK_3270_PrintScreen);
return;}
if(!tmpl.compare("up")){
keys << AutoTypeAction(TypeKey, XK_Up);
return;}
if(!tmpl.compare("down")){
keys << AutoTypeAction(TypeKey, XK_Down);
return;}
if(!tmpl.compare("left")){
keys << AutoTypeAction(TypeKey, XK_Left);
return;}
if(!tmpl.compare("right")){
keys << AutoTypeAction(TypeKey, XK_Right);
return;}
if(!tmpl.compare("f1")){
keys << AutoTypeAction(TypeKey, XK_F1);
return;}
if(!tmpl.compare("f2")){
keys << AutoTypeAction(TypeKey, XK_F2);
return;}
if(!tmpl.compare("f3")){
keys << AutoTypeAction(TypeKey, XK_F3);
return;}
if(!tmpl.compare("f4")){
keys << AutoTypeAction(TypeKey, XK_F4);
return;}
if(!tmpl.compare("f5")){
keys << AutoTypeAction(TypeKey, XK_F5);
return;}
if(!tmpl.compare("f6")){
keys << AutoTypeAction(TypeKey, XK_F6);
return;}
if(!tmpl.compare("f7")){
keys << AutoTypeAction(TypeKey, XK_F7);
return;}
if(!tmpl.compare("f8")){
keys << AutoTypeAction(TypeKey, XK_F8);
return;}
if(!tmpl.compare("f9")){
keys << AutoTypeAction(TypeKey, XK_F9);
return;}
if(!tmpl.compare("f10")){
keys << AutoTypeAction(TypeKey, XK_F10);
return;}
if(!tmpl.compare("f11")){
keys << AutoTypeAction(TypeKey, XK_F11);
return;}
if(!tmpl.compare("f12")){
keys << AutoTypeAction(TypeKey, XK_F12);
return;}
if(!tmpl.compare("f13")){
keys << AutoTypeAction(TypeKey, XK_F13);
return;}
if(!tmpl.compare("f14")){
keys << AutoTypeAction(TypeKey, XK_F14);
return;}
if(!tmpl.compare("f15")){
keys << AutoTypeAction(TypeKey, XK_F15);
return;}
if(!tmpl.compare("f16")){
keys << AutoTypeAction(TypeKey, XK_F16);
return;}
if(!tmpl.compare("add") || !tmpl.compare("plus")){
keys << AutoTypeAction(TypeKey, HelperX11::getKeysym('+'));
return;}
if(!tmpl.compare("subtract")){
keys << AutoTypeAction(TypeKey, HelperX11::getKeysym('-'));
return;}
if(!tmpl.compare("multiply")){
keys << AutoTypeAction(TypeKey, HelperX11::getKeysym('+'));
return;}
if(!tmpl.compare("divide")){
keys << AutoTypeAction(TypeKey, HelperX11::getKeysym('/'));
return;}
if(!tmpl.compare("at")){
keys << AutoTypeAction(TypeKey, HelperX11::getKeysym('@'));
return;}
if(!tmpl.compare("percent")){
keys << AutoTypeAction(TypeKey, HelperX11::getKeysym('%'));
return;}
if(!tmpl.compare("caret")){
keys << AutoTypeAction(TypeKey, HelperX11::getKeysym('^'));
return;}
if(!tmpl.compare("tilde")){
keys << AutoTypeAction(TypeKey, HelperX11::getKeysym('~'));
return;}
if(!tmpl.compare("leftbrace")){
keys << AutoTypeAction(TypeKey, HelperX11::getKeysym('{'));
return;}
if(!tmpl.compare("rightbrace")){
keys << AutoTypeAction(TypeKey, HelperX11::getKeysym('}'));
return;}
if(!tmpl.compare("leftparen")){
keys << AutoTypeAction(TypeKey, HelperX11::getKeysym('('));
return;}
if(!tmpl.compare("rightparen")){
keys << AutoTypeAction(TypeKey, HelperX11::getKeysym(')'));
return;}
if(!tmpl.compare("winl")){
keys << AutoTypeAction(TypeKey, XK_Super_L);
return;}
if(!tmpl.compare("winr")){
keys << AutoTypeAction(TypeKey, XK_Super_R);
return;}
if(!tmpl.compare("win")){
keys << AutoTypeAction(TypeKey, XK_Super_L);
return;}
if(!tmpl.compare("tab")){
keys << AutoTypeAction(TypeKey, XK_Tab);
return;}
if(tmpl.startsWith("delay ") && tmpl.length()>6){
bool ok;
quint16 delay = tmpl.right(tmpl.length()-6).toInt(&ok);
if (ok && delay>0 && delay<=10000)
keys << AutoTypeAction(Delay, delay);
}
}
void AutoTypePrivate::stringToKeysyms(const QString& string,QList<AutoTypeAction>& KeySymList){
for(int i=0; i<string.length();i++)
KeySymList << AutoTypeAction(TypeKey, HelperX11::getKeysym(string[i]));
}
QString AutoTypePrivate::getRootGroupName(IEntryHandle* entry){
IGroupHandle* group = entry->group();
int level = group->level();
for (int i=0; i<level; i++)
group = group->parent();
return group->title();
}