Сообщения ip1981
I'm rejecting scantaylor
http://osdir.com/ml/ubuntu-archive/2009-05/msg00413.html
I'm rejecting scantaylor.
It includes an icon arrow_in which is licenced under creative commons. This is compiled into a binary which is otherwise under the GPL. Since these licences are incompatible the binary can not be distributed
Копирайт в принципе порочен, и GPL тут не спасёт.
Патч для Критикал Масс
Патч для Критикал Масс (http://criticalmass.sourceforge.net/), дающий бессмертие.
Добавляет параметр HeroImmortal. Его надо вписать в файл ~/.critter/config.txt, например так: set HeroImmortal = true
Так очень хорошо тренироваться.
diff -urdbN CriticalMass-0.9.11/game/Hero.cpp CriticalMass-0.9.11.pin/game/Hero.cpp
--- CriticalMass-0.9.11/game/Hero.cpp 2004-12-18 05:40:39.000000000 +0300
+++ CriticalMass-0.9.11.pin/game/Hero.cpp 2005-05-26 09:50:59.000000000 +0400
@@ -57,6 +57,8 @@
_shieldEnergy=30;
_weaponEnergy=100.0;
_damageMultiplier = 1.0;
+ _immortal = false;
+ ConfigS::instance()->getBoolean( "HeroImmortal", _immortal);
for( int i=0; i<Hero::MAX_WEAPONS; i++)
{
@@ -172,6 +174,8 @@
//hero dead...
if( _energy <= 0)
{
+ if (_immortal) _energy=100;
+ else {
static ParticleGroup *effects =
ParticleGroupManagerS::instance()->getParticleGroup(EFFECTS_GROUP2);
@@ -185,6 +189,7 @@
}
_isAlive = false;
}
+ }
}
bool Hero::init( void)
diff -urdbN CriticalMass-0.9.11/game/Hero.hpp CriticalMass-0.9.11.pin/game/Hero.hpp
--- CriticalMass-0.9.11/game/Hero.hpp 2004-12-18 05:40:39.000000000 +0300
+++ CriticalMass-0.9.11.pin/game/Hero.hpp 2005-05-26 09:44:51.000000000 +0400
@@ -110,6 +110,7 @@
float _moveUp;
float _moveDown;
bool _isAlive;
+ bool _immortal;
int _energy;
int _shieldEnergy;
Суперпатч для PowerManga
Патч для игрушки PowerManga, слегка исправляющий установку, чтение и запись параметров, но главное — добавляющий режим holiday, в котором бонусы так и сыплются!
diff -urdb powermanga-0.90/Makefile.am powermanga-0.90.pin/Makefile.am
--- powermanga-0.90/Makefile.am 2007-08-13 10:43:21.000000000 +0400
+++ powermanga-0.90.pin/Makefile.am 2009-10-21 00:47:22.000000000 +0400
@@ -2,6 +2,6 @@
SUBDIRS = texts src graphics graphics/bitmap graphics/bitmap/fonts graphics/sprites graphics/sprites/guardians graphics/sprites/stars graphics/sprites/meteors graphics/sprites/spaceships data data/curves data/levels/curves_phase data/levels/grids_phase sounds sounds/handheld_console
EXTRA_DIST = bootstrap
-pkgdatadir = $(mandir)
+pkgdatadir = $(mandir)/man6
dist_pkgdata_DATA = powermanga.6
diff -urdb powermanga-0.90/src/bonus.c powermanga-0.90.pin/src/bonus.c
--- powermanga-0.90/src/bonus.c 2007-08-24 11:55:16.000000000 +0400
+++ powermanga-0.90.pin/src/bonus.c 2009-10-21 00:47:22.000000000 +0400
@@ -582,6 +582,30 @@
/* test only
btype = BONUS_INC_ENERGY;
*/
+
+ if (power_conf->holiday && btype != PENALITY_LONELY_FOE)
+ {
+ switch (rand() % 6)
+ {
+ case 0:
+ btype = BONUS_INC_BY_1;
+ break;
+ case 1:
+ btype = BONUS_INC_BY_2;
+ break;
+ case 2:
+ btype = BONUS_ADD_SATELLITE;
+ break;
+ case 3:
+ btype = BONUS_INC_ENERGY;
+ break;
+ case 4:
+ btype = BONUS_SCR_MULTIPLIER;
+ break;
+ default:
+ break;
+ }
+ }
return btype;
}
@@ -753,6 +777,30 @@
btype = PENALITY_LONELY_FOE;
}
}
+
+ if (power_conf->holiday && btype != PENALITY_LONELY_FOE)
+ {
+ switch (rand() % 6)
+ {
+ case 0:
+ btype = BONUS_INC_BY_1;
+ break;
+ case 1:
+ btype = BONUS_INC_BY_2;
+ break;
+ case 2:
+ btype = BONUS_ADD_SATELLITE;
+ break;
+ case 3:
+ btype = BONUS_INC_ENERGY;
+ break;
+ case 4:
+ btype = BONUS_SCR_MULTIPLIER;
+ break;
+ default:
+ break;
+ }
+ }
return btype;
}
diff -urdb powermanga-0.90/src/config_file.c powermanga-0.90.pin/src/config_file.c
--- powermanga-0.90/src/config_file.c 2007-09-02 18:55:29.000000000 +0400
+++ powermanga-0.90.pin/src/config_file.c 2009-10-21 00:48:12.000000000 +0400
@@ -65,6 +65,7 @@
{
power_conf->fullscreen = TRUE;
power_conf->nosound = FALSE;
+ power_conf->holiday = FALSE;
power_conf->resolution = 640;
power_conf->verbose = 0;
power_conf->difficulty = 1;
@@ -244,10 +245,22 @@
{
power_conf->nosync = FALSE;
}
+ if (!lisp_read_bool (lst, "holiday", &power_conf->holiday))
+ {
+ power_conf->holiday = FALSE;
+ }
if (!lisp_read_int (lst, "verbose", &power_conf->verbose))
{
power_conf->verbose = 0;
}
+ if (!lisp_read_int (lst, "difficulty", &power_conf->difficulty))
+ {
+ power_conf->difficulty = 1;
+ }
+ if (power_conf->difficulty < 0 || power_conf->difficulty > 2)
+ {
+ power_conf->difficulty = 1;
+ }
if (!lisp_read_int (lst, "scale_x", &power_conf->scale_x))
{
power_conf->scale_x = 2;
@@ -289,6 +302,7 @@
power_conf->fullscreen ? "#t" : "#f");
fprintf (config, "\t(nosound %s)\n", power_conf->nosound ? "#t" : "#f");
fprintf (config, "\t(nosync %s)\n", power_conf->nosync ? "#t" : "#f");
+ fprintf (config, "\t(holiday %s)\n", power_conf->holiday ? "#t" : "#f");
fprintf (config, "\n\t;; window size (320 or 640):\n");
fprintf (config, "\t(resolution %d)\n", power_conf->resolution);
@@ -303,7 +317,7 @@
fprintf (config, "\n\t;; difficulty 0 (easy), 1 (normal) or 2 (hard)\n");
fprintf (config, "\t(difficulty %d)\n", power_conf->difficulty);
- fprintf (config, "\n\t;; langage en or fr\n");
+ fprintf (config, "\n\t;; language en or fr\n");
fprintf (config, "\t(lang ");
switch (power_conf->lang)
{
@@ -392,9 +406,13 @@
fprintf (stdout, "\noptions:\n"
"-h, --help print Help (this message) and exit\n"
"--version print version information and exit\n"
+ "\n\n"
+ "These options will be saved to config file:\n"
"--320 game run in a 320*200 window (slow machine)\n"
- "--2x scale2x\n"
- "--3x scale3x\n" "--4x scale4x\n");
+ "--640 game run in a 640*480 window\n"
+ "--2x scale 640*480 by 2x\n"
+ "--3x scale 640*480 by 3x\n"
+ "--4x scale 640*480 by 4x\n");
#ifdef POWERMANGA_SDL
fprintf (stdout,
"--window windowed mode (full screen by default) \n");
@@ -405,8 +423,13 @@
"--nosound force no sound\n"
"--sound force sound\n"
"--nosync disable timer\n"
- "--easy easy bonuses\n"
- "--hard hard bonuses\n"
+ "--sync enable timer\n"
+ "\n"
+ "--easy easy game\n"
+ "--normal normal game\n"
+ "--hard hard game\n"
+ "--holiday more bonuses!\n"
+ "--noholiday usual game (easy, normal or hard)\n"
"--------------------------------------------------------------\n"
"keys recognized during the game:\n"
"[Ctrl] + [S] enable/disable the music\n"
@@ -517,12 +540,36 @@
continue;
}
- /* difficulty: easy or hard (normal bu default) */
+ /* enable timer */
+ if (!strcmp (arg_values[i], "--sync"))
+ {
+ power_conf->nosync = FALSE;
+ continue;
+ }
+
+ /* more bonuses! */
+ if (!strcmp (arg_values[i], "--holiday"))
+ {
+ power_conf->holiday = TRUE;
+ continue;
+ }
+ if (!strcmp (arg_values[i], "--noholiday"))
+ {
+ power_conf->holiday = FALSE;
+ continue;
+ }
+
+ /* difficulty: easy or hard (normal by default) */
if (!strcmp (arg_values[i], "--easy"))
{
power_conf->difficulty = 0;
continue;
}
+ if (!strcmp (arg_values[i], "--normal"))
+ {
+ power_conf->difficulty = 1;
+ continue;
+ }
if (!strcmp (arg_values[i], "--hard"))
{
power_conf->difficulty = 2;
diff -urdb powermanga-0.90/src/config_file.h powermanga-0.90.pin/src/config_file.h
--- powermanga-0.90/src/config_file.h 2007-07-10 00:21:36.000000000 +0400
+++ powermanga-0.90.pin/src/config_file.h 2009-10-21 00:47:22.000000000 +0400
@@ -58,6 +58,8 @@
Sint32 verbose;
/** 0 = easy, 1 = normal or 2 = hard */
Sint32 difficulty;
+ /** More bonuses! */
+ bool holiday;
/** 0 = EN or 1 = FR */
Sint32 lang;
} config_file;
diff -urdb powermanga-0.90/src/Makefile.am powermanga-0.90.pin/src/Makefile.am
--- powermanga-0.90/src/Makefile.am 2007-09-01 00:46:43.000000000 +0400
+++ powermanga-0.90.pin/src/Makefile.am 2009-10-21 00:47:22.000000000 +0400
@@ -1,6 +1,6 @@
-gamesdir = $(prefix)/games
-scoredir = /var/games
+gamesdir = $(prefix)/bin
+scoredir = /var/lib/games
score = powermanga.hi
games_PROGRAMS = powermanga
Первый замечательный предел :-)
Der erste fantastisch Grenzwert
Webalizer
Обновился Webalizer — программа для статистической обработки журналов Apache, Squid, и др. серверов.
В разработке Вебалайзера был перерыв на шесть лет.
В новых версиях:
- исправлены некоторые проблемы безопасности;
- добавлено множество параметров настройки (например, обрезание CGI, глубина анализа более 12 месяцев);
- добавлена проверка страны по IP-адресу (GeoIP);
- добавлена поддержка сжатых bzip2 файлов;
- добавлена поддержка форматов W3C;
- добавлена поддержка IPv6.
Подробности
Перемещено Shaman007 из OpenSource
Наука vs любовь
Фраза "заниматься наукой" имеет такое же отношение к науке, как фраза "заниматься любовью" к любви.
Дискасс!
Очко в очко
Взятка борзыми щенками
http://lenta.ru/news/2009/10/01/limit/
Министерство внутренних дел России предложило ограничить оборот наличных денег в стране для более эффективной борьбы с коррупцией.
Дискасс.
Первые на Луне
http://lenta.ru/news/2009/09/30/lro/
Лунный зонд LRO сфотографировал место высадки американского корабля "Аполлон-11".
А где теперь есть падонкизатор сайтов?
Гуглится только уже мёртвый webox.kiev.ua
Шателен. «Русские электротехники XIX века»
Шателен. "Русские электротехники XIX века"
http://thepiratebay.org/torrent/5102336
http://slil.ru/28021196
http://depositfiles.com/files/i2p04yrsn
http://rapidshare.com/files/285755974/shatelen-xix.djvu.html
[По просьбам трудящихся] Newslack
Чиновники --- за анониманость в сети
[Slackware] What's new in /etc ?
Апдейт к www.linux.org.ru/view-message.jsp?msgid=4068051
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import sys
import os
import stat
import glob
import difflib
import string
import subprocess
from PyQt4 import QtGui, QtCore
from pygments import highlight
from pygments.lexers import DiffLexer
from pygments.formatters import HtmlFormatter
CWD = os.getcwd()
EDITOR = 'gvim -f'
PATCH = 'patch -p0'
DIR = '/etc'
def usage():
print "Usage: %s directory" % sys.argv[0]
# find all *.new files in /etc
def findnew (top = '.', depthfirst = True):
os.chdir(top)
names = glob.glob('*.new')
if not depthfirst:
yield top, names
for name in names:
try:
st = os.lstat(os.path.join(top, name))
except os.error:
continue
if stat.S_ISDIR(st.st_mode):
for (newtop, children) in findnew (os.path.join(top, name), depthfirst):
yield newtop, children
if depthfirst:
yield top, names
class MainWindow(QtGui.QWidget):
newlist = None # QListWidget
diff = None # QTextEdit
edit = None # QPushButton
accept = None # QPushButton
reject = None # QPushButton
patch = None # QPushButton
newfile = None # /etc/file.new
oldfile = None # /etc/file
@QtCore.pyqtSlot()
def on_partial_diff(self):
cursor = self.diff.textCursor()
start = cursor.selectionStart()
end = cursor.selectionEnd()
# starting and ending line numbers for the selection
start_line = self.diff.document().findBlock(start).firstLineNumber()
end_line = self.diff.document().findBlock(end).firstLineNumber()
fulldiff = self.diff.toPlainText().split('\n');
max_lines = len(fulldiff) - 1
# two first lines
partdiff = fulldiff[0] + '\n' + fulldiff[1] + '\n'
# looking for start of diff block (@@ -16,7 +16,7 @@)
if start_line < 2:
start_line = 2
else:
while fulldiff[start_line][0:2] != '@@':
start_line = start_line - 1
# looking for end of diff block (next @@ ... @@ or EOF)
if end_line <= start_line:
end_line = start_line + 1
while end_line < max_lines:
if fulldiff[end_line][0:2] == '@@':
break
end_line = end_line + 1
for l in range(start_line, end_line):
partdiff = partdiff + fulldiff[l] + '\n'
# apply partial patch
pipe = subprocess.Popen(PATCH, shell=True, stdin=subprocess.PIPE)
pipe.stdin.writelines(partdiff)
pipe.stdin.close()
self.reloaddiff(self.newfile)
def enable_buttons(self):
n = self.newlist.count()
self.edit.setEnabled(n > 0)
self.accept.setEnabled(n > 0)
self.reject.setEnabled(n > 0)
@QtCore.pyqtSlot()
def on_selection_changed(self):
self.patch.setEnabled(
self.diff.textCursor().selectionStart() != self.diff.textCursor().selectionEnd()
)
@QtCore.pyqtSlot()
def on_accept(self):
os.rename(self.newfile, self.oldfile)
self.newlist.takeItem(self.newlist.currentRow())
self.enable_buttons()
@QtCore.pyqtSlot()
def on_reject(self):
os.remove(self.newfile)
self.newlist.takeItem(self.newlist.currentRow())
self.enable_buttons()
@QtCore.pyqtSlot()
def on_edit(self):
self.accept.setEnabled(False)
self.newlist.setEnabled(False)
p = subprocess.Popen(EDITOR + ' ' + self.oldfile, shell=True)
sts = os.waitpid(p.pid, 0)
self.reloaddiff(self.newfile)
self.newlist.setEnabled(True)
self.accept.setEnabled(True)
@QtCore.pyqtSlot(QtCore.QString)
def reloaddiff(self, newfile):
self.diff.clear()
self.newfile = str(newfile)
self.oldfile = self.newfile[0:self.newfile.find('.new')]
if self.newfile:
tolines = open(self.newfile, 'U').readlines()
fromlines = open(self.oldfile, 'U').readlines()
difflines = difflib.unified_diff(fromlines, tolines, self.oldfile, self.newfile)
difftext = string.join(difflines, '')
self.edit.setToolTip(EDITOR + ' ' + self.oldfile)
self.reject.setToolTip('Remove ' + self.newfile)
self.accept.setToolTip(self.newfile + ' -> ' + self.oldfile)
self.accept.setEnabled(bool(difftext))
colored_rtf = highlight(difftext, DiffLexer(), HtmlFormatter(full=True))
self.diff.setText(colored_rtf)
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
mvbox = QtGui.QVBoxLayout() # main layout
split = QtGui.QSplitter(QtCore.Qt.Horizontal, self) # left-right splitter
rpart = QtGui.QWidget(split) # right side
lpart = QtGui.QWidget(split) # left side
rvbox = QtGui.QVBoxLayout() # right side layout
lvbox = QtGui.QVBoxLayout() # left side layout
rpart.setLayout(rvbox)
lpart.setLayout(lvbox)
self.diff = QtGui.QTextEdit() # to show diff
self.diff.setReadOnly(True)
self.newlist = QtGui.QListWidget() # to show all *.new files
# Load all *.new files
for (basepath, children) in findnew(DIR):
for child in children:
self.newlist.addItem(os.path.join(basepath, child))
os.chdir(CWD)
quit = QtGui.QPushButton('&Quit', self)
self.accept = QtGui.QPushButton('&Accept', self)
self.reject = QtGui.QPushButton('&Reject', self)
self.edit = QtGui.QPushButton('&Edit old...', self)
self.patch = QtGui.QPushButton('A&pply selection', self)
self.patch.setEnabled(False)
self.patch.setToolTip('Patch using block with selected text')
lvbox.addWidget(self.diff) # diff is on the left side
lvbox.addWidget(self.patch) # "apply patch" button (can be invisible)
buttons = QtGui.QHBoxLayout() # buttons are below it
lvbox.addLayout(buttons) # buttons layout
buttons.addWidget(self.accept)
buttons.addWidget(self.reject)
buttons.addWidget(self.edit)
rvbox.addWidget(self.newlist) # file list is on the right side
rvbox.addWidget(quit) # quit button is below it
mvbox.addWidget(split) # split is the main widget of main window
split.addWidget(lpart) # add the left side on the split
split.addWidget(rpart) # add the right side on the split
self.resize(640, 480)
self.setWindowTitle("What\'s new in %s ?" % DIR)
self.setLayout(mvbox)
self.connect(quit, QtCore.SIGNAL('clicked()'), QtGui.qApp, QtCore.SLOT('quit()'))
self.connect(self.edit, QtCore.SIGNAL('clicked()'), self, QtCore.SLOT('on_edit()'))
self.connect(self.accept, QtCore.SIGNAL('clicked()'), self, QtCore.SLOT('on_accept()'))
self.connect(self.reject, QtCore.SIGNAL('clicked()'), self, QtCore.SLOT('on_reject()'))
self.connect(self.diff, QtCore.SIGNAL('selectionChanged()'), self, QtCore.SLOT('on_selection_changed()'))
self.connect(self.newlist, QtCore.SIGNAL('currentTextChanged(QString)'),
self, QtCore.SLOT('reloaddiff(QString)'))
self.newlist.setCurrentRow(0)
self.enable_buttons()
if len(sys.argv) > 2:
usage()
sys.exit(1)
elif len(sys.argv) == 2:
DIR = sys.argv[1]
app = QtGui.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
[Суррогаты]
Интересно, почему у Брюса Уиллиса моск не вскипел.
:-)
Стерлитамакская государственная педагогическая академия ЖЖОТ!
[Slackware] What's new in /etc ?
После обновления Слаки с директории /etc остаётся несколько файлов типа rc.inet1.new, которые по идее должны заменить старые файлы (типа rc.inet1).
Я обысно это делал руками: diff -u rc.inet1 rc.inet1.new, а затем принимал решение о замене. мне это надоело, и я написал программу на Питоне, которая это автоматизирует. Программа графическая, использует Qt4, pygments.
http://picasaweb.google.ru/lh/photo/EVmsIvYlCcb-ZmFgkTSdNQ?feat=directlink
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import sys
import os
import stat
import glob
import difflib
import string
from PyQt4 import QtGui, QtCore
from pygments import highlight
from pygments.lexers import DiffLexer
from pygments.formatters import HtmlFormatter
editor = 'gvim -f'
# find all *.new files in /etc
def findnew (top = '/etc', depthfirst = True):
os.chdir(top)
names = glob.glob('*.new')
if not depthfirst:
yield top, names
for name in names:
try:
st = os.lstat(os.path.join(top, name))
except os.error:
continue
if stat.S_ISDIR(st.st_mode):
for (newtop, children) in findnew (os.path.join(top, name), depthfirst):
yield newtop, children
if depthfirst:
yield top, names
class MainWindow(QtGui.QWidget):
newlist = None # QListWidget
diff = None # QTextEdit
edit = None # QPushButton
accept = None # QPushButton
reject = None # QPushButton
newfile = None # /etc/file.new
oldfile = None # /etc/file
def enable_buttons(self):
n = self.newlist.count()
self.edit.setEnabled(n > 0)
self.accept.setEnabled(n > 0)
self.reject.setEnabled(n > 0)
@QtCore.pyqtSlot()
def on_accept(self):
os.rename(self.newfile, self.oldfile)
self.newlist.takeItem(self.newlist.currentRow())
self.enable_buttons()
@QtCore.pyqtSlot()
def on_reject(self):
os.remove(self.newfile)
self.newlist.takeItem(self.newlist.currentRow())
self.enable_buttons()
@QtCore.pyqtSlot()
def on_edit(self):
self.accept.setEnabled(False)
self.newlist.setEnabled(False)
os.system(editor + ' ' + self.oldfile)
self.reloaddiff(self.newfile)
self.newlist.setEnabled(True)
self.accept.setEnabled(True)
@QtCore.pyqtSlot(QtCore.QString)
def reloaddiff(self, newfile):
self.diff.clear()
self.newfile = str(newfile)
self.oldfile = self.newfile[0:self.newfile.find('.new')]
if self.newfile:
tolines = open(self.newfile, 'U').readlines()
fromlines = open(self.oldfile, 'U').readlines()
difflines = difflib.unified_diff(fromlines, tolines, self.oldfile, self.newfile)
difftext = string.join(difflines, '')
self.edit.setToolTip(editor + ' ' + self.oldfile)
self.reject.setToolTip('Remove ' + self.newfile)
self.accept.setToolTip(self.newfile + ' -> ' + self.oldfile)
self.accept.setEnabled(bool(difftext))
colored_rtf = highlight(difftext,
DiffLexer(),
HtmlFormatter(full=True))
self.diff.setText(colored_rtf)
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
mvbox = QtGui.QVBoxLayout() # main layout
split = QtGui.QSplitter(QtCore.Qt.Horizontal, self) # left-right splitter
rpart = QtGui.QWidget(split) # right side
lpart = QtGui.QWidget(split) # left side
rvbox = QtGui.QVBoxLayout() # right side layout
lvbox = QtGui.QVBoxLayout() # left side layout
rpart.setLayout(rvbox)
lpart.setLayout(lvbox)
self.diff = QtGui.QTextEdit() # to show diff
self.diff.setReadOnly(True)
self.newlist = QtGui.QListWidget() # to show all *.new files
# Load all *.new files
for (basepath, children) in findnew():
for child in children:
self.newlist.addItem(os.path.join(basepath, child))
quit = QtGui.QPushButton('&Quit', self)
self.accept = QtGui.QPushButton('&Accept', self)
self.reject = QtGui.QPushButton('&Reject', self)
self.edit = QtGui.QPushButton('&Edit old...', self)
lvbox.addWidget(self.diff) # diff is on the left side
buttons = QtGui.QHBoxLayout() # buttons are below it
lvbox.addLayout(buttons) # buttons layout
buttons.addWidget(self.accept)
buttons.addWidget(self.reject)
buttons.addWidget(self.edit)
rvbox.addWidget(self.newlist) # file list is on the right side
rvbox.addWidget(quit) # quit button is below it
mvbox.addWidget(split) # split is the main widget of main window
split.addWidget(lpart) # add the left side on the split
split.addWidget(rpart) # add the right side on the split
self.resize(640, 480)
self.setWindowTitle('What\'s new in /etc ?')
self.setLayout(mvbox)
self.connect(quit, QtCore.SIGNAL('clicked()'), QtGui.qApp, QtCore.SLOT('quit()'))
self.connect(self.edit, QtCore.SIGNAL('clicked()'), self, QtCore.SLOT('on_edit()'))
self.connect(self.accept, QtCore.SIGNAL('clicked()'), self, QtCore.SLOT('on_accept()'))
self.connect(self.reject, QtCore.SIGNAL('clicked()'), self, QtCore.SLOT('on_reject()'))
self.connect(self.newlist, QtCore.SIGNAL('currentTextChanged(QString)'),
self, QtCore.SLOT('reloaddiff(QString)'))
self.newlist.setCurrentRow(0)
self.enable_buttons()
app = QtGui.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
Информационные технологии в России
Ещё один jabber-shell
Идея витает в воздухе давно, есть несколько реализаций разной степени запущенности. Большинство использует Net::XMPP и Net::Jabber и имеют проблемы.
Этот скрипт использует AnyEvent::XMPP и основан на примере в исходниках оного. Работает.
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
use utf8;
use locale;
use open qw( :utf8 :std );
use Getopt::Long qw(:config bundling);
use AnyEvent;
use AnyEvent::XMPP::Client;
use AnyEvent::XMPP::Ext::Disco;
use AnyEvent::XMPP::Ext::Version;
use AnyEvent::XMPP::Namespaces qw/xmpp_ns/;
my $SCRIPT = $0;
my $VERSION = '0.1';
my $PORT = '5222';
my $PASSWORD = '';
my @ADMINS = ();
my $JID = '';
my $DEBUG = 0;
my $TLS = 1;
my $HTTP = 0;
sub usage
{
print <<USAGE;
Jabber shell v$VERSION: shell robot to execute commands via jabber
Usage: $SCRIPT [options]
Options (default in brackets):
--jid, -j jabber ID, e. g. 'name\@jabber.org' or 'name\@jabber.org/resource'
--password, -w password for the account ($PASSWORD)
--port, -p port to connect ($PORT)
--admin, -a authorized accounts to execute commands from (@ADMINS)
--[no]debug turn debug on/off ($DEBUG)
--help, -h this help message
Examples:
$SCRIPT -j solo\@jabber.ru/home -w qwerty --admin buck\@jabber.org
USAGE
exit (0);
}
GetOptions(
'port|p=i' => \$PORT,
'password|passwd|w=s' => \$PASSWORD,
'admin|a=s' => \@ADMINS,
'debug|d!' => \$DEBUG,
'jid|jabber|j=s' => \$JID,
'help|h' => sub {usage}
);
unless ($JID)
{
usage();
}
my $j = AnyEvent->condvar;
my $cl = AnyEvent::XMPP::Client->new (debug => $DEBUG);
my $disco = AnyEvent::XMPP::Ext::Disco->new;
my $version = AnyEvent::XMPP::Ext::Version->new;
$cl->add_extension ($disco);
$cl->add_extension ($version);
$cl->set_presence (undef, "Jabber shell bot v$VERSION", 1);
$cl->add_account ($JID, $PASSWORD);
warn "connecting to $JID...\n";
$cl->reg_cb (
session_ready => sub {
my ($cl, $acc) = @_;
warn "connected!\n";
},
contact_request_subscribe => sub {
my ($cl, $acc, $roster, $contact) = @_;
$contact->send_subscribed;
warn 'Subscribed to ' . $contact->jid . "\n";
},
error => sub {
my ($cl, $acc, $error) = @_;
warn 'Error encountered: ' . $error->string . "\n";
$j->broadcast;
},
disconnect => sub {
warn "Got disconnected: [@_]\n";
$j->broadcast;
},
message => sub {
my ($cl, $acc, $msg) = @_;
return unless $msg;
my $cmd = $msg->any_body;
my $adm = $msg->from;
warn "# $adm -> $cmd:\n";
my $repl = $msg->make_reply;
if ($adm ~~ @ADMINS)
{
my $out = '';
if ($cmd =~ s/^\s*cd\s+//)
{
$out = chdir($cmd) ? `pwd` : 'Failed'
} else
{
$out = `$cmd 2>&1`
}
if ($out)
{
warn $out;
$repl->add_body($out);
}
} else
{
warn "Forbidden.\n";
$repl->add_body('Forbidden');
}
$repl->send;
},
);
$cl->start;
$j->wait;
exit(0);
← назад | следующие → |