Форум » [x]Harbour » Облачные сервисы (WebDAV, CalDAV &Co) » Ответить

Облачные сервисы (WebDAV, CalDAV &Co)

Dr. Oldwarez: После некоторого разбирательства с прогой удалось организовать импорт из ICAL-файлов и экспорт в оные. Но тут шеф захотел, чтобы был прямой контакт с CalDav через интернет. Я знаю, что на питоне такое возможно. На дельфине и даже Xojo (RealBasic) тоже - через спецбиблиотеку. Но как реализовать подключение к облачному сервису в Harbour/Minigui? Возможно ли это вообще?

Ответов - 174, стр: 1 2 3 4 5 6 7 8 9 All

Петр: Каждый VEVENT в этом объекте должен иметь идентичный UID. Соотносится с информацией по ссылке выше (пост №1647) Каждый объект должен содержать только 1 событие или задачу. Попробуйте указать для всех VEVENT одинаковый UID и посмотреть, что из этой затеи получится.

Dr. Oldwarez: Петр пишет: Каждый объект должен содержать только 1 событие или задачу. Попробуйте указать для всех VEVENT одинаковый UID и посмотреть, что из этой затеи получится. Получилось то, что второе событие импортировалось, а первое - нет. Вывод: надо импортировать поодиночке в цикле

Dr. Oldwarez: И даже это не срабатывает Просто ничего не выводит и не импортирует!!!


Петр: curl -k -u USERNAME:PASSWORD -T localname.ics -X "PUT" https://webmail.kleeblatt.com/rpc.php/calendars/USERNAME/calendar~GhGVum1xWexaffEfhiVkNN7/remotename.ics где remotename == UID VEVENTа помещенного в remotename.ics BEGIN:VCALENDAR .. BEGIN:VEVENT .. UID: xxxxxxxx .. END:VEVENT END:VCALENDAR

Dr. Oldwarez: Петр пишет: curl -k -u USERNAME:PASSWORD -T localname.ics -X "PUT" https://webmail.kleeblatt.com/rpc.php/calendars/USERNAME/calendar~GhGVum1xWexaffEfhiVkNN7/remotename.ics где remotename == UID VEVENTа помещенного в remotename.ics BEGIN:VCALENDAR .. BEGIN:VEVENT .. UID: xxxxxxxx .. END:VEVENT END:VCALENDAR И так делал, а всё не получается. Localname.ics можно брать любое или тоже UID? "PUT" - закавычивать или нет?

Петр: Dr. Oldwarez пишет: "PUT" - закавычивать или нет? Нет Dr. Oldwarez пишет: Localname.ics можно брать любое Любое добавьте в командную строку -Dhead И покажите содержимое файла head здесь, и командную строку тоже без купюр. Ну конечно без личных данных

Dr. Oldwarez: Петр пишет: И покажите содержимое файла head здесь, и командную строку тоже купюр. Ну конечно без личных данных curl -k -u USERNAME:PASSWORD -T C:\MINIGUI\MYPROG\TEMP\qwerty.ics -X PUT https://webmail.kleeblatt.com/rpc.php/calendars/USERNAME/calendar~GhGVum1xWexaffEfhiVkNN7/817474de-31f6-446d-a09b-d4976f554e5b.ics Где 817474de-31f6-446d-a09b-d4976f554e5b.ics - это имя сгенерированное функцией генератора UID qwerty.ics - локальный файл в одно событие А куда здесь ставить -Dhead?

Петр: curl -Dhead -k ..

Dr. Oldwarez: Петр пишет: curl -Dhead -k .. Да. И тот же результат curl -Dhead -k -u USERNAME:PASSWORD -T C:\MINIGUI\MYPROG\TEMP\localfile.ics -X PUT https://webmail.kleeblatt.com/rpc.php/calendars/USERNAME/calendar~GhGVum1xWexaffEfhiVkNN7/817474de-31f6-446d-a09b-d4976f554e5b.ics И заголовок [pre2]HTTP/1.1 100 Continue HTTP/1.1 204 No Content Date: Mon, 29 Mar 2021 13:54:37 GMT Server: Apache X-Powered-By: PHP/7.3.27 Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate Pragma: no-cache Vary: Accept-Encoding Set-Cookie: PHPSESSID=blunlmi2m5vrs8g6gdahahrrfn; path=/ Set-Cookie: horde_secret_key=blunlmi2m5vrs8g6gdahahrrfn; path=/; domain=webmail.kleeblatt.com; HttpOnly Set-Cookie: default_horde_view=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=webmail.kleeblatt.com X-Powered-By: PleskLin Content-Type: text/html; charset=UTF-8[/pre2]

Петр: В общем-то результат нормальный. HTTP/1.1 100 Continue HTTP/1.1 204 No Content Показывает когда файл уже сохранен на сервере и вы пытаетесь его сохранить снова. Зайдите в C:\MINIGUI\MYPROG\TEMP\localfile.ics, измените LOCATION, примените PUT, а потом GET к 817474de-31f6-446d-a09b-d4976f554e5b.ics P.S. 204 No Content

Dr. Oldwarez: Петр пишет: В общем-то результат нормальный. HTTP/1.1 100 Continue HTTP/1.1 204 No Content Показывает когда файл уже сохранен на сервере и вы пытаетесь его сохранить снова. Зайдите в C:\MINIGUI\MYPROG\TEMP\localfile.ics, измените LOCATION, примените PUT, а потом GET к 817474de-31f6-446d-a09b-d4976f554e5b.ics P.S. УРА!!! Заработало!

Dr. Oldwarez: Извините, оно не работает. Не заносит данные из DBF в календарь. Может, с библиотекой попробовать? Притом, что ICSы генерятся [pre]BEGIN:VCALENDAR VERSION:2.0 PRODID:-//AaaaBbbbCccc BEGIN:VEVENT UID:c60a4464-2dec-4f83-8a9f-02d2463352e8 DTSTAMP:20210428T154800Z DTSTART:20210601T154700Z DTEND:20210601T161700Z SUMMARY:Тест DESCRIPTION:Просто тест LOCATION: Урюпинск END:VEVENT END:VCALENDAR[/pre] [pre]curl -k -u '+cCALName+':'+cCALPWD+' -T '+cOutput+' -X PUT '+cCalName+IIF(RIGHT(cCalName,1)='/','','/')+cUID+'.ics[/pre] где cOutput - это и есть вышеупомянутый ics файл

Петр: Dr. Oldwarez пишет: Притом, что ICSы генерятся У Вас программа генерирует невалидные ics файлы iCalendar Validator Problem! Found 1 warning Warnings Line length should not be longer than 75 characters near line # 9 Reference: RFC 5545 3.1. Content Lines Problem! Found 1 error Errors Missing VCALENDAR object near line # 1 Reference: RFC 5545 3.4 iCalendar Object

Петр: И второе - Вы не анализируете ответ сервера (-Dhead и т.д.), а то бы сразу увидели что-то вроде HTTP/1.1 100 Continue HTTP/1.1 415 Unsupported Media Type

Dr. Oldwarez: Петр пишет: У Вас программа генерирует невалидные ics файлы iCalendar Validator Problem! Found 1 warning Warnings Line length should not be longer than 75 characters near line # 9 Reference: RFC 5545 3.1. Content Lines Problem! Found 1 error Errors Missing VCALENDAR object near line # 1 Reference: RFC 5545 3.4 iCalendar Object Уже исправил Вот теперь [pre2] Results File Size: 13 lines, 323 bytes Number of events found: 1 Success! No errors found. Permalinks are available when validating by URL. You can use a permalink to send a link of the validation results page using e-mail or web posting. Show source data BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Qwwwwerty//UUUIIIOOOPP BEGIN:VEVENT UID:09a8e21b-fb27-49eb-9479-5b9c8ad1ba57 DTSTAMP:20210429T185200Z DTSTART:20210601T150000Z DTEND:20210601T190000Z SUMMARY:MYNAME: Birthday DESCRIPTION:My Birthday LOCATION:Pizzeria END:VEVENT END:VCALENDAR [/pre2] Но всё равно ничего в календарь не попадает. Скажите, пожалуйста, а как Dhead вывести тоже в отдельный файл отчёта, чтобы потом его проанализировать

Петр: Dr. Oldwarez пишет: а как Dhead вывести тоже Не Dhead, а -Dhead -D, --dump-header <filename> Write the received headers to <filename> Читайте файл с именем head (или назовите его так как Вам нужно) и анализируйте. Но всё равно ничего в календарь не попадает УРА!!! Заработало! Что же у Вас заработало?

Dr. Oldwarez: Петр пишет: Не Dhead, а -Dhead -D, --dump-header <filename> Write the received headers to <filename> Читайте файл с именем head (или назовите его так как Вам нужно) и анализируйте. И вот он, этот файл, который я назвал wtf.txt [pre2] HTTP/1.1 100 Continue HTTP/1.1 401 Unauthorized Date: Mon, 03 May 2021 04:31:57 GMT Server: Apache X-Powered-By: PHP/7.3.27 Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate Pragma: no-cache WWW-Authenticate: Basic realm="Horde DAV Server" Vary: Accept-Encoding Set-Cookie: PHPSESSID=bub17ffsgkd7249csku3c3brkt; path=/ X-Powered-By: PleskLin Transfer-Encoding: chunked Content-Type: application/xml; charset=utf-8 [/pre2] Я так понял, это что-то с авторизацией. Но ведь логин и пароль при ручном вводе подходят! И почему что-то там истекло 19 ноября 1981 года? В чём же проблема?

Петр: Dr. Oldwarez пишет: И почему что-то там истекло 19 ноября 1981 года? В чём же проблема? Какая там проблема .. It's an attempt to disable caching. The date is the birthday of the developer Sascha Schumann who added the code. From session.c: Authors: Sascha Schumann <sascha@schumann.cx> Andrei Zmievski <andrei@php.net> // ... CACHE_LIMITER_FUNC(private) { ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT"); CACHE_LIMITER(private_no_expire)(TSRMLS_C); } Этот заголовок (ещё `Pragma: no-cache`) добавляется автоматически, когда запускается сессия (`session_start()`) для отключения кэша. Дата, на самом деле, не важна, главное чтобы она была из прошлого, чтобы кэш считался невалидным. Curl кэширует запросы. Помните это.

Петр: Код робочей консольной программы для загрузки файлов календаря на сервер. Может кому-то будет интересно. [pre2] #include "hbmxml.ch" #include "ics.ch" #command ?C <message> => QOutClr( <message>, .T. ) #command ?! <message> => QOutClr( <message>, .F. ) #define DIR_UTILS ( hb_DirBase() + "utils" ) REQUEST HB_CODEPAGE_UTF8 MEMVAR mxml_error MEMVAR mxml_error_msg INIT PROCEDURE _OnInit() PUBLIC mxml_error PUBLIC mxml_error_msg FErase( hb_DirBase() + "_err.log" ) FErase( hb_DirBase() + "_header.log" ) FErase( hb_DirBase() + "_out.xml" ) // Проверка доступности cURL IF ! hb_FileExists( hb_DirSepAdd( DIR_UTILS ) + "curl.exe" ) ?! "#white+#Can't find #red+#curl.exe" ErrorLevel( 2 ) __Quit() ENDIF M->mxml_error := .F. M->mxml_error_msg := "" mxmlSetErrorCallback( @cb_error() ) RETURN /* */ PROCEDURE cb_error( cErrorMsg ) M->mxml_error_msg := cErrorMsg M->mxml_error := .T. RETURN /* */ FUNCTION cb_type( xmlNode ) LOCAL cType := mxmlElementGetAttr( xmlNode, "type" ) LOCAL nResult IF Empty( cType ) cType := mxmlGetElement( xmlNode ) ENDIF SWITCH Lower( cType ) CASE "s:exception" CASE "s:sabredav-version" nResult := MXML_TEXT EXIT CASE "s:message" nResult := MXML_OPAQUE EXIT OTHERWISE nResult := MXML_IGNORE EXIT ENDSWITCH RETURN nResult /* */ STATIC FUNCTION sf_GetEvent( aSource ) LOCAL nStart, nEnd, nLen, e1, e2 hb_default( @aSource, {} ) IF ! Empty( aSource ) nStart := nEnd := 0 FOR EACH e1 IN aSource IF e1[ ICS_PARAM ] = "BEGIN" FOR EACH e2 IN e1[ ICS_VALS ] IF hb_LeftEq( e2, "VEVENT" ) nStart := e1:__enumIndex() EXIT ENDIF NEXT ELSEIF e1[ ICS_PARAM ] = "END" FOR EACH e2 IN e1[ ICS_VALS ] IF hb_LeftEq( e2, "VEVENT" ) nEnd := e1:__enumIndex() EXIT ENDIF NEXT ENDIF IF nEnd > 0 EXIT ENDIF NEXT IF nStart != 0 .AND. nStart < nEnd nLen := nEnd - nStart + 1 RETURN ACopy( aSource, Array( nLen ), nStart, nLen ) ENDIF ENDIF RETURN {} /* */ STATIC FUNCTION sf_GetEventUID( aSource ) LOCAL nPos hb_default( @aSource, {} ) IF ! Empty( aSource ) nPos := AScan( aSource, {| e | e[ ICS_PARAM ] = "UID" } ) IF nPos > 0 RETURN aSource[ nPos ][ ICS_VALS ][ ICS_PARAM ] ENDIF ENDIF RETURN "" /* */ STATIC FUNCTION sf_GetError( cArg, cException, cMessage ) LOCAL xmlTree, xmlNode, xmlSubNode // Check arguments... IF ! HB_ISSTRING( cArg ) .OR. Empty( cArg ) RETURN .F. ENDIF xmlTree := iif( hb_LeftEq( cArg, "<" ), ; mxmlLoadString( NIL, cArg, @cb_type() ), mxmlLoadFile( NIL, cArg, @cb_type() ) ) IF M->mxml_error .OR. Empty( xmlTree ) RETURN .F. ENDIF xmlNode := mxmlFindElement( xmlTree, xmlTree, "d:error",,, MXML_DESCEND ) IF Empty( xmlNode ) mxmlDelete( xmlTree ) RETURN .F. ENDIF xmlSubNode := mxmlGetFirstChild( xmlNode ) DO WHILE ! Empty( xmlSubNode ) IF mxmlGetType( xmlSubNode ) == MXML_ELEMENT IF mxmlGetElement( xmlSubNode ) == "s:exception" cException := mxmlGetText( xmlSubNode ) ELSEIF mxmlGetElement( xmlSubNode ) == "s:message" cMessage := mxmlGetOpaque( xmlSubNode ) ENDIF ENDIF xmlSubNode := mxmlGetNextSibling( xmlSubNode ) ENDDO mxmlDelete( xmlTree ) RETURN .T. /* */ STATIC FUNCTION sf_GetHTTPStatusCode( cFile, cCode, cDesc ) LOCAL cStr := hb_MemoRead( cFile ) LOCAL aStr := hb_ATokens( cStr, hb_eol() ) LOCAL nAt := hb_RAScan( aStr, {| s | hb_LeftEq( s, 'HTTP' ) } ) IF nAt > 0 cStr := aStr[ nAt ] cCode := hb_tokenGet( cStr, 2, ' ' ) aStr := hb_ATokens( cStr, cCode ) cDesc := LTrim( aStr[ 2 ] ) RETURN .T. ENDIF RETURN .F. /* */ STATIC PROCEDURE Usage() OutStd( "Syntax: fput <file>" + hb_eol() + hb_eol() ) RETURN /* */ PROCEDURE Main( cFile ) LOCAL cStr LOCAL aEvent, w := 0, cUid LOCAL cOpt LOCAL cCmdLn := '%1$s\curl.exe -u "%2$s:%3$s" %4$s -T "%5$s" -X %6$s %7$s%8$s%9$s' LOCAL cUser := "b329767865754" LOCAL cPwd := "xk567vjh0t" LOCAL cCalDav := "https://dav.fruux.com/" LOCAL cHRef := "calendars/a3298166498/ae6b576a-981f-4697-8c00-ac043a96d075/" LOCAL cStdOut, cStdErr LOCAL cException := "", cMessage := "", cCode := "", cDescription := "" IF Empty( cFile ) Usage() ErrorLevel( 0 ) __Quit() ENDIF // Read iCalendar file cStr := hb_MemoRead( cFile ) // Get VEVENT aEvent := sf_GetEvent( IcsToArray2( cStr, @w ) ) IF w # 0 ?C "Warning:#white+# Missing newline at end of input" ENDIF // Get VEVENT UID cUid := sf_GetEventUID( aEvent ) IF Empty( cUid ) ?! "#white+#Do nothing for #red+#" + cFile ErrorLevel( 3 ) __Quit() ENDIF /* PUT /calendars/johndoe/home/somerandomstring.ics HTTP/1.1 Content-Type: text/calendar; charset=utf-8 BEGIN:VCALENDAR .... END:VCALENDAR */ cOpt := '--insecure --no-progress-meter ' cOpt += '--http1.1 ' cOpt += '--header "Content-Type: text/calendar; charset=utf-8" ' cOpt += '--dump-header _header.log ' cStr := RTrim( cUid ) + '.ics' cCmdLn := hb_StrFormat( cCmdLn, DIR_UTILS, cUser, cPwd, cOpt, cFile, "PUT", cCalDav, cHRef, cStr ) hb_processRun( cCmdLn, , @cStdOut, @cStdErr ) IF ! Empty( cStdErr ) hb_MemoWrit( hb_DirBase() + "_err.log", cStdErr ) ErrorLevel( 4 ) __Quit() ENDIF IF ! Empty( cStdOut ) hb_MemoWrit( hb_DirBase() + "_out.xml", cStdOut ) IF sf_GetHTTPStatusCode( '_header.log', @cCode, @cDescription ) ?C 'HTTP status code: #white+#' + cCode + '# (' + cDescription + ')' ENDIF IF sf_GetError( cStdOut, @cException, @cMessage ) ?! "#red+#" + cException + hb_eol() ?C "#white+#" + cMessage ErrorLevel( 5 ) __Quit() ENDIF IF M->mxml_error ?! "#red+#An error occured while parsing an XML document." + hb_eol() ?C "#white+#" + M->mxml_error_msg ErrorLevel( 6 ) __Quit() ENDIF ENDIF OutStd( "Done" + hb_eol() ) IF sf_GetHTTPStatusCode( '_header.log', @cCode, @cDescription ) ?C 'HTTP status code: #white+#' + cCode + '# (' + cDescription + ')' ENDIF RETURN [/pre2] P.S. Нет предела совершенству - это я знаю

Петр: Файл сборки [pre2] # fput.hbp -w3 #-es2 #-mt -I../../include -inc -workdir=.hbmk -ofput -strip -instpath=.\ #Libs -lhbmxml -lmxml -lics -L../../lib #Link with harbour-32-x64.dll #-shared fput.prg colorize.prg [/pre2]



полная версия страницы