PascalScript in Syncovery


Syncovery 8 adds the PascalScript language, allowing you to customize your profile’s behavior in many ways.

Please note that the syntax for many functions has changed since the Syncovery 8 release candidates. Any parameters named Profile have been removed.

To change a particular behavior, you need to write a hook function and write some code. In most cases, our tech support will write the code for you when we receive a feature request that is best implemented with a customized script. However, we will try to document the available hooks and functions fully so you can experiment on your own.

The script is specified in the profile via the “Pascal Script…” checkmark on the Job settings category tab sheet.

Useful ready-to-use scripts

The following scripts can be used as it is, just paste the script into the PascalScript dialog.

  • Convert Disallowed Characters for Windows
    This script allows you do have the disallowed characters /:\?|<>“* in file names on the left-hand side. The right-hand side can be Windows compliant storage such as a local NTFS drive.
  • Simple E-Mail Notifications
    This script simplifies the e-mail notifications and can be edited easily to customize your emails.

Available PascalScript Hooks

The following hooks are currently available. Additional hooks will be added as needed to fulfill customer requests.

  • OnDownloadComplete
  • OnGetCustomHeaders
  • OnGetProfilePathBeforeListing
  • OnGetProfilePathBeforeCopying
  • OnHttpPost
  • OnIncludeItem
  • OnProfileResults
  • OnMoveFileToDeletedFolder
  • OnReplaceFilenameLeftToRight
  • OnReplaceFilenameRightToLeft
  • OnScanFolder
  • OnSendEmail
  • OnUploadComplete
  • OnVolumeShadowComplete

Available PascalScript Functions

The following functions are available for you to call.

  • standard functions such as Pos, Copy, Length, Ord
  • function ConcatPath(const a,b:UnicodeString; const t: Int64):UnicodeString;
  • function ConcatPathWithDelim(const a,b,delim:UnicodeString):UnicodeString;
  • function ExtractFileName(const s: UnicodeString):UnicodeString;
  • function ExtractFilePath(const s: UnicodeString):UnicodeString;
  • function ExtractURLPartAfterServer(const s: UnicodeString):UnicodeString;
  • function ExtractFileExt(const s: UnicodeString):UnicodeString;
  • function ChangeFileExt(const s,t: UnicodeString):UnicodeString;
  • function FileExists(const FileName: UnicodeString):Boolean;
  • procedure Log(const s:UnicodeString);
  • function Execute(const s:UnicodeString; const TimeOutSeconds: Int64):Int64;
  • function GetProfileName:UnicodeString;
  • procedure SetProfileResult(const AResultText:UnicodeString);
  • function ConnFileExists(const Trav:Int64; const FileName: UnicodeString):Boolean;
  • function ConnCustomFTPCommand(const t:Int64; const ACommand: UnicodeString;const AOkResponse1,AOkResponse2,AOkResponse3:Integer;var ResponseText: UnicodeString):Integer;
  • function ConnRenameFile(const t:Int64; const AFromFileName,AToFileName: UnicodeString):Boolean;
  • function StringReplace(const Source, OldPattern, NewPattern: UnicodeString;const CaseSensitive:Boolean): UnicodeString;
  • function EncodeBase64(const s: UnicodeString):UnicodeString;
  • function DecodeBase64(const s: UnicodeString):UnicodeString;
  • function SimpleEncrypt(const s: UnicodeString):UnicodeString;
  • function SimpleDecrypt(const s: UnicodeString):UnicodeString;
  • function GetInput(const s: UnicodeString):UnicodeString;
  • function GetPassword(const s: UnicodeString):UnicodeString;
  • function ReadRegistryString(const Key,OptName:UnicodeString):UnicodeString;
  • procedure WriteRegistryString(const Key,OptName,Value:UnicodeString);
  • function GetProfileRunID:UnicodeString;
  • procedure ClearBody;
  • function GetBodyLine(const i:Integer):UnicodeString;
  • procedure SetBodyLine(const i:Integer;const s:UnicodeString);
  • procedure DeleteBodyLine(const i:Integer);
  • procedure AddBodyText(const s:UnicodeString);
  • function GetActionList:UnicodeString;
  • function GetProfileSettings:UnicodeString;
  • function Now:Double;
  • function NowUTC:Double;
  • function OffsetFromUTC:Double;
  • function TimeToStr(const DateTime: Double):UnicodeString;
  • function DateTimeToStr(const DateTime: Double):UnicodeString;
  • function DateToStr(const DateTime: Double):UnicodeString’;
  • function DateTimeToStrWithFormat(const DateTime: Double;const FormatString:UnicodeString):UnicodeString;
  • function OpenTextFile(const s:UnicodeString):Opaque;
  • function ReadLine(const F:Opaque):UnicodeString;
  • procedure CloseFile(const F:Opaque);

OnGetCustomHeaders Sample Script

This hook allows you to add custom HTTP headers to Amazon S3 requests. In future Syncovery versions, this feature can be added to other cloud storages and protocols (on customer request – just ask for it).

function OnGetCustomHeaders(const RelativePath: UnicodeString;const
        URL:AnsiString;var MIMEType, Headers: AnsiString;const Connector:
        Opaque):Boolean;
var strDate:string;
begin
  Result:=true;
  Headers:='Cache-Control: 10';
  Log('');
  Log('Headers Added to '+RelativePath);
  Log(Headers);
  Log('');
  end;

OnIncludeItem Sample Scripts

The OnIncludeItem hook is called individually for each side of the synchronization. The isRightSide parameter indicates which side we are currently looking at.

The following script serves to exclude files without filename extension. Such an exclusion is not possible via the Exclusion Masks.

function OnIncludeItem(const FileName, RelativePath: UnicodeString;
        const isRightSide, isFolder:Boolean;
        const FileSize:Int64; const FileAttr:LongWord;
        const Connector: Opaque):Boolean;
begin
  Result:=isFolder or (Pos('.',FileName)>0);
  end;

The second example for OnIncludeItem will only process subfolders that contain the file READY.toprocess, as well as any subfolders that exist on the right-hand side.

function OnIncludeItem(const FileName, RelativePath: UnicodeString;
        const isRightSide, isFolder:Boolean;
        const FileSize:Int64; const FileAttr:LongWord;
        const Connector: Opaque):Boolean;
begin
  Result:=isRightSide or not isFolder or
    ConnFileExists(Connector,ConcatPath(ConcatPath(LeftBasePath,RelativePath,Connector),FileName,Connector)+
    '\READY.toprocess');
  end;

OnScanFolder Sample Script

This is probably a better way to lookfor ‘READY.toprocess’. The OnScanFolder hook is called just before the folder would be scanned, and knowledge of both sides can be used in the hook.

function OnScanFolder(const FolderLevel: Integer;
        const RelativePath, LeftCompletePath, RightCompletePath: UnicodeString;
        const LeftExists,RightExists:Boolean;
        const LeftConnector, RightConnector: Opaque):Boolean;
begin
  Result:=RightExists or ConnFileExists(LeftConnector,LeftCompletePath+'\READY.toprocess');
  end;

OnReplaceFilenameLeftToRight Sample Script

This script will rename files when the file is copied from left to right. In our example, ‘-draft’ is added before the filename extension.

function OnReplaceFilenameLeftToRight(const FileName: UnicodeString;
        const isFolder: Boolean):UnicodeString;
begin
  if isFolder then
    Result:=FileName
  else
    Result:=ChangeFileExt(FileName,'')+'-draft'+ExtractFileExt(FileName);
  end;

OnReplaceFilenameRightToLeft Sample Script

If you do a two-way sync, and new files might appear on the right-hand side, we also need a way to rename in the other direction. This sample script removes the ‘-draft’ insert from the names.

function OnReplaceFilenameRightToLeft(const FileName: UnicodeString;
        const isFolder: Boolean):UnicodeString;
var ToFind:UnicodeString;
    P:Integer;
begin
  if isFolder then
    Result:=FileName
  else begin
    ToFind:=''-draft''+ExtractFileExt(FileName);
    p:=Pos(ToFind,FileName);
    if p>0 then
      Result:=Copy(FileName,1,p-1)+ExtractFileExt(FileName)
    else
      Result:=FileName
    end;
  end;

OnUploadComplete Sample Script

This script will set permissions for files uploaded via FTP to 777.

function OnUploadComplete(const FileName, LocalFilePath, CompleteURL: UnicodeString;
        const isRightSide:Boolean;
        const FileSize:Int64;
        const Connector: Opaque):Boolean;
var CmdRes:Int64;
    ResponseText:UnicodeString;
begin
  CmdRes:=ConnCustomFTPCommand(Connector,'SITE CHMOD 777 '+FileName,200,200,200,ResponseText);
  Log('Set Permissions for '+FileName+': '+ResponseText);
  Result:=true;
  end;

OnDownloadComplete Sample Script

This script will rename downloaded files by adding an additional “.downloaded” extension.

function OnDownloadComplete(const FileName, CompleteURL, LocalFilePath: UnicodeString;
        const isRightSide:Boolean;
        const FileSize:Int64;
        const Connector: Opaque):Boolean;
begin
  if ConnRenameFile(Connector,CompleteURL,FileName+'.downloaded') then
    Log('Renamed '+FileName+' to '+FileName+'.downloaded')
  else
    Log('Rename failed: '+FileName+' to '+FileName+'.downloaded');
  Result:=true;
  end;

OnVolumeShadowComplete Sample Script

This script will execute an external command (batch or CMD file) just after a volume shadow has been created.

function OnVolumeShadowComplete(const Volume,ShadowPath:UnicodeString):Boolean;
begin
  Result:=Execute('C:\Tests\test.bat',120)=0;
  end;