Sub ConvertDBF()
Sheets("DST").Columns("A:A").ColumnWidth = 3
Sheets("DST").Columns("B:B").ColumnWidth = 5
Sheets("DST").Columns("B:B").NumberFormat = "@"
Sheets("DST").Columns("C:C").ColumnWidth = 5
Sheets("DST").Columns("D:D").ColumnWidth = 6
Sheets("DST").Columns("E:E").ColumnWidth = 8
Sheets("DST").Columns("F:F").ColumnWidth = 23
Sheets("DST").Columns("G:G").ColumnWidth = 23
Sheets("DST").Columns("H:H").ColumnWidth = 23
Sheets("DST").Columns("I:I").ColumnWidth = 21
Sheets("DST").Columns("J:J").ColumnWidth = 12
i = 3
Do
If Sheets("SRC").Cells(i, 5).Value = "" Then
Exit Do
End If
Sheets("DST").Cells(i - 2, 1) = Sheets("SRC").Cells(i, 4)
Sheets("DST").Cells(i - 2, 2) = "002"
Sheets("DST").Cells(i - 2, 3) = "21"
Sheets("DST").Cells(i - 2, 4) = Sheets("SRC").Cells(i, 6)
Sheets("DST").Cells(i - 2, 5) = Sheets("SRC").Cells(i, 7)
FIO = Trim(Sheets("SRC").Cells(i, 5))
FirstSpacePos = InStr(1, FIO, " ", vbTextCompare)
If FirstSpacePos > 0 Then
Sheets("DST").Cells(i - 2, 6) = Left(FIO, FirstSpacePos - 1)
End If
SecondSpacePos = InStr(FirstSpacePos + 1, FIO, " ", vbTextCompare)
If SecondSpacePos > 0 Then
Sheets("DST").Cells(i - 2, 7) = Mid(FIO, FirstSpacePos + 1, SecondSpacePos - FirstSpacePos)
Sheets("DST").Cells(i - 2, 8) = Mid(FIO, SecondSpacePos + 1)
End If
Sheets("DST").Cells(i - 2, 9) = Sheets("SRC").Cells(i, 14)
Sheets("DST").Cells(i - 2, 10) = Sheets("SRC").Cells(i, 12)
i = i + 1
Loop
End Sub
7 нояб. 2013 г.
Перестановка колонок, выделение Ф.И.О из ФИО
Фокус еще в том, что исходный файл был DBF-ом, поэтому данные с 3 строки попадают в 1-ю в назначение (чтобы не трогать заголовки колонок)
2 сент. 2013 г.
Эвакуация автомобиля с Амуркабеля
Вот так теперь выглядит ГСК дяди Коли. Едва уговорили вывезти машину к нам.
Воды по край сапог. Пробираться можно только по краю.
В воде лежит шланг от помпы. Мы думали, что это они нам накачали. Нет. Это Красная речка к нам пришла. За гаражами речка вровень с двором ГСК.
Качают из канализации дома вдоль ул.Союзная (под 90 градусов к дому дяди Коли). Палатка стоит. В ней место для отдыха помпосмотрителя.
В подвале, видимо, полно воды, т.к. на улице сидели 2 белые кошки. Когда мы подошли - замяукали жалобно, но не убежали. Видимо, слегка одурели от того, что дома у них внезапно не стало. Машину своим ходом выгонять не рискнули, Никита вытащил Деликой.
Пробег, кстати у нее меньше 1500 км - новая (но дверьми хлопать надо все равно сильно - автоВАЗ). А цвет ГИБДД определил как серо-сине-зеленый. Привет Люсе в алмазах!
1 авг. 2013 г.
Округление в выделенном диапазоне, Excel
Sub MyRoundRange()
For Each cell In Selection
cell.Value = WorksheetFunction.Round(cell.Value, 0)
Next cell
End Sub
19 июн. 2013 г.
Вывод из Excel в файл
Любят бухгалтера все делать в Excel.А Диасофт 4х4 грузит из текстовых файлов.
Const BASE = 9000
Sub Макрос1()
Dim fs, f
Set fs = CreateObject("Scripting.FileSystemObject")
Set f = fs.OpenTextFile("c:\clients.txt", 2, 8)
i = 1
Do
If Cells(i, 1).Value = "" Then
Exit Do
End If
f.WriteLine ("%КЛИЕНТ")
f.WriteLine ("ИМЯ1 :" + Mid(Cells(i, 1).Value, 1, 40))
f.WriteLine ("ИМЯ2 :" + Mid(Cells(i, 1).Value, 41, 40))
f.WriteLine ("ИМЯ3 :" + Mid(Cells(i, 1).Value, 81, 40))
f.WriteLine ("ИМЯ4 :" + Mid(Cells(i, 1).Value, 121, 40))
f.WriteLine ("ТИП :Ю")
f.WriteLine ("АДРЕС1 :")
f.WriteLine ("АДРЕС2 :")
f.WriteLine ("ТЕЛЕФОН1 :")
f.WriteLine ("ТЕЛЕФОН2 :")
f.WriteLine ("КОД :" + Trim(Str(i + BASE)))
f.WriteLine ("ИНН :" + Trim(Str(Cells(i, 2).Value)))
f.WriteLine ("КПП :" + Trim(Str(Cells(i, 3).Value)))
f.WriteLine ("ГРУППА :Юридические лица")
f.WriteLine ("ДЕЙСТВИЕ :Add")
f.WriteLine ("%END")
i = i + 1
Loop
f.Close
End
End Sub
5 июн. 2013 г.
ED206 - поиск внутри файла
Ищем внутри файлов слово ED206, те файлы, в которых находим, копируем в специально отведенное место.
grep -c "ED206" *.ED0| gawk "{print \"cp \"$1\" ED206/\"$1 }" |
sed -e "/........\....:0/d" -e "s/\(........\....\)\(:1\)/\1/g"|
cmd.exe
29 апр. 2013 г.
Открытие сезона. Мост на Уссурийский остров.
Открыл сезон, прокатив первые 50 километров, съездил к новому мосту. Моста еще нет, но опоры уже стоят. Постоянно по новой дороге ездит народ, интересуется. На указателе уже "Пограничный переход" - только речку надо перепрыгнуть.

Указатель в никуда

Дорога в никуда

Опоры моста

А тут был наплавной мост.
Указатель в никуда
Дорога в никуда
Опоры моста
А тут был наплавной мост.
Excel из PHP
Есть система ведения распоряжений по курсам валют в обменниках. Обеспечивает ввод, печать, подтверждение курсов. Внезапно старшие товарищи решили нас осчастливить и обеспечить "автоматическую" загрузку курсов в Диасофт 5NT. Пришлось для получения требуемого к загрузке файла в формате MS Excel научиться изготавливать из CSV XLS.
include_once "Spreadsheet/Excel/Writer.php";
$xls =& new Spreadsheet_Excel_Writer();
$name=$_GET['rasp'];
$xls->send("KURS_".substr($name,0,3)."_".substr($name,7).".xls");
$f = fopen($name, "rt") or die("Ошибка!");
$sheet =& $xls->addWorksheet('Распоряжение');
$format =& $xls->addFormat();
$format->setColor("black");
$dateFmt =& $xls->addFormat();
$dateFmt->setColor("black");
$dateFmt->setNumFormat("D MMMM,YYYY");
$sheet->setColumn(0,5,20);
for ($i=0; $data=fgetcsv($f,1000,","); $i++){
$sheet->writeString(2, 0, "Филиал банка в г.Москве", $format);
$sheet->writeString(4, 0, "Приказ № ".$data[0], $format);
$sheet->writeString(6, 3, $data[2], $dateFmt);
$sheet->writeString(12, 0, "Доллары США:", $format);
$sheet->writeString(13, 0, "покупка -", $format);
$sheet->writeString(13, 1, $data[3], $format);
$sheet->writeString(13, 3, "продажа -", $format);
$sheet->writeString(13, 4, $data[4], $format);
$sheet->writeString(15, 0, "Евро:", $format);
$sheet->writeString(16, 0, "покупка -", $format);
$sheet->writeString(16, 1, $data[6], $format);
$sheet->writeString(16, 3, "продажа -", $format);
$sheet->writeString(16, 4, $data[7], $format);
$sheet->writeString(18, 0, "Английские фунты стерлингов:", $format);
$sheet->writeString(19, 0, "покупка -", $format);
$sheet->writeString(19, 1, $data[9], $format);
$sheet->writeString(19, 3, "продажа -", $format);
$sheet->writeString(19, 4, $data[10], $format);
$sheet->writeString(21, 0, "Швейцарские франки:", $format);
$sheet->writeString(22, 0, "покупка -", $format);
$sheet->writeString(22, 1, $data[12], $format);
$sheet->writeString(22, 3, "продажа -", $format);
$sheet->writeString(22, 4, $data[13], $format);
$sheet->writeString(26, 1, "USD", $format);
$sheet->writeString(26, 2, "EUR", $format);
$sheet->writeString(26, 3, "GBP", $format);
$sheet->writeString(26, 4, "CHF", $format);
$sheet->writeString(27, 0, "USD", $format);
$sheet->writeString(28, 0, "EUR", $format);
$sheet->writeString(29, 0, "GBP", $format);
$sheet->writeString(30, 0, "CHF", $format);
$sheet->writeString(27, 1, "X", $format);
$sheet->writeString(27, 2, $data[16], $format); //USD-EUR
$sheet->writeString(27, 3, "0.00", $format);
$sheet->writeString(27, 4, "0.00", $format);
$sheet->writeString(28, 1, $data[15], $format); //EUR-USD
$sheet->writeString(28, 2, "X", $format);
$sheet->writeString(28, 3, "0.00", $format);
$sheet->writeString(28, 4, "0.00", $format);
$sheet->writeString(29, 1, "0.00", $format);
$sheet->writeString(29, 2, "0.00", $format);
$sheet->writeString(29, 3, "X", $format);
$sheet->writeString(29, 4, "0.00", $format);
$sheet->writeString(30, 1, "0.00", $format);
$sheet->writeString(30, 2, "0.00", $format);
$sheet->writeString(30, 3, "0.00", $format);
$sheet->writeString(30, 4, "X", $format);
$sheet->writeString(35, 0, $data[17], $format);
$sheet->writeString(35, 3, $data[18], $format);
$sheet->writeString(36, 0, $data[19], $format);
$sheet =& $xls->addWorksheet('Приложение');
$sheet->writeString(0,5,$data[2]);
for($i=0;$i<3;$i++){
$sheet->writeString($i+2,3,$data[1]); //time of the day
}
$sheet->writeString(2,5,"Ф-Л");
$sheet->writeString(3,5,"ДО 1");
$sheet->writeString(4,5,"ДО 2");
}
fclose($f);
$xls->close();
exit;
18 мар. 2013 г.
Загрузка в Диасофт FA# 5NT из 4х4 с поиском фамилий и счетов регэкспами
Программка берет из командной строки имя файла, в котором содержатся платежи в формате Диасофт 4х4. Загружает их, находит в назначении платежа с помощью регулярных выражений (библиотека Copyright (c) 1999-2004 Andrey V. Sorokin, St.Petersburg, Russia) ФИО, номер счета. Затем выгружает текстовые файлы, пригодные к загрузке в Диасофт FA# 5NT, в каталоги, необходимые для последующей загрузки.
Основное назначение - автоматизировать зачисление пришедших на физиков платежей с реквизитами счетов в назначении платежа.
Основное назначение - автоматизировать зачисление пришедших на физиков платежей с реквизитами счетов в назначении платежа.
unit SDIMAIN;
interface
uses Windows, Classes, Graphics, Forms, Controls, Menus,
Dialogs, StdCtrls, Buttons, ExtCtrls, ComCtrls, ImgList, StdActns,
ActnList, ToolWin, Grids, SysUtils, StrUtils, RegExpr;
type
TMyGrid=class(TCustomGrid);
TSDIAppForm = class(TForm)
OpenDialog: TOpenDialog;
SaveDialog: TSaveDialog;
ToolBar1: TToolBar;
ToolButton1: TToolButton;
SaveButton: TToolButton;
ActionList1: TActionList;
FileNew1: TAction;
FileOpen1: TAction;
FileSave1: TAction;
FileSaveAs1: TAction;
FileExit1: TAction;
EditCut1: TEditCut;
EditCopy1: TEditCopy;
EditPaste1: TEditPaste;
HelpAbout1: TAction;
StatusBar: TStatusBar;
ImageList1: TImageList;
Panel1: TPanel;
StringGrid1: TStringGrid;
DelBtn: TBitBtn;
ToolButton3: TToolButton;
BtnSaveToCard: TBitBtn;
procedure BtnSaveToCardClick(Sender: TObject);
procedure DelBtnClick(Sender: TObject);
function ToOEM(S:String):String;
function ToAnsi(S:String):String;
function LeftPad(S: string; Ch: Char; Len: Integer): string;
function RightPad(S: string; Ch: Char; Len: Integer): string;
procedure LoadInFile();
procedure FormShow(Sender: TObject);
procedure FileNew1Execute(Sender: TObject);
procedure FileOpen1Execute(Sender: TObject);
procedure FileSave1Execute(Sender: TObject);
procedure FileExit1Execute(Sender: TObject);
procedure DeleteARow(Grid: TStringGrid; ARow: Integer);
private
{ Private declarations }
public
{ Public declarations }
end;
var
SDIAppForm: TSDIAppForm;
STag,Val: String;
SIn,SOut: String;
FamilyName,FirstName,SurName: String;
InFile,OutFile: TextFile;
TagLength: Integer;
RegExp: TRegExpr;
Colwidths: array[0..6] of integer = (25,18,18,3,20,31,250);
// !!! This for 5NT File, don't touch
implementation
{$R *.dfm}
procedure TSDIAppForm.DelBtnClick(Sender: TObject);
begin
DeleteARow(StringGrid1, StringGrid1.Row);
end;
procedure TSDIAppForm.DeleteARow(Grid: TStringGrid; ARow: Integer);
begin
TMyGrid(Grid).DeleteRow(ARow);
end;
procedure TSDIAppForm.FileNew1Execute(Sender: TObject);
begin
{ Do nothing }
end;
procedure TSDIAppForm.FileOpen1Execute(Sender: TObject);
begin
OpenDialog.Execute;
SDIAppForm.caption:='Зачисление переводов - '+ OpenDialog.Filename;
if OpenDialog.Filename<>'' then
begin
DelBtn.Enabled:=false;
SaveButton.Enabled:=false;
BtnSaveToCard.Enabled:=false;
LoadInFile;
if (StringGrid1.RowCount > 1) and (StringGrid1.Cells[6,1] <> '') then
begin
SaveButton.Enabled:=true;
BtnSaveToCard.Enabled:=true;
Delbtn.Enabled:=true;
end;
end;
end;
procedure TSDIAppForm.LoadInFile;
var
col,row:Integer;
begin
AssignFile(InFile,OpenDialog.Filename);
Reset(InFile);
StringGrid1.RowCount:=2;
row:=0;
for col := 0 to 6 do {clear second line}
begin
StringGrid1.Cells[col,1]:='';
end;
while not Eof(InFile) do
begin
Readln(InFile, SIn);
SOut:=ToAnsi(SIn);
TagLength:=AnsiPos(':',SIn)-1;
if TagLength=-1 then
begin
STag:=SOut;
end
else
begin
STag:=MidStr(SOut,1,TagLength);
Val:=MidStr(SOut,TagLength+2,Length(SOut)-TagLength-1);
end;
if STag='%МЕЖБНКДОК' then
begin
row:=row+1;
if row>1 then
StringGrid1.RowCount:=row+1;
end;
if STag='ВАЛЮТА ' then
StringGrid1.Cells[3,row]:=Val;
if STag='СУММА ' then
StringGrid1.Cells[5,row]:=Val;
if (midstr(STag,1,4)='ПРИМ') and (length(Val)<>0) then
StringGrid1.Cells[6,row]:=StringGrid1.Cells[6,row]+Val;
if (midstr(STag,1,4)='%END') then
begin
try
RegExp := TRegExpr.Create;
RegExp.Expression := '[А-Я]{1}[а-я]{2,}\s[А-Я]{1}[а-я]{2,}\s[А-Я]{1}[а-я]{2,}';
if RegExp.Exec(StringGrid1.Cells[6,row]) then
begin
RegExp.Expression := '[А-Я]{1}[А-Яа-я]{2,}';
RegExp.Exec(RegExp.Match[0]);
StringGrid1.Cells[0,row]:=RegExp.Match[0];
RegExp.ExecNext;
StringGrid1.Cells[1,row]:=RegExp.Match[0];
RegExp.ExecNext;
StringGrid1.Cells[2,row]:=RegExp.Match[0];
end;
RegExp.Expression := '(40817|42301|42302|42303|42304|42305|42306|42307)[0-9]{15}';
if RegExp.Exec(StringGrid1.Cells[6,row]) then
begin
StringGrid1.Cells[4,row]:=RegExp.Match[0];
end;
finally
RegExp.Free;
end;
end;
end;
CloseFile(InFile);
end;
procedure TSDIAppForm.FileSave1Execute(Sender: TObject);
var i,j:Integer;
S,Today:string;
begin
Today:=DateTimeToStr(Now);
SaveDialog.FileName:='b'+Midstr(Today,9,2)+Midstr(Today,4,2)+Midstr(Today,1,2)+'a.777';
SaveDialog.InitialDir:='c:\ObmenPC40\Dividend\';
SaveDialog.Execute;
Rewrite(OutFile,SaveDialog.FileName);
for i := 1 to StringGrid1.RowCount - 1 do
begin
for j := 0 to StringGrid1.ColCount - 1 do
begin
S:=Trim(Midstr(StringGrid1.Cells[j,i],1,Colwidths[j]));
if Colwidths[j]>length(S) then
S:=LeftPad(S,' ',Colwidths[j]);
Write(OutFile,' '+ToOEM(S));//!!!
end;
Write(OutFile,''#13+#10);
end;
Flush(OutFile);
CloseFile(OutFile);
end;
procedure TSDIAppForm.BtnSaveToCardClick(Sender: TObject);
var i,j:Integer;
Today:string;
begin
Today:=DateTimeToStr(Now);
SaveDialog.FileName:='b'+Midstr(Today,9,2)+Midstr(Today,4,2)+Midstr(Today,1,2)+'a.777';
SaveDialog.InitialDir:='c:\ObmenPC40\Card\';
SaveDialog.Execute;
Rewrite(OutFile,SaveDialog.FileName);
for i := 1 to StringGrid1.RowCount - 1 do
begin
Write(OutFile,Trim(IntToStr(i)));
Write(OutFile,'^777');
for j := 0 to StringGrid1.ColCount - 1 do
begin
Write(OutFile,'^'+ToOEM(Trim(StringGrid1.Cells[j,i])));//!!!
end;
Write(OutFile,''#13+#10);
end;
Flush(OutFile);
CloseFile(OutFile);
end;
procedure TSDIAppForm.FormShow(Sender: TObject);
var
col: Integer;
begin
StringGrid1.ColCount:=7;
StringGrid1.RowCount:=2;
StringGrid1.FixedRows:=1;
StringGrid1.ColWidths[0]:=90; StringGrid1.Cells[0,0]:='Фамилия';
StringGrid1.ColWidths[1]:=90; StringGrid1.Cells[1,0]:='Имя';
StringGrid1.ColWidths[2]:=90; StringGrid1.Cells[2,0]:='Отчество';
StringGrid1.ColWidths[3]:=20; StringGrid1.Cells[3,0]:='Вал';
StringGrid1.ColWidths[4]:=105; StringGrid1.Cells[4,0]:='Номер счета';
StringGrid1.ColWidths[5]:=70; StringGrid1.Cells[5,0]:='Сумма';
StringGrid1.ColWidths[6]:=1180; StringGrid1.Cells[6,0]:='Примечание';
for col := 0 to 6 do {clear second line}
begin
StringGrid1.Cells[col,1]:='';
end;
DelBtn.Enabled:=false;
SaveButton.Enabled:=false;
BtnSaveToCard.Enabled:=false;
OpenDialog.FileName:= ParamStr(1);
SDIAppForm.Caption:='Зачисление переводов - '+ ParamStr(1);
if ParamStr(1) <> '' then
begin
LoadInFile;
if (StringGrid1.RowCount > 1) and (StringGrid1.Cells[6,1] <> '') then
begin
SaveButton.Enabled:=true;
BtnSaveToCard.Enabled:=true;
Delbtn.Enabled:=true;
end;
end;
end;
procedure TSDIAppForm.FileExit1Execute(Sender: TObject);
begin
Close;
end;
function TSDIAppForm.ToOEM(S:String):String;
{ ConvertAnsiToOem translates a string into the OEM-defined character set }
{$IFNDEF WIN32}
var
Source, Dest : array[0..255] of Char;
{$ENDIF}
begin
{$IFDEF WIN32}
SetLength(Result, Length(S));
if Length(Result) > 0 then
AnsiToOem(PChar(S), PChar(Result));
{$ELSE}
if Length(Result) > 0 then
begin
AnsiToOem(StrPCopy(Source, S), Dest);
Result := StrPas(Dest);
end;
{$ENDIF}
end; { ConvertAnsiToOem }
function TSDIAppForm.ToAnsi(S:String):String;
{ ConvertOemToAnsi translates a string into the OEM-defined character set }
{$IFNDEF WIN32}
var
Source, Dest : array[0..255] of Char;
{$ENDIF}
begin
{$IFDEF WIN32}
SetLength(Result, Length(S));
if Length(Result) > 0 then
OemToAnsi(PChar(S), PChar(Result));
{$ELSE}
if Length(Result) > 0 then
begin
OemToAnsi(StrPCopy(Source, S), Dest);
Result := StrPas(Dest);
end;
{$ENDIF}
end; { ConvertOemToAnsi }
function TSDIAppForm.LeftPad(S: string; Ch: Char; Len: Integer): string;
var
RestLen: Integer;
begin
Result := S;
RestLen := Len - Length(s);
if RestLen < 1 then Exit;
Result := S + StringOfChar(Ch, RestLen);
end;
function TSDIAppForm.RightPad(S: string; Ch: Char; Len: Integer): string;
var
RestLen: Integer;
begin
Result := S;
RestLen := Len - Length(s);
if RestLen < 1 then Exit;
Result := StringOfChar(Ch, RestLen) + S;
end;
end.
21 февр. 2013 г.
Создание VPN точка-точка на OpenVPN
Возникла необходимость сделать VPN точка-точка на W7.
Решили сделать на OpenVPN. Сделали, теперь пишу, чтобы не забыть.
1. Качаем инсталляцию с сайта. Для Windows сборки на 64 и 32 разряда разные.
2. Инсталлируем. Не забываем поставить GUI.
3. Одну машину ставим в режим сервера, другую в режим клиента.
Та, что будет в режиме сервера - с фиксированным IP, за firewall-ом. В нем ковыряем дырочку, по не стандартному порту, чтобы затруднить сканирование.
Применять будем протокол UDP, по 2-м причинам:
- опять-таки сканировать труднее,
- производительность даже визуально живее. Проверялось при обращении к мапированному диску в винде, чтении с него аксессовской БД.
Сначала сделали c shared keys. Заработало быстро.
Делов собственно два:
- сгенерировать ключ и разложить на обе машины. Можно прямо в каталог config.
<pre>
- написать конфиг, положить туда же.
Будет желтым, пока кто-нибудь не подцепится. Тогда станет зеленым.
На клиенте, том кто вызывает, просто запускаем гуй, "подключить", смотрим какое все зеленое. На сертификатах все сложнее, однако только на первый взгляд. В виндовой инсталляции есть каталог easy-rsa, где лежат скрипты для генерации необходимой инфраструктуры открытых ключей.
Сначала переименовываем vars.bat и правим его. В принципе, достаточно одной правки - указать каталог ключей. Но! Необходимо в этот каталог скопировать файлы index.txt и serial, переименовав их. Если этого не сделать, то CA сгенерируется нормально, а вот ключи для работы не будут подписываться, будут оставаться только запросами на сертификаты, а не сертификатами.
Из запущенного сеанса cmd.exe запускаем последовательно vars.bat, затем командные файлы, которые генерируют dh, ключ и сертификат CA, затем ключи и сертификаты сервера и клиентов. Важно при генерации указывать разные DN для каждого клиента, если только специальной опцией не разрешить проглатывать одинаковые DN.
При каждой генерации образуется закрытый ключ (с расширением key) и сертификат (с расширением srt). Если получается другое расширение, значит открытый ключ у нас сгенерировался, но не подписался ключом CA и осталсягрязнулей запросом на сертификат.
Для работы вся эта куча ключей не нужна. На каждой машине кладется сертификат CA, чтобы проверять подлинность сертификатов, предъявляемых другой стороной, свой закрытый ключ, свой сертификат.
Соответственно, закрытый ключ CA прячем, т.к. он нужен для подписания новых ключей, а значит на рабочих машинах ему делать нечего, а лежать он будет в укромном месте.
Потом правим конфиги на работу с сертификатами, кладем ca.srt, client.srt, client.key (или srv.srt и srv.key) прямо в конфиг, чтобы не искать. Далее - все так же как и с shared keys - щелкаем мышкой по гую, соединяемся, отсоединяемся.
1. Качаем инсталляцию с сайта. Для Windows сборки на 64 и 32 разряда разные.
2. Инсталлируем. Не забываем поставить GUI.
3. Одну машину ставим в режим сервера, другую в режим клиента.
Та, что будет в режиме сервера - с фиксированным IP, за firewall-ом. В нем ковыряем дырочку, по не стандартному порту, чтобы затруднить сканирование.
Применять будем протокол UDP, по 2-м причинам:
- опять-таки сканировать труднее,
- производительность даже визуально живее. Проверялось при обращении к мапированному диску в винде, чтении с него аксессовской БД.
Сначала сделали c shared keys. Заработало быстро.
Делов собственно два:
- сгенерировать ключ и разложить на обе машины. Можно прямо в каталог config.
<pre>
openvpn --genkey --secret secret.key</pre>
- написать конфиг, положить туда же.
Клиент: <pre> remote 195.1.2.3 1194 dev tun client proto udp ifconfig 10.10.10.2 10.10.10.1 secret secret.key keepalive 60 300 comp-lzo verb 1 mute 20 log-append ../connect.log status ../status </pre> Сервер: <pre> port 1194 dev tun udp-server proto udp ifconfig 10.10.10.1 10.10.10.2 secret secret.key comp-lzo verb 1 mute 20 log-append ../connect.log
</pre>Все, на значке гуя на сервере щелкаем "подключить", он становится желтым.
Будет желтым, пока кто-нибудь не подцепится. Тогда станет зеленым.
На клиенте, том кто вызывает, просто запускаем гуй, "подключить", смотрим какое все зеленое. На сертификатах все сложнее, однако только на первый взгляд. В виндовой инсталляции есть каталог easy-rsa, где лежат скрипты для генерации необходимой инфраструктуры открытых ключей.
Сначала переименовываем vars.bat и правим его. В принципе, достаточно одной правки - указать каталог ключей. Но! Необходимо в этот каталог скопировать файлы index.txt и serial, переименовав их. Если этого не сделать, то CA сгенерируется нормально, а вот ключи для работы не будут подписываться, будут оставаться только запросами на сертификаты, а не сертификатами.
Из запущенного сеанса cmd.exe запускаем последовательно vars.bat, затем командные файлы, которые генерируют dh, ключ и сертификат CA, затем ключи и сертификаты сервера и клиентов. Важно при генерации указывать разные DN для каждого клиента, если только специальной опцией не разрешить проглатывать одинаковые DN.
При каждой генерации образуется закрытый ключ (с расширением key) и сертификат (с расширением srt). Если получается другое расширение, значит открытый ключ у нас сгенерировался, но не подписался ключом CA и остался
Для работы вся эта куча ключей не нужна. На каждой машине кладется сертификат CA, чтобы проверять подлинность сертификатов, предъявляемых другой стороной, свой закрытый ключ, свой сертификат.
Соответственно, закрытый ключ CA прячем, т.к. он нужен для подписания новых ключей, а значит на рабочих машинах ему делать нечего, а лежать он будет в укромном месте.
Потом правим конфиги на работу с сертификатами, кладем ca.srt, client.srt, client.key (или srv.srt и srv.key) прямо в конфиг, чтобы не искать. Далее - все так же как и с shared keys - щелкаем мышкой по гую, соединяемся, отсоединяемся.
Клиент: remote 195.239.178.94 11940 dev tun tls-client proto udp ifconfig 10.10.10.2 10.10.10.1 dh dh1024.pem ca ca.crt cert client.crt key client.key keepalive 60 300 comp-lzo verb 1 mute 20 log-append ../connect.log status ../status Сервер: port 11940 dev tun tls-server proto udp ifconfig 10.10.10.1 10.10.10.2 dh dh1024.pem ca ca.crt cert server.crt key server.key comp-lzo verb 1 mute 20 log-append ../connect.logЕще не раскрыта тема длины ключей, отозванных сертификатов и маршрутизации.
18 февр. 2013 г.
Доработка файлов по 365-П (GUID, переименование, поиск ошибок и т.д.)
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, StrUtils, DateUtils, ComCtrls, ExtCtrls, ToolWin;
type
TForm1 = class(TForm)
Go_Button: TButton;
OpenDialog1: TOpenDialog;
OpenButton: TButton;
SaveDialog1: TSaveDialog;
BtnRe: TButton;
ToolBar1: TToolBar;
Panel1: TPanel;
StatusBar1: TStatusBar;
ProgressBar1: TProgressBar;
SrcOpenDialog: TOpenDialog;
MProtocol: TRichEdit;
procedure FormCreate(Sender: TObject);
procedure BtnReClick(Sender: TObject);
procedure OpenButtonClick(Sender: TObject);
procedure Go_ButtonClick(Sender: TObject);
function ToOEM(S:String):String;
function ToAnsi(S:String):String;
function WriteLog(Level:Integer; S:String):String;
function FileSizeByName(Name:String): Integer;
function isNum(const st:string): boolean;
private
{ Private declarations }
public
{ Public declarations }
end;
const
OstPref='BOS1_';
OstSrcPref='RBN';
OperPref='BV100_';
OperSrcPref='ZNO';
NalschPref='BNS1_';
NalschSrcPref='ZNO';
ReceiptPref='PB1_';
ChunkLimit=470000; //524288 - 512К
Bic='10813823';
INN='7744001497';
ERR=0;
WARN=1;
INFO=2;
var
Form1: TForm1;
InFile,OutFile: TextFile;
CurrentFileNum,NumOutFiles,OutFileSize: Integer;
SIn,SOut: String;
InFileSize, InFilePosition: Integer;
DateZapr,KodNO,NomZapr,NomResh,DateResh :String;
NumericTags: TStringList;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
DateZapr:='';
NomZapr:='';
NomResh:='';
DateResh:='';
NumericTags := TStringList.Create;
NumericTags.Add('ИННКО');
NumericTags.Add('КППКО');
NumericTags.Add('БИК');
NumericTags.Add('ИНННП');
NumericTags.Add('КППНП');
NumericTags.Add('НомСчПП');
NumericTags.Add('НомСч');
NumericTags.Add('БИКБП');
NumericTags.Add('НомКоррСч');
NumericTags.Add('НомДок');
NumericTags.Sort; //for Find method!
end;
procedure TForm1.OpenButtonClick(Sender: TObject);
begin
OpenDialog1.execute;
DateZapr:='';
NomZapr:='';
NomResh:='';
DateResh:='';
MProtocol.Text:='';
WriteLog(INFO,'Файл к обработке: '+OpenDialog1.Filename+''#13+#10);
end;
procedure TForm1.BtnReClick(Sender: TObject);
var
FileName,DateStr: String;
NameLength: Integer;
Today: TDateTime;
begin
//Формирование подтерждения по заданному файлу
//ZNO10813823_774820120203_000594###
//10@@@
//2012-02-06@@@
//10:35:37@@@
//===
if (AnsiPos('.',ExtractFileName(OpenDialog1.FileName))<>0) then
SaveDialog1.FileName:=ReceiptPref+MidStr(ExtractFileName(OpenDialog1.FileName),1,AnsiPos('.',ExtractFileName(OpenDialog1.FileName))-1)+'.TXT'
else
SaveDialog1.FileName:=ReceiptPref+ExtractFileName(OpenDialog1.FileName)+'.TXT';
SaveDialog1.Execute;
WriteLog(INFO,'Имя файла подтверждения: '+SaveDialog1.FileName+''#13+#10);
Rewrite(OutFile,SaveDialog1.FileName);
FileName:=ExtractFileName(OpenDialog1.FileName);
Writelog(INFO,''#13+#10); // empty line before receipt
Write(OutFile,MidStr(FileName,1,Length(FileName)-4)+'###'+''#13+#10);
WriteLog(INFO,MidStr(FileName,1,Length(FileName)-4)+'###'+''#13+#10);
Write(OutFile,'10@@@'+''#13+#10);
Writelog(INFO,'10@@@'+''#13+#10);
DateStr:=DateToStr(Now);
Write(OutFile,MidStr(DateStr,7,4)+'-'+MidStr(DateStr,4,2)+'-'+MidStr(DateStr,1,2)+'@@@'+''#13+#10);
Writelog(INFO,MidStr(DateStr,7,4)+'-'+MidStr(DateStr,4,2)+'-'+MidStr(DateStr,1,2)+'@@@'+''#13+#10);
Write(OutFile,TimeToStr(Now)+'@@@'+''#13+#10);
Writelog(INFO,TimeToStr(Now)+'@@@'+''#13+#10);
Write(OutFile,'==='+''#13+#10);
Writelog(INFO,'==='+''#13+#10);
Flush(OutFile);
CloseFile(OutFile);
end;
procedure TForm1.Go_ButtonClick(Sender: TObject);
var
Id: TGUID;
StringNo, StringCount,Code: Integer;
Tag,Val,HeaderTag,HeaderVal,StrNo,StrFileNo,StrNumOutFiles,DateForName,NomForName, InfType, Pref: String;
TagLength,HeaderTagLength,i: Integer;
RetCode:Boolean;
TopHeader,ThirdHeader: Array of String;
TopHeaderLength,ThirdHeaderLength,HeaderState: Integer;
Index: Integer;
begin
CurrentFileNum:=1;
OutFileSize:=0;
InFilePosition:=0;
MProtocol.Text:='';
WriteLog(INFO,'Файл к обработке: '+OpenDialog1.Filename+''#13+#10);
if not (FileExists(OpenDialog1.Filename)) then exit;
InFileSize:=FileSizeByName(OpenDialog1.Filename);
ProgressBar1.Min:=0;
ProgressBar1.Max:=InFileSize;
ProgressBar1.Position:=0;
AssignFile(InFile,OpenDialog1.Filename);
// Rewrite(OutFile, OpenDialog1.Filename+'.chk1');
Rewrite(OutFile, OpenDialog1.Filename+'.chk'+Format('%.2d',[CurrentFileNum]));
Reset(InFile);
if InFileSize > ChunkLimit then
begin
WriteLog(WARN,'Размер файла больше предельного размера одной части'#13+#10);
NumOutFiles:=(InFileSize div ChunkLimit)+1;
Str(NumOutFiles,StrNumOutFiles);
end;
HeaderState:=0;
TopHeaderLength:=0;
ThirdHeaderLength:=0;
while not Eof(InFile) do
begin
Readln(InFile, SIn);
SOut:=ToAnsi(SIn);
if HeaderState < 3 then //Еще не считали все заголовки
begin
if HeaderState=0 then
begin //read top header
TopHeaderLength:=TopHeaderLength+1;
SetLength(TopHeader,TopHeaderLength);
TopHeader[TopHeaderLength-1]:=SOut;
end;
if HeaderState=2 then
begin //read 3rd header
ThirdHeaderLength:=ThirdHeaderLength+1;
SetLength(ThirdHeader,ThirdHeaderLength);
ThirdHeader[ThirdHeaderLength-1]:=SOut;
end;
if SOut='###' then HeaderState:=HeaderState+1;
end;
StringNo:=StringNo+1;
Str(StringNo,StrNo);
TagLength:=AnsiPos(':',SOut)-1;
if TagLength<>-1 then
begin
Tag:=MidStr(SOut,1,TagLength);
Val:=MidStr(SOut,TagLength+2,Length(SOut)-TagLength-1);
if (Tag = 'НомСч') and (HeaderState >=3) then // found new 3rd header when already read top 3 headers
begin
HeaderState:=2; //return to 3rd header mode
ThirdHeaderLength:=1; //set 1st line of 3rd header
ThirdHeader[ThirdHeaderLength-1]:=SOut; // write it down
WriteLog(INFO,'Строка '+StrNo+' - Найдено:'+SOut);
end;
if Tag = 'ТипИнф' then
begin
InfType:=Val;
WriteLog(INFO,'Строка '+StrNo+' - Найден ТипИнф:'+InfType);
end;
if Tag = 'ИдФайл' then
begin
CreateGUID(Id);
SOut:='ИдФайл:'+ Val + MidStr(GUIDToString(Id),2,36);
WriteLog(INFO,'Строка '+StrNo+' - Добавлен GUID к ИдФайл');
end;
if Tag = 'КодНО' then
begin
KodNO:=Val;
WriteLog(INFO,'Строка '+StrNo+' - Найден КодНО:'+KodNO);
end;
if Tag = 'ИдДок' then
begin
CreateGUID(Id);
SOut:='ИдДок:'+ MidStr(GUIDToString(Id),2,36);
WriteLog(INFO,'Строка '+StrNo+' - добавлен GUID к ИдДок');
end;
if (Tag = 'НомЧасти') and (InFileSize <= ChunkLimit) then
begin
SOut:='';
WriteLog(INFO,'Строка '+StrNo+' - Удален НомЧасти');
end;
if (Tag = 'КолДок') and (InFileSize > ChunkLimit) then
begin
SOut:='КолДок:'+StrNumOutFiles;
WriteLog(INFO,'Строка '+StrNo+' - КолДок исправлен');
end;
if Tag = 'НомЗапр' then
begin
NomZapr:='';
for i := length(Val) to 6 - 1 do NomZapr:=NomZapr+'0';
NomZapr:=NomZapr+Val;
WriteLog(INFO,'Строка '+StrNo+' - Найден НомЗапр:'+NomZapr);
end;
if Tag = 'ДатаЗапр' then
begin
DateZapr:=MidStr(Val,7,4)+MidStr(Val,4,2)+MidStr(Val,1,2);
WriteLog(INFO,'Строка '+StrNo+' - Найдена ДатаЗапр:'+DateZapr);
end;
if Tag = 'НомРеш' then
begin
NomResh:='';
for i := length(Val) to 6 - 1 do NomResh:=NomResh+'0';
NomResh:=NomResh+Val;
WriteLog(INFO,'Строка '+StrNo+' - Найден НомРеш:'+NomResh);
end;
if Tag = 'ДатаРеш' then
begin
DateResh:=MidStr(Val,7,4)+MidStr(Val,4,2)+MidStr(Val,1,2);
WriteLog(INFO,'Строка '+StrNo+' - Найдена ДатаРеш:'+DateResh);
end;
if (NumericTags.Find(Tag,index)) then // Проверка корректности значений числовых тегов
begin
if not isNum(Val) then
WriteLog(ERR,'Строка '+StrNo+' - Ошибка: Не числовые значения:'+Tag+':'+Val);
end;
if (Val='') and (Tag<>'ИдДок') then // Только последним, после обработки других
begin
WriteLog(WARN,'Строка '+StrNo+' - Обнаружен пустой тег:'+Tag);
end;
end
else //No tags found!
begin
if (AnsiPos('Ошибка',SOut))<>0 then
begin
WriteLog(ERR,'Строка '+StrNo+' - Найдена ошибка: '+SOut);
end;
if (AnsiPos('Ожидается',SOut))<>0 then
begin
WriteLog(ERR,'Строка '+StrNo+' - Найдена ошибка: '+SOut);
end;
end;
if SOut<>'' then
begin
Writeln(OutFile,ToOEM(SOut));
OutFileSize:=OutFileSize+Length(SOut);
InFilePosition:=InFilePosition+Length(SOut);
ProgressBar1.Position:=InFilePosition;
if (OutFileSize > ChunkLimit) and (TagLength =-1) then
//достигли предела и не в середине документа
begin
Writeln(OutFile,'@@@');
Writeln(OutFile,'===');
OutFileSize:=0;
Flush(OutFile);
CloseFile(OutFile);
CurrentFileNum:=CurrentFileNum+1;
StrFileNo:=Format('%.2d',[CurrentFileNum]); // for filename - with leading zero's
WriteLog(INFO,'Строка '+StrNo+' - Начало части '+StrFileNo);
Rewrite(OutFile, OpenDialog1.Filename+'.chk'+StrFileNo);
Str(CurrentFileNum,StrFileNo); // for tag in the file - without leading zeros
for i:=0 to TopHeaderLength - 1 do
begin
HeaderTagLength:=AnsiPos(':',TopHeader[i])-1;
HeaderTag:=MidStr(TopHeader[i],1,HeaderTagLength);
HeaderVal:=MidStr(TopHeader[i],HeaderTagLength+2,Length(TopHeader[i])-HeaderTagLength-1);
if HeaderTag='ИдФайл' then
TopHeader[i]:='ИдФайл:'+ MidStr(HeaderVal,1,29) + MidStr(GUIDToString(Id),2,36);
if HeaderTag='НомЧасти' then
TopHeader[i]:='НомЧасти:'+ StrFileNo;
if HeaderTag='КолДок' then
TopHeader[i]:='КолДок:'+ StrNumOutFiles;
Writeln(OutFile,ToOEM(TopHeader[i]));
end;
Writeln(OutFile,ToOEM('@@@')); // добавить недостающие собаки после первого заголовка
for i:=0 to ThirdHeaderLength - 1 do
Writeln(OutFile,ToOEM(ThirdHeader[i]));
end;
end;
end;
Flush(OutFile);
CloseFile(OutFile);
SaveDialog1.FileName:='';
if MessageDlg('Исходный запрос был получен электронно?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then
begin
SrcOpenDialog.Title:='Выберите файл исходного запроса';
SrcOpenDialog.Execute();
SaveDialog1.FileName:=MidStr(ExtractFileName(SrcOpenDialog.FileName),1,AnsiPos('.',ExtractFileName(SrcOpenDialog.FileName))-1);
if (InfType='ОСТАТКИ') then Pref:=OstPref;
if (InfType='ОПЕРАЦИИПОСЧ') then Pref:=OperPref;
if (InfType='НАЛСЧЕТОВ') then Pref:=NalschPref;
SaveDialog1.FileName:=Pref+SaveDialog1.FileName;
end
else // create name from file contents
begin
if (InfType='ОСТАТКИ') then
SaveDialog1.FileName:=OstPref+OstSrcPref+Bic+'_'+KodNO+DateResh+'_'+NomResh;
if (InfType='ОПЕРАЦИИПОСЧ') then
SaveDialog1.FileName:=OperPref+OperSrcPref+Bic+'_'+KodNO;
if (InfType='НАЛСЧЕТОВ') then
SaveDialog1.FileName:=NalschPref+NalschSrcPref+Bic+'_'+KodNO;
if ((InfType='ОПЕРАЦИИПОСЧ') or (InfType='НАЛСЧЕТОВ')) then
SaveDialog1.FileName:=SaveDialog1.FileName+DateZapr+'_'+NomZapr;
end;
SaveDialog1.FileName:=SaveDialog1.FileName+'.TXT';
ProgressBar1.Position:=0;
if SaveDialog1.Execute then
begin
if NumOutFiles > 1 then
begin // больше чем один файл - нумеруем с "1"
for i := 1 to NumOutfiles do
begin
// Str(i,StrFileNo);
StrFileNo:=Format('%.2d',[i]);
RetCode:=RenameFile(OpenDialog1.Filename+'.chk'+StrFileNo, ReplaceStr(SaveDialog1.FileName,'BV100','BV1'+StrFileNo));
if RetCode=false then
MessageDlg('Невозможно сохранить файл '+ReplaceStr(SaveDialog1.FileName,'BV100','BV1'+StrFileNo), mtError,[mbOk], 0, mbOk)
else
MessageDlg('Файл сохранен как: '+ReplaceStr(SaveDialog1.FileName,'BV100','BV1'+StrFileNo),mtInformation,[mbOk], 0, mbOk);
end;
end
else // один файл нумеруется с "0"
begin
StrFileNo:='01';
RetCode:=RenameFile(OpenDialog1.Filename+'.chk'+StrFileNo,SaveDialog1.FileName);
if RetCode=false then
MessageDlg('Невозможно сохранить файл '+SaveDialog1.FileName, mtError,[mbOk], 0, mbOk)
else
MessageDlg('Файл сохранен как: '+SaveDialog1.FileName,mtInformation,[mbOk], 0, mbOk);
end;
end;
end;
function TForm1.WriteLog(Level:Integer; S:String):String;
var
AColor:Integer;
begin
case Level of
ERR : AColor := clRed;
INFO: AColor := clLime;
WARN: AColor := clYellow;
else
AColor := clLime;
end;
with MProtocol do
begin
SelStart := Length(Text);
SelAttributes.Color := AColor;
Lines.Add(S);
end;
MProtocol.SelStart := MaxInt;
SendMessage(MProtocol.handle, EM_SCROLLCARET,0,0);
Result:=S;
end;
function TForm1.ToOEM(S:String):String;
{ ConvertAnsiToOem translates a string into the OEM-defined character set }
{$IFNDEF WIN32}
var
Source, Dest : array[0..255] of Char;
{$ENDIF}
begin
{$IFDEF WIN32}
SetLength(Result, Length(S));
if Length(Result) > 0 then
AnsiToOem(PChar(S), PChar(Result));
{$ELSE}
if Length(Result) > 0 then
begin
AnsiToOem(StrPCopy(Source, S), Dest);
Result := StrPas(Dest);
end;
{$ENDIF}
end; { ConvertAnsiToOem }
function TForm1.ToAnsi(S:String):String;
{ ConvertOemToAnsi translates a string into the OEM-defined character set }
{$IFNDEF WIN32}
var
Source, Dest : array[0..255] of Char;
{$ENDIF}
begin
{$IFDEF WIN32}
SetLength(Result, Length(S));
if Length(Result) > 0 then
OemToAnsi(PChar(S), PChar(Result));
{$ELSE}
if Length(Result) > 0 then
begin
OemToAnsi(StrPCopy(Source, S), Dest);
Result := StrPas(Dest);
end;
{$ENDIF}
end; { ConvertOemToAnsi }
function TForm1.FileSizeByName(Name:String): Integer;
var
F: File of byte;
begin
AssignFile(F, Name);
Reset(F);
Result:=FileSize(F);
CloseFile(F);
end;
function TForm1.isNum(const st:string): boolean;
var
i: Integer;
begin
isNum:=True;
for i := 1 to Length(st) do
if not (st[i] in ['0'..'9']) then isNum:=False;
end;
end.
Подписаться на:
Комментарии (Atom)



